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