Imported Upstream version 1.57.0
[platform/upstream/boost.git] / boost / lexical_cast / detail / converter_lexical.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_HPP
19 #define BOOST_LEXICAL_CAST_DETAIL_CONVERTER_LEXICAL_HPP
20
21 #include <boost/config.hpp>
22 #ifdef BOOST_HAS_PRAGMA_ONCE
23 #   pragma once
24 #endif
25
26 #if defined(BOOST_NO_STRINGSTREAM) || defined(BOOST_NO_STD_WSTRING)
27 #define BOOST_LCAST_NO_WCHAR_T
28 #endif
29
30 #include <cstddef>
31 #include <string>
32 #include <boost/limits.hpp>
33 #include <boost/mpl/if.hpp>
34 #include <boost/type_traits/ice.hpp>
35 #include <boost/type_traits/is_integral.hpp>
36 #include <boost/type_traits/is_float.hpp>
37 #include <boost/type_traits/has_left_shift.hpp>
38 #include <boost/type_traits/has_right_shift.hpp>
39 #include <boost/static_assert.hpp>
40 #include <boost/detail/lcast_precision.hpp>
41
42 #include <boost/lexical_cast/detail/widest_char.hpp>
43 #include <boost/lexical_cast/detail/is_character.hpp>
44
45 #ifndef BOOST_NO_CXX11_HDR_ARRAY
46 #include <array>
47 #endif
48
49 #include <boost/array.hpp>
50 #include <boost/range/iterator_range_core.hpp>
51 #include <boost/container/container_fwd.hpp>
52
53 #include <boost/lexical_cast/detail/converter_lexical_streams.hpp>
54
55 namespace boost {
56
57     namespace detail // normalize_single_byte_char<Char>
58     {
59         // Converts signed/unsigned char to char
60         template < class Char >
61         struct normalize_single_byte_char 
62         {
63             typedef Char type;
64         };
65
66         template <>
67         struct normalize_single_byte_char< signed char >
68         {
69             typedef char type;
70         };
71
72         template <>
73         struct normalize_single_byte_char< unsigned char >
74         {
75             typedef char type;
76         };
77     }
78
79     namespace detail // deduce_character_type_later<T>
80     {
81         // Helper type, meaning that stram character for T must be deduced 
82         // at Stage 2 (See deduce_source_char<T> and deduce_target_char<T>)
83         template < class T > struct deduce_character_type_later {};
84     }
85
86     namespace detail // stream_char_common<T>
87     {
88         // Selectors to choose stream character type (common for Source and Target)
89         // Returns one of char, wchar_t, char16_t, char32_t or deduce_character_type_later<T> types
90         // Executed on Stage 1 (See deduce_source_char<T> and deduce_target_char<T>)
91         template < typename Type >
92         struct stream_char_common: public boost::mpl::if_c<
93             boost::detail::is_character< Type >::value,
94             Type,
95             boost::detail::deduce_character_type_later< Type >
96         > {};
97
98         template < typename Char >
99         struct stream_char_common< Char* >: public boost::mpl::if_c<
100             boost::detail::is_character< Char >::value,
101             Char,
102             boost::detail::deduce_character_type_later< Char* >
103         > {};
104
105         template < typename Char >
106         struct stream_char_common< const Char* >: public boost::mpl::if_c<
107             boost::detail::is_character< Char >::value,
108             Char,
109             boost::detail::deduce_character_type_later< const Char* >
110         > {};
111
112         template < typename Char >
113         struct stream_char_common< boost::iterator_range< Char* > >: public boost::mpl::if_c<
114             boost::detail::is_character< Char >::value,
115             Char,
116             boost::detail::deduce_character_type_later< boost::iterator_range< Char* > >
117         > {};
118     
119         template < typename Char >
120         struct stream_char_common< boost::iterator_range< const Char* > >: public boost::mpl::if_c<
121             boost::detail::is_character< Char >::value,
122             Char,
123             boost::detail::deduce_character_type_later< boost::iterator_range< const Char* > >
124         > {};
125
126         template < class Char, class Traits, class Alloc >
127         struct stream_char_common< std::basic_string< Char, Traits, Alloc > >
128         {
129             typedef Char type;
130         };
131
132         template < class Char, class Traits, class Alloc >
133         struct stream_char_common< boost::container::basic_string< Char, Traits, Alloc > >
134         {
135             typedef Char type;
136         };
137
138         template < typename Char, std::size_t N >
139         struct stream_char_common< boost::array< Char, N > >: public boost::mpl::if_c<
140             boost::detail::is_character< Char >::value,
141             Char,
142             boost::detail::deduce_character_type_later< boost::array< Char, N > >
143         > {};
144
145         template < typename Char, std::size_t N >
146         struct stream_char_common< boost::array< const Char, N > >: public boost::mpl::if_c<
147             boost::detail::is_character< Char >::value,
148             Char,
149             boost::detail::deduce_character_type_later< boost::array< const Char, N > >
150         > {};
151
152 #ifndef BOOST_NO_CXX11_HDR_ARRAY
153         template < typename Char, std::size_t N >
154         struct stream_char_common< std::array<Char, N > >: public boost::mpl::if_c<
155             boost::detail::is_character< Char >::value,
156             Char,
157             boost::detail::deduce_character_type_later< std::array< Char, N > >
158         > {};
159
160         template < typename Char, std::size_t N >
161         struct stream_char_common< std::array< const Char, N > >: public boost::mpl::if_c<
162             boost::detail::is_character< Char >::value,
163             Char,
164             boost::detail::deduce_character_type_later< std::array< const Char, N > >
165         > {};
166 #endif
167
168 #ifdef BOOST_HAS_INT128
169         template <> struct stream_char_common< boost::int128_type >: public boost::mpl::identity< char > {};
170         template <> struct stream_char_common< boost::uint128_type >: public boost::mpl::identity< char > {};
171 #endif
172
173 #if !defined(BOOST_LCAST_NO_WCHAR_T) && defined(BOOST_NO_INTRINSIC_WCHAR_T)
174         template <>
175         struct stream_char_common< wchar_t >
176         {
177             typedef char type;
178         };
179 #endif
180     }
181
182     namespace detail // deduce_source_char_impl<T>
183     {
184         // If type T is `deduce_character_type_later` type, then tries to deduce
185         // character type using boost::has_left_shift<T> metafunction.
186         // Otherwise supplied type T is a character type, that must be normalized
187         // using normalize_single_byte_char<Char>.
188         // Executed at Stage 2  (See deduce_source_char<T> and deduce_target_char<T>)
189         template < class Char > 
190         struct deduce_source_char_impl
191         { 
192             typedef BOOST_DEDUCED_TYPENAME boost::detail::normalize_single_byte_char< Char >::type type; 
193         };
194         
195         template < class T > 
196         struct deduce_source_char_impl< deduce_character_type_later< T > > 
197         {
198             typedef boost::has_left_shift< std::basic_ostream< char >, T > result_t;
199
200 #if defined(BOOST_LCAST_NO_WCHAR_T)
201             BOOST_STATIC_ASSERT_MSG((result_t::value), 
202                 "Source type is not std::ostream`able and std::wostream`s are not supported by your STL implementation");
203             typedef char type;
204 #else
205             typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_c<
206                 result_t::value, char, wchar_t
207             >::type type;
208
209             BOOST_STATIC_ASSERT_MSG((result_t::value || boost::has_left_shift< std::basic_ostream< type >, T >::value), 
210                 "Source type is neither std::ostream`able nor std::wostream`able");
211 #endif
212         };
213     }
214
215     namespace detail  // deduce_target_char_impl<T>
216     {
217         // If type T is `deduce_character_type_later` type, then tries to deduce
218         // character type using boost::has_right_shift<T> metafunction.
219         // Otherwise supplied type T is a character type, that must be normalized
220         // using normalize_single_byte_char<Char>.
221         // Executed at Stage 2  (See deduce_source_char<T> and deduce_target_char<T>)
222         template < class Char > 
223         struct deduce_target_char_impl 
224         { 
225             typedef BOOST_DEDUCED_TYPENAME normalize_single_byte_char< Char >::type type; 
226         };
227         
228         template < class T > 
229         struct deduce_target_char_impl< deduce_character_type_later<T> > 
230         { 
231             typedef boost::has_right_shift<std::basic_istream<char>, T > result_t;
232
233 #if defined(BOOST_LCAST_NO_WCHAR_T)
234             BOOST_STATIC_ASSERT_MSG((result_t::value), 
235                 "Target type is not std::istream`able and std::wistream`s are not supported by your STL implementation");
236             typedef char type;
237 #else
238             typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_c<
239                 result_t::value, char, wchar_t
240             >::type type;
241             
242             BOOST_STATIC_ASSERT_MSG((result_t::value || boost::has_right_shift<std::basic_istream<wchar_t>, T >::value), 
243                 "Target type is neither std::istream`able nor std::wistream`able");
244 #endif
245         };
246     } 
247
248     namespace detail  // deduce_target_char<T> and deduce_source_char<T>
249     {
250         // We deduce stream character types in two stages.
251         //
252         // Stage 1 is common for Target and Source. At Stage 1 we get 
253         // non normalized character type (may contain unsigned/signed char)
254         // or deduce_character_type_later<T> where T is the original type.
255         // Stage 1 is executed by stream_char_common<T>
256         //
257         // At Stage 2 we normalize character types or try to deduce character 
258         // type using metafunctions. 
259         // Stage 2 is executed by deduce_target_char_impl<T> and 
260         // deduce_source_char_impl<T>
261         //
262         // deduce_target_char<T> and deduce_source_char<T> functions combine 
263         // both stages
264
265         template < class T >
266         struct deduce_target_char
267         {
268             typedef BOOST_DEDUCED_TYPENAME stream_char_common< T >::type stage1_type;
269             typedef BOOST_DEDUCED_TYPENAME deduce_target_char_impl< stage1_type >::type stage2_type;
270
271             typedef stage2_type type;
272         };
273
274         template < class T >
275         struct deduce_source_char
276         {
277             typedef BOOST_DEDUCED_TYPENAME stream_char_common< T >::type stage1_type;
278             typedef BOOST_DEDUCED_TYPENAME deduce_source_char_impl< stage1_type >::type stage2_type;
279
280             typedef stage2_type type;
281         };
282     }
283
284     namespace detail // extract_char_traits template
285     {
286         // We are attempting to get char_traits<> from T
287         // template parameter. Otherwise we'll be using std::char_traits<Char>
288         template < class Char, class T >
289         struct extract_char_traits
290                 : boost::false_type
291         {
292             typedef std::char_traits< Char > trait_t;
293         };
294
295         template < class Char, class Traits, class Alloc >
296         struct extract_char_traits< Char, std::basic_string< Char, Traits, Alloc > >
297             : boost::true_type
298         {
299             typedef Traits trait_t;
300         };
301
302         template < class Char, class Traits, class Alloc>
303         struct extract_char_traits< Char, boost::container::basic_string< Char, Traits, Alloc > >
304             : boost::true_type
305         {
306             typedef Traits trait_t;
307         };
308     }
309
310     namespace detail // array_to_pointer_decay<T>
311     {
312         template<class T>
313         struct array_to_pointer_decay
314         {
315             typedef T type;
316         };
317
318         template<class T, std::size_t N>
319         struct array_to_pointer_decay<T[N]>
320         {
321             typedef const T * type;
322         };
323     }
324
325     namespace detail // is_this_float_conversion_optimized<Float, Char>
326     {
327         // this metafunction evaluates to true, if we have optimized comnversion 
328         // from Float type to Char array. 
329         // Must be in sync with lexical_stream_limited_src<Char, ...>::shl_real_type(...)
330         template <typename Float, typename Char>
331         struct is_this_float_conversion_optimized 
332         {
333             typedef boost::type_traits::ice_and<
334                 boost::is_float<Float>::value,
335 #if !defined(BOOST_LCAST_NO_WCHAR_T) && !defined(BOOST_NO_SWPRINTF) && !defined(__MINGW32__)
336                 boost::type_traits::ice_or<
337                     boost::type_traits::ice_eq<sizeof(Char), sizeof(char) >::value,
338                     boost::is_same<Char, wchar_t>::value
339                 >::value
340 #else
341                 boost::type_traits::ice_eq<sizeof(Char), sizeof(char) >::value
342 #endif
343             > result_type;
344
345             BOOST_STATIC_CONSTANT(bool, value = (result_type::value) );
346         };
347     }
348     
349     namespace detail // lcast_src_length
350     {
351         // Return max. length of string representation of Source;
352         template< class Source,         // Source type of lexical_cast.
353                   class Enable = void   // helper type
354                 >
355         struct lcast_src_length
356         {
357             BOOST_STATIC_CONSTANT(std::size_t, value = 1);
358         };
359
360         // Helper for integral types.
361         // Notes on length calculation:
362         // Max length for 32bit int with grouping "\1" and thousands_sep ',':
363         // "-2,1,4,7,4,8,3,6,4,7"
364         //  ^                    - is_signed
365         //   ^                   - 1 digit not counted by digits10
366         //    ^^^^^^^^^^^^^^^^^^ - digits10 * 2
367         //
368         // Constant is_specialized is used instead of constant 1
369         // to prevent buffer overflow in a rare case when
370         // <boost/limits.hpp> doesn't add missing specialization for
371         // numeric_limits<T> for some integral type T.
372         // When is_specialized is false, the whole expression is 0.
373         template <class Source>
374         struct lcast_src_length<
375                     Source, BOOST_DEDUCED_TYPENAME boost::enable_if<boost::is_integral<Source> >::type
376                 >
377         {
378 #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
379             BOOST_STATIC_CONSTANT(std::size_t, value =
380                   std::numeric_limits<Source>::is_signed +
381                   std::numeric_limits<Source>::is_specialized + /* == 1 */
382                   std::numeric_limits<Source>::digits10 * 2
383               );
384 #else
385             BOOST_STATIC_CONSTANT(std::size_t, value = 156);
386             BOOST_STATIC_ASSERT(sizeof(Source) * CHAR_BIT <= 256);
387 #endif
388         };
389
390 #ifndef BOOST_LCAST_NO_COMPILE_TIME_PRECISION
391         // Helper for floating point types.
392         // -1.23456789e-123456
393         // ^                   sign
394         //  ^                  leading digit
395         //   ^                 decimal point 
396         //    ^^^^^^^^         lcast_precision<Source>::value
397         //            ^        "e"
398         //             ^       exponent sign
399         //              ^^^^^^ exponent (assumed 6 or less digits)
400         // sign + leading digit + decimal point + "e" + exponent sign == 5
401         template<class Source>
402         struct lcast_src_length<
403                 Source, BOOST_DEDUCED_TYPENAME boost::enable_if<boost::is_float<Source> >::type
404             >
405         {
406             BOOST_STATIC_ASSERT(
407                     std::numeric_limits<Source>::max_exponent10 <=  999999L &&
408                     std::numeric_limits<Source>::min_exponent10 >= -999999L
409                 );
410
411             BOOST_STATIC_CONSTANT(std::size_t, value =
412                     5 + lcast_precision<Source>::value + 6
413                 );
414         };
415 #endif // #ifndef BOOST_LCAST_NO_COMPILE_TIME_PRECISION
416     }
417
418     namespace detail // lexical_cast_stream_traits<Source, Target>
419     {
420         template <class Source, class Target>
421         struct lexical_cast_stream_traits {
422             typedef BOOST_DEDUCED_TYPENAME boost::detail::array_to_pointer_decay<Source>::type src;
423             typedef BOOST_DEDUCED_TYPENAME boost::remove_cv<src>::type            no_cv_src;
424                 
425             typedef boost::detail::deduce_source_char<no_cv_src>                           deduce_src_char_metafunc;
426             typedef BOOST_DEDUCED_TYPENAME deduce_src_char_metafunc::type           src_char_t;
427             typedef BOOST_DEDUCED_TYPENAME boost::detail::deduce_target_char<Target>::type target_char_t;
428                 
429             typedef BOOST_DEDUCED_TYPENAME boost::detail::widest_char<
430                 target_char_t, src_char_t
431             >::type char_type;
432
433 #if !defined(BOOST_NO_CXX11_CHAR16_T) && defined(BOOST_NO_CXX11_UNICODE_LITERALS)
434             BOOST_STATIC_ASSERT_MSG(( !boost::is_same<char16_t, src_char_t>::value
435                                         && !boost::is_same<char16_t, target_char_t>::value),
436                 "Your compiler does not have full support for char16_t" );
437 #endif
438 #if !defined(BOOST_NO_CXX11_CHAR32_T) && defined(BOOST_NO_CXX11_UNICODE_LITERALS)
439             BOOST_STATIC_ASSERT_MSG(( !boost::is_same<char32_t, src_char_t>::value
440                                         && !boost::is_same<char32_t, target_char_t>::value),
441                 "Your compiler does not have full support for char32_t" );
442 #endif
443
444             typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_c<
445                 boost::detail::extract_char_traits<char_type, Target>::value,
446                 BOOST_DEDUCED_TYPENAME boost::detail::extract_char_traits<char_type, Target>,
447                 BOOST_DEDUCED_TYPENAME boost::detail::extract_char_traits<char_type, no_cv_src>
448             >::type::trait_t traits;
449
450             typedef boost::type_traits::ice_and<
451                 boost::is_same<char, src_char_t>::value,                                  // source is not a wide character based type
452                 boost::type_traits::ice_ne<sizeof(char), sizeof(target_char_t) >::value,  // target type is based on wide character
453                 boost::type_traits::ice_not<
454                     boost::detail::is_character<no_cv_src>::value                     // single character widening is optimized
455                 >::value                                                                  // and does not requires stringbuffer
456             >   is_string_widening_required_t;
457
458             typedef boost::type_traits::ice_not< boost::type_traits::ice_or<
459                 boost::is_integral<no_cv_src>::value,
460                 boost::detail::is_this_float_conversion_optimized<no_cv_src, char_type >::value,
461                 boost::detail::is_character<
462                     BOOST_DEDUCED_TYPENAME deduce_src_char_metafunc::stage1_type          // if we did not get character type at stage1
463                 >::value                                                                  // then we have no optimization for that type
464             >::value >   is_source_input_not_optimized_t;
465
466             // If we have an optimized conversion for
467             // Source, we do not need to construct stringbuf.
468             BOOST_STATIC_CONSTANT(bool, requires_stringbuf = 
469                 (boost::type_traits::ice_or<
470                     is_string_widening_required_t::value, is_source_input_not_optimized_t::value
471                 >::value)
472             );
473             
474             typedef boost::detail::lcast_src_length<no_cv_src> len_t;
475         };
476     }
477  
478     namespace detail
479     {
480         template<typename Target, typename Source>
481         struct lexical_converter_impl
482         {
483             typedef lexical_cast_stream_traits<Source, Target>  stream_trait;
484
485             typedef detail::lexical_istream_limited_src<
486                 BOOST_DEDUCED_TYPENAME stream_trait::char_type,
487                 BOOST_DEDUCED_TYPENAME stream_trait::traits,
488                 stream_trait::requires_stringbuf,
489                 stream_trait::len_t::value + 1
490             > i_interpreter_type;
491
492             typedef detail::lexical_ostream_limited_src<
493                 BOOST_DEDUCED_TYPENAME stream_trait::char_type,
494                 BOOST_DEDUCED_TYPENAME stream_trait::traits
495             > o_interpreter_type;
496
497             static inline bool try_convert(const Source& arg, Target& result) {
498                 i_interpreter_type i_interpreter;
499
500                 // Disabling ADL, by directly specifying operators.
501                 if (!(i_interpreter.operator <<(arg)))
502                     return false;
503
504                 o_interpreter_type out(i_interpreter.cbegin(), i_interpreter.cend());
505
506                 // Disabling ADL, by directly specifying operators.
507                 if(!(out.operator >>(result)))
508                     return false;
509
510                 return true;
511             }
512         };
513     }
514
515 } // namespace boost
516
517 #undef BOOST_LCAST_NO_WCHAR_T
518
519 #endif // BOOST_LEXICAL_CAST_DETAIL_CONVERTER_LEXICAL_HPP
520