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