// Copyright Kevlin Henney, 2000-2005. // Copyright Alexander Nasonov, 2006-2010. // Copyright Antony Polukhin, 2011-2019. // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // // what: lexical_cast custom keyword cast // who: contributed by Kevlin Henney, // enhanced with contributions from Terje Slettebo, // with additional fixes and suggestions from Gennaro Prota, // Beman Dawes, Dave Abrahams, Daryle Walker, Peter Dimov, // Alexander Nasonov, Antony Polukhin, Justin Viiret, Michael Hofmann, // Cheng Yang, Matthew Bradbury, David W. Birdsall, Pavel Korzh and other Boosters // when: November 2000, March 2003, June 2005, June 2006, March 2011 - 2014 #ifndef BOOST_LEXICAL_CAST_DETAIL_CONVERTER_LEXICAL_HPP #define BOOST_LEXICAL_CAST_DETAIL_CONVERTER_LEXICAL_HPP #include #ifdef BOOST_HAS_PRAGMA_ONCE # pragma once #endif #if defined(BOOST_NO_STRINGSTREAM) || defined(BOOST_NO_STD_WSTRING) #define BOOST_LCAST_NO_WCHAR_T #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef BOOST_NO_CXX11_HDR_ARRAY #include #endif #include #include #include #include namespace boost { namespace detail // normalize_single_byte_char { // Converts signed/unsigned char to char template < class Char > struct normalize_single_byte_char { typedef Char type; }; template <> struct normalize_single_byte_char< signed char > { typedef char type; }; template <> struct normalize_single_byte_char< unsigned char > { typedef char type; }; } namespace detail // deduce_character_type_later { // Helper type, meaning that stram character for T must be deduced // at Stage 2 (See deduce_source_char and deduce_target_char) template < class T > struct deduce_character_type_later {}; } namespace detail // stream_char_common { // Selectors to choose stream character type (common for Source and Target) // Returns one of char, wchar_t, char16_t, char32_t or deduce_character_type_later types // Executed on Stage 1 (See deduce_source_char and deduce_target_char) template < typename Type > struct stream_char_common: public boost::conditional< boost::detail::is_character< Type >::value, Type, boost::detail::deduce_character_type_later< Type > > {}; template < typename Char > struct stream_char_common< Char* >: public boost::conditional< boost::detail::is_character< Char >::value, Char, boost::detail::deduce_character_type_later< Char* > > {}; template < typename Char > struct stream_char_common< const Char* >: public boost::conditional< boost::detail::is_character< Char >::value, Char, boost::detail::deduce_character_type_later< const Char* > > {}; template < typename Char > struct stream_char_common< boost::iterator_range< Char* > >: public boost::conditional< boost::detail::is_character< Char >::value, Char, boost::detail::deduce_character_type_later< boost::iterator_range< Char* > > > {}; template < typename Char > struct stream_char_common< boost::iterator_range< const Char* > >: public boost::conditional< boost::detail::is_character< Char >::value, Char, boost::detail::deduce_character_type_later< boost::iterator_range< const Char* > > > {}; template < class Char, class Traits, class Alloc > struct stream_char_common< std::basic_string< Char, Traits, Alloc > > { typedef Char type; }; template < class Char, class Traits, class Alloc > struct stream_char_common< boost::container::basic_string< Char, Traits, Alloc > > { typedef Char type; }; template < typename Char, std::size_t N > struct stream_char_common< boost::array< Char, N > >: public boost::conditional< boost::detail::is_character< Char >::value, Char, boost::detail::deduce_character_type_later< boost::array< Char, N > > > {}; template < typename Char, std::size_t N > struct stream_char_common< boost::array< const Char, N > >: public boost::conditional< boost::detail::is_character< Char >::value, Char, boost::detail::deduce_character_type_later< boost::array< const Char, N > > > {}; #ifndef BOOST_NO_CXX11_HDR_ARRAY template < typename Char, std::size_t N > struct stream_char_common< std::array >: public boost::conditional< boost::detail::is_character< Char >::value, Char, boost::detail::deduce_character_type_later< std::array< Char, N > > > {}; template < typename Char, std::size_t N > struct stream_char_common< std::array< const Char, N > >: public boost::conditional< boost::detail::is_character< Char >::value, Char, boost::detail::deduce_character_type_later< std::array< const Char, N > > > {}; #endif #ifdef BOOST_HAS_INT128 template <> struct stream_char_common< boost::int128_type >: public boost::type_identity< char > {}; template <> struct stream_char_common< boost::uint128_type >: public boost::type_identity< char > {}; #endif #if !defined(BOOST_LCAST_NO_WCHAR_T) && defined(BOOST_NO_INTRINSIC_WCHAR_T) template <> struct stream_char_common< wchar_t > { typedef char type; }; #endif } namespace detail // deduce_source_char_impl { // If type T is `deduce_character_type_later` type, then tries to deduce // character type using boost::has_left_shift metafunction. // Otherwise supplied type T is a character type, that must be normalized // using normalize_single_byte_char. // Executed at Stage 2 (See deduce_source_char and deduce_target_char) template < class Char > struct deduce_source_char_impl { typedef BOOST_DEDUCED_TYPENAME boost::detail::normalize_single_byte_char< Char >::type type; }; template < class T > struct deduce_source_char_impl< deduce_character_type_later< T > > { typedef boost::has_left_shift< std::basic_ostream< char >, T > result_t; #if defined(BOOST_LCAST_NO_WCHAR_T) BOOST_STATIC_ASSERT_MSG((result_t::value), "Source type is not std::ostream`able and std::wostream`s are not supported by your STL implementation"); typedef char type; #else typedef BOOST_DEDUCED_TYPENAME boost::conditional< result_t::value, char, wchar_t >::type type; BOOST_STATIC_ASSERT_MSG((result_t::value || boost::has_left_shift< std::basic_ostream< type >, T >::value), "Source type is neither std::ostream`able nor std::wostream`able"); #endif }; } namespace detail // deduce_target_char_impl { // If type T is `deduce_character_type_later` type, then tries to deduce // character type using boost::has_right_shift metafunction. // Otherwise supplied type T is a character type, that must be normalized // using normalize_single_byte_char. // Executed at Stage 2 (See deduce_source_char and deduce_target_char) template < class Char > struct deduce_target_char_impl { typedef BOOST_DEDUCED_TYPENAME normalize_single_byte_char< Char >::type type; }; template < class T > struct deduce_target_char_impl< deduce_character_type_later > { typedef boost::has_right_shift, T > result_t; #if defined(BOOST_LCAST_NO_WCHAR_T) BOOST_STATIC_ASSERT_MSG((result_t::value), "Target type is not std::istream`able and std::wistream`s are not supported by your STL implementation"); typedef char type; #else typedef BOOST_DEDUCED_TYPENAME boost::conditional< result_t::value, char, wchar_t >::type type; BOOST_STATIC_ASSERT_MSG((result_t::value || boost::has_right_shift, T >::value), "Target type is neither std::istream`able nor std::wistream`able"); #endif }; } namespace detail // deduce_target_char and deduce_source_char { // We deduce stream character types in two stages. // // Stage 1 is common for Target and Source. At Stage 1 we get // non normalized character type (may contain unsigned/signed char) // or deduce_character_type_later where T is the original type. // Stage 1 is executed by stream_char_common // // At Stage 2 we normalize character types or try to deduce character // type using metafunctions. // Stage 2 is executed by deduce_target_char_impl and // deduce_source_char_impl // // deduce_target_char and deduce_source_char functions combine // both stages template < class T > struct deduce_target_char { typedef BOOST_DEDUCED_TYPENAME stream_char_common< T >::type stage1_type; typedef BOOST_DEDUCED_TYPENAME deduce_target_char_impl< stage1_type >::type stage2_type; typedef stage2_type type; }; template < class T > struct deduce_source_char { typedef BOOST_DEDUCED_TYPENAME stream_char_common< T >::type stage1_type; typedef BOOST_DEDUCED_TYPENAME deduce_source_char_impl< stage1_type >::type stage2_type; typedef stage2_type type; }; } namespace detail // extract_char_traits template { // We are attempting to get char_traits<> from T // template parameter. Otherwise we'll be using std::char_traits template < class Char, class T > struct extract_char_traits : boost::false_type { typedef std::char_traits< Char > trait_t; }; template < class Char, class Traits, class Alloc > struct extract_char_traits< Char, std::basic_string< Char, Traits, Alloc > > : boost::true_type { typedef Traits trait_t; }; template < class Char, class Traits, class Alloc> struct extract_char_traits< Char, boost::container::basic_string< Char, Traits, Alloc > > : boost::true_type { typedef Traits trait_t; }; } namespace detail // array_to_pointer_decay { template struct array_to_pointer_decay { typedef T type; }; template struct array_to_pointer_decay { typedef const T * type; }; } namespace detail // lcast_src_length { // Return max. length of string representation of Source; template< class Source, // Source type of lexical_cast. class Enable = void // helper type > struct lcast_src_length { BOOST_STATIC_CONSTANT(std::size_t, value = 1); }; // Helper for integral types. // Notes on length calculation: // Max length for 32bit int with grouping "\1" and thousands_sep ',': // "-2,1,4,7,4,8,3,6,4,7" // ^ - is_signed // ^ - 1 digit not counted by digits10 // ^^^^^^^^^^^^^^^^^^ - digits10 * 2 // // Constant is_specialized is used instead of constant 1 // to prevent buffer overflow in a rare case when // doesn't add missing specialization for // numeric_limits for some integral type T. // When is_specialized is false, the whole expression is 0. template struct lcast_src_length< Source, BOOST_DEDUCED_TYPENAME boost::enable_if >::type > { #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS BOOST_STATIC_CONSTANT(std::size_t, value = std::numeric_limits::is_signed + std::numeric_limits::is_specialized + /* == 1 */ std::numeric_limits::digits10 * 2 ); #else BOOST_STATIC_CONSTANT(std::size_t, value = 156); BOOST_STATIC_ASSERT(sizeof(Source) * CHAR_BIT <= 256); #endif }; // Helper for floating point types. // -1.23456789e-123456 // ^ sign // ^ leading digit // ^ decimal point // ^^^^^^^^ lcast_precision::value // ^ "e" // ^ exponent sign // ^^^^^^ exponent (assumed 6 or less digits) // sign + leading digit + decimal point + "e" + exponent sign == 5 template struct lcast_src_length< Source, BOOST_DEDUCED_TYPENAME boost::enable_if >::type > { #ifndef BOOST_LCAST_NO_COMPILE_TIME_PRECISION BOOST_STATIC_ASSERT( std::numeric_limits::max_exponent10 <= 999999L && std::numeric_limits::min_exponent10 >= -999999L ); BOOST_STATIC_CONSTANT(std::size_t, value = 5 + lcast_precision::value + 6 ); #else // #ifndef BOOST_LCAST_NO_COMPILE_TIME_PRECISION BOOST_STATIC_CONSTANT(std::size_t, value = 156); #endif // #ifndef BOOST_LCAST_NO_COMPILE_TIME_PRECISION }; } namespace detail // lexical_cast_stream_traits { template struct lexical_cast_stream_traits { typedef BOOST_DEDUCED_TYPENAME boost::detail::array_to_pointer_decay::type src; typedef BOOST_DEDUCED_TYPENAME boost::remove_cv::type no_cv_src; typedef boost::detail::deduce_source_char deduce_src_char_metafunc; typedef BOOST_DEDUCED_TYPENAME deduce_src_char_metafunc::type src_char_t; typedef BOOST_DEDUCED_TYPENAME boost::detail::deduce_target_char::type target_char_t; typedef BOOST_DEDUCED_TYPENAME boost::detail::widest_char< target_char_t, src_char_t >::type char_type; #if !defined(BOOST_NO_CXX11_CHAR16_T) && defined(BOOST_NO_CXX11_UNICODE_LITERALS) BOOST_STATIC_ASSERT_MSG(( !boost::is_same::value && !boost::is_same::value), "Your compiler does not have full support for char16_t" ); #endif #if !defined(BOOST_NO_CXX11_CHAR32_T) && defined(BOOST_NO_CXX11_UNICODE_LITERALS) BOOST_STATIC_ASSERT_MSG(( !boost::is_same::value && !boost::is_same::value), "Your compiler does not have full support for char32_t" ); #endif typedef BOOST_DEDUCED_TYPENAME boost::conditional< boost::detail::extract_char_traits::value, BOOST_DEDUCED_TYPENAME boost::detail::extract_char_traits, BOOST_DEDUCED_TYPENAME boost::detail::extract_char_traits >::type::trait_t traits; typedef boost::integral_constant< bool, boost::is_same::value && // source is not a wide character based type (sizeof(char) != sizeof(target_char_t)) && // target type is based on wide character (!(boost::detail::is_character::value)) > is_string_widening_required_t; typedef boost::integral_constant< bool, !(boost::is_integral::value || boost::detail::is_character< BOOST_DEDUCED_TYPENAME deduce_src_char_metafunc::stage1_type // if we did not get character type at stage1 >::value // then we have no optimization for that type ) > is_source_input_not_optimized_t; // If we have an optimized conversion for // Source, we do not need to construct stringbuf. BOOST_STATIC_CONSTANT(bool, requires_stringbuf = (is_string_widening_required_t::value || is_source_input_not_optimized_t::value) ); typedef boost::detail::lcast_src_length len_t; }; } namespace detail { template struct lexical_converter_impl { typedef lexical_cast_stream_traits stream_trait; typedef detail::lexical_istream_limited_src< BOOST_DEDUCED_TYPENAME stream_trait::char_type, BOOST_DEDUCED_TYPENAME stream_trait::traits, stream_trait::requires_stringbuf, stream_trait::len_t::value + 1 > i_interpreter_type; typedef detail::lexical_ostream_limited_src< BOOST_DEDUCED_TYPENAME stream_trait::char_type, BOOST_DEDUCED_TYPENAME stream_trait::traits > o_interpreter_type; static inline bool try_convert(const Source& arg, Target& result) { i_interpreter_type i_interpreter; // Disabling ADL, by directly specifying operators. if (!(i_interpreter.operator <<(arg))) return false; o_interpreter_type out(i_interpreter.cbegin(), i_interpreter.cend()); // Disabling ADL, by directly specifying operators. if(!(out.operator >>(result))) return false; return true; } }; } } // namespace boost #undef BOOST_LCAST_NO_WCHAR_T #endif // BOOST_LEXICAL_CAST_DETAIL_CONVERTER_LEXICAL_HPP