Line data Source code
1 : // Copyright Kevlin Henney, 2000-2005.
2 : // Copyright Alexander Nasonov, 2006-2010.
3 : // Copyright Antony Polukhin, 2011-2025.
4 : //
5 : // Distributed under the Boost Software License, Version 1.0. (See
6 : // accompanying file LICENSE_1_0.txt or copy at
7 : // http://www.boost.org/LICENSE_1_0.txt)
8 : //
9 : // what: lexical_cast custom keyword cast
10 : // who: contributed by Kevlin Henney,
11 : // enhanced with contributions from Terje Slettebo,
12 : // with additional fixes and suggestions from Gennaro Prota,
13 : // Beman Dawes, Dave Abrahams, Daryle Walker, Peter Dimov,
14 : // Alexander Nasonov, Antony Polukhin, Justin Viiret, Michael Hofmann,
15 : // Cheng Yang, Matthew Bradbury, David W. Birdsall, Pavel Korzh and other Boosters
16 : // when: November 2000, March 2003, June 2005, June 2006, March 2011 - 2014, Nowember 2016
17 :
18 : #ifndef BOOST_LEXICAL_CAST_DETAIL_CONVERTER_LEXICAL_STREAMS_HPP
19 : #define BOOST_LEXICAL_CAST_DETAIL_CONVERTER_LEXICAL_STREAMS_HPP
20 :
21 : #include <boost/config.hpp>
22 : #ifdef BOOST_HAS_PRAGMA_ONCE
23 : # pragma once
24 : #endif
25 :
26 :
27 : #if defined(BOOST_NO_STRINGSTREAM) || defined(BOOST_NO_STD_WSTRING)
28 : #define BOOST_LCAST_NO_WCHAR_T
29 : #endif
30 :
31 : #include <cstddef>
32 : #include <string>
33 : #include <cstring>
34 : #include <cstdio>
35 : #include <type_traits>
36 : #include <boost/limits.hpp>
37 : #include <boost/detail/lcast_precision.hpp>
38 : #include <boost/lexical_cast/detail/type_traits.hpp>
39 : #include <boost/config/workaround.hpp>
40 : #include <boost/core/snprintf.hpp>
41 :
42 : #ifndef BOOST_NO_STD_LOCALE
43 : # include <locale>
44 : #else
45 : # ifndef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE
46 : // Getting error at this point means, that your STL library is old/lame/misconfigured.
47 : // If nothing can be done with STL library, define BOOST_LEXICAL_CAST_ASSUME_C_LOCALE,
48 : // but beware: lexical_cast will understand only 'C' locale delimeters and thousands
49 : // separators.
50 : # error "Unable to use <locale> header. Define BOOST_LEXICAL_CAST_ASSUME_C_LOCALE to force "
51 : # error "boost::lexical_cast to use only 'C' locale during conversions."
52 : # endif
53 : #endif
54 :
55 : #ifdef BOOST_NO_STRINGSTREAM
56 : #include <strstream>
57 : #else
58 : #include <sstream>
59 : #endif
60 :
61 : #include <boost/lexical_cast/detail/buffer_view.hpp>
62 : #include <boost/lexical_cast/detail/lcast_char_constants.hpp>
63 : #include <boost/lexical_cast/detail/lcast_unsigned_converters.hpp>
64 : #include <boost/lexical_cast/detail/lcast_basic_unlockedbuf.hpp>
65 : #include <boost/lexical_cast/detail/inf_nan.hpp>
66 :
67 : #include <istream>
68 :
69 : #include <array>
70 :
71 : #include <boost/container/container_fwd.hpp>
72 : #ifndef BOOST_NO_CWCHAR
73 : # include <cwchar>
74 : #endif
75 :
76 : // Forward declarations
77 : namespace boost {
78 : template<class T, std::size_t N>
79 : class array;
80 : template<class IteratorT>
81 : class iterator_range;
82 :
83 : // forward declaration of boost::basic_string_view from Utility
84 : template<class Ch, class Tr> class basic_string_view;
85 : }
86 :
87 : namespace boost { namespace detail { namespace lcast {
88 :
89 : template <typename T>
90 : struct exact {
91 : static_assert(!std::is_const<T>::value, "");
92 : static_assert(!std::is_reference<T>::value, "");
93 :
94 : const T& payload;
95 : };
96 :
97 : template< class CharT // a result of widest_char transformation
98 : , class Traits
99 : , std::size_t CharacterBufferSize
100 : >
101 : class optimized_src_stream {
102 : CharT buffer[CharacterBufferSize];
103 :
104 : // After the `stream_in(` finishes, `[start, finish)` is
105 : // the range to output by `operator >>`
106 : const CharT* start;
107 : const CharT* finish;
108 : public:
109 : optimized_src_stream(optimized_src_stream&&) = delete;
110 : optimized_src_stream(const optimized_src_stream&) = delete;
111 : optimized_src_stream& operator=(optimized_src_stream&&) = delete;
112 : optimized_src_stream& operator=(const optimized_src_stream&) = delete;
113 :
114 30000 : optimized_src_stream() noexcept
115 15000 : : start(buffer)
116 15000 : , finish(buffer + CharacterBufferSize)
117 30000 : {}
118 :
119 15000 : const CharT* cbegin() const noexcept {
120 15000 : return start;
121 : }
122 :
123 15000 : const CharT* cend() const noexcept {
124 15000 : return finish;
125 : }
126 :
127 : private:
128 : bool shl_char(CharT ch) noexcept {
129 : Traits::assign(buffer[0], ch);
130 : finish = start + 1;
131 : return true;
132 : }
133 :
134 : #ifndef BOOST_LCAST_NO_WCHAR_T
135 : template <class T>
136 : bool shl_char(T ch) {
137 : static_assert(sizeof(T) <= sizeof(CharT),
138 : "boost::lexical_cast does not support narrowing of char types."
139 : "Use boost::locale instead" );
140 : #ifndef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE
141 : std::locale loc;
142 : CharT const w = BOOST_USE_FACET(std::ctype<CharT>, loc).widen(ch);
143 : #else
144 : CharT const w = static_cast<CharT>(ch);
145 : #endif
146 : Traits::assign(buffer[0], w);
147 : finish = start + 1;
148 : return true;
149 : }
150 : #endif
151 :
152 : bool shl_char_array(CharT const* str_value) noexcept {
153 : start = str_value;
154 : finish = start + Traits::length(str_value);
155 : return true;
156 : }
157 :
158 : bool shl_char_array_limited(CharT const* str, std::size_t max_size) noexcept {
159 : start = str;
160 : finish = start;
161 : const auto zero = Traits::to_char_type(0);
162 : while (finish < start + max_size && zero != *finish) {
163 : ++ finish;
164 : }
165 : return true;
166 : }
167 :
168 : template <class T>
169 : inline bool shl_unsigned(const T n) {
170 : CharT* tmp_finish = buffer + CharacterBufferSize;
171 : start = lcast_put_unsigned<Traits, T, CharT>(n, tmp_finish).convert();
172 : finish = tmp_finish;
173 : return true;
174 : }
175 :
176 : template <class T>
177 : inline bool shl_signed(const T n) {
178 : CharT* tmp_finish = buffer + CharacterBufferSize;
179 : typedef typename boost::detail::lcast::make_unsigned<T>::type utype;
180 : CharT* tmp_start = lcast_put_unsigned<Traits, utype, CharT>(lcast_to_unsigned(n), tmp_finish).convert();
181 : if (n < 0) {
182 : --tmp_start;
183 : CharT const minus = lcast_char_constants<CharT>::minus;
184 : Traits::assign(*tmp_start, minus);
185 : }
186 : start = tmp_start;
187 : finish = tmp_finish;
188 : return true;
189 : }
190 :
191 : bool shl_real_type(lcast::exact<float> val, char* begin) {
192 : const double val_as_double = static_cast<double>(val.payload);
193 : finish = start +
194 : boost::core::snprintf(begin, CharacterBufferSize,
195 : "%.*g", static_cast<int>(boost::detail::lcast_precision<float>::value), val_as_double);
196 : return finish > start;
197 : }
198 :
199 : bool shl_real_type(lcast::exact<double> val, char* begin) {
200 : finish = start +
201 : boost::core::snprintf(begin, CharacterBufferSize,
202 : "%.*g", static_cast<int>(boost::detail::lcast_precision<double>::value), val.payload);
203 : return finish > start;
204 : }
205 :
206 : #ifndef __MINGW32__
207 : bool shl_real_type(lcast::exact<long double> val, char* begin) {
208 : finish = start +
209 : boost::core::snprintf(begin, CharacterBufferSize,
210 : "%.*Lg", static_cast<int>(boost::detail::lcast_precision<long double>::value), val.payload );
211 : return finish > start;
212 : }
213 : #else
214 : bool shl_real_type(lcast::exact<long double> val, char* begin) {
215 : return shl_real_type(lcast::exact<double>{static_cast<double>(val.payload)}, begin);
216 : }
217 : #endif
218 :
219 : #if !defined(BOOST_LCAST_NO_WCHAR_T)
220 : bool shl_real_type(lcast::exact<float> val, wchar_t* begin) {
221 : const double val_as_double = static_cast<double>(val.payload);
222 : finish = start + boost::core::swprintf(
223 : begin, CharacterBufferSize, L"%.*g",
224 : static_cast<int>(boost::detail::lcast_precision<float>::value),
225 : val_as_double
226 : );
227 : return finish > start;
228 : }
229 :
230 : bool shl_real_type(lcast::exact<double> val, wchar_t* begin) {
231 : finish = start + boost::core::swprintf(
232 : begin, CharacterBufferSize, L"%.*g",
233 : static_cast<int>(boost::detail::lcast_precision<double>::value),
234 : val.payload
235 : );
236 : return finish > start;
237 : }
238 :
239 : bool shl_real_type(lcast::exact<long double> val, wchar_t* begin) {
240 : finish = start + boost::core::swprintf(
241 : begin, CharacterBufferSize, L"%.*Lg",
242 : static_cast<int>(boost::detail::lcast_precision<long double>::value),
243 : val.payload
244 : );
245 : return finish > start;
246 : }
247 : #endif
248 : public:
249 : template <class C>
250 : using enable_if_compatible_char_t = typename std::enable_if<
251 : std::is_same<const C, const CharT>::value || (
252 : std::is_same<const char, const CharT>::value && (
253 : std::is_same<const C, const unsigned char>::value ||
254 : std::is_same<const C, const signed char>::value
255 : )
256 : ), bool
257 : >::type;
258 :
259 : template<class CharTraits, class Alloc>
260 15000 : bool stream_in(lcast::exact<std::basic_string<CharT,CharTraits,Alloc>> x) noexcept {
261 15000 : start = x.payload.data();
262 15000 : finish = start + x.payload.length();
263 15000 : return true;
264 : }
265 :
266 : template<class CharTraits, class Alloc>
267 : bool stream_in(lcast::exact<boost::container::basic_string<CharT,CharTraits,Alloc>> x) noexcept {
268 : start = x.payload.data();
269 : finish = start + x.payload.length();
270 : return true;
271 : }
272 :
273 : bool stream_in(lcast::exact<bool> x) noexcept {
274 : CharT const czero = lcast_char_constants<CharT>::zero;
275 : Traits::assign(buffer[0], Traits::to_char_type(czero + x.payload));
276 : finish = start + 1;
277 : return true;
278 : }
279 :
280 : bool stream_in(lcast::exact<boost::conversion::detail::buffer_view<CharT>> x) noexcept {
281 : start = x.payload.begin;
282 : finish = x.payload.end;
283 : return true;
284 : }
285 :
286 : template <class C>
287 : enable_if_compatible_char_t<C>
288 : stream_in(lcast::exact<boost::iterator_range<C*>> x) noexcept {
289 : auto buf = boost::conversion::detail::make_buffer_view(x.payload.begin(), x.payload.end());
290 : return stream_in(lcast::exact<decltype(buf)>{buf});
291 : }
292 :
293 : bool stream_in(lcast::exact<char> x) { return shl_char(x.payload); }
294 : bool stream_in(lcast::exact<unsigned char> x) { return shl_char(static_cast<char>(x.payload)); }
295 : bool stream_in(lcast::exact<signed char> x) { return shl_char(static_cast<char>(x.payload)); }
296 :
297 : #if !defined(BOOST_NO_INTRINSIC_WCHAR_T)
298 : template <class C>
299 : typename std::enable_if<boost::detail::is_character<C>::value, bool>::type
300 : stream_in(lcast::exact<C> x) { return shl_char(x.payload); }
301 : #endif
302 :
303 : template <class Type>
304 : enable_if_compatible_char_t<Type>
305 : stream_in(lcast::exact<Type*> x) { return shl_char_array(reinterpret_cast<CharT const*>(x.payload)); }
306 :
307 : template <class Type>
308 : typename std::enable_if<!std::is_floating_point<Type>::value && boost::detail::lcast::is_signed<Type>::value && !std::is_enum<Type>::value, bool>::type
309 : stream_in(lcast::exact<Type> x) { return shl_signed(x.payload); }
310 :
311 : template <class Type>
312 : typename std::enable_if<boost::detail::lcast::is_unsigned<Type>::value && !std::is_enum<Type>::value, bool>::type
313 : stream_in(lcast::exact<Type> x) { return shl_unsigned(x.payload); }
314 :
315 : template <class Type>
316 : auto stream_in(lcast::exact<Type> x) -> decltype(shl_real_type(x, buffer)) {
317 : const CharT* inf_nan = detail::get_inf_nan(x.payload, CharT());
318 : if (inf_nan) {
319 : start = inf_nan;
320 : finish = start + Traits::length(inf_nan);
321 : return true;
322 : }
323 : return shl_real_type(x, buffer);
324 : }
325 :
326 : template <class C, std::size_t N>
327 : enable_if_compatible_char_t<C>
328 : stream_in(lcast::exact<boost::array<C, N>> x) noexcept {
329 : return shl_char_array_limited(reinterpret_cast<const CharT*>(x.payload.data()), N);
330 : }
331 :
332 : template <class C, std::size_t N>
333 : enable_if_compatible_char_t<C>
334 : stream_in(lcast::exact<std::array<C, N>> x) noexcept {
335 : return shl_char_array_limited(reinterpret_cast<const CharT*>(x.payload.data()), N);
336 : }
337 :
338 : #ifndef BOOST_NO_CXX17_HDR_STRING_VIEW
339 : template <class C, class CharTraits>
340 : enable_if_compatible_char_t<C>
341 : stream_in(lcast::exact<std::basic_string_view<C, CharTraits>> x) noexcept {
342 : start = reinterpret_cast<const CharT*>(x.payload.data());
343 : finish = start + x.payload.size();
344 : return true;
345 : }
346 : #endif
347 : template <class C, class CharTraits>
348 : enable_if_compatible_char_t<C>
349 : stream_in(lcast::exact<boost::basic_string_view<C, CharTraits>> x) noexcept {
350 : start = reinterpret_cast<const CharT*>(x.payload.data());
351 : finish = start + x.payload.size();
352 : return true;
353 : }
354 : };
355 :
356 :
357 : template <class CharT, class Traits>
358 : class ios_src_stream {
359 : typedef detail::lcast::out_stream_t<CharT, Traits> deduced_out_stream_t;
360 : typedef detail::lcast::stringbuffer_t<CharT, Traits> deduced_out_buffer_t;
361 :
362 : deduced_out_buffer_t out_buffer;
363 : deduced_out_stream_t out_stream;
364 :
365 : const CharT* start = nullptr;
366 : const CharT* finish = nullptr;
367 : public:
368 : ios_src_stream(ios_src_stream&&) = delete;
369 : ios_src_stream(const ios_src_stream&) = delete;
370 : ios_src_stream& operator=(ios_src_stream&&) = delete;
371 : ios_src_stream& operator=(const ios_src_stream&) = delete;
372 :
373 : ios_src_stream(): out_buffer(), out_stream(&out_buffer) {}
374 :
375 : const CharT* cbegin() const noexcept {
376 : return start;
377 : }
378 :
379 : const CharT* cend() const noexcept {
380 : return finish;
381 : }
382 : private:
383 : const deduced_out_buffer_t* get_rdbuf() const {
384 : return static_cast<deduced_out_buffer_t*>(
385 : out_stream.rdbuf()
386 : );
387 : }
388 :
389 : template<typename InputStreamable>
390 : bool shl_input_streamable(InputStreamable& input) {
391 : #if defined(BOOST_NO_STRINGSTREAM) || defined(BOOST_NO_STD_LOCALE)
392 : // If you have compilation error at this point, than your STL library
393 : // does not support such conversions. Try updating it.
394 : static_assert(std::is_same<char, CharT>::value, "");
395 : #endif
396 :
397 : #ifndef BOOST_NO_EXCEPTIONS
398 : out_stream.exceptions(std::ios::badbit);
399 : try {
400 : #endif
401 : bool const result = !(out_stream << input).fail();
402 : const auto* const p = get_rdbuf();
403 : start = p->pbase();
404 : finish = p->pptr();
405 : return result;
406 : #ifndef BOOST_NO_EXCEPTIONS
407 : } catch (const ::std::ios_base::failure& /*f*/) {
408 : return false;
409 : }
410 : #endif
411 : }
412 :
413 : template <class T>
414 : bool shl_char_array(T const* str_value) {
415 : static_assert(sizeof(T) <= sizeof(CharT),
416 : "boost::lexical_cast does not support narrowing of char types."
417 : "Use boost::locale instead" );
418 : return shl_input_streamable(str_value);
419 : }
420 :
421 : template <class T>
422 : bool shl_real(T val) {
423 : const CharT* inf_nan = detail::get_inf_nan(val, CharT());
424 : if (inf_nan) {
425 : start = inf_nan;
426 : finish = start + Traits::length(inf_nan);
427 : return true;
428 : }
429 :
430 : boost::detail::lcast_set_precision(out_stream, &val);
431 : return shl_input_streamable(val);
432 : }
433 :
434 : public:
435 : template <class Type>
436 : typename std::enable_if<boost::detail::is_character<Type>::value && sizeof(char) == sizeof(Type), bool>::type
437 : stream_in(lcast::exact<const Type*> x) { return shl_char_array(reinterpret_cast<char const*>(x.payload)); }
438 :
439 : template <class Type>
440 : typename std::enable_if<boost::detail::is_character<Type>::value && sizeof(char) != sizeof(Type), bool>::type
441 : stream_in(lcast::exact<const Type*> x) { return shl_char_array(x.payload); }
442 :
443 : bool stream_in(lcast::exact<float> x) { return shl_real(x.payload); }
444 : bool stream_in(lcast::exact<double> x) { return shl_real(x.payload); }
445 : bool stream_in(lcast::exact<long double> x) {
446 : #ifndef __MINGW32__
447 : return shl_real(x.payload);
448 : #else
449 : return shl_real(static_cast<double>(x.payload));
450 : #endif
451 : }
452 :
453 : template <class C>
454 : typename std::enable_if<boost::detail::is_character<C>::value, bool>::type
455 : stream_in(lcast::exact<iterator_range<C*>> x) noexcept {
456 : auto buf = boost::conversion::detail::make_buffer_view(x.payload.begin(), x.payload.end());
457 : return stream_in(lcast::exact<decltype(buf)>{buf});
458 : }
459 :
460 : template <class C>
461 : typename std::enable_if<boost::detail::is_character<C>::value, bool>::type
462 : stream_in(lcast::exact<iterator_range<const C*>> x) noexcept {
463 : auto buf = boost::conversion::detail::make_buffer_view(x.payload.begin(), x.payload.end());
464 : return stream_in(lcast::exact<decltype(buf)>{buf});
465 : }
466 :
467 : template <class InStreamable>
468 : bool stream_in(lcast::exact<InStreamable> x) { return shl_input_streamable(x.payload); }
469 : };
470 :
471 :
472 : template <class CharT, class Traits>
473 : class to_target_stream {
474 : //`[start, finish)` is the range to output by `operator >>`
475 : const CharT* start;
476 : const CharT* const finish;
477 :
478 : public:
479 : to_target_stream(to_target_stream&&) = delete;
480 : to_target_stream(const to_target_stream&) = delete;
481 : to_target_stream& operator=(to_target_stream&&) = delete;
482 : to_target_stream& operator=(const to_target_stream&) = delete;
483 :
484 30000 : to_target_stream(const CharT* begin, const CharT* end) noexcept
485 15000 : : start(begin)
486 15000 : , finish(end)
487 30000 : {}
488 :
489 : private:
490 : template <typename Type>
491 : #if defined(__clang__) && (__clang_major__ > 3 || __clang_minor__ > 6)
492 : __attribute__((no_sanitize("unsigned-integer-overflow")))
493 : #endif
494 0 : bool shr_unsigned(Type& output) {
495 0 : if (start == finish) return false;
496 0 : CharT const minus = lcast_char_constants<CharT>::minus;
497 0 : CharT const plus = lcast_char_constants<CharT>::plus;
498 0 : bool const has_minus = Traits::eq(minus, *start);
499 :
500 : /* We won`t use `start' any more, so no need in decrementing it after */
501 0 : if (has_minus || Traits::eq(plus, *start)) {
502 0 : ++start;
503 0 : }
504 :
505 0 : bool const succeed = lcast_ret_unsigned<Traits, Type, CharT>(output, start, finish).convert();
506 :
507 0 : if (has_minus) {
508 0 : output = static_cast<Type>(0u - output);
509 0 : }
510 :
511 0 : return succeed;
512 0 : }
513 :
514 : template <typename Type>
515 : #if defined(__clang__) && (__clang_major__ > 3 || __clang_minor__ > 6)
516 : __attribute__((no_sanitize("unsigned-integer-overflow")))
517 : #endif
518 15000 : bool shr_signed(Type& output) {
519 15000 : if (start == finish) return false;
520 15000 : CharT const minus = lcast_char_constants<CharT>::minus;
521 15000 : CharT const plus = lcast_char_constants<CharT>::plus;
522 : typedef typename boost::detail::lcast::make_unsigned<Type>::type utype;
523 15000 : utype out_tmp = 0;
524 15000 : bool const has_minus = Traits::eq(minus, *start);
525 :
526 : /* We won`t use `start' any more, so no need in decrementing it after */
527 15000 : if (has_minus || Traits::eq(plus, *start)) {
528 0 : ++start;
529 0 : }
530 :
531 15000 : bool succeed = lcast_ret_unsigned<Traits, utype, CharT>(out_tmp, start, finish).convert();
532 15000 : if (has_minus) {
533 0 : utype const comp_val = (static_cast<utype>(1) << std::numeric_limits<Type>::digits);
534 0 : succeed = succeed && out_tmp<=comp_val;
535 0 : output = static_cast<Type>(0u - out_tmp);
536 0 : } else {
537 15000 : utype const comp_val = static_cast<utype>((std::numeric_limits<Type>::max)());
538 15000 : succeed = succeed && out_tmp<=comp_val;
539 15000 : output = static_cast<Type>(out_tmp);
540 : }
541 15000 : return succeed;
542 15000 : }
543 :
544 : template<typename InputStreamable>
545 : bool shr_using_base_class(InputStreamable& output)
546 : {
547 : static_assert(
548 : !std::is_pointer<InputStreamable>::value,
549 : "boost::lexical_cast can not convert to pointers"
550 : );
551 :
552 : #if defined(BOOST_NO_STRINGSTREAM) || defined(BOOST_NO_STD_LOCALE)
553 : static_assert(std::is_same<char, CharT>::value,
554 : "boost::lexical_cast can not convert, because your STL library does not "
555 : "support such conversions. Try updating it."
556 : );
557 : #endif
558 :
559 : #if defined(BOOST_NO_STRINGSTREAM)
560 : std::istrstream stream(start, static_cast<std::istrstream::streamsize>(finish - start));
561 : #else
562 : typedef detail::lcast::buffer_t<CharT, Traits> buffer_t;
563 : buffer_t buf;
564 : // Usually `istream` and `basic_istream` do not modify
565 : // content of buffer; `buffer_t` assures that this is true
566 : buf.setbuf(const_cast<CharT*>(start), static_cast<typename buffer_t::streamsize>(finish - start));
567 : #if defined(BOOST_NO_STD_LOCALE)
568 : std::istream stream(&buf);
569 : #else
570 : std::basic_istream<CharT, Traits> stream(&buf);
571 : #endif // BOOST_NO_STD_LOCALE
572 : #endif // BOOST_NO_STRINGSTREAM
573 :
574 : #ifndef BOOST_NO_EXCEPTIONS
575 : stream.exceptions(std::ios::badbit);
576 : try {
577 : #endif
578 : stream.unsetf(std::ios::skipws);
579 : boost::detail::lcast_set_precision(stream, static_cast<InputStreamable*>(0));
580 :
581 : return (stream >> output)
582 : && (stream.get() == Traits::eof());
583 :
584 : #ifndef BOOST_NO_EXCEPTIONS
585 : } catch (const ::std::ios_base::failure& /*f*/) {
586 : return false;
587 : }
588 : #endif
589 : }
590 :
591 : template<class T>
592 : inline bool shr_xchar(T& output) noexcept {
593 : static_assert(sizeof(CharT) == sizeof(T),
594 : "boost::lexical_cast does not support narrowing of character types."
595 : "Use boost::locale instead" );
596 : bool const ok = (finish - start == 1);
597 : if (ok) {
598 : CharT out;
599 : Traits::assign(out, *start);
600 : output = static_cast<T>(out);
601 : }
602 : return ok;
603 : }
604 :
605 : template <std::size_t N, class ArrayT>
606 : bool shr_std_array(ArrayT& output) noexcept {
607 : const std::size_t size = static_cast<std::size_t>(finish - start);
608 : if (size > N - 1) { // `-1` because we need to store \0 at the end
609 : return false;
610 : }
611 :
612 : std::memcpy(&output[0], start, size * sizeof(CharT));
613 : output[size] = Traits::to_char_type(0);
614 : return true;
615 : }
616 :
617 : public:
618 0 : bool stream_out(unsigned short& output) { return shr_unsigned(output); }
619 : bool stream_out(unsigned int& output) { return shr_unsigned(output); }
620 : bool stream_out(unsigned long int& output) { return shr_unsigned(output); }
621 7500 : bool stream_out(short& output) { return shr_signed(output); }
622 : bool stream_out(int& output) { return shr_signed(output); }
623 : bool stream_out(long int& output) { return shr_signed(output); }
624 : #if defined(BOOST_HAS_LONG_LONG)
625 : bool stream_out(boost::ulong_long_type& output) { return shr_unsigned(output); }
626 7500 : bool stream_out(boost::long_long_type& output) { return shr_signed(output); }
627 : #elif defined(BOOST_HAS_MS_INT64)
628 : bool stream_out(unsigned __int64& output) { return shr_unsigned(output); }
629 : bool stream_out(__int64& output) { return shr_signed(output); }
630 : #endif
631 :
632 : #ifdef BOOST_HAS_INT128
633 : bool stream_out(boost::uint128_type& output) { return shr_unsigned(output); }
634 : bool stream_out(boost::int128_type& output) { return shr_signed(output); }
635 : #endif
636 :
637 : bool stream_out(char& output) { return shr_xchar(output); }
638 : bool stream_out(unsigned char& output) { return shr_xchar(output); }
639 : bool stream_out(signed char& output) { return shr_xchar(output); }
640 : #if !defined(BOOST_LCAST_NO_WCHAR_T) && !defined(BOOST_NO_INTRINSIC_WCHAR_T)
641 : bool stream_out(wchar_t& output) { return shr_xchar(output); }
642 : #endif
643 : #if !defined(BOOST_NO_CXX11_CHAR16_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS)
644 : bool stream_out(char16_t& output) { return shr_xchar(output); }
645 : #endif
646 : #if !defined(BOOST_NO_CXX11_CHAR32_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS)
647 : bool stream_out(char32_t& output) { return shr_xchar(output); }
648 : #endif
649 : template<class CharTraits, class Alloc>
650 : bool stream_out(std::basic_string<CharT,CharTraits,Alloc>& str) {
651 : str.assign(start, finish); return true;
652 : }
653 :
654 : template<class CharTraits, class Alloc>
655 : bool stream_out(boost::container::basic_string<CharT,CharTraits,Alloc>& str) {
656 : str.assign(start, finish); return true;
657 : }
658 :
659 : template <class C, std::size_t N>
660 : bool stream_out(std::array<C, N>& output) noexcept {
661 : static_assert(sizeof(C) == sizeof(CharT), "");
662 : return shr_std_array<N>(output);
663 : }
664 :
665 : template <class C, std::size_t N>
666 : bool stream_out(boost::array<C, N>& output) noexcept {
667 : static_assert(sizeof(C) == sizeof(CharT), "");
668 : return shr_std_array<N>(output);
669 : }
670 :
671 : bool stream_out(bool& output) noexcept {
672 : output = false; // Suppress warning about uninitalized variable
673 :
674 : if (start == finish) return false;
675 : CharT const zero = lcast_char_constants<CharT>::zero;
676 : CharT const plus = lcast_char_constants<CharT>::plus;
677 : CharT const minus = lcast_char_constants<CharT>::minus;
678 :
679 : const CharT* const dec_finish = finish - 1;
680 : output = Traits::eq(*dec_finish, zero + 1);
681 : if (!output && !Traits::eq(*dec_finish, zero)) {
682 : return false; // Does not ends on '0' or '1'
683 : }
684 :
685 : if (start == dec_finish) return true;
686 :
687 : // We may have sign at the beginning
688 : if (Traits::eq(plus, *start) || (Traits::eq(minus, *start) && !output)) {
689 : ++ start;
690 : }
691 :
692 : // Skipping zeros
693 : while (start != dec_finish) {
694 : if (!Traits::eq(zero, *start)) {
695 : return false; // Not a zero => error
696 : }
697 :
698 : ++ start;
699 : }
700 :
701 : return true;
702 : }
703 :
704 : private:
705 : // Not optimised converter
706 : template <class T>
707 : bool float_types_converter_internal(T& output) {
708 : if (parse_inf_nan(start, finish, output)) return true;
709 : bool const return_value = shr_using_base_class(output);
710 :
711 : /* Some compilers and libraries successfully
712 : * parse 'inf', 'INFINITY', '1.0E', '1.0E-'...
713 : * We are trying to provide a unified behaviour,
714 : * so we just forbid such conversions (as some
715 : * of the most popular compilers/libraries do)
716 : * */
717 : CharT const minus = lcast_char_constants<CharT>::minus;
718 : CharT const plus = lcast_char_constants<CharT>::plus;
719 : CharT const capital_e = lcast_char_constants<CharT>::capital_e;
720 : CharT const lowercase_e = lcast_char_constants<CharT>::lowercase_e;
721 : if ( return_value &&
722 : (
723 : Traits::eq(*(finish-1), lowercase_e) // 1.0e
724 : || Traits::eq(*(finish-1), capital_e) // 1.0E
725 : || Traits::eq(*(finish-1), minus) // 1.0e- or 1.0E-
726 : || Traits::eq(*(finish-1), plus) // 1.0e+ or 1.0E+
727 : )
728 : ) return false;
729 :
730 : return return_value;
731 : }
732 :
733 : public:
734 : bool stream_out(float& output) { return float_types_converter_internal(output); }
735 : bool stream_out(double& output) { return float_types_converter_internal(output); }
736 : bool stream_out(long double& output) { return float_types_converter_internal(output); }
737 :
738 : // Generic istream-based algorithm.
739 : // lcast_streambuf_for_target<InputStreamable>::value is true.
740 : template <typename InputStreamable>
741 : bool stream_out(InputStreamable& output) {
742 : return shr_using_base_class(output);
743 : }
744 : };
745 :
746 : }}} // namespace boost::detail::lcast
747 :
748 : #undef BOOST_LCAST_NO_WCHAR_T
749 :
750 : #endif // BOOST_LEXICAL_CAST_DETAIL_CONVERTER_LEXICAL_HPP
751 :
|