1 // Copyright Kevlin Henney, 2000-2005.
2 // Copyright Alexander Nasonov, 2006-2010.
3 // Copyright Antony Polukhin, 2011-2014.
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)
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
18 #ifndef BOOST_LEXICAL_CAST_DETAIL_CONVERTER_LEXICAL_HPP
19 #define BOOST_LEXICAL_CAST_DETAIL_CONVERTER_LEXICAL_HPP
21 #include <boost/config.hpp>
22 #ifdef BOOST_HAS_PRAGMA_ONCE
26 #if defined(BOOST_NO_STRINGSTREAM) || defined(BOOST_NO_STD_WSTRING)
27 #define BOOST_LCAST_NO_WCHAR_T
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>
42 #include <boost/lexical_cast/detail/widest_char.hpp>
43 #include <boost/lexical_cast/detail/is_character.hpp>
45 #ifndef BOOST_NO_CXX11_HDR_ARRAY
49 #include <boost/array.hpp>
50 #include <boost/range/iterator_range_core.hpp>
51 #include <boost/container/container_fwd.hpp>
53 #include <boost/lexical_cast/detail/converter_lexical_streams.hpp>
57 namespace detail // normalize_single_byte_char<Char>
59 // Converts signed/unsigned char to char
60 template < class Char >
61 struct normalize_single_byte_char
67 struct normalize_single_byte_char< signed char >
73 struct normalize_single_byte_char< unsigned char >
79 namespace detail // deduce_character_type_later<T>
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 {};
86 namespace detail // stream_char_common<T>
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,
95 boost::detail::deduce_character_type_later< Type >
98 template < typename Char >
99 struct stream_char_common< Char* >: public boost::mpl::if_c<
100 boost::detail::is_character< Char >::value,
102 boost::detail::deduce_character_type_later< Char* >
105 template < typename Char >
106 struct stream_char_common< const Char* >: public boost::mpl::if_c<
107 boost::detail::is_character< Char >::value,
109 boost::detail::deduce_character_type_later< const Char* >
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,
116 boost::detail::deduce_character_type_later< boost::iterator_range< Char* > >
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,
123 boost::detail::deduce_character_type_later< boost::iterator_range< const Char* > >
126 template < class Char, class Traits, class Alloc >
127 struct stream_char_common< std::basic_string< Char, Traits, Alloc > >
132 template < class Char, class Traits, class Alloc >
133 struct stream_char_common< boost::container::basic_string< Char, Traits, Alloc > >
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,
142 boost::detail::deduce_character_type_later< boost::array< Char, N > >
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,
149 boost::detail::deduce_character_type_later< boost::array< const Char, N > >
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,
157 boost::detail::deduce_character_type_later< std::array< Char, N > >
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,
164 boost::detail::deduce_character_type_later< std::array< const Char, N > >
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 > {};
173 #if !defined(BOOST_LCAST_NO_WCHAR_T) && defined(BOOST_NO_INTRINSIC_WCHAR_T)
175 struct stream_char_common< wchar_t >
182 namespace detail // deduce_source_char_impl<T>
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
192 typedef BOOST_DEDUCED_TYPENAME boost::detail::normalize_single_byte_char< Char >::type type;
196 struct deduce_source_char_impl< deduce_character_type_later< T > >
198 typedef boost::has_left_shift< std::basic_ostream< char >, T > result_t;
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");
205 typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_c<
206 result_t::value, char, wchar_t
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");
215 namespace detail // deduce_target_char_impl<T>
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
225 typedef BOOST_DEDUCED_TYPENAME normalize_single_byte_char< Char >::type type;
229 struct deduce_target_char_impl< deduce_character_type_later<T> >
231 typedef boost::has_right_shift<std::basic_istream<char>, T > result_t;
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");
238 typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_c<
239 result_t::value, char, wchar_t
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");
248 namespace detail // deduce_target_char<T> and deduce_source_char<T>
250 // We deduce stream character types in two stages.
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>
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>
262 // deduce_target_char<T> and deduce_source_char<T> functions combine
266 struct deduce_target_char
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;
271 typedef stage2_type type;
275 struct deduce_source_char
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;
280 typedef stage2_type type;
284 namespace detail // extract_char_traits template
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
292 typedef std::char_traits< Char > trait_t;
295 template < class Char, class Traits, class Alloc >
296 struct extract_char_traits< Char, std::basic_string< Char, Traits, Alloc > >
299 typedef Traits trait_t;
302 template < class Char, class Traits, class Alloc>
303 struct extract_char_traits< Char, boost::container::basic_string< Char, Traits, Alloc > >
306 typedef Traits trait_t;
310 namespace detail // array_to_pointer_decay<T>
313 struct array_to_pointer_decay
318 template<class T, std::size_t N>
319 struct array_to_pointer_decay<T[N]>
321 typedef const T * type;
325 namespace detail // is_this_float_conversion_optimized<Float, Char>
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
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
341 boost::type_traits::ice_eq<sizeof(Char), sizeof(char) >::value
345 BOOST_STATIC_CONSTANT(bool, value = (result_type::value) );
349 namespace detail // lcast_src_length
351 // Return max. length of string representation of Source;
352 template< class Source, // Source type of lexical_cast.
353 class Enable = void // helper type
355 struct lcast_src_length
357 BOOST_STATIC_CONSTANT(std::size_t, value = 1);
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"
365 // ^ - 1 digit not counted by digits10
366 // ^^^^^^^^^^^^^^^^^^ - digits10 * 2
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
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
385 BOOST_STATIC_CONSTANT(std::size_t, value = 156);
386 BOOST_STATIC_ASSERT(sizeof(Source) * CHAR_BIT <= 256);
390 #ifndef BOOST_LCAST_NO_COMPILE_TIME_PRECISION
391 // Helper for floating point types.
392 // -1.23456789e-123456
396 // ^^^^^^^^ lcast_precision<Source>::value
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
407 std::numeric_limits<Source>::max_exponent10 <= 999999L &&
408 std::numeric_limits<Source>::min_exponent10 >= -999999L
411 BOOST_STATIC_CONSTANT(std::size_t, value =
412 5 + lcast_precision<Source>::value + 6
415 #endif // #ifndef BOOST_LCAST_NO_COMPILE_TIME_PRECISION
418 namespace detail // lexical_cast_stream_traits<Source, Target>
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;
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;
429 typedef BOOST_DEDUCED_TYPENAME boost::detail::widest_char<
430 target_char_t, src_char_t
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" );
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" );
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;
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;
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;
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
474 typedef boost::detail::lcast_src_length<no_cv_src> len_t;
480 template<typename Target, typename Source>
481 struct lexical_converter_impl
483 typedef lexical_cast_stream_traits<Source, Target> stream_trait;
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;
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;
497 static inline bool try_convert(const Source& arg, Target& result) {
498 i_interpreter_type i_interpreter;
500 // Disabling ADL, by directly specifying operators.
501 if (!(i_interpreter.operator <<(arg)))
504 o_interpreter_type out(i_interpreter.cbegin(), i_interpreter.cend());
506 // Disabling ADL, by directly specifying operators.
507 if(!(out.operator >>(result)))
517 #undef BOOST_LCAST_NO_WCHAR_T
519 #endif // BOOST_LEXICAL_CAST_DETAIL_CONVERTER_LEXICAL_HPP