Imported Upstream version 1.57.0
[platform/upstream/boost.git] / boost / lexical_cast / detail / converter_lexical_streams.hpp
1 // Copyright Kevlin Henney, 2000-2005.
2 // Copyright Alexander Nasonov, 2006-2010.
3 // Copyright Antony Polukhin, 2011-2014.
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
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/mpl/if.hpp>
37 #include <boost/type_traits/ice.hpp>
38 #include <boost/type_traits/is_pointer.hpp>
39 #include <boost/static_assert.hpp>
40 #include <boost/detail/workaround.hpp>
41
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 #include <boost/lexical_cast/detail/lcast_float_converters.hpp>
66
67 #include <istream>
68
69 #ifndef BOOST_NO_CXX11_HDR_ARRAY
70 #include <array>
71 #endif
72
73 #include <boost/array.hpp>
74 #include <boost/type_traits/make_unsigned.hpp>
75 #include <boost/type_traits/is_integral.hpp>
76 #include <boost/type_traits/is_float.hpp>
77 #include <boost/range/iterator_range_core.hpp>
78 #include <boost/container/container_fwd.hpp>
79 #include <boost/integer.hpp>
80 #include <boost/detail/basic_pointerbuf.hpp>
81 #include <boost/noncopyable.hpp>
82 #ifndef BOOST_NO_CWCHAR
83 #   include <cwchar>
84 #endif
85
86 namespace boost {
87
88     namespace detail // basic_unlockedbuf
89     {
90         // acts as a stream buffer which wraps around a pair of pointers
91         // and gives acces to internals
92         template <class BufferType, class CharT>
93         class basic_unlockedbuf : public basic_pointerbuf<CharT, BufferType> {
94         public:
95            typedef basic_pointerbuf<CharT, BufferType> base_type;
96            typedef BOOST_DEDUCED_TYPENAME base_type::streamsize streamsize;
97
98 #ifndef BOOST_NO_USING_TEMPLATE
99             using base_type::pptr;
100             using base_type::pbase;
101             using base_type::setbuf;
102 #else
103             charT* pptr() const { return base_type::pptr(); }
104             charT* pbase() const { return base_type::pbase(); }
105             BufferType* setbuf(char_type* s, streamsize n) { return base_type::setbuf(s, n); }
106 #endif
107         };
108     }
109
110     namespace detail
111     {
112         struct do_not_construct_out_stream_t{};
113         
114         template <class CharT, class Traits>
115         struct out_stream_helper_trait {
116 #if defined(BOOST_NO_STRINGSTREAM)
117             typedef std::ostrstream                                 out_stream_t;
118             typedef void                                            buffer_t;
119 #elif defined(BOOST_NO_STD_LOCALE)
120             typedef std::ostringstream                              out_stream_t;
121             typedef basic_unlockedbuf<std::streambuf, char>         buffer_t;
122 #else
123             typedef std::basic_ostringstream<CharT, Traits> 
124                 out_stream_t;
125             typedef basic_unlockedbuf<std::basic_streambuf<CharT, Traits>, CharT>  
126                 buffer_t;
127 #endif
128         };   
129     }
130
131     namespace detail // optimized stream wrappers
132     {
133         template< class CharT // a result of widest_char transformation
134                 , class Traits
135                 , bool RequiresStringbuffer
136                 , std::size_t CharacterBufferSize
137                 >
138         class lexical_istream_limited_src: boost::noncopyable {
139             typedef BOOST_DEDUCED_TYPENAME out_stream_helper_trait<CharT, Traits>::buffer_t
140                 buffer_t;
141
142             typedef BOOST_DEDUCED_TYPENAME out_stream_helper_trait<CharT, Traits>::out_stream_t
143                 out_stream_t;
144     
145             typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_c<
146                 RequiresStringbuffer,
147                 out_stream_t,
148                 do_not_construct_out_stream_t
149             >::type deduced_out_stream_t;
150
151             // A string representation of Source is written to `buffer`.
152             deduced_out_stream_t out_stream;
153             CharT   buffer[CharacterBufferSize];
154
155             // After the `operator <<`  finishes, `[start, finish)` is
156             // the range to output by `operator >>` 
157             const CharT*  start;
158             const CharT*  finish;
159
160         public:
161             lexical_istream_limited_src() BOOST_NOEXCEPT
162               : start(buffer)
163               , finish(buffer + CharacterBufferSize)
164             {}
165     
166             const CharT* cbegin() const BOOST_NOEXCEPT {
167                 return start;
168             }
169
170             const CharT* cend() const BOOST_NOEXCEPT {
171                 return finish;
172             }
173
174         private:
175             // Undefined:
176             lexical_istream_limited_src(lexical_istream_limited_src const&);
177             void operator=(lexical_istream_limited_src const&);
178
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) BOOST_NOEXCEPT {
205                 start = str;
206                 finish = start + Traits::length(str);
207                 return true;
208             }
209
210             template <class T>
211             bool shl_char_array(T const* str) {
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);
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 buffer_t* const p = static_cast<buffer_t*>(
238                     static_cast<std::basic_streambuf<CharT, Traits>*>(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 #if defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(__SGI_STL_PORT) && !defined(_STLPORT_VERSION)
284                     sprintf_s(begin, CharacterBufferSize,
285 #else
286                     sprintf(begin, 
287 #endif
288                     "%.*g", static_cast<int>(boost::detail::lcast_get_precision<float>()), val_as_double);
289                 return finish > start;
290             }
291
292             bool shl_real_type(double val, char* begin) {
293                 using namespace std;
294                 finish = start +
295 #if defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(__SGI_STL_PORT) && !defined(_STLPORT_VERSION)
296                     sprintf_s(begin, CharacterBufferSize,
297 #else
298                     sprintf(begin, 
299 #endif
300                     "%.*g", static_cast<int>(boost::detail::lcast_get_precision<double>()), val);
301                 return finish > start;
302             }
303
304 #ifndef __MINGW32__
305             bool shl_real_type(long double val, char* begin) {
306                 using namespace std;
307                 finish = start +
308 #if defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(__SGI_STL_PORT) && !defined(_STLPORT_VERSION)
309                     sprintf_s(begin, CharacterBufferSize,
310 #else
311                     sprintf(begin, 
312 #endif
313                     "%.*Lg", static_cast<int>(boost::detail::lcast_get_precision<long double>()), val );
314                 return finish > start;
315             }
316 #endif
317
318
319 #if !defined(BOOST_LCAST_NO_WCHAR_T) && !defined(BOOST_NO_SWPRINTF) && !defined(__MINGW32__)
320             bool shl_real_type(float val, wchar_t* begin) {
321                 using namespace std;
322                 const double val_as_double = val;
323                 finish = start + swprintf(begin, CharacterBufferSize,
324                                        L"%.*g",
325                                        static_cast<int>(boost::detail::lcast_get_precision<float >()),
326                                        val_as_double );
327                 return finish > start;
328             }
329
330             bool shl_real_type(double val, wchar_t* begin) {
331                 using namespace std;
332                 finish = start + swprintf(begin, CharacterBufferSize,
333                                           L"%.*g", static_cast<int>(boost::detail::lcast_get_precision<double >()), val );
334                 return finish > start;
335             }
336
337             bool shl_real_type(long double val, wchar_t* begin) {
338                 using namespace std;
339                 finish = start + swprintf(begin, CharacterBufferSize,
340                                           L"%.*Lg", static_cast<int>(boost::detail::lcast_get_precision<long double >()), val );
341                 return finish > start;
342             }
343 #endif
344             template <class T>
345             bool shl_real(T val) {
346                 CharT* tmp_finish = buffer + CharacterBufferSize;
347                 if (put_inf_nan(buffer, tmp_finish, val)) {
348                     finish = tmp_finish;
349                     return true;
350                 }
351
352                 return shl_real_type(val, static_cast<CharT*>(buffer));
353             }
354
355 /************************************ OPERATORS << ( ... ) ********************************/
356         public:
357             template<class Alloc>
358             bool operator<<(std::basic_string<CharT,Traits,Alloc> const& str) BOOST_NOEXCEPT {
359                 start = str.data();
360                 finish = start + str.length();
361                 return true;
362             }
363
364             template<class Alloc>
365             bool operator<<(boost::container::basic_string<CharT,Traits,Alloc> const& str) BOOST_NOEXCEPT {
366                 start = str.data();
367                 finish = start + str.length();
368                 return true;
369             }
370
371             bool operator<<(bool value) BOOST_NOEXCEPT {
372                 CharT const czero = lcast_char_constants<CharT>::zero;
373                 Traits::assign(buffer[0], Traits::to_char_type(czero + value));
374                 finish = start + 1;
375                 return true;
376             }
377
378             template <class C>
379             BOOST_DEDUCED_TYPENAME boost::disable_if<boost::is_const<C>, bool>::type 
380             operator<<(const iterator_range<C*>& rng) BOOST_NOEXCEPT {
381                 return (*this) << iterator_range<const C*>(rng.begin(), rng.end());
382             }
383             
384             bool operator<<(const iterator_range<const CharT*>& rng) BOOST_NOEXCEPT {
385                 start = rng.begin();
386                 finish = rng.end();
387                 return true; 
388             }
389
390             bool operator<<(const iterator_range<const signed char*>& rng) BOOST_NOEXCEPT {
391                 return (*this) << iterator_range<const char*>(
392                     reinterpret_cast<const char*>(rng.begin()),
393                     reinterpret_cast<const char*>(rng.end())
394                 );
395             }
396
397             bool operator<<(const iterator_range<const unsigned char*>& rng) BOOST_NOEXCEPT {
398                 return (*this) << iterator_range<const char*>(
399                     reinterpret_cast<const char*>(rng.begin()),
400                     reinterpret_cast<const char*>(rng.end())
401                 );
402             }
403
404             bool operator<<(char ch)                    { return shl_char(ch); }
405             bool operator<<(unsigned char ch)           { return ((*this) << static_cast<char>(ch)); }
406             bool operator<<(signed char ch)             { return ((*this) << static_cast<char>(ch)); }
407 #if !defined(BOOST_LCAST_NO_WCHAR_T)
408             bool operator<<(wchar_t const* str)         { return shl_char_array(str); }
409             bool operator<<(wchar_t * str)              { return shl_char_array(str); }
410 #ifndef BOOST_NO_INTRINSIC_WCHAR_T
411             bool operator<<(wchar_t ch)                 { return shl_char(ch); }
412 #endif
413 #endif
414 #if !defined(BOOST_NO_CXX11_CHAR16_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS)
415             bool operator<<(char16_t ch)                { return shl_char(ch); }
416             bool operator<<(char16_t * str)             { return shl_char_array(str); }
417             bool operator<<(char16_t const * str)       { return shl_char_array(str); }
418 #endif
419 #if !defined(BOOST_NO_CXX11_CHAR32_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS)
420             bool operator<<(char32_t ch)                { return shl_char(ch); }
421             bool operator<<(char32_t * str)             { return shl_char_array(str); }
422             bool operator<<(char32_t const * str)       { return shl_char_array(str); }
423 #endif
424             bool operator<<(unsigned char const* ch)    { return ((*this) << reinterpret_cast<char const*>(ch)); }
425             bool operator<<(unsigned char * ch)         { return ((*this) << reinterpret_cast<char *>(ch)); }
426             bool operator<<(signed char const* ch)      { return ((*this) << reinterpret_cast<char const*>(ch)); }
427             bool operator<<(signed char * ch)           { return ((*this) << reinterpret_cast<char *>(ch)); }
428             bool operator<<(char const* str)            { return shl_char_array(str); }
429             bool operator<<(char* str)                  { return shl_char_array(str); }
430             bool operator<<(short n)                    { return shl_signed(n); }
431             bool operator<<(int n)                      { return shl_signed(n); }
432             bool operator<<(long n)                     { return shl_signed(n); }
433             bool operator<<(unsigned short n)           { return shl_unsigned(n); }
434             bool operator<<(unsigned int n)             { return shl_unsigned(n); }
435             bool operator<<(unsigned long n)            { return shl_unsigned(n); }
436
437 #if defined(BOOST_HAS_LONG_LONG)
438             bool operator<<(boost::ulong_long_type n)   { return shl_unsigned(n); }
439             bool operator<<(boost::long_long_type n)    { return shl_signed(n); }
440 #elif defined(BOOST_HAS_MS_INT64)
441             bool operator<<(unsigned __int64 n)         { return shl_unsigned(n); }
442             bool operator<<(         __int64 n)         { return shl_signed(n); }
443 #endif
444
445 #ifdef BOOST_HAS_INT128
446             bool operator<<(const boost::uint128_type& n)   { return shl_unsigned(n); }
447             bool operator<<(const boost::int128_type& n)    { return shl_signed(n); }
448 #endif
449             bool operator<<(float val)                  { return shl_real(val); }
450             bool operator<<(double val)                 { return shl_real(val); }
451             bool operator<<(long double val)            {
452 #ifndef __MINGW32__
453                 return shl_real(val);
454 #else
455                 return shl_real(static_cast<double>(val));
456 #endif
457             }
458             
459             // Adding constness to characters. Constness does not change layout
460             template <class C, std::size_t N>
461             BOOST_DEDUCED_TYPENAME boost::disable_if<boost::is_const<C>, bool>::type
462             operator<<(boost::array<C, N> const& input) BOOST_NOEXCEPT { 
463                 BOOST_STATIC_ASSERT_MSG(
464                     (sizeof(boost::array<const C, N>) == sizeof(boost::array<C, N>)),
465                     "boost::array<C, N> and boost::array<const C, N> must have exactly the same layout."
466                 );
467                 return ((*this) << reinterpret_cast<boost::array<const C, N> const& >(input)); 
468             }
469
470             template <std::size_t N>
471             bool operator<<(boost::array<const CharT, N> const& input) BOOST_NOEXCEPT { 
472                 return shl_char_array_limited(input.begin(), N); 
473             }
474
475             template <std::size_t N>
476             bool operator<<(boost::array<const unsigned char, N> const& input) BOOST_NOEXCEPT { 
477                 return ((*this) << reinterpret_cast<boost::array<const char, N> const& >(input)); 
478             }
479
480             template <std::size_t N>
481             bool operator<<(boost::array<const signed char, N> const& input) BOOST_NOEXCEPT { 
482                 return ((*this) << reinterpret_cast<boost::array<const char, N> const& >(input)); 
483             }
484  
485 #ifndef BOOST_NO_CXX11_HDR_ARRAY
486             // Making a Boost.Array from std::array
487             template <class C, std::size_t N>
488             bool operator<<(std::array<C, N> const& input) BOOST_NOEXCEPT { 
489                 BOOST_STATIC_ASSERT_MSG(
490                     (sizeof(std::array<C, N>) == sizeof(boost::array<C, N>)),
491                     "std::array and boost::array must have exactly the same layout. "
492                     "Bug in implementation of std::array or boost::array."
493                 );
494                 return ((*this) << reinterpret_cast<boost::array<C, N> const& >(input)); 
495             }
496 #endif
497             template <class InStreamable>
498             bool operator<<(const InStreamable& input)  { return shl_input_streamable(input); }
499         };
500
501
502         template <class CharT, class Traits>
503         class lexical_ostream_limited_src: boost::noncopyable {
504             //`[start, finish)` is the range to output by `operator >>` 
505             const CharT*        start;
506             const CharT* const  finish;
507
508         public:
509             lexical_ostream_limited_src(const CharT* begin, const CharT* end) BOOST_NOEXCEPT
510               : start(begin)
511               , finish(end)
512             {}
513
514 /************************************ HELPER FUNCTIONS FOR OPERATORS >> ( ... ) ********************************/
515         private:
516             template <typename Type>
517             bool shr_unsigned(Type& output) {
518                 if (start == finish) return false;
519                 CharT const minus = lcast_char_constants<CharT>::minus;
520                 CharT const plus = lcast_char_constants<CharT>::plus;
521                 bool const has_minus = Traits::eq(minus, *start);
522
523                 /* We won`t use `start' any more, so no need in decrementing it after */
524                 if (has_minus || Traits::eq(plus, *start)) {
525                     ++start;
526                 }
527
528                 bool const succeed = lcast_ret_unsigned<Traits, Type, CharT>(output, start, finish).convert();
529
530                 if (has_minus) {
531                     output = static_cast<Type>(0u - output);
532                 }
533
534                 return succeed;
535             }
536
537             template <typename Type>
538             bool shr_signed(Type& output) {
539                 if (start == finish) return false;
540                 CharT const minus = lcast_char_constants<CharT>::minus;
541                 CharT const plus = lcast_char_constants<CharT>::plus;
542                 typedef BOOST_DEDUCED_TYPENAME make_unsigned<Type>::type utype;
543                 utype out_tmp = 0;
544                 bool const has_minus = Traits::eq(minus, *start);
545
546                 /* We won`t use `start' any more, so no need in decrementing it after */
547                 if (has_minus || Traits::eq(plus, *start)) {
548                     ++start;
549                 }
550
551                 bool succeed = lcast_ret_unsigned<Traits, utype, CharT>(out_tmp, start, finish).convert();
552                 if (has_minus) {
553                     utype const comp_val = (static_cast<utype>(1) << std::numeric_limits<Type>::digits);
554                     succeed = succeed && out_tmp<=comp_val;
555                     output = static_cast<Type>(0u - out_tmp);
556                 } else {
557                     utype const comp_val = static_cast<utype>((std::numeric_limits<Type>::max)());
558                     succeed = succeed && out_tmp<=comp_val;
559                     output = static_cast<Type>(out_tmp);
560                 }
561                 return succeed;
562             }
563
564             template<typename InputStreamable>
565             bool shr_using_base_class(InputStreamable& output)
566             {
567                 BOOST_STATIC_ASSERT_MSG(
568                     (!boost::is_pointer<InputStreamable>::value),
569                     "boost::lexical_cast can not convert to pointers"
570                 );
571
572 #if defined(BOOST_NO_STRINGSTREAM) || defined(BOOST_NO_STD_LOCALE)
573                 BOOST_STATIC_ASSERT_MSG((boost::is_same<char, CharT>::value),
574                     "boost::lexical_cast can not convert, because your STL library does not "
575                     "support such conversions. Try updating it."
576                 );
577 #endif
578                 typedef BOOST_DEDUCED_TYPENAME out_stream_helper_trait<CharT, Traits>::buffer_t
579                     buffer_t;
580
581 #if defined(BOOST_NO_STRINGSTREAM)
582                 std::istrstream stream(start, finish - start);
583 #else
584
585                 buffer_t buf;
586                 // Usually `istream` and `basic_istream` do not modify 
587                 // content of buffer; `buffer_t` assures that this is true
588                 buf.setbuf(const_cast<CharT*>(start), finish - start);
589 #if defined(BOOST_NO_STD_LOCALE)
590                 std::istream stream(&buf);
591 #else
592                 std::basic_istream<CharT, Traits> stream(&buf);
593 #endif // BOOST_NO_STD_LOCALE
594 #endif // BOOST_NO_STRINGSTREAM
595
596 #ifndef BOOST_NO_EXCEPTIONS
597                 stream.exceptions(std::ios::badbit);
598                 try {
599 #endif
600                 stream.unsetf(std::ios::skipws);
601                 lcast_set_precision(stream, static_cast<InputStreamable*>(0));
602
603                 return (stream >> output) 
604                     && (stream.get() == Traits::eof());
605
606 #ifndef BOOST_NO_EXCEPTIONS
607                 } catch (const ::std::ios_base::failure& /*f*/) {
608                     return false;
609                 }
610 #endif
611             }
612
613             template<class T>
614             inline bool shr_xchar(T& output) BOOST_NOEXCEPT {
615                 BOOST_STATIC_ASSERT_MSG(( sizeof(CharT) == sizeof(T) ),
616                     "boost::lexical_cast does not support narrowing of character types."
617                     "Use boost::locale instead" );
618                 bool const ok = (finish - start == 1);
619                 if (ok) {
620                     CharT out;
621                     Traits::assign(out, *start);
622                     output = static_cast<T>(out);
623                 }
624                 return ok;
625             }
626
627             template <std::size_t N, class ArrayT>
628             bool shr_std_array(ArrayT& output) BOOST_NOEXCEPT {
629                 using namespace std;
630                 const std::size_t size = static_cast<std::size_t>(finish - start);
631                 if (size > N - 1) { // `-1` because we need to store \0 at the end 
632                     return false;
633                 }
634
635                 memcpy(&output[0], start, size * sizeof(CharT));
636                 output[size] = Traits::to_char_type(0);
637                 return true;
638             }
639
640 /************************************ OPERATORS >> ( ... ) ********************************/
641         public:
642             bool operator>>(unsigned short& output)             { return shr_unsigned(output); }
643             bool operator>>(unsigned int& output)               { return shr_unsigned(output); }
644             bool operator>>(unsigned long int& output)          { return shr_unsigned(output); }
645             bool operator>>(short& output)                      { return shr_signed(output); }
646             bool operator>>(int& output)                        { return shr_signed(output); }
647             bool operator>>(long int& output)                   { return shr_signed(output); }
648 #if defined(BOOST_HAS_LONG_LONG)
649             bool operator>>(boost::ulong_long_type& output)     { return shr_unsigned(output); }
650             bool operator>>(boost::long_long_type& output)      { return shr_signed(output); }
651 #elif defined(BOOST_HAS_MS_INT64)
652             bool operator>>(unsigned __int64& output)           { return shr_unsigned(output); }
653             bool operator>>(__int64& output)                    { return shr_signed(output); }
654 #endif
655
656 #ifdef BOOST_HAS_INT128
657             bool operator>>(boost::uint128_type& output)        { return shr_unsigned(output); }
658             bool operator>>(boost::int128_type& output)         { return shr_signed(output); }
659 #endif
660
661             bool operator>>(char& output)                       { return shr_xchar(output); }
662             bool operator>>(unsigned char& output)              { return shr_xchar(output); }
663             bool operator>>(signed char& output)                { return shr_xchar(output); }
664 #if !defined(BOOST_LCAST_NO_WCHAR_T) && !defined(BOOST_NO_INTRINSIC_WCHAR_T)
665             bool operator>>(wchar_t& output)                    { return shr_xchar(output); }
666 #endif
667 #if !defined(BOOST_NO_CXX11_CHAR16_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS)
668             bool operator>>(char16_t& output)                   { return shr_xchar(output); }
669 #endif
670 #if !defined(BOOST_NO_CXX11_CHAR32_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS)
671             bool operator>>(char32_t& output)                   { return shr_xchar(output); }
672 #endif
673             template<class Alloc>
674             bool operator>>(std::basic_string<CharT,Traits,Alloc>& str) { 
675                 str.assign(start, finish); return true; 
676             }
677
678             template<class Alloc>
679             bool operator>>(boost::container::basic_string<CharT,Traits,Alloc>& str) { 
680                 str.assign(start, finish); return true; 
681             }
682
683             template <std::size_t N>
684             bool operator>>(boost::array<CharT, N>& output) BOOST_NOEXCEPT { 
685                 return shr_std_array<N>(output); 
686             }
687
688             template <std::size_t N>
689             bool operator>>(boost::array<unsigned char, N>& output) BOOST_NOEXCEPT { 
690                 return ((*this) >> reinterpret_cast<boost::array<char, N>& >(output)); 
691             }
692
693             template <std::size_t N>
694             bool operator>>(boost::array<signed char, N>& output) BOOST_NOEXCEPT { 
695                 return ((*this) >> reinterpret_cast<boost::array<char, N>& >(output)); 
696             }
697  
698 #ifndef BOOST_NO_CXX11_HDR_ARRAY
699             template <class C, std::size_t N>
700             bool operator>>(std::array<C, N>& output) BOOST_NOEXCEPT { 
701                 BOOST_STATIC_ASSERT_MSG(
702                     (sizeof(boost::array<C, N>) == sizeof(boost::array<C, N>)),
703                     "std::array<C, N> and boost::array<C, N> must have exactly the same layout."
704                 );
705                 return ((*this) >> reinterpret_cast<boost::array<C, N>& >(output));
706             }
707 #endif
708
709             bool operator>>(bool& output) BOOST_NOEXCEPT {
710                 output = false; // Suppress warning about uninitalized variable
711
712                 if (start == finish) return false;
713                 CharT const zero = lcast_char_constants<CharT>::zero;
714                 CharT const plus = lcast_char_constants<CharT>::plus;
715                 CharT const minus = lcast_char_constants<CharT>::minus;
716
717                 const CharT* const dec_finish = finish - 1;
718                 output = Traits::eq(*dec_finish, zero + 1);
719                 if (!output && !Traits::eq(*dec_finish, zero)) {
720                     return false; // Does not ends on '0' or '1'
721                 }
722
723                 if (start == dec_finish) return true;
724
725                 // We may have sign at the beginning
726                 if (Traits::eq(plus, *start) || (Traits::eq(minus, *start) && !output)) {
727                     ++ start;
728                 }
729
730                 // Skipping zeros
731                 while (start != dec_finish) {
732                     if (!Traits::eq(zero, *start)) {
733                         return false; // Not a zero => error
734                     }
735
736                     ++ start;
737                 }
738
739                 return true;
740             }
741
742             bool operator>>(float& output) { return lcast_ret_float<Traits>(output,start,finish); }
743
744         private:
745             // Not optimised converter
746             template <class T>
747             bool float_types_converter_internal(T& output, int /*tag*/) {
748                 if (parse_inf_nan(start, finish, output)) return true;
749                 bool const return_value = shr_using_base_class(output);
750
751                 /* Some compilers and libraries successfully
752                  * parse 'inf', 'INFINITY', '1.0E', '1.0E-'...
753                  * We are trying to provide a unified behaviour,
754                  * so we just forbid such conversions (as some
755                  * of the most popular compilers/libraries do)
756                  * */
757                 CharT const minus = lcast_char_constants<CharT>::minus;
758                 CharT const plus = lcast_char_constants<CharT>::plus;
759                 CharT const capital_e = lcast_char_constants<CharT>::capital_e;
760                 CharT const lowercase_e = lcast_char_constants<CharT>::lowercase_e;
761                 if ( return_value &&
762                      (
763                         Traits::eq(*(finish-1), lowercase_e)                   // 1.0e
764                         || Traits::eq(*(finish-1), capital_e)                  // 1.0E
765                         || Traits::eq(*(finish-1), minus)                      // 1.0e- or 1.0E-
766                         || Traits::eq(*(finish-1), plus)                       // 1.0e+ or 1.0E+
767                      )
768                 ) return false;
769
770                 return return_value;
771             }
772
773             // Optimised converter
774             bool float_types_converter_internal(double& output, char /*tag*/) {
775                 return lcast_ret_float<Traits>(output, start, finish);
776             }
777         public:
778
779             bool operator>>(double& output) {
780                 /*
781                  * Some compilers implement long double as double. In that case these types have
782                  * same size, same precision, same max and min values... And it means,
783                  * that current implementation of lcast_ret_float cannot be used for type
784                  * double, because it will give a big precision loss.
785                  * */
786                 boost::mpl::if_c<
787 #if (defined(BOOST_HAS_LONG_LONG) || defined(BOOST_HAS_MS_INT64)) && !defined(BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS)
788                     boost::type_traits::ice_eq< sizeof(double), sizeof(long double) >::value,
789 #else
790                      1,
791 #endif
792                     int,
793                     char
794                 >::type tag = 0;
795
796                 return float_types_converter_internal(output, tag);
797             }
798
799             bool operator>>(long double& output) {
800                 int tag = 0;
801                 return float_types_converter_internal(output, tag);
802             }
803
804             // Generic istream-based algorithm.
805             // lcast_streambuf_for_target<InputStreamable>::value is true.
806             template <typename InputStreamable>
807             bool operator>>(InputStreamable& output) { 
808                 return shr_using_base_class(output); 
809             }
810         };
811     }
812 } // namespace boost
813
814 #undef BOOST_LCAST_NO_WCHAR_T
815
816 #endif // BOOST_LEXICAL_CAST_DETAIL_CONVERTER_LEXICAL_HPP
817