| // Copyright Kevlin Henney, 2000-2005. |
| // Copyright Alexander Nasonov, 2006-2010. |
| // Copyright Antony Polukhin, 2011-2014. |
| // |
| // 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 <boost/config.hpp> |
| #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 <cstddef> |
| #include <string> |
| #include <boost/limits.hpp> |
| #include <boost/mpl/if.hpp> |
| #include <boost/type_traits/ice.hpp> |
| #include <boost/type_traits/is_integral.hpp> |
| #include <boost/type_traits/is_float.hpp> |
| #include <boost/type_traits/has_left_shift.hpp> |
| #include <boost/type_traits/has_right_shift.hpp> |
| #include <boost/static_assert.hpp> |
| #include <boost/detail/lcast_precision.hpp> |
| |
| #include <boost/lexical_cast/detail/widest_char.hpp> |
| #include <boost/lexical_cast/detail/is_character.hpp> |
| |
| #ifndef BOOST_NO_CXX11_HDR_ARRAY |
| #include <array> |
| #endif |
| |
| #include <boost/array.hpp> |
| #include <boost/range/iterator_range_core.hpp> |
| #include <boost/container/container_fwd.hpp> |
| |
| #include <boost/lexical_cast/detail/converter_lexical_streams.hpp> |
| |
| namespace boost { |
| |
| namespace detail // normalize_single_byte_char<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<T> |
| { |
| // Helper type, meaning that stram character for T must be deduced |
| // at Stage 2 (See deduce_source_char<T> and deduce_target_char<T>) |
| template < class T > struct deduce_character_type_later {}; |
| } |
| |
| namespace detail // stream_char_common<T> |
| { |
| // 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<T> types |
| // Executed on Stage 1 (See deduce_source_char<T> and deduce_target_char<T>) |
| template < typename Type > |
| struct stream_char_common: public boost::mpl::if_c< |
| boost::detail::is_character< Type >::value, |
| Type, |
| boost::detail::deduce_character_type_later< Type > |
| > {}; |
| |
| template < typename Char > |
| struct stream_char_common< Char* >: public boost::mpl::if_c< |
| 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::mpl::if_c< |
| 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::mpl::if_c< |
| 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::mpl::if_c< |
| 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::mpl::if_c< |
| 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::mpl::if_c< |
| 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<Char, N > >: public boost::mpl::if_c< |
| 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::mpl::if_c< |
| 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::mpl::identity< char > {}; |
| template <> struct stream_char_common< boost::uint128_type >: public boost::mpl::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<T> |
| { |
| // If type T is `deduce_character_type_later` type, then tries to deduce |
| // character type using boost::has_left_shift<T> metafunction. |
| // Otherwise supplied type T is a character type, that must be normalized |
| // using normalize_single_byte_char<Char>. |
| // Executed at Stage 2 (See deduce_source_char<T> and deduce_target_char<T>) |
| 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::mpl::if_c< |
| 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<T> |
| { |
| // If type T is `deduce_character_type_later` type, then tries to deduce |
| // character type using boost::has_right_shift<T> metafunction. |
| // Otherwise supplied type T is a character type, that must be normalized |
| // using normalize_single_byte_char<Char>. |
| // Executed at Stage 2 (See deduce_source_char<T> and deduce_target_char<T>) |
| 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<T> > |
| { |
| typedef boost::has_right_shift<std::basic_istream<char>, 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::mpl::if_c< |
| result_t::value, char, wchar_t |
| >::type type; |
| |
| BOOST_STATIC_ASSERT_MSG((result_t::value || boost::has_right_shift<std::basic_istream<wchar_t>, T >::value), |
| "Target type is neither std::istream`able nor std::wistream`able"); |
| #endif |
| }; |
| } |
| |
| namespace detail // deduce_target_char<T> and deduce_source_char<T> |
| { |
| // 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<T> where T is the original type. |
| // Stage 1 is executed by stream_char_common<T> |
| // |
| // At Stage 2 we normalize character types or try to deduce character |
| // type using metafunctions. |
| // Stage 2 is executed by deduce_target_char_impl<T> and |
| // deduce_source_char_impl<T> |
| // |
| // deduce_target_char<T> and deduce_source_char<T> 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<Char> |
| 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<T> |
| { |
| template<class T> |
| struct array_to_pointer_decay |
| { |
| typedef T type; |
| }; |
| |
| template<class T, std::size_t N> |
| struct array_to_pointer_decay<T[N]> |
| { |
| typedef const T * type; |
| }; |
| } |
| |
| namespace detail // is_this_float_conversion_optimized<Float, Char> |
| { |
| // this metafunction evaluates to true, if we have optimized comnversion |
| // from Float type to Char array. |
| // Must be in sync with lexical_stream_limited_src<Char, ...>::shl_real_type(...) |
| template <typename Float, typename Char> |
| struct is_this_float_conversion_optimized |
| { |
| typedef boost::type_traits::ice_and< |
| boost::is_float<Float>::value, |
| #if !defined(BOOST_LCAST_NO_WCHAR_T) && !defined(BOOST_NO_SWPRINTF) && !defined(__MINGW32__) |
| boost::type_traits::ice_or< |
| boost::type_traits::ice_eq<sizeof(Char), sizeof(char) >::value, |
| boost::is_same<Char, wchar_t>::value |
| >::value |
| #else |
| boost::type_traits::ice_eq<sizeof(Char), sizeof(char) >::value |
| #endif |
| > result_type; |
| |
| BOOST_STATIC_CONSTANT(bool, value = (result_type::value) ); |
| }; |
| } |
| |
| 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 |
| // <boost/limits.hpp> doesn't add missing specialization for |
| // numeric_limits<T> for some integral type T. |
| // When is_specialized is false, the whole expression is 0. |
| template <class Source> |
| struct lcast_src_length< |
| Source, BOOST_DEDUCED_TYPENAME boost::enable_if<boost::is_integral<Source> >::type |
| > |
| { |
| #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS |
| BOOST_STATIC_CONSTANT(std::size_t, value = |
| std::numeric_limits<Source>::is_signed + |
| std::numeric_limits<Source>::is_specialized + /* == 1 */ |
| std::numeric_limits<Source>::digits10 * 2 |
| ); |
| #else |
| BOOST_STATIC_CONSTANT(std::size_t, value = 156); |
| BOOST_STATIC_ASSERT(sizeof(Source) * CHAR_BIT <= 256); |
| #endif |
| }; |
| |
| #ifndef BOOST_LCAST_NO_COMPILE_TIME_PRECISION |
| // Helper for floating point types. |
| // -1.23456789e-123456 |
| // ^ sign |
| // ^ leading digit |
| // ^ decimal point |
| // ^^^^^^^^ lcast_precision<Source>::value |
| // ^ "e" |
| // ^ exponent sign |
| // ^^^^^^ exponent (assumed 6 or less digits) |
| // sign + leading digit + decimal point + "e" + exponent sign == 5 |
| template<class Source> |
| struct lcast_src_length< |
| Source, BOOST_DEDUCED_TYPENAME boost::enable_if<boost::is_float<Source> >::type |
| > |
| { |
| BOOST_STATIC_ASSERT( |
| std::numeric_limits<Source>::max_exponent10 <= 999999L && |
| std::numeric_limits<Source>::min_exponent10 >= -999999L |
| ); |
| |
| BOOST_STATIC_CONSTANT(std::size_t, value = |
| 5 + lcast_precision<Source>::value + 6 |
| ); |
| }; |
| #endif // #ifndef BOOST_LCAST_NO_COMPILE_TIME_PRECISION |
| } |
| |
| namespace detail // lexical_cast_stream_traits<Source, Target> |
| { |
| template <class Source, class Target> |
| struct lexical_cast_stream_traits { |
| typedef BOOST_DEDUCED_TYPENAME boost::detail::array_to_pointer_decay<Source>::type src; |
| typedef BOOST_DEDUCED_TYPENAME boost::remove_cv<src>::type no_cv_src; |
| |
| typedef boost::detail::deduce_source_char<no_cv_src> 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<Target>::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<char16_t, src_char_t>::value |
| && !boost::is_same<char16_t, target_char_t>::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<char32_t, src_char_t>::value |
| && !boost::is_same<char32_t, target_char_t>::value), |
| "Your compiler does not have full support for char32_t" ); |
| #endif |
| |
| typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_c< |
| boost::detail::extract_char_traits<char_type, Target>::value, |
| BOOST_DEDUCED_TYPENAME boost::detail::extract_char_traits<char_type, Target>, |
| BOOST_DEDUCED_TYPENAME boost::detail::extract_char_traits<char_type, no_cv_src> |
| >::type::trait_t traits; |
| |
| typedef boost::type_traits::ice_and< |
| boost::is_same<char, src_char_t>::value, // source is not a wide character based type |
| boost::type_traits::ice_ne<sizeof(char), sizeof(target_char_t) >::value, // target type is based on wide character |
| boost::type_traits::ice_not< |
| boost::detail::is_character<no_cv_src>::value // single character widening is optimized |
| >::value // and does not requires stringbuffer |
| > is_string_widening_required_t; |
| |
| typedef boost::type_traits::ice_not< boost::type_traits::ice_or< |
| boost::is_integral<no_cv_src>::value, |
| boost::detail::is_this_float_conversion_optimized<no_cv_src, char_type >::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 |
| >::value > 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 = |
| (boost::type_traits::ice_or< |
| is_string_widening_required_t::value, is_source_input_not_optimized_t::value |
| >::value) |
| ); |
| |
| typedef boost::detail::lcast_src_length<no_cv_src> len_t; |
| }; |
| } |
| |
| namespace detail |
| { |
| template<typename Target, typename Source> |
| struct lexical_converter_impl |
| { |
| typedef lexical_cast_stream_traits<Source, Target> 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 |
| |