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