From dbda7689e0609d822f5f9ddf893dd7acf91366a5 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Sun, 2 Dec 2012 09:33:42 +0000 Subject: [PATCH] Merge lexical_cast from trunk: * Deduce stream character type for user defined classes (fixes #6786) * Deprecated macros replaced with new ones (thanks to Marshall Clow) * Updated documentation (refs #6786, fixes #7582) * More tests and minor bugfixes [SVN r81668] --- doc/lexical_cast.qbk | 13 +- include/boost/lexical_cast.hpp | 723 +++++++++++--------- lexical_cast_test.cpp | 38 +- test/Jamfile.v2 | 2 + test/lexical_cast_arrays_test.cpp | 12 +- test/lexical_cast_containers_test.cpp | 4 +- test/lexical_cast_empty_input_test.cpp | 4 +- test/lexical_cast_float_types_test.cpp | 4 + test/lexical_cast_inf_nan_test.cpp | 4 + test/lexical_cast_integral_types_test.cpp | 4 +- test/lexical_cast_iterator_range_test.cpp | 8 +- test/lexical_cast_loopback_test.cpp | 4 + test/lexical_cast_stream_detection_test.cpp | 307 +++++++++ test/lexical_cast_stream_traits_test.cpp | 155 +++++ test/lexical_cast_wchars_test.cpp | 4 +- 15 files changed, 927 insertions(+), 359 deletions(-) create mode 100644 test/lexical_cast_stream_detection_test.cpp create mode 100644 test/lexical_cast_stream_traits_test.cpp diff --git a/doc/lexical_cast.qbk b/doc/lexical_cast.qbk index ddc0e06..3d0e319 100644 --- a/doc/lexical_cast.qbk +++ b/doc/lexical_cast.qbk @@ -119,15 +119,14 @@ The requirements on the argument and result types for both functions are: * Target is CopyConstructible [20.1.3]. * Target is DefaultConstructible, meaning that it is possible to default-initialize an object of that type [8.5, 20.1.4]. -The character type of the underlying stream is assumed to be `char` unless either the `Source` or the `Target` requires wide-character streaming, in which case the underlying stream uses `wchar_t`, `char16_t` or `char32_t`. Wide-character streaming is currently detected for: +The character type of the underlying stream is assumed to be `char` unless either the `Source` or the `Target` requires wide-character streaming, in which case the underlying stream uses `wchar_t`. Following types also can use `char16_t` or `char32_t` for wide-character streaming: -* Single character: `wchar_t`, `char16_t`, `char32_t` -* Arrays of characters: `wchar_t *`, `char16_t *`, `char32_t *`, `const wchar_t *`, `const char16_t *`, `const char32_t *` +* Single character: `char16_t`, `char32_t` +* Arrays of characters: `char16_t *`, `char32_t *`, `const char16_t *`, `const char32_t *` * Strings: `std::basic_string`, `boost::containers::basic_string` * `boost::iterator_range`, where `WideCharPtr` is a pointer to wide-character or pointer to const wide-character * `boost::array` and `std::array`, `boost::array` and `std::array` - [important Many compilers and runtime libraries fail to make conversions using new Unicode characters. Make sure that the following code compiles and outputs nonzero values, before using new types: `` std::cout @@ -235,7 +234,7 @@ It breaks my `operator>>` that works only in presence of this flag. Can you remo * [*Answer:] May be in a future version. There is no requirement in __proposallong__ to reset the flag but remember that __proposalshort__ is not yet accepted by the committee. By the way, it's a great opportunity to -make your `operator>>` conform to the standard. +make your `operator>>` more general. Read a good C++ book, study `std::sentry` and [@boost:libs/io/doc/ios_state.html `ios_state_saver`]. [pre @@ -273,6 +272,10 @@ limitation of compiler options that you use. [section Changes] +* [*boost 1.53.0 :] + + * Much better input and output streams detection for user defined types. + * [*boost 1.52.0 :] * Restored compilation on MSVC-2003 (was broken in 1.51.0). diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index c475982..cfb98cf 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -112,7 +112,7 @@ namespace boost return *target; } -#ifndef BOOST_NO_NOEXCEPT +#ifndef BOOST_NO_CXX11_NOEXCEPT virtual const char *what() const noexcept #else virtual const char *what() const throw() @@ -122,7 +122,7 @@ namespace boost "source type value could not be interpreted as target"; } -#ifndef BOOST_NO_NOEXCEPT +#ifndef BOOST_NO_CXX11_NOEXCEPT virtual ~bad_lexical_cast() BOOST_NOEXCEPT #else virtual ~bad_lexical_cast() throw() @@ -162,6 +162,8 @@ namespace boost #include #include #include +#include +#include #include #include #include @@ -171,242 +173,376 @@ namespace boost #endif namespace boost { - namespace detail // widest_char<...> (continuation) - { - struct not_a_character_type{}; - template - struct widest_char - { - typedef CharT type; - }; - - template - struct widest_char< CharT, not_a_character_type > - { - typedef CharT type; - }; - - template <> - struct widest_char< not_a_character_type, not_a_character_type > - { - typedef char type; - }; - } - - namespace detail // is_char_or_wchar<...> and stream_char<...> templates + namespace detail // is_char_or_wchar<...> { // returns true, if T is one of the character types - template + template < typename T > struct is_char_or_wchar { - typedef ::boost::type_traits::ice_or< - ::boost::is_same< T, char >::value, + typedef boost::type_traits::ice_or< + boost::is_same< T, char >::value, #ifndef BOOST_LCAST_NO_WCHAR_T - ::boost::is_same< T, wchar_t >::value, + boost::is_same< T, wchar_t >::value, #endif - #ifndef BOOST_NO_CHAR16_T - ::boost::is_same< T, char16_t >::value, + #ifndef BOOST_NO_CXX11_CHAR16_T + boost::is_same< T, char16_t >::value, #endif - #ifndef BOOST_NO_CHAR32_T - ::boost::is_same< T, char32_t >::value, + #ifndef BOOST_NO_CXX11_CHAR32_T + boost::is_same< T, char32_t >::value, #endif - ::boost::is_same< T, unsigned char >::value, - ::boost::is_same< T, signed char >::value + boost::is_same< T, unsigned char >::value, + boost::is_same< T, signed char >::value > result_type; BOOST_STATIC_CONSTANT(bool, value = (result_type::value) ); }; + } - // selectors for choosing stream character type - // returns one of char, wchar_t, char16_t, char32_t or not_a_character_type types - template - struct stream_char + namespace detail // normalize_single_byte_char + { + // Converts signed/unsigned char to char + template < class Char > + struct normalize_single_byte_char { - typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_c< - is_char_or_wchar::value, - Type, - boost::detail::not_a_character_type - >::type type; + typedef Char type; }; template <> - struct stream_char + struct normalize_single_byte_char< signed char > { typedef char type; }; template <> - struct stream_char + struct normalize_single_byte_char< unsigned char > { typedef char type; }; + } - template - struct stream_char - { - typedef BOOST_DEDUCED_TYPENAME stream_char::type 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 {}; + } - template - struct stream_char - { - typedef BOOST_DEDUCED_TYPENAME stream_char::type type; - }; + 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::mpl::if_c< + boost::detail::is_char_or_wchar< Type >::value, + Type, + boost::detail::deduce_character_type_later< Type > + > {}; - template - struct stream_char > - { - typedef BOOST_DEDUCED_TYPENAME stream_char::type type; - }; + template < typename Char > + struct stream_char_common< Char* >: public boost::mpl::if_c< + boost::detail::is_char_or_wchar< 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_char_or_wchar< 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_char_or_wchar< Char >::value, + Char, + boost::detail::deduce_character_type_later< boost::iterator_range< Char* > > + > {}; - template - struct stream_char > + template < typename Char > + struct stream_char_common< boost::iterator_range< const Char* > >: public boost::mpl::if_c< + boost::detail::is_char_or_wchar< 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 BOOST_DEDUCED_TYPENAME stream_char::type type; + typedef Char type; }; - template - struct stream_char< std::basic_string > + template < class Char, class Traits, class Alloc > + struct stream_char_common< boost::container::basic_string< Char, Traits, Alloc > > { - typedef CharT type; + typedef Char type; }; - template - struct stream_char< ::boost::container::basic_string > - { - typedef CharT type; - }; + template < typename Char, std::size_t N > + struct stream_char_common< boost::array< Char, N > >: public boost::mpl::if_c< + boost::detail::is_char_or_wchar< Char >::value, + Char, + boost::detail::deduce_character_type_later< boost::array< Char, N > > + > {}; - template - struct stream_char > - { - typedef BOOST_DEDUCED_TYPENAME stream_char::type type; - }; - - template - struct stream_char > - { - typedef BOOST_DEDUCED_TYPENAME stream_char::type type; - }; + template < typename Char, std::size_t N > + struct stream_char_common< boost::array< const Char, N > >: public boost::mpl::if_c< + boost::detail::is_char_or_wchar< Char >::value, + Char, + boost::detail::deduce_character_type_later< boost::array< const Char, N > > + > {}; #if !defined(BOOST_NO_CXX11_HDR_ARRAY) && defined(BOOST_HAS_TR1_ARRAY) - template - struct stream_char > - { - typedef BOOST_DEDUCED_TYPENAME stream_char::type type; - }; + template < typename Char, std::size_t N > + struct stream_char_common< std::array >: public boost::mpl::if_c< + boost::detail::is_char_or_wchar< Char >::value, + Char, + boost::detail::deduce_character_type_later< std::array< Char, N > > + > {}; - template - struct stream_char > - { - typedef BOOST_DEDUCED_TYPENAME stream_char::type type; - }; + template < typename Char, std::size_t N > + struct stream_char_common< std::array< const Char, N > >: public boost::mpl::if_c< + boost::detail::is_char_or_wchar< Char >::value, + Char, + boost::detail::deduce_character_type_later< std::array< const Char, N > > + > {}; #endif // !defined(BOOST_NO_CXX11_HDR_ARRAY) && defined(BOOST_HAS_TR1_ARRAY) #if !defined(BOOST_LCAST_NO_WCHAR_T) && defined(BOOST_NO_INTRINSIC_WCHAR_T) - template<> - struct stream_char + template <> + struct stream_char_common< wchar_t > { - typedef boost::detail::not_a_character_type type; - }; - - template<> - struct stream_char - { - typedef wchar_t type; - }; - - template<> - struct stream_char - { - typedef wchar_t type; + 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::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 + { + // 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::mpl::if_c< + 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 // deduce_char_traits template { - - template + // We are attempting to get char_traits<> from Source or Tagret + // template parameter. Otherwise we'll be using std::char_traits + template < class Char, class Target, class Source > struct deduce_char_traits { - typedef std::char_traits type; + typedef std::char_traits< Char > type; }; - template - struct deduce_char_traits< CharT - , std::basic_string + template < class Char, class Traits, class Alloc, class Source > + struct deduce_char_traits< Char + , std::basic_string< Char, Traits, Alloc > , Source > { typedef Traits type; }; - template - struct deduce_char_traits< CharT + template < class Char, class Target, class Traits, class Alloc > + struct deduce_char_traits< Char , Target - , std::basic_string + , std::basic_string< Char, Traits, Alloc > > { typedef Traits type; }; - template - struct deduce_char_traits< CharT - , ::boost::container::basic_string + template < class Char, class Traits, class Alloc, class Source > + struct deduce_char_traits< Char + , boost::container::basic_string< Char, Traits, Alloc > , Source > { typedef Traits type; }; - template - struct deduce_char_traits< CharT + template < class Char, class Target, class Traits, class Alloc > + struct deduce_char_traits< Char , Target - , ::boost::container::basic_string + , boost::container::basic_string< Char, Traits, Alloc > > { typedef Traits type; }; - template - struct deduce_char_traits< CharT - , std::basic_string - , std::basic_string + template < class Char, class Traits, class Alloc1, class Alloc2 > + struct deduce_char_traits< Char + , std::basic_string< Char, Traits, Alloc1 > + , std::basic_string< Char, Traits, Alloc2 > > { typedef Traits type; }; - template - struct deduce_char_traits< CharT - , ::boost::container::basic_string - , ::boost::container::basic_string + template + struct deduce_char_traits< Char + , boost::container::basic_string< Char, Traits, Alloc1 > + , boost::container::basic_string< Char, Traits, Alloc2 > > { typedef Traits type; }; - template - struct deduce_char_traits< CharT - , ::boost::container::basic_string - , ::std::basic_string + template < class Char, class Traits, class Alloc1, class Alloc2 > + struct deduce_char_traits< Char + , boost::container::basic_string< Char, Traits, Alloc1 > + , std::basic_string< Char, Traits, Alloc2 > > { typedef Traits type; }; - template - struct deduce_char_traits< CharT - , ::std::basic_string - , ::boost::container::basic_string + template < class Char, class Traits, class Alloc1, class Alloc2 > + struct deduce_char_traits< Char + , std::basic_string< Char, Traits, Alloc1 > + , boost::container::basic_string< Char, Traits, Alloc2 > > { typedef Traits type; }; } + 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 // is_this_float_conversion_optimized + { + // 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::shl_real_type(...) + template + struct is_this_float_conversion_optimized + { + typedef boost::type_traits::ice_and< + boost::is_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::value, + boost::is_same::value + >::value +#else + boost::type_traits::ice_eq::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; @@ -516,9 +652,67 @@ namespace boost { #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::detail::deduce_char_traits< + char_type, Target, no_cv_src + >::type traits; + + typedef boost::type_traits::ice_and< + boost::is_same::value, // source is not a wide character based type + boost::type_traits::ice_ne::value, // target type is based on wide character + boost::type_traits::ice_not< + boost::detail::is_char_or_wchar::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::value, + boost::detail::is_this_float_conversion_optimized::value, + boost::detail::is_char_or_wchar< + 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 len_t; + }; + } + namespace detail // '0', '+' and '-' constants { - template struct lcast_char_constants; + template < typename Char > struct lcast_char_constants; template<> struct lcast_char_constants @@ -544,7 +738,7 @@ namespace boost { }; #endif -#if !defined(BOOST_NO_CHAR16_T) && !defined(BOOST_NO_UNICODE_LITERALS) +#if !defined(BOOST_NO_CXX11_CHAR16_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS) template<> struct lcast_char_constants { @@ -557,7 +751,7 @@ namespace boost { }; #endif -#if !defined(BOOST_NO_CHAR32_T) && !defined(BOOST_NO_UNICODE_LITERALS) +#if !defined(BOOST_NO_CXX11_CHAR32_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS) template<> struct lcast_char_constants { @@ -907,7 +1101,7 @@ namespace boost { } #endif -#if !defined(BOOST_NO_CHAR16_T) && !defined(BOOST_NO_UNICODE_LITERALS) +#if !defined(BOOST_NO_CXX11_CHAR16_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS) template bool parse_inf_nan(const char16_t* begin, const char16_t* end, T& value) BOOST_NOEXCEPT { @@ -923,7 +1117,7 @@ namespace boost { return put_inf_nan_impl(begin, end, value, u"nan", u"infinity"); } #endif -#if !defined(BOOST_NO_CHAR32_T) && !defined(BOOST_NO_UNICODE_LITERALS) +#if !defined(BOOST_NO_CXX11_CHAR32_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS) template bool parse_inf_nan(const char32_t* begin, const char32_t* end, T& value) BOOST_NOEXCEPT { @@ -1247,7 +1441,7 @@ namespace boost { typedef std::basic_ostringstream out_stream_t; typedef stl_buf_unlocker, CharT> unlocked_but_t; #endif - typedef BOOST_DEDUCED_TYPENAME ::boost::mpl::if_c< + typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_c< RequiresStringbuffer, out_stream_t, do_not_construct_out_stream_t @@ -1288,7 +1482,7 @@ namespace boost { std::locale loc; CharT const w = BOOST_USE_FACET(std::ctype, loc).widen(ch); #else - CharT const w = ch; + CharT const w = static_cast(ch); #endif Traits::assign(*start, w); finish = start + 1; @@ -1439,7 +1633,7 @@ namespace boost { } template - bool operator<<(::boost::container::basic_string const& str) BOOST_NOEXCEPT + bool operator<<(boost::container::basic_string const& str) BOOST_NOEXCEPT { start = const_cast(str.data()); finish = start + str.length(); @@ -1510,12 +1704,12 @@ namespace boost { bool operator<<(wchar_t ch) { return shl_char(ch); } #endif #endif -#if !defined(BOOST_NO_CHAR16_T) && !defined(BOOST_NO_UNICODE_LITERALS) +#if !defined(BOOST_NO_CXX11_CHAR16_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS) bool operator<<(char16_t ch) { return shl_char(ch); } bool operator<<(char16_t * str) { return shl_char_array(str); } bool operator<<(char16_t const * str) { return shl_char_array(str); } #endif -#if !defined(BOOST_NO_CHAR32_T) && !defined(BOOST_NO_UNICODE_LITERALS) +#if !defined(BOOST_NO_CXX11_CHAR32_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS) bool operator<<(char32_t ch) { return shl_char(ch); } bool operator<<(char32_t * str) { return shl_char_array(str); } bool operator<<(char32_t const * str) { return shl_char_array(str); } @@ -1767,17 +1961,17 @@ namespace boost { #if !defined(BOOST_LCAST_NO_WCHAR_T) && !defined(BOOST_NO_INTRINSIC_WCHAR_T) bool operator>>(wchar_t& output) { return shr_xchar(output); } #endif -#if !defined(BOOST_NO_CHAR16_T) && !defined(BOOST_NO_UNICODE_LITERALS) +#if !defined(BOOST_NO_CXX11_CHAR16_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS) bool operator>>(char16_t& output) { return shr_xchar(output); } #endif -#if !defined(BOOST_NO_CHAR32_T) && !defined(BOOST_NO_UNICODE_LITERALS) +#if !defined(BOOST_NO_CXX11_CHAR32_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS) bool operator>>(char32_t& output) { return shr_xchar(output); } #endif template bool operator>>(std::basic_string& str) { str.assign(start, finish); return true; } template - bool operator>>(::boost::container::basic_string& str) { str.assign(start, finish); return true; } + bool operator>>(boost::container::basic_string& str) { str.assign(start, finish); return true; } private: @@ -1917,7 +2111,7 @@ namespace boost { * */ boost::mpl::if_c< #if defined(BOOST_HAS_LONG_LONG) || defined(BOOST_HAS_MS_INT64) - ::boost::type_traits::ice_eq< sizeof(double), sizeof(long double) >::value, + boost::type_traits::ice_eq< sizeof(double), sizeof(long double) >::value, #else 0 #endif @@ -1943,18 +2137,6 @@ namespace boost { namespace detail { - template - struct array_to_pointer_decay - { - typedef T type; - }; - - template - struct array_to_pointer_decay - { - typedef const T * type; - }; - template struct is_stdstring { @@ -1968,7 +2150,7 @@ namespace boost { }; template - struct is_stdstring< ::boost::container::basic_string > + struct is_stdstring< boost::container::basic_string > { BOOST_STATIC_CONSTANT(bool, value = true ); }; @@ -1978,13 +2160,13 @@ namespace boost { { BOOST_STATIC_CONSTANT(bool, value = ( - ::boost::type_traits::ice_and< - ::boost::is_arithmetic::value, - ::boost::is_arithmetic::value, - ::boost::type_traits::ice_not< + boost::type_traits::ice_and< + boost::is_arithmetic::value, + boost::is_arithmetic::value, + boost::type_traits::ice_not< detail::is_char_or_wchar::value >::value, - ::boost::type_traits::ice_not< + boost::type_traits::ice_not< detail::is_char_or_wchar::value >::value >::value @@ -2002,14 +2184,14 @@ namespace boost { { BOOST_STATIC_CONSTANT(bool, value = ( - ::boost::type_traits::ice_or< - ::boost::type_traits::ice_and< + boost::type_traits::ice_or< + boost::type_traits::ice_and< is_same::value, is_char_or_wchar::value >::value, - ::boost::type_traits::ice_and< - ::boost::type_traits::ice_eq< sizeof(char),sizeof(Target)>::value, - ::boost::type_traits::ice_eq< sizeof(char),sizeof(Source)>::value, + boost::type_traits::ice_and< + boost::type_traits::ice_eq< sizeof(char),sizeof(Target)>::value, + boost::type_traits::ice_eq< sizeof(char),sizeof(Source)>::value, is_char_or_wchar::value, is_char_or_wchar::value >::value @@ -2018,28 +2200,6 @@ namespace boost { ); }; - - // 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::shl_real_type(...) - template - struct is_this_float_conversion_optimized - { - typedef ::boost::type_traits::ice_and< - ::boost::is_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::value, - ::boost::is_same::value - >::value -#else - ::boost::type_traits::ice_eq::value -#endif - > result_type; - - BOOST_STATIC_CONSTANT(bool, value = (result_type::value) ); - }; - template struct is_char_array_to_stdstring { @@ -2059,13 +2219,13 @@ namespace boost { }; template - struct is_char_array_to_stdstring< ::boost::container::basic_string, CharT* > + struct is_char_array_to_stdstring< boost::container::basic_string, CharT* > { BOOST_STATIC_CONSTANT(bool, value = true ); }; template - struct is_char_array_to_stdstring< ::boost::container::basic_string, const CharT* > + struct is_char_array_to_stdstring< boost::container::basic_string, const CharT* > { BOOST_STATIC_CONSTANT(bool, value = true ); }; @@ -2081,60 +2241,21 @@ namespace boost { { static inline Target lexical_cast_impl(const Source& arg) { - typedef BOOST_DEDUCED_TYPENAME detail::array_to_pointer_decay::type src; - typedef BOOST_DEDUCED_TYPENAME ::boost::remove_cv::type no_cv_src; - typedef BOOST_DEDUCED_TYPENAME detail::stream_char::type target_char_t; - typedef BOOST_DEDUCED_TYPENAME detail::stream_char::type src_char_type; - typedef BOOST_DEDUCED_TYPENAME detail::widest_char< - target_char_t, src_char_type - >::type char_type; - -#if !defined(BOOST_NO_CHAR16_T) && defined(BOOST_NO_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_CHAR32_T) && defined(BOOST_NO_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::detail::deduce_char_traits< - char_type, Target, no_cv_src - >::type traits; - - typedef ::boost::type_traits::ice_and< - ::boost::detail::is_char_or_wchar::value, // source is lexical type - ::boost::detail::is_char_or_wchar::value, // target is a lexical type - ::boost::is_same::value, // source is not a wide character based type - ::boost::type_traits::ice_ne::value // target type is based on wide character - > is_string_widening_required_t; - - typedef ::boost::type_traits::ice_or< - ::boost::is_integral::value, - ::boost::detail::is_this_float_conversion_optimized::value, - ::boost::detail::is_char_or_wchar::value - > is_source_input_optimized_t; + typedef lexical_cast_stream_traits stream_trait; + + typedef detail::lexical_stream_limited_src< + BOOST_DEDUCED_TYPENAME stream_trait::char_type, + BOOST_DEDUCED_TYPENAME stream_trait::traits, + stream_trait::requires_stringbuf + > interpreter_type; // Target type must be default constructible - Target result; + Target result; - // If we have an optimized conversion for - // Source, we do not need to construct stringbuf. - const bool requires_stringbuf = ::boost::type_traits::ice_or< - is_string_widening_required_t::value, - ::boost::type_traits::ice_not< is_source_input_optimized_t::value >::value - >::value; - - typedef detail::lexical_stream_limited_src interpreter_type; + BOOST_DEDUCED_TYPENAME stream_trait::char_type buf[stream_trait::len_t::value + 1]; + stream_trait::len_t::check_coverage(); - typedef detail::lcast_src_length lcast_src_length; - std::size_t const src_len = lcast_src_length::value; - char_type buf[src_len + 1]; - lcast_src_length::check_coverage(); - - interpreter_type interpreter(buf, buf + src_len); + interpreter_type interpreter(buf, buf + stream_trait::len_t::value + 1); // Disabling ADL, by directly specifying operators. if(!(interpreter.operator <<(arg) && interpreter.operator >>(result))) @@ -2163,7 +2284,7 @@ namespace boost { typedef Source source_type ; typedef BOOST_DEDUCED_TYPENAME mpl::if_< - ::boost::is_arithmetic, Source, Source const& + boost::is_arithmetic, Source, Source const& >::type argument_type ; static source_type nearbyint ( argument_type s ) @@ -2247,19 +2368,19 @@ namespace boost { { static inline Target lexical_cast_impl(const Source &arg) { - typedef BOOST_DEDUCED_TYPENAME ::boost::mpl::if_c< - ::boost::type_traits::ice_and< - ::boost::type_traits::ice_or< - ::boost::is_signed::value, - ::boost::is_float::value + typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_c< + boost::type_traits::ice_and< + boost::type_traits::ice_or< + boost::is_signed::value, + boost::is_float::value >::value, - ::boost::type_traits::ice_not< - ::boost::is_same::value + boost::type_traits::ice_not< + boost::is_same::value >::value, - ::boost::type_traits::ice_not< - ::boost::is_same::value + boost::type_traits::ice_not< + boost::is_same::value >::value, - ::boost::is_unsigned::value + boost::is_unsigned::value >::value, lexical_cast_dynamic_num_ignoring_minus, lexical_cast_dynamic_num_not_ignoring_minus @@ -2273,86 +2394,44 @@ namespace boost { template inline Target lexical_cast(const Source &arg) { - typedef BOOST_DEDUCED_TYPENAME ::boost::detail::array_to_pointer_decay::type src; + typedef BOOST_DEDUCED_TYPENAME boost::detail::array_to_pointer_decay::type src; - typedef BOOST_DEDUCED_TYPENAME ::boost::type_traits::ice_or< - ::boost::detail::is_xchar_to_xchar::value, - ::boost::detail::is_char_array_to_stdstring::value, - ::boost::type_traits::ice_and< - ::boost::is_same::value, - ::boost::detail::is_stdstring::value + typedef BOOST_DEDUCED_TYPENAME boost::type_traits::ice_or< + boost::detail::is_xchar_to_xchar::value, + boost::detail::is_char_array_to_stdstring::value, + boost::type_traits::ice_and< + boost::is_same::value, + boost::detail::is_stdstring::value >::value > shall_we_copy_t; typedef BOOST_DEDUCED_TYPENAME - ::boost::detail::is_arithmetic_and_not_xchars shall_we_copy_with_dynamic_check_t; + boost::detail::is_arithmetic_and_not_xchars shall_we_copy_with_dynamic_check_t; - typedef BOOST_DEDUCED_TYPENAME ::boost::mpl::if_c< + typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_c< shall_we_copy_t::value, - ::boost::detail::lexical_cast_copy, - BOOST_DEDUCED_TYPENAME ::boost::mpl::if_c< + boost::detail::lexical_cast_copy, + BOOST_DEDUCED_TYPENAME boost::mpl::if_c< shall_we_copy_with_dynamic_check_t::value, - ::boost::detail::lexical_cast_dynamic_num, - ::boost::detail::lexical_cast_do_cast + boost::detail::lexical_cast_dynamic_num, + boost::detail::lexical_cast_do_cast >::type >::type caster_type; return caster_type::lexical_cast_impl(arg); } - template - inline Target lexical_cast(const char* chars, std::size_t count) + template + inline Target lexical_cast(const CharType* chars, std::size_t count) { - return ::boost::lexical_cast( - ::boost::iterator_range(chars, chars + count) - ); - } + BOOST_STATIC_ASSERT_MSG(boost::detail::is_char_or_wchar::value, + "CharType must be a character or wide character type"); - - template - inline Target lexical_cast(const unsigned char* chars, std::size_t count) - { - return ::boost::lexical_cast( - ::boost::iterator_range(chars, chars + count) + return boost::lexical_cast( + boost::iterator_range(chars, chars + count) ); } - template - inline Target lexical_cast(const signed char* chars, std::size_t count) - { - return ::boost::lexical_cast( - ::boost::iterator_range(chars, chars + count) - ); - } - -#ifndef BOOST_LCAST_NO_WCHAR_T - template - inline Target lexical_cast(const wchar_t* chars, std::size_t count) - { - return ::boost::lexical_cast( - ::boost::iterator_range(chars, chars + count) - ); - } -#endif -#ifndef BOOST_NO_CHAR16_T - template - inline Target lexical_cast(const char16_t* chars, std::size_t count) - { - return ::boost::lexical_cast( - ::boost::iterator_range(chars, chars + count) - ); - } -#endif -#ifndef BOOST_NO_CHAR32_T - template - inline Target lexical_cast(const char32_t* chars, std::size_t count) - { - return ::boost::lexical_cast( - ::boost::iterator_range(chars, chars + count) - ); - } -#endif - } // namespace boost #else // #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION diff --git a/lexical_cast_test.cpp b/lexical_cast_test.cpp index fd51557..18e063b 100644 --- a/lexical_cast_test.cpp +++ b/lexical_cast_test.cpp @@ -82,10 +82,10 @@ void test_wallocator(); #endif void test_char_types_conversions(); void operators_overload_test(); -#if !defined(BOOST_NO_CHAR16_T) && !defined(BOOST_NO_UNICODE_LITERALS) +#if !defined(BOOST_NO_CXX11_CHAR16_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS) void test_char16_conversions(); #endif -#if !defined(BOOST_NO_CHAR32_T) && !defined(BOOST_NO_UNICODE_LITERALS) +#if !defined(BOOST_NO_CXX11_CHAR32_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS) void test_char32_conversions(); #endif void test_getting_pointer_to_function(); @@ -120,10 +120,10 @@ unit_test::test_suite *init_unit_test_suite(int, char *[]) suite->add(BOOST_TEST_CASE(&test_char_types_conversions)); suite->add(BOOST_TEST_CASE(&operators_overload_test)); -#if !defined(BOOST_NO_CHAR16_T) && !defined(BOOST_NO_UNICODE_LITERALS) +#if !defined(BOOST_NO_CXX11_CHAR16_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS) suite->add(BOOST_TEST_CASE(&test_char16_conversions)); #endif -#if !defined(BOOST_NO_CHAR32_T) && !defined(BOOST_NO_UNICODE_LITERALS) +#if !defined(BOOST_NO_CXX11_CHAR32_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS) suite->add(BOOST_TEST_CASE(&test_char32_conversions)); #endif suite->add(BOOST_TEST_CASE(&test_getting_pointer_to_function)); @@ -243,9 +243,15 @@ void test_conversion_to_bool() BOOST_CHECK_EQUAL(false, lexical_cast(0)); BOOST_CHECK_THROW(lexical_cast(123), bad_lexical_cast); BOOST_CHECK_EQUAL(true, lexical_cast(1.0)); + BOOST_CHECK_THROW(lexical_cast(-123), bad_lexical_cast); BOOST_CHECK_EQUAL(false, lexical_cast(0.0)); + BOOST_CHECK_THROW(lexical_cast(1234), bad_lexical_cast); +#if !defined(_CRAYC) + // Looks like a bug in CRAY compiler (throws bad_lexical_cast) + // TODO: localize the bug and report it to developers. BOOST_CHECK_EQUAL(true, lexical_cast(true)); BOOST_CHECK_EQUAL(false, lexical_cast(false)); +#endif BOOST_CHECK_EQUAL(true, lexical_cast("1")); BOOST_CHECK_EQUAL(false, lexical_cast("0")); BOOST_CHECK_THROW(lexical_cast(""), bad_lexical_cast); @@ -585,7 +591,7 @@ void operators_overload_test() } -#if !defined(BOOST_NO_CHAR16_T) && !defined(BOOST_NO_UNICODE_LITERALS) +#if !defined(BOOST_NO_CXX11_CHAR16_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS) void test_char16_conversions() { BOOST_CHECK(u"100" == lexical_cast(u"100")); @@ -593,7 +599,7 @@ void test_char16_conversions() } #endif -#if !defined(BOOST_NO_CHAR16_T) && !defined(BOOST_NO_UNICODE_LITERALS) +#if !defined(BOOST_NO_CXX11_CHAR16_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS) void test_char32_conversions() { BOOST_CHECK(U"100" == lexical_cast(U"100")); @@ -601,17 +607,21 @@ void test_char32_conversions() } #endif -template -To try_cast_by_ptr(const From& from, const Func& f) { - return f(from); -}; - void test_getting_pointer_to_function() { // Just checking that &lexical_cast is not ambiguous - BOOST_CHECK_EQUAL(100, try_cast_by_ptr("100", &boost::lexical_cast)); - BOOST_CHECK_EQUAL(100, try_cast_by_ptr("100", &boost::lexical_cast)); - BOOST_CHECK_EQUAL(std::string("100"), try_cast_by_ptr(100, &boost::lexical_cast)); + typedef char char_arr[4]; + typedef int(*f1)(const char_arr&); + f1 p1 = &boost::lexical_cast; + BOOST_CHECK(p1); + + typedef int(*f2)(const std::string&); + f2 p2 = &boost::lexical_cast; + BOOST_CHECK(p2); + + typedef std::string(*f3)(const int&); + f3 p3 = &boost::lexical_cast; + BOOST_CHECK(p3); } diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index f77a845..ea13e64 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -49,5 +49,7 @@ test-suite conversion [ run lexical_cast_iterator_range_test.cpp ] [ run lexical_cast_arrays_test.cpp ] [ run lexical_cast_integral_types_test.cpp ] + [ run lexical_cast_stream_detection_test.cpp ] + [ run lexical_cast_stream_traits_test.cpp ] ; diff --git a/test/lexical_cast_arrays_test.cpp b/test/lexical_cast_arrays_test.cpp index 6aff2d9..2ed009e 100644 --- a/test/lexical_cast_arrays_test.cpp +++ b/test/lexical_cast_arrays_test.cpp @@ -91,7 +91,7 @@ static void testing_template_array_output_on_spec_value(T val) #endif -#if !defined(BOOST_NO_CHAR16_T) && !defined(BOOST_NO_UNICODE_LITERALS) +#if !defined(BOOST_NO_CXX11_CHAR16_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS) typedef ArrayT u16arr_type; typedef ArrayT u16short_arr_type; std::u16string u16ethalon(u"100"); @@ -109,7 +109,7 @@ static void testing_template_array_output_on_spec_value(T val) BOOST_CHECK_THROW(lexical_cast(val), boost::bad_lexical_cast); #endif -#if !defined(BOOST_NO_CHAR32_T) && !defined(BOOST_NO_UNICODE_LITERALS) +#if !defined(BOOST_NO_CXX11_CHAR32_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS) typedef ArrayT u32arr_type; typedef ArrayT u32short_arr_type; std::u32string u32ethalon(U"100"); @@ -190,7 +190,7 @@ static void testing_template_array_output_on_char_value() #endif -#if !defined(BOOST_NO_CHAR16_T) && !defined(BOOST_NO_UNICODE_LITERALS) +#if !defined(BOOST_NO_CXX11_CHAR16_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS) typedef ArrayT u16arr_type; typedef ArrayT u16short_arr_type; std::u16string u16ethalon(u"100"); @@ -217,7 +217,7 @@ static void testing_template_array_output_on_char_value() BOOST_CHECK_THROW(lexical_cast(val), boost::bad_lexical_cast); #endif -#if !defined(BOOST_NO_CHAR32_T) && !defined(BOOST_NO_UNICODE_LITERALS) +#if !defined(BOOST_NO_CXX11_CHAR32_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS) typedef ArrayT u32arr_type; typedef ArrayT u32short_arr_type; std::u32string u32ethalon(U"100"); @@ -328,7 +328,7 @@ static void testing_generic_array_input_conversion() } #endif -#if !defined(BOOST_NO_CHAR16_T) && !defined(BOOST_NO_UNICODE_LITERALS) +#if !defined(BOOST_NO_CXX11_CHAR16_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS) { const ArrayT var_zero_terminated_const_var_const_char = {{ u'1', u'0', u'0', u'\0'}}; BOOST_CHECK(lexical_cast(var_zero_terminated_const_var_const_char) == u"100"); @@ -339,7 +339,7 @@ static void testing_generic_array_input_conversion() } #endif -#if !defined(BOOST_NO_CHAR32_T) && !defined(BOOST_NO_UNICODE_LITERALS) +#if !defined(BOOST_NO_CXX11_CHAR32_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS) { const ArrayT var_zero_terminated_const_var_const_char = {{ U'1', U'0', U'0', U'\0'}}; BOOST_CHECK(lexical_cast(var_zero_terminated_const_var_const_char) == U"100"); diff --git a/test/lexical_cast_containers_test.cpp b/test/lexical_cast_containers_test.cpp index bb13f31..47bedc3 100644 --- a/test/lexical_cast_containers_test.cpp +++ b/test/lexical_cast_containers_test.cpp @@ -71,12 +71,12 @@ void testing_boost_containers_string_widening() BOOST_CHECK(boost::lexical_cast(char_array) == wchar_array); #endif -#if !defined(BOOST_NO_CHAR16_T) && !defined(BOOST_NO_UNICODE_LITERALS) && defined(BOOST_STL_SUPPORTS_NEW_UNICODE_LOCALES) +#if !defined(BOOST_NO_CXX11_CHAR16_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS) && defined(BOOST_STL_SUPPORTS_NEW_UNICODE_LOCALES) const char16_t char16_array[] = u"Test string"; BOOST_CHECK(boost::lexical_cast >(char_array) == char16_array); #endif -#if !defined(BOOST_NO_CHAR32_T) && !defined(BOOST_NO_UNICODE_LITERALS) && defined(BOOST_STL_SUPPORTS_NEW_UNICODE_LOCALES) +#if !defined(BOOST_NO_CXX11_CHAR32_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS) && defined(BOOST_STL_SUPPORTS_NEW_UNICODE_LOCALES) const char32_t char32_array[] = U"Test string"; BOOST_CHECK(boost::lexical_cast >(char_array) == char32_array); #endif diff --git a/test/lexical_cast_empty_input_test.cpp b/test/lexical_cast_empty_input_test.cpp index df05981..e307ea2 100755 --- a/test/lexical_cast_empty_input_test.cpp +++ b/test/lexical_cast_empty_input_test.cpp @@ -84,12 +84,12 @@ void test_empty_string() #endif // Currently, no compiler and STL library fully support char16_t and char32_t -//#ifndef BOOST_NO_CHAR16_T +//#ifndef BOOST_NO_CXX11_CHAR16_T // std::basic_string v16w; // do_test_on_empty_input(v16w); // BOOST_CHECK_THROW(lexical_cast(v16w), bad_lexical_cast); //#endif -//#ifndef BOOST_NO_CHAR32_T +//#ifndef BOOST_NO_CXX11_CHAR32_T // std::basic_string v32w; // do_test_on_empty_input(v32w); // BOOST_CHECK_THROW(lexical_cast(v32w), bad_lexical_cast); diff --git a/test/lexical_cast_float_types_test.cpp b/test/lexical_cast_float_types_test.cpp index 3df245b..2bc3d05 100755 --- a/test/lexical_cast_float_types_test.cpp +++ b/test/lexical_cast_float_types_test.cpp @@ -505,7 +505,11 @@ void test_conversion_from_to_double() } void test_conversion_from_to_long_double() { +// We do not run tests on compilers with bugs +#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS test_conversion_from_to_float(); +#endif + BOOST_CHECK(true); } diff --git a/test/lexical_cast_inf_nan_test.cpp b/test/lexical_cast_inf_nan_test.cpp index af1caa0..2c79ea8 100755 --- a/test/lexical_cast_inf_nan_test.cpp +++ b/test/lexical_cast_inf_nan_test.cpp @@ -186,7 +186,11 @@ void test_inf_nan_double() void test_inf_nan_long_double() { +// We do not run tests on compilers with bugs +#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS test_inf_nan_templated(); +#endif + BOOST_CHECK(true); } unit_test::test_suite *init_unit_test_suite(int, char *[]) diff --git a/test/lexical_cast_integral_types_test.cpp b/test/lexical_cast_integral_types_test.cpp index 2cbdbf5..7139ee6 100644 --- a/test/lexical_cast_integral_types_test.cpp +++ b/test/lexical_cast_integral_types_test.cpp @@ -386,12 +386,12 @@ void test_conversion_from_to_integral() test_conversion_from_integral_to_char(wzero); test_conversion_from_char_to_integral(wzero); #endif -#if !defined(BOOST_NO_CHAR16_T) && !defined(BOOST_NO_UNICODE_LITERALS) +#if !defined(BOOST_NO_CXX11_CHAR16_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS) char16_t const u16zero = u'0'; test_conversion_from_integral_to_char(u16zero); test_conversion_from_char_to_integral(u16zero); #endif -#if !defined(BOOST_NO_CHAR32_T) && !defined(BOOST_NO_UNICODE_LITERALS) +#if !defined(BOOST_NO_CXX11_CHAR32_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS) char32_t const u32zero = u'0'; test_conversion_from_integral_to_char(u32zero); test_conversion_from_char_to_integral(u32zero); diff --git a/test/lexical_cast_iterator_range_test.cpp b/test/lexical_cast_iterator_range_test.cpp index 59e8eae..a50528b 100644 --- a/test/lexical_cast_iterator_range_test.cpp +++ b/test/lexical_cast_iterator_range_test.cpp @@ -134,7 +134,7 @@ void test_it_range_using_char(CharT* one, CharT* eleven) BOOST_CHECK(lexical_cast(crng2) == L"1"); #endif -#if !defined(BOOST_NO_CHAR16_T) && !defined(BOOST_NO_UNICODE_LITERALS) && defined(BOOST_STL_SUPPORTS_NEW_UNICODE_LOCALES) +#if !defined(BOOST_NO_CXX11_CHAR16_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS) && defined(BOOST_STL_SUPPORTS_NEW_UNICODE_LOCALES) typedef std::basic_string my_char16_string; BOOST_CHECK(lexical_cast(rng1) == u"1"); BOOST_CHECK(lexical_cast(crng1) == u"1"); @@ -142,7 +142,7 @@ void test_it_range_using_char(CharT* one, CharT* eleven) BOOST_CHECK(lexical_cast(crng2) == u"1"); #endif -#if !defined(BOOST_NO_CHAR32_T) && !defined(BOOST_NO_UNICODE_LITERALS) && defined(BOOST_STL_SUPPORTS_NEW_UNICODE_LOCALES) +#if !defined(BOOST_NO_CXX11_CHAR32_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS) && defined(BOOST_STL_SUPPORTS_NEW_UNICODE_LOCALES) typedef std::basic_string my_char32_string; BOOST_CHECK(lexical_cast(rng1) == U"1"); BOOST_CHECK(lexical_cast(crng1) == U"1"); @@ -194,7 +194,7 @@ void test_wchar_iterator_ranges() void test_char16_iterator_ranges() { -#if !defined(BOOST_NO_CHAR16_T) && !defined(BOOST_NO_UNICODE_LITERALS) +#if !defined(BOOST_NO_CXX11_CHAR16_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS) typedef char16_t test_char_type; test_char_type data1[] = u"1"; test_char_type data2[] = u"11"; @@ -206,7 +206,7 @@ void test_char16_iterator_ranges() void test_char32_iterator_ranges() { -#if !defined(BOOST_NO_CHAR32_T) && !defined(BOOST_NO_UNICODE_LITERALS) +#if !defined(BOOST_NO_CXX11_CHAR32_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS) typedef char32_t test_char_type; test_char_type data1[] = U"1"; test_char_type data2[] = U"11"; diff --git a/test/lexical_cast_loopback_test.cpp b/test/lexical_cast_loopback_test.cpp index 25b18ec..d50e3a0 100644 --- a/test/lexical_cast_loopback_test.cpp +++ b/test/lexical_cast_loopback_test.cpp @@ -86,7 +86,11 @@ void test_round_conversion_double() void test_round_conversion_long_double() { +// We do not run tests on compilers with bugs +#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS test_round_conversion(); test_msvc_magic_values(); +#endif + BOOST_CHECK(true); } diff --git a/test/lexical_cast_stream_detection_test.cpp b/test/lexical_cast_stream_detection_test.cpp new file mode 100644 index 0000000..82bc562 --- /dev/null +++ b/test/lexical_cast_stream_detection_test.cpp @@ -0,0 +1,307 @@ +// Unit test for boost::lexical_cast. +// +// See http://www.boost.org for most recent version, including documentation. +// +// Copyright Antony Polukhin, 2011-2012. +// +// 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). + + +#include +#include + +#include + +#include + + +///////////////////////// char streamable classes /////////////////////////////////////////// + +struct streamable_easy { enum ENU {value = 0}; }; +std::ostream& operator << (std::ostream& ostr, const streamable_easy&) { + return ostr << streamable_easy::value; +} +std::istream& operator >> (std::istream& istr, const streamable_easy&) { + int i; istr >> i; BOOST_CHECK_EQUAL(i, streamable_easy::value); + return istr; +} + +struct streamable_medium { enum ENU {value = 1}; }; +template +typename boost::enable_if, std::basic_ostream&>::type +operator << (std::basic_ostream& ostr, const streamable_medium&) { + return ostr << streamable_medium::value; +} +template +typename boost::enable_if, std::basic_istream&>::type +operator >> (std::basic_istream& istr, const streamable_medium&) { + int i; istr >> i; BOOST_CHECK_EQUAL(i, streamable_medium::value); + return istr; +} + +struct streamable_hard { enum ENU {value = 2}; }; +template +typename boost::enable_if, std::basic_ostream&>::type +operator << (std::basic_ostream& ostr, const streamable_hard&) { + return ostr << streamable_hard::value; +} +template +typename boost::enable_if, std::basic_istream&>::type +operator >> (std::basic_istream& istr, const streamable_hard&) { + int i; istr >> i; BOOST_CHECK_EQUAL(i, streamable_hard::value); + return istr; +} + +struct streamable_hard2 { enum ENU {value = 3}; }; +template +std::basic_ostream& operator << (std::basic_ostream& ostr, const streamable_hard2&) { + return ostr << streamable_hard2::value; +} +template +std::basic_istream& operator >> (std::basic_istream& istr, const streamable_hard2&) { + int i; istr >> i; BOOST_CHECK_EQUAL(i, streamable_hard2::value); + return istr; +} + + +///////////////////////// wchar_t streamable classes /////////////////////////////////////////// + +struct wstreamable_easy { enum ENU {value = 4}; }; +std::wostream& operator << (std::wostream& ostr, const wstreamable_easy&) { + return ostr << wstreamable_easy::value; +} +std::wistream& operator >> (std::wistream& istr, const wstreamable_easy&) { + int i; istr >> i; BOOST_CHECK_EQUAL(i, wstreamable_easy::value); + return istr; +} + +struct wstreamable_medium { enum ENU {value = 5}; }; +template +typename boost::enable_if, std::basic_ostream& >::type +operator << (std::basic_ostream& ostr, const wstreamable_medium&) { + return ostr << wstreamable_medium::value; +} +template +typename boost::enable_if, std::basic_istream& >::type +operator >> (std::basic_istream& istr, const wstreamable_medium&) { + int i; istr >> i; BOOST_CHECK_EQUAL(i, wstreamable_medium::value); + return istr; +} + +struct wstreamable_hard { enum ENU {value = 6}; }; +template +typename boost::enable_if, std::basic_ostream&>::type +operator << (std::basic_ostream& ostr, const wstreamable_hard&) { + return ostr << wstreamable_hard::value; +} +template +typename boost::enable_if, std::basic_istream&>::type +operator >> (std::basic_istream& istr, const wstreamable_hard&) { + int i; istr >> i; BOOST_CHECK_EQUAL(i, wstreamable_hard::value); + return istr; +} + +struct wstreamable_hard2 { enum ENU {value = 7}; }; +template +std::basic_ostream& operator << (std::basic_ostream& ostr, const wstreamable_hard2&) { + return ostr << wstreamable_hard2::value; +} +template +std::basic_istream& operator >> (std::basic_istream& istr, const wstreamable_hard2&) { + int i; istr >> i; BOOST_CHECK_EQUAL(i, wstreamable_hard2::value); + return istr; +} + +///////////////////////// char and wchar_t streamable classes /////////////////////////////////////////// + + +struct bistreamable_easy { enum ENU {value = 8}; }; +std::ostream& operator << (std::ostream& ostr, const bistreamable_easy&) { + return ostr << bistreamable_easy::value; +} +std::istream& operator >> (std::istream& istr, const bistreamable_easy&) { + int i; istr >> i; BOOST_CHECK_EQUAL(i, bistreamable_easy::value); + return istr; +} + +std::wostream& operator << (std::wostream& ostr, const bistreamable_easy&) { + return ostr << bistreamable_easy::value + 100; +} +std::wistream& operator >> (std::wistream& istr, const bistreamable_easy&) { + int i; istr >> i; BOOST_CHECK_EQUAL(i, bistreamable_easy::value + 100); + return istr; +} + +struct bistreamable_medium { enum ENU {value = 9}; }; +template +std::basic_ostream& operator << (std::basic_ostream& ostr, const bistreamable_medium&) { + return ostr << bistreamable_medium::value + (sizeof(CharT) == 1 ? 0 : 100); +} +template +std::basic_istream& operator >> (std::basic_istream& istr, const bistreamable_medium&) { + int i; istr >> i; BOOST_CHECK_EQUAL(i, bistreamable_medium::value + (sizeof(CharT) == 1 ? 0 : 100)); + return istr; +} + +struct bistreamable_hard { enum ENU {value = 10}; }; +template +std::basic_ostream& operator << (std::basic_ostream& ostr, const bistreamable_hard&) { + return ostr << bistreamable_hard::value + (sizeof(CharT) == 1 ? 0 : 100); +} +template +std::basic_istream& operator >> (std::basic_istream& istr, const bistreamable_hard&) { + int i; istr >> i; BOOST_CHECK_EQUAL(i, bistreamable_hard::value + (sizeof(CharT) == 1 ? 0 : 100)); + return istr; +} + +struct bistreamable_hard2 { enum ENU {value = 11}; }; +template +std::basic_ostream& operator << (std::basic_ostream& ostr, const bistreamable_hard2&) { + return ostr << bistreamable_hard2::value; +} +template +std::basic_istream& operator >> (std::basic_istream& istr, const bistreamable_hard2&) { + int i; istr >> i; BOOST_CHECK_EQUAL(i, bistreamable_hard2::value); + return istr; +} + +template +std::basic_ostream& operator << (std::basic_ostream& ostr, const bistreamable_hard2&) { + return ostr << bistreamable_hard2::value + 100; +} +template +std::basic_istream& operator >> (std::basic_istream& istr, const bistreamable_hard2&) { + int i; istr >> i; BOOST_CHECK_EQUAL(i, bistreamable_hard2::value + 100); + return istr; +} + + +void test_ostream_character_detection(); +void test_istream_character_detection(); +void test_mixed_stream_character_detection(); + +boost::unit_test::test_suite *init_unit_test_suite(int, char *[]) +{ + boost::unit_test::test_suite *suite = + BOOST_TEST_SUITE("lexical_cast stream character detection"); + suite->add(BOOST_TEST_CASE(&test_ostream_character_detection)); + suite->add(BOOST_TEST_CASE(&test_istream_character_detection)); + suite->add(BOOST_TEST_CASE(&test_mixed_stream_character_detection)); + + return suite; +} + +template +static void test_ostr_impl() { + T streamable; + BOOST_CHECK_EQUAL(T::value, boost::lexical_cast(streamable)); + BOOST_CHECK_EQUAL(boost::lexical_cast(T::value), boost::lexical_cast(streamable)); +} + +template +static void test_wostr_impl() { + T streamable; + BOOST_CHECK_EQUAL(T::value, boost::lexical_cast(streamable)); + // BOOST_CHECK_EQUAL(boost::lexical_cast(T::value), boost::lexical_cast(streamable)); // Shall not compile??? + BOOST_CHECK(boost::lexical_cast(T::value) == boost::lexical_cast(streamable)); +} + +template +static void test_bistr_impl() { + T streamable; + + BOOST_CHECK_EQUAL(T::value, boost::lexical_cast(streamable)); + BOOST_CHECK_EQUAL(boost::lexical_cast(T::value), boost::lexical_cast(streamable)); + + BOOST_CHECK(boost::lexical_cast(T::value + 100) == boost::lexical_cast(streamable)); +} + +void test_ostream_character_detection() { + test_ostr_impl(); + test_ostr_impl(); + test_ostr_impl(); + test_ostr_impl(); + + test_wostr_impl(); + test_wostr_impl(); + test_wostr_impl(); + test_wostr_impl(); + + test_bistr_impl(); + test_bistr_impl(); + test_bistr_impl(); + test_bistr_impl(); +} + + +template +static void test_istr_impl() { + boost::lexical_cast(T::value); + boost::lexical_cast(boost::lexical_cast(T::value)); +} + +template +static void test_wistr_impl() { + boost::lexical_cast(T::value); + //boost::lexical_cast(boost::lexical_cast(T::value)); // Shall not compile??? + boost::lexical_cast(boost::lexical_cast(T::value)); +} + +template +static void test_bistr_instr_impl() { + boost::lexical_cast(T::value); + boost::lexical_cast(boost::lexical_cast(T::value)); + boost::lexical_cast(boost::lexical_cast(T::value + 100)); +} + +void test_istream_character_detection() { + test_istr_impl(); + test_istr_impl(); + test_istr_impl(); + test_istr_impl(); + + test_wistr_impl(); + test_wistr_impl(); + test_wistr_impl(); + test_wistr_impl(); + + test_bistr_instr_impl(); + test_bistr_instr_impl(); + test_bistr_instr_impl(); + test_bistr_instr_impl(); +} + + + + + + +struct wistreamble_ostreamable { enum ENU {value = 200}; }; +std::ostream& operator << (std::ostream& ostr, const wistreamble_ostreamable&) { + return ostr << wistreamble_ostreamable::value; +} +std::wistream& operator >> (std::wistream& istr, const wistreamble_ostreamable&) { + int i; istr >> i; BOOST_CHECK_EQUAL(i, wistreamble_ostreamable::value); + return istr; +} + +struct istreamble_wostreamable { enum ENU {value = 201}; }; +std::wostream& operator << (std::wostream& ostr, const istreamble_wostreamable&) { + return ostr << istreamble_wostreamable::value; +} +std::istream& operator >> (std::istream& istr, const istreamble_wostreamable&) { + int i; istr >> i; BOOST_CHECK_EQUAL(i, istreamble_wostreamable::value); + return istr; +} + +void test_mixed_stream_character_detection() { + //boost::lexical_cast(std::string("qwe")); // TODO: ALLOW IT AS EXTENSION! + + boost::lexical_cast(wistreamble_ostreamable::value); + BOOST_CHECK_EQUAL(boost::lexical_cast(wistreamble_ostreamable()), wistreamble_ostreamable::value); + + boost::lexical_cast(istreamble_wostreamable::value); + BOOST_CHECK_EQUAL(boost::lexical_cast(istreamble_wostreamable()), istreamble_wostreamable::value); +} diff --git a/test/lexical_cast_stream_traits_test.cpp b/test/lexical_cast_stream_traits_test.cpp new file mode 100644 index 0000000..8198ae8 --- /dev/null +++ b/test/lexical_cast_stream_traits_test.cpp @@ -0,0 +1,155 @@ +// Unit test for boost::lexical_cast. +// +// See http://www.boost.org for most recent version, including documentation. +// +// Copyright Antony Polukhin, 2012. +// +// 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). + +#include + +#include + +#include + +template +static void test_optimized_types_to_string_const() +{ + namespace de = boost::detail; + typedef de::lexical_cast_stream_traits trait_1; + BOOST_CHECK(!trait_1::is_source_input_not_optimized_t::value); + BOOST_CHECK((boost::is_same::value)); + BOOST_CHECK((boost::is_same::value)); + BOOST_CHECK((boost::is_same::value)); + BOOST_CHECK(!trait_1::is_string_widening_required_t::value); + BOOST_CHECK(!trait_1::is_source_input_not_optimized_t::value); + + typedef de::lexical_cast_stream_traits trait_2; + BOOST_CHECK(!trait_2::is_source_input_not_optimized_t::value); + BOOST_CHECK((boost::is_same::value)); + BOOST_CHECK((boost::is_same::value)); + BOOST_CHECK((boost::is_same::value)); + BOOST_CHECK(!trait_2::is_string_widening_required_t::value); + BOOST_CHECK(!trait_2::is_source_input_not_optimized_t::value); + + typedef de::lexical_cast_stream_traits trait_3; + BOOST_CHECK(!trait_3::is_source_input_not_optimized_t::value); + BOOST_CHECK((boost::is_same::value)); + BOOST_CHECK((boost::is_same::value)); + BOOST_CHECK((boost::is_same::value)); + + BOOST_CHECK((boost::detail::is_char_or_wchar::value != trait_3::is_string_widening_required_t::value)); + + BOOST_CHECK(!trait_3::is_source_input_not_optimized_t::value); +} + + +template +static void test_optimized_types_to_string() +{ + test_optimized_types_to_string_const(); + + namespace de = boost::detail; + typedef de::lexical_cast_stream_traits trait_4; + BOOST_CHECK(!trait_4::is_source_input_not_optimized_t::value); + BOOST_CHECK((boost::is_same::value)); + BOOST_CHECK((boost::is_same::value)); + BOOST_CHECK((boost::is_same::value)); + BOOST_CHECK(!trait_4::is_string_widening_required_t::value); + BOOST_CHECK(!trait_4::is_source_input_not_optimized_t::value); + + typedef de::lexical_cast_stream_traits trait_5; + BOOST_CHECK(!trait_5::is_source_input_not_optimized_t::value); + BOOST_CHECK((boost::is_same::value)); + BOOST_CHECK((boost::is_same::value)); + BOOST_CHECK((boost::is_same::value)); + BOOST_CHECK(!trait_5::is_string_widening_required_t::value); + BOOST_CHECK(!trait_5::is_source_input_not_optimized_t::value); + + typedef de::lexical_cast_stream_traits trait_6; + BOOST_CHECK(!trait_6::is_source_input_not_optimized_t::value); + BOOST_CHECK((boost::is_same::value)); + BOOST_CHECK((boost::is_same::value)); + BOOST_CHECK((boost::is_same::value)); + BOOST_CHECK(!trait_6::is_string_widening_required_t::value); +} + +void test_metafunctions() +{ + test_optimized_types_to_string(); + test_optimized_types_to_string(); + test_optimized_types_to_string(); + test_optimized_types_to_string(); + test_optimized_types_to_string(); + test_optimized_types_to_string(); + test_optimized_types_to_string(); + test_optimized_types_to_string(); + test_optimized_types_to_string(); + test_optimized_types_to_string(); + +#if defined(BOOST_HAS_LONG_LONG) + test_optimized_types_to_string(); + test_optimized_types_to_string(); +#elif defined(BOOST_HAS_MS_INT64) + test_optimized_types_to_string(); + test_optimized_types_to_string<__int64>(); +#endif + + test_optimized_types_to_string(); + test_optimized_types_to_string(); + test_optimized_types_to_string(); + //test_optimized_types_to_string(); + //test_optimized_types_to_string(); + test_optimized_types_to_string(); + //test_optimized_types_to_string(); + //test_optimized_types_to_string(); + test_optimized_types_to_string(); + //test_optimized_types_to_string(); + //test_optimized_types_to_string(); + test_optimized_types_to_string >(); + test_optimized_types_to_string >(); + test_optimized_types_to_string >(); + test_optimized_types_to_string >(); + test_optimized_types_to_string >(); + test_optimized_types_to_string >(); + test_optimized_types_to_string >(); + test_optimized_types_to_string >(); + test_optimized_types_to_string >(); + + test_optimized_types_to_string_const >(); + test_optimized_types_to_string_const >(); + test_optimized_types_to_string_const >(); + test_optimized_types_to_string_const >(); + test_optimized_types_to_string_const >(); + test_optimized_types_to_string_const >(); + test_optimized_types_to_string_const >(); + test_optimized_types_to_string_const >(); + test_optimized_types_to_string_const >(); + +#if !defined(BOOST_NO_CXX11_HDR_ARRAY) && defined(BOOST_HAS_TR1_ARRAY) + test_optimized_types_to_string >(); + test_optimized_types_to_string >(); + test_optimized_types_to_string >(); + test_optimized_types_to_string >(); + test_optimized_types_to_string >(); + test_optimized_types_to_string >(); + + test_optimized_types_to_string_const >(); + test_optimized_types_to_string_const >(); + test_optimized_types_to_string_const >(); + test_optimized_types_to_string_const >(); + test_optimized_types_to_string_const >(); + test_optimized_types_to_string_const >(); +#endif +} + +boost::unit_test::test_suite *init_unit_test_suite(int, char *[]) +{ + boost::unit_test::test_suite *suite = + BOOST_TEST_SUITE("lexical_cast traits tests"); + suite->add(BOOST_TEST_CASE(&test_metafunctions)); + return suite; +} + diff --git a/test/lexical_cast_wchars_test.cpp b/test/lexical_cast_wchars_test.cpp index f78de1d..dede81e 100755 --- a/test/lexical_cast_wchars_test.cpp +++ b/test/lexical_cast_wchars_test.cpp @@ -58,7 +58,7 @@ void test_char_types_conversions_wchar_t() void test_char_types_conversions_char16_t() { -#if !defined(BOOST_NO_CHAR16_T) && !defined(BOOST_NO_UNICODE_LITERALS) && defined(BOOST_STL_SUPPORTS_NEW_UNICODE_LOCALES) +#if !defined(BOOST_NO_CXX11_CHAR16_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS) && defined(BOOST_STL_SUPPORTS_NEW_UNICODE_LOCALES) test_impl(u"Test array of chars"); #endif @@ -67,7 +67,7 @@ void test_char_types_conversions_char16_t() void test_char_types_conversions_char32_t() { -#if !defined(BOOST_NO_CHAR32_T) && !defined(BOOST_NO_UNICODE_LITERALS) && defined(BOOST_STL_SUPPORTS_NEW_UNICODE_LOCALES) +#if !defined(BOOST_NO_CXX11_CHAR32_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS) && defined(BOOST_STL_SUPPORTS_NEW_UNICODE_LOCALES) test_impl(U"Test array of chars"); #endif