diff --git a/doc/lexical_cast.qbk b/doc/lexical_cast.qbk index ffab311..c786fbc 100644 --- a/doc/lexical_cast.qbk +++ b/doc/lexical_cast.qbk @@ -97,7 +97,21 @@ The requirements on the argument and result types 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`. Source types that require wide-character streaming are `wchar_t`, `wchar_t *`, and `std::wstring`. Target types that require wide-character streaming are `wchar_t` and `std::wstring`. +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: + +* 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 *` +* 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 + +[important Many compilers and runtime libraries fail to make conversions using new Unicode characters. Make shure that the following code compiles and outputs nonzero values, before using new types: +`` + std::cout + << booat::lexical_cast(1.0).size() + << " " + << booat::lexical_cast(1.0).size(); +`` +] Where a higher degree of control is required over conversions, `std::stringstream` and `std::wstringstream` offer a more appropriate path. Where non-stream-based conversions are required, `lexical_cast` is the wrong tool for the job and is not special-cased for such scenarios. [endsect] @@ -115,6 +129,7 @@ Exception used to indicate runtime lexical_cast failure. [endsect] +[/ Commenting out bad advise (this will break the ability to get correct function pointers via &lexical_cast) [section Tuning classes for fast lexical conversions] Because of `boost::lexical_cast` optimizations for `boost::iterator_range`, it is possibile to make very fast lexical conversions for non zero terminated strings, substrings and user-defined classes. @@ -145,9 +160,9 @@ Consider the following example: This is a good generic solution for most use cases. But we can make it even faster for some performance critical applications. During conversion, we loose speed at: -* `std::ostream` construction (it makes some heap allocations) -* `operator <<` (it copyies one by one all the symbols to an instance of `std::ostream`) -* `std::ostream` destruction (it makes some heap deallocations) + * `std::ostream` construction (it makes some heap allocations) + * `operator <<` (it copyies one by one all the symbols to an instance of `std::ostream`) + * `std::ostream` destruction (it makes some heap deallocations) We can avoid all of this, by specifieng an overload for `boost::lexical_cast`: `` @@ -162,7 +177,7 @@ namespace boost { `` Now `boost::lexical_cast(example_class_instance)` conversions won't copy data and construct heavy STL stream objects. See [link boost_lexical_cast.performance Performance] section for info on `boost::iterator_range` conversion performance. [endsect] - +] [section Frequently Asked Questions] diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index 61501d6..2e5c140 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -28,36 +28,20 @@ #include #include -#include #include #include #include #include #include -#include #include #include #include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include +#include #include #include #include -#include -#if !defined(__SUNPRO_CC) -#include -#endif // !defined(__SUNPRO_CC) -#ifndef BOOST_NO_CWCHAR -# include -#endif + #ifndef BOOST_NO_STD_LOCALE # include @@ -137,118 +121,9 @@ namespace boost const std::type_info *target; }; - namespace detail // selectors for choosing stream character type + namespace detail // widest_char { - template - struct stream_char - { - typedef char type; - }; - -#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION - 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 - struct stream_char< std::basic_string > - { - typedef CharT type; - }; - -#if !defined(__SUNPRO_CC) - template - struct stream_char< ::boost::container::basic_string > - { - typedef CharT type; - }; -#endif // !defined(__SUNPRO_CC) -#endif - -#ifndef BOOST_LCAST_NO_WCHAR_T -#ifndef BOOST_NO_INTRINSIC_WCHAR_T - template<> - struct stream_char - { - typedef wchar_t type; - }; -#endif - - template<> - struct stream_char - { - typedef wchar_t type; - }; - - template<> - struct stream_char - { - typedef wchar_t type; - }; - -#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION - template<> - struct stream_char - { - typedef wchar_t type; - }; -#endif -#endif - - -#ifndef BOOST_NO_CHAR16_T - - template<> - struct stream_char - { - typedef char16_t type; - }; - - template<> - struct stream_char - { - typedef char16_t type; - }; - - template<> - struct stream_char - { - typedef char16_t type; - }; - -#endif - -#ifndef BOOST_NO_CHAR32_T - - template<> - struct stream_char - { - typedef char32_t type; - }; - - template<> - struct stream_char - { - typedef char32_t type; - }; - - template<> - struct stream_char - { - typedef char32_t type; - }; - -#endif - - template + template struct widest_char { typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_c< @@ -257,10 +132,162 @@ namespace boost , SourceChar >::type type; }; } +} // namespace boost + +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if !defined(__SUNPRO_CC) +#include +#endif // !defined(__SUNPRO_CC) +#ifndef BOOST_NO_CWCHAR +# include +#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 + { + // returns true, if T is one of the character types + template + struct is_char_or_wchar + { + 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, + #endif + #ifndef BOOST_NO_CHAR16_T + ::boost::is_same< T, char16_t >::value, + #endif + #ifndef BOOST_NO_CHAR32_T + ::boost::is_same< T, char32_t >::value, + #endif + ::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 + { + typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_c< + is_char_or_wchar::value, + Type, + boost::detail::not_a_character_type + >::type type; + }; + + template <> + struct stream_char + { + typedef char type; + }; + + template <> + struct stream_char + { + typedef char type; + }; + + 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 + struct stream_char > + { + typedef BOOST_DEDUCED_TYPENAME stream_char::type type; + }; + + template + struct stream_char > + { + typedef BOOST_DEDUCED_TYPENAME stream_char::type type; + }; + + template + struct stream_char< std::basic_string > + { + typedef CharT type; + }; + +#if !defined(__SUNPRO_CC) + template + struct stream_char< ::boost::container::basic_string > + { + typedef CharT type; + }; +#endif // !defined(__SUNPRO_CC) + +#if !defined(BOOST_LCAST_NO_WCHAR_T) && defined(BOOST_NO_INTRINSIC_WCHAR_T) + template<> + struct stream_char + { + typedef boost::detail::not_a_character_type type; + }; + + template<> + struct stream_char + { + typedef wchar_t type; + }; + + template<> + struct stream_char + { + typedef wchar_t type; + }; +#endif + } namespace detail // deduce_char_traits template { -#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + template struct deduce_char_traits { @@ -325,7 +352,7 @@ namespace boost template struct deduce_char_traits< CharT , ::boost::container::basic_string - , std::basic_string + , ::std::basic_string > { typedef Traits type; @@ -333,14 +360,13 @@ namespace boost template struct deduce_char_traits< CharT - , std::basic_string + , ::std::basic_string , ::boost::container::basic_string > { typedef Traits type; }; #endif // !defined(__SUNPRO_CC) -#endif } namespace detail // lcast_src_length @@ -383,7 +409,7 @@ namespace boost BOOST_STATIC_ASSERT(sizeof(Source) * CHAR_BIT <= 256); #endif }; -// TODO: FIX for char16_t, char32_t, we can ignore CharT + #define BOOST_LCAST_DEF(T) \ template<> struct lcast_src_length \ : lcast_src_length_integral \ @@ -1217,7 +1243,7 @@ namespace boost bool shl_char(T ch) { BOOST_STATIC_ASSERT_MSG(( sizeof(T) <= sizeof(CharT)) , - "boost::lexical_cast does not support conversions from wchar_t to char types." + "boost::lexical_cast does not support conversions from wide character to char types." "Use boost::locale instead" ); #ifndef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE std::locale loc; @@ -1243,7 +1269,7 @@ namespace boost bool shl_char_array(T const* str) { BOOST_STATIC_ASSERT_MSG(( sizeof(T) <= sizeof(CharT)), - "boost::lexical_cast does not support conversions from wchar_t to char types." + "boost::lexical_cast does not support conversions from wide characters to char types." "Use boost::locale instead" ); return shl_input_streamable(str); } @@ -1430,6 +1456,16 @@ namespace boost #ifndef BOOST_NO_INTRINSIC_WCHAR_T bool operator<<(wchar_t ch) { return shl_char(ch); } #endif +#endif +#if !defined(BOOST_NO_CHAR16_T) && !defined(BOOST_NO_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) + 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); } #endif bool operator<<(unsigned char const* ch) { return ((*this) << reinterpret_cast(ch)); } bool operator<<(unsigned char * ch) { return ((*this) << reinterpret_cast(ch)); } @@ -1634,19 +1670,13 @@ namespace boost #if !defined(BOOST_NO_CHAR32_T) && !defined(BOOST_NO_UNICODE_LITERALS) bool operator>>(char32_t& output) { return shr_xchar(output); } #endif -#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION - bool operator>>(std::string& str) { str.assign(start, finish); return true; } -# ifndef BOOST_LCAST_NO_WCHAR_T - bool operator>>(std::wstring& str) { str.assign(start, finish); return true; } -# endif -#else template bool operator>>(std::basic_string& str) { str.assign(start, finish); return true; } #if !defined(__SUNPRO_CC) template bool operator>>(::boost::container::basic_string& str) { str.assign(start, finish); return true; } #endif // !defined(__SUNPRO_CC) -#endif + /* * case "-0" || "0" || "+0" : output = false; return true; * case "1" || "+1": output = true; return true; @@ -1752,10 +1782,6 @@ namespace boost }; } -#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION - - // call-by-const reference version - namespace detail { template @@ -1788,60 +1814,6 @@ namespace boost BOOST_STATIC_CONSTANT(bool, value = true ); }; #endif // !defined(__SUNPRO_CC) - template - struct is_char_or_wchar - { - private: -#ifndef BOOST_LCAST_NO_WCHAR_T - typedef wchar_t wchar_t_if_supported; -#else - typedef char wchar_t_if_supported; -#endif - -#ifndef BOOST_NO_CHAR16_T - typedef char16_t char16_t_if_supported; -#else - typedef char char16_t_if_supported; -#endif - -#ifndef BOOST_NO_CHAR32_T - typedef char32_t char32_t_if_supported; -#else - typedef char char32_t_if_supported; -#endif - public: - - BOOST_STATIC_CONSTANT(bool, value = - ( - ::boost::type_traits::ice_or< - is_same< T, char >::value, - is_same< T, wchar_t_if_supported >::value, - is_same< T, char16_t_if_supported >::value, - is_same< T, char32_t_if_supported >::value, - is_same< T, unsigned char >::value, - is_same< T, signed char >::value - >::value - ) - ); - }; - - template - struct is_char_iterator_range - { - BOOST_STATIC_CONSTANT(bool, value = false ); - }; - - template - struct is_char_iterator_range > - { - BOOST_STATIC_CONSTANT(bool, value = (is_char_or_wchar::value) ); - }; - - template - struct is_char_iterator_range > - { - BOOST_STATIC_CONSTANT(bool, value = (is_char_or_wchar::value) ); - }; template struct is_arithmetic_and_not_xchars @@ -1970,51 +1942,34 @@ namespace boost "Your compiler does not have full support for char32_t" ); #endif - typedef detail::lcast_src_length lcast_src_length; + 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(); - typedef BOOST_DEDUCED_TYPENAME - deduce_char_traits::type traits; + typedef BOOST_DEDUCED_TYPENAME ::boost::detail::deduce_char_traits< + char_type, Target, Source + >::type traits; - typedef BOOST_DEDUCED_TYPENAME remove_pointer::type removed_ptr_t_1; - typedef BOOST_DEDUCED_TYPENAME remove_cv::type removed_ptr_t; + 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; - // is_char_types_match variable value can be computed via - // sizeof(char_type) == sizeof(removed_ptr_t). But when - // removed_ptr_t is an incomplete type or void*, compilers - // produce warnings or errors. - const bool is_char_types_match = - (::boost::type_traits::ice_or< - ::boost::type_traits::ice_and< - ::boost::type_traits::ice_eq::value, - ::boost::type_traits::ice_or< - ::boost::is_same::value, - ::boost::is_same::value, - ::boost::is_same::value - >::value - >::value, - ::boost::is_same::value - >::value); + 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; - const bool requires_stringbuf = - !( - ::boost::type_traits::ice_or< - ::boost::detail::is_stdstring::value, - ::boost::is_integral::value, - ::boost::detail::is_this_float_conversion_optimized::value, - ::boost::type_traits::ice_and< - ::boost::detail::is_char_iterator_range::value, - is_char_types_match - >::value, - ::boost::type_traits::ice_and< - ::boost::is_pointer::value, - ::boost::detail::is_char_or_wchar::value, - is_char_types_match - >::value - >::value - ); + // 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; detail::lexical_stream_limited_src interpreter(buf, buf + src_len); @@ -2030,7 +1985,7 @@ namespace boost # pragma warning( pop ) #endif - template + template struct lexical_cast_copy { static inline Source lexical_cast_impl(const Source &arg) @@ -2039,7 +1994,7 @@ namespace boost } }; - template + template struct detect_precision_loss { typedef boost::numeric::Trunc Rounder; @@ -2063,7 +2018,7 @@ namespace boost typedef typename Rounder::round_style round_style; } ; - template + template struct nothrow_overflow_handler { void operator() ( boost::numeric::range_check_result r ) @@ -2073,7 +2028,7 @@ namespace boost } } ; - template + template struct lexical_cast_dynamic_num_not_ignoring_minus { static inline Target lexical_cast_impl(const Source &arg) @@ -2088,7 +2043,7 @@ namespace boost } }; - template + template struct lexical_cast_dynamic_num_ignoring_minus { static inline Target lexical_cast_impl(const Source &arg) @@ -2125,7 +2080,7 @@ namespace boost * optional, so if a negative number is read, no errors will arise * and the result will be the two's complement. */ - template + template struct lexical_cast_dynamic_num { static inline Target lexical_cast_impl(const Source &arg) @@ -2153,40 +2108,80 @@ namespace boost }; } - template + 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::type_traits::ice_or< - ::boost::detail::is_xchar_to_xchar::value, - ::boost::detail::is_char_array_to_stdstring::value, + ::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 + ::boost::is_same::value, + ::boost::detail::is_stdstring::value >::value - > do_copy_type; + > shall_we_copy_t; typedef BOOST_DEDUCED_TYPENAME - ::boost::detail::is_arithmetic_and_not_xchars do_copy_with_dynamic_check_type; + ::boost::detail::is_arithmetic_and_not_xchars shall_we_copy_with_dynamic_check_t; typedef BOOST_DEDUCED_TYPENAME ::boost::mpl::if_c< - do_copy_type::value, - detail::lexical_cast_copy, + shall_we_copy_t::value, + ::boost::detail::lexical_cast_copy, BOOST_DEDUCED_TYPENAME ::boost::mpl::if_c< - do_copy_with_dynamic_check_type::value, - ::boost::detail::lexical_cast_dynamic_num, - ::boost::detail::lexical_cast_do_cast + shall_we_copy_with_dynamic_check_t::value, + ::boost::detail::lexical_cast_dynamic_num, + ::boost::detail::lexical_cast_do_cast >::type >::type caster_type; return caster_type::lexical_cast_impl(arg); } - #else +} // namespace boost - namespace detail // stream wrapper for handling lexical conversions +#else // #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + +namespace boost { + namespace detail { + + // selectors for choosing stream character type + template + struct stream_char + { + typedef char type; + }; + +#ifndef BOOST_LCAST_NO_WCHAR_T +#ifndef BOOST_NO_INTRINSIC_WCHAR_T + template<> + struct stream_char + { + typedef wchar_t type; + }; +#endif + + template<> + struct stream_char + { + typedef wchar_t type; + }; + + template<> + struct stream_char + { + typedef wchar_t type; + }; + + template<> + struct stream_char + { + typedef wchar_t type; + }; +#endif + + // stream wrapper for handling lexical conversions template class lexical_stream { @@ -2276,8 +2271,9 @@ namespace boost return result; } - #endif -} +} // namespace boost + +#endif // Copyright Kevlin Henney, 2000-2005. // Copyright Alexander Nasonov, 2006-2010. @@ -2287,5 +2283,8 @@ namespace boost // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +#undef BOOST_LCAST_THROW_BAD_CAST #undef BOOST_LCAST_NO_WCHAR_T -#endif + +#endif // BOOST_LEXICAL_CAST_INCLUDED + diff --git a/lexical_cast_test.cpp b/lexical_cast_test.cpp index 4e70bdd..844ee71 100644 --- a/lexical_cast_test.cpp +++ b/lexical_cast_test.cpp @@ -427,7 +427,6 @@ void test_conversion_to_wstring() BOOST_CHECK(str == lexical_cast(str)); BOOST_CHECK(L"123" == lexical_cast(123)); BOOST_CHECK(L"1.23" == lexical_cast(1.23)); - BOOST_CHECK(L"1.111111111" == lexical_cast(1.111111111)); BOOST_CHECK(L"1" == lexical_cast(true)); BOOST_CHECK(L"0" == lexical_cast(false)); #if !defined(BOOST_NO_INTRINSIC_WCHAR_T) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 2673009..6edd59b 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -12,6 +12,7 @@ project : requirements /boost/test//boost_unit_test_framework static + gcc-4.8:BOOST_STL_SUPPORTS_NEW_UNICODE_LOCALES ; # Thanks to Steven Watanabe for helping with feature diff --git a/test/lexical_cast_containers_test.cpp b/test/lexical_cast_containers_test.cpp index 0c6315b..e6c544a 100644 --- a/test/lexical_cast_containers_test.cpp +++ b/test/lexical_cast_containers_test.cpp @@ -14,6 +14,8 @@ void testing_boost_containers_basic_string(); void testing_boost_containers_string_std_string(); +void testing_boost_containers_string_widening(); + using namespace boost; @@ -23,6 +25,7 @@ boost::unit_test::test_suite *init_unit_test_suite(int, char *[]) BOOST_TEST_SUITE("Testing boost::lexical_cast with boost::container::string"); suite->add(BOOST_TEST_CASE(testing_boost_containers_basic_string)); suite->add(BOOST_TEST_CASE(testing_boost_containers_string_std_string)); + suite->add(BOOST_TEST_CASE(testing_boost_containers_string_widening)); return suite; } @@ -58,3 +61,23 @@ void testing_boost_containers_string_std_string() #endif } + +void testing_boost_containers_string_widening() +{ + const char char_array[] = "Test string"; + +#ifndef BOOST_LCAST_NO_WCHAR_T + const wchar_t wchar_array[] = L"Test string"; + 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) + 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) + const char32_t char32_array[] = U"Test string"; + BOOST_CHECK(boost::lexical_cast >(char_array) == char32_array); +#endif +} diff --git a/test/lexical_cast_iterator_range_test.cpp b/test/lexical_cast_iterator_range_test.cpp index 7afb1ae..d54de7a 100644 --- a/test/lexical_cast_iterator_range_test.cpp +++ b/test/lexical_cast_iterator_range_test.cpp @@ -43,7 +43,7 @@ inline std::basic_istream& operator >> (std::basic_istream& istr, template -void do_test_iterator_range(const RngT& rng) +void do_test_iterator_range_impl(const RngT& rng) { BOOST_CHECK_EQUAL(lexical_cast(rng), 1); BOOST_CHECK_EQUAL(lexical_cast(rng), 1u); @@ -51,11 +51,13 @@ void do_test_iterator_range(const RngT& rng) BOOST_CHECK_EQUAL(lexical_cast(rng), 1u); BOOST_CHECK_EQUAL(lexical_cast(rng), 1); BOOST_CHECK_EQUAL(lexical_cast(rng), 1u); + +#ifdef BOOST_STL_SUPPORTS_NEW_UNICODE_LOCALES BOOST_CHECK_EQUAL(lexical_cast(rng), 1.0f); BOOST_CHECK_EQUAL(lexical_cast(rng), 1.0); BOOST_CHECK_EQUAL(lexical_cast(rng), 1.0L); BOOST_CHECK_EQUAL(lexical_cast(rng), 1); - +#endif #if defined(BOOST_HAS_LONG_LONG) BOOST_CHECK_EQUAL(lexical_cast(rng), 1u); BOOST_CHECK_EQUAL(lexical_cast(rng), 1); @@ -63,115 +65,139 @@ void do_test_iterator_range(const RngT& rng) BOOST_CHECK_EQUAL(lexical_cast(rng), 1u); BOOST_CHECK_EQUAL(lexical_cast<__int64>(rng), 1); #endif +} + +template +void test_it_range_using_any_chars(CharT* one, CharT* eleven) +{ + typedef CharT test_char_type; + + // Zero terminated + iterator_range rng1(one, one + 1); + do_test_iterator_range_impl(rng1); + + iterator_range crng1(one, one + 1); + do_test_iterator_range_impl(crng1); + + // Non zero terminated + iterator_range rng2(eleven, eleven + 1); + do_test_iterator_range_impl(rng2); + + iterator_range crng2(eleven, eleven + 1); + do_test_iterator_range_impl(crng2); +} + +template +void test_it_range_using_char(CharT* one, CharT* eleven) +{ + typedef CharT test_char_type; + + iterator_range rng1(one, one + 1); + BOOST_CHECK_EQUAL(lexical_cast(rng1), "1"); + + iterator_range crng1(one, one + 1); + BOOST_CHECK_EQUAL(lexical_cast(crng1), "1"); + + iterator_range rng2(eleven, eleven + 1); + BOOST_CHECK_EQUAL(lexical_cast(rng2), "1"); + + iterator_range crng2(eleven, eleven + 1); + BOOST_CHECK_EQUAL(lexical_cast(crng2), "1"); + + BOOST_CHECK_EQUAL(lexical_cast(rng1), 1.0f); + BOOST_CHECK_EQUAL(lexical_cast(rng1), 1.0); + BOOST_CHECK_EQUAL(lexical_cast(rng1), 1.0L); + BOOST_CHECK_EQUAL(lexical_cast(rng1), 1); + + BOOST_CHECK_EQUAL(lexical_cast(crng2), 1.0f); + BOOST_CHECK_EQUAL(lexical_cast(crng2), 1.0); + BOOST_CHECK_EQUAL(lexical_cast(crng2), 1.0L); + BOOST_CHECK_EQUAL(lexical_cast(crng2), 1); #ifndef BOOST_LCAST_NO_WCHAR_T - BOOST_CHECK(lexical_cast(rng) == L"1"); + BOOST_CHECK(lexical_cast(rng1) == L"1"); + BOOST_CHECK(lexical_cast(crng1) == L"1"); + BOOST_CHECK(lexical_cast(rng2) == L"1"); + 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) + typedef std::basic_string my_char16_string; + BOOST_CHECK(lexical_cast(rng1) == u"1"); + BOOST_CHECK(lexical_cast(crng1) == u"1"); + BOOST_CHECK(lexical_cast(rng2) == u"1"); + 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) + typedef std::basic_string my_char32_string; + BOOST_CHECK(lexical_cast(rng1) == U"1"); + BOOST_CHECK(lexical_cast(crng1) == U"1"); + BOOST_CHECK(lexical_cast(rng2) == U"1"); + BOOST_CHECK(lexical_cast(crng2) == U"1"); #endif } void test_char_iterator_ranges() { typedef char test_char_type; - - // Zero terminated test_char_type data1[] = "1"; - iterator_range rng1(data1, data1 + 1); - do_test_iterator_range(rng1); - BOOST_CHECK_EQUAL(lexical_cast(rng1), "1"); - - const test_char_type cdata1[] = "1"; - iterator_range crng1(cdata1, cdata1 + 1); - do_test_iterator_range(crng1); - BOOST_CHECK_EQUAL(lexical_cast(crng1), "1"); - - // Non zero terminated test_char_type data2[] = "11"; - iterator_range rng2(data2, data2 + 1); - do_test_iterator_range(rng2); - BOOST_CHECK_EQUAL(lexical_cast(rng2), "1"); - - const test_char_type cdata2[] = "11"; - iterator_range crng2(cdata2, cdata2 + 1); - do_test_iterator_range(crng2); - BOOST_CHECK_EQUAL(lexical_cast(crng2), "1"); + test_it_range_using_any_chars(data1, data2); + test_it_range_using_char(data1, data2); } + + void test_unsigned_char_iterator_ranges() { typedef unsigned char test_char_type; - - // Zero terminated test_char_type data1[] = "1"; - iterator_range rng1(data1, data1 + 1); - do_test_iterator_range(rng1); - BOOST_CHECK_EQUAL(lexical_cast(rng1), "1"); - - const test_char_type cdata1[] = "1"; - iterator_range crng1(cdata1, cdata1 + 1); - do_test_iterator_range(crng1); - BOOST_CHECK_EQUAL(lexical_cast(crng1), "1"); - - // Non zero terminated test_char_type data2[] = "11"; - iterator_range rng2(data2, data2 + 1); - do_test_iterator_range(rng2); - BOOST_CHECK_EQUAL(lexical_cast(rng2), "1"); - - const test_char_type cdata2[] = "11"; - iterator_range crng2(cdata2, cdata2 + 1); - do_test_iterator_range(crng2); - BOOST_CHECK_EQUAL(lexical_cast(crng2), "1"); + test_it_range_using_any_chars(data1, data2); + test_it_range_using_char(data1, data2); } void test_signed_char_iterator_ranges() { typedef signed char test_char_type; - - // Zero terminated test_char_type data1[] = "1"; - iterator_range rng1(data1, data1 + 1); - do_test_iterator_range(rng1); - BOOST_CHECK_EQUAL(lexical_cast(rng1), "1"); - - const test_char_type cdata1[] = "1"; - iterator_range crng1(cdata1, cdata1 + 1); - do_test_iterator_range(crng1); - BOOST_CHECK_EQUAL(lexical_cast(crng1), "1"); - - // Non zero terminated test_char_type data2[] = "11"; - iterator_range rng2(data2, data2 + 1); - do_test_iterator_range(rng2); - BOOST_CHECK_EQUAL(lexical_cast(rng2), "1"); - - const test_char_type cdata2[] = "11"; - iterator_range crng2(cdata2, cdata2 + 1); - do_test_iterator_range(crng2); - BOOST_CHECK_EQUAL(lexical_cast(crng2), "1"); + test_it_range_using_any_chars(data1, data2); + test_it_range_using_char(data1, data2); } -void test_wide_char_iterator_ranges() +void test_wchar_iterator_ranges() { #ifndef BOOST_LCAST_NO_WCHAR_T typedef wchar_t test_char_type; - - // Zero terminated test_char_type data1[] = L"1"; - iterator_range rng1(data1, data1 + 1); - do_test_iterator_range(rng1); - - const test_char_type cdata1[] = L"1"; - iterator_range crng1(cdata1, cdata1 + 1); - do_test_iterator_range(crng1); - - // Non zero terminated test_char_type data2[] = L"11"; - iterator_range rng2(data2, data2 + 1); - do_test_iterator_range(rng2); + test_it_range_using_any_chars(data1, data2); +#endif - const test_char_type cdata2[] = L"11"; - iterator_range crng2(cdata2, cdata2 + 1); - do_test_iterator_range(crng2); + BOOST_CHECK(true); +} + +void test_char16_iterator_ranges() +{ +#if !defined(BOOST_NO_CHAR16_T) && !defined(BOOST_NO_UNICODE_LITERALS) + typedef char16_t test_char_type; + test_char_type data1[] = u"1"; + test_char_type data2[] = u"11"; + test_it_range_using_any_chars(data1, data2); +#endif + + BOOST_CHECK(true); +} + +void test_char32_iterator_ranges() +{ +#if !defined(BOOST_NO_CHAR32_T) && !defined(BOOST_NO_UNICODE_LITERALS) + typedef char32_t test_char_type; + test_char_type data1[] = U"1"; + test_char_type data2[] = U"11"; + test_it_range_using_any_chars(data1, data2); #endif BOOST_CHECK(true); @@ -183,7 +209,9 @@ unit_test::test_suite *init_unit_test_suite(int, char *[]) suite->add(BOOST_TEST_CASE(&test_char_iterator_ranges)); suite->add(BOOST_TEST_CASE(&test_unsigned_char_iterator_ranges)); suite->add(BOOST_TEST_CASE(&test_signed_char_iterator_ranges)); - suite->add(BOOST_TEST_CASE(&test_wide_char_iterator_ranges)); + suite->add(BOOST_TEST_CASE(&test_wchar_iterator_ranges)); + suite->add(BOOST_TEST_CASE(&test_char16_iterator_ranges)); + suite->add(BOOST_TEST_CASE(&test_char32_iterator_ranges)); return suite; } diff --git a/test/lexical_cast_wchars_test.cpp b/test/lexical_cast_wchars_test.cpp index acd78b1..f78de1d 100755 --- a/test/lexical_cast_wchars_test.cpp +++ b/test/lexical_cast_wchars_test.cpp @@ -2,7 +2,7 @@ // // See http://www.boost.org for most recent version, including documentation. // -// Copyright Antony Polukhin, 2011. +// Copyright Antony Polukhin, 2011-2012. // // Distributed under the Boost // Software License, Version 1.0. (See accompanying file @@ -17,40 +17,70 @@ #endif #include - -#include #include -#include using namespace boost; -void test_char_types_conversions() +#if defined(BOOST_NO_STRINGSTREAM) || defined(BOOST_NO_STD_WSTRING) +#define BOOST_LCAST_NO_WCHAR_T +#endif + +template +void test_impl(const CharT* wc_arr) { -#ifndef BOOST_LCAST_NO_WCHAR_T + typedef CharT wide_char; + typedef std::basic_string wide_string; const char c_arr[] = "Test array of chars"; const unsigned char uc_arr[] = "Test array of chars"; const signed char sc_arr[] = "Test array of chars"; - const wchar_t wc_arr[] =L"Test array of chars"; // Following tests depend on realization of std::locale // and pass for popular compilers and STL realizations - BOOST_CHECK(boost::lexical_cast(c_arr[0]) == wc_arr[0]); - BOOST_CHECK(boost::lexical_cast(c_arr) == std::wstring(wc_arr)); + BOOST_CHECK(boost::lexical_cast(c_arr[0]) == wc_arr[0]); + BOOST_CHECK(boost::lexical_cast(c_arr) == wide_string(wc_arr)); - BOOST_CHECK(boost::lexical_cast(sc_arr) == std::wstring(wc_arr) ); - BOOST_CHECK(boost::lexical_cast(uc_arr) == std::wstring(wc_arr) ); + BOOST_CHECK(boost::lexical_cast(sc_arr) == wide_string(wc_arr) ); + BOOST_CHECK(boost::lexical_cast(uc_arr) == wide_string(wc_arr) ); - BOOST_CHECK_EQUAL(boost::lexical_cast(uc_arr[0]), wc_arr[0]); - BOOST_CHECK_EQUAL(boost::lexical_cast(sc_arr[0]), wc_arr[0]); + BOOST_CHECK_EQUAL(boost::lexical_cast(uc_arr[0]), wc_arr[0]); + BOOST_CHECK_EQUAL(boost::lexical_cast(sc_arr[0]), wc_arr[0]); +} + + +void test_char_types_conversions_wchar_t() +{ +#ifndef BOOST_LCAST_NO_WCHAR_T + test_impl(L"Test array of chars"); #endif - BOOST_CHECK(1); + + BOOST_CHECK(true); +} + +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) + test_impl(u"Test array of chars"); +#endif + + BOOST_CHECK(true); +} + +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) + test_impl(U"Test array of chars"); +#endif + + BOOST_CHECK(true); } unit_test::test_suite *init_unit_test_suite(int, char *[]) { unit_test::test_suite *suite = - BOOST_TEST_SUITE("lexical_cast char<->wchar_t unit test"); - suite->add(BOOST_TEST_CASE(&test_char_types_conversions)); + BOOST_TEST_SUITE("lexical_cast char => wide characters unit test (widening test)"); + suite->add(BOOST_TEST_CASE(&test_char_types_conversions_wchar_t)); + suite->add(BOOST_TEST_CASE(&test_char_types_conversions_char16_t)); + suite->add(BOOST_TEST_CASE(&test_char_types_conversions_char32_t)); return suite; }