From e41ef929d2f48b705b246883a4430140cdcd02f3 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Thu, 12 May 2011 17:21:07 +0000 Subject: [PATCH 01/39] FIx #5536 [SVN r71901] --- lexical_cast.htm | 70 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 49 insertions(+), 21 deletions(-) diff --git a/lexical_cast.htm b/lexical_cast.htm index 4bbdc8e..efc7219 100644 --- a/lexical_cast.htm +++ b/lexical_cast.htm @@ -196,38 +196,60 @@ public: failure.
+ + -

Frequently Asked Questions

-

Q: Why does lexical_cast<int8_t>("127") throw bad_lexical_cast? -
A: The type int8_t is a typedef to char or signed char. +

Frequently Asked Questions

+ + + + + + + + + + + + + + + + + + + + + + + + +
Question:Why does lexical_cast<int8_t>("127") throw bad_lexical_cast?
Answer:The type int8_t is a typedef to char or signed char. Lexical conversion to these types is simply reading a byte from source but since the source has more than one byte, the exception is thrown. -

Please use other integer types such as int or short int. If bounds checking + Please use other integer types such as int or short int. If bounds checking is important, you can also call numeric_cast: -

numeric_cast<int8_t>(lexical_cast<int>("127"));
+
Question:What does lexical_cast<std::string> of an int8_t or uint8_t not do what I expect?
Answer:As above, note that int8_t and uint8_t are actually chars and are formatted as such. To avoid this, cast to an integer type first: +
lexical_cast<std::string>(static_cast<int>(n));
+
Question:The implementation always resets the ios_base::skipws flag of an underlying stream object. It breaks my operator>> that works only in presence of this flag. Can you remove code that resets the flag?
Answer:May be in a future version. There is no requirement in [N1973] to reset the flag but remember that [N1973] is not yet accepted by the committee. By the way, it's a great opportunity to make your operator>> conform to the standard. Read a good C++ book, study std::sentry and ios_state_saver. +
-

Q: What does lexical_cast<std::string> of an int8_t or uint8_t not do what I expect? -
A: As above, note that int8_t and uint8_t are actually chars and are formatted as such. To avoid this, cast to an integer type first: - -

lexical_cast<std::string>(static_cast<int>(n));
- -

Q: The implementation always resets the ios_base::skipws flag of an underlying stream object. It breaks my operator>> that works only in presence of this flag. Can you remove code that resets the flag? -
A: May be in a future version. There is no requirement in [N1973] to reset the flag but remember that [N1973] is not yet accepted by the committee. By the way, it's a great opportunity to make your operator>> conform to the standard. Read a good C++ book, study std::sentry and ios_state_saver. - -

References

+

References

Changes

+

May 2011:

+
    +
  • Better performance for conversions from arithmetic type to arithmetic type.
  • +
  • Directly construct Target from Source on some conversions (like conversions from string to string, from char array to string, from char to char and others).
  • +

August, October 2006:

  • Better performance for many combinations of Source and Target diff --git a/lexical_cast_test.cpp b/lexical_cast_test.cpp index a994d13..3f0991b 100644 --- a/lexical_cast_test.cpp +++ b/lexical_cast_test.cpp @@ -2,7 +2,7 @@ // // See http://www.boost.org for most recent version, including documentation. // -// Copyright Terje Slettebø and Kevlin Henney, 2005. +// Copyright Terje Sletteb and Kevlin Henney, 2005. // Copyright Alexander Nasonov, 2006. // // Distributed under the Boost @@ -84,6 +84,9 @@ void test_conversion_from_to_uintmax_t(); void test_conversion_from_to_longlong(); void test_conversion_from_to_ulonglong(); #endif +void test_conversion_from_to_float(); +void test_conversion_from_to_double(); +void test_conversion_from_to_long_double(); #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION void test_traits(); void test_wtraits(); @@ -122,6 +125,9 @@ unit_test::test_suite *init_unit_test_suite(int, char *[]) suite->add(BOOST_TEST_CASE(&test_conversion_from_to_longlong)); suite->add(BOOST_TEST_CASE(&test_conversion_from_to_ulonglong)); #endif + suite->add(BOOST_TEST_CASE(&test_conversion_from_to_float)); + suite->add(BOOST_TEST_CASE(&test_conversion_from_to_double)); + suite->add(BOOST_TEST_CASE(&test_conversion_from_to_long_double)); #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION suite->add(BOOST_TEST_CASE(&test_traits)); suite->add(BOOST_TEST_CASE(&test_wtraits)); @@ -447,6 +453,24 @@ void test_conversion_from_integral_to_char(CharT zero) BOOST_CHECK_THROW(lexical_cast(t), bad_lexical_cast); } +template +void test_conversion_from_char_to_integral(CharT zero) +{ + BOOST_CHECK(lexical_cast( static_cast(zero + 0)) == static_cast(0) ); + BOOST_CHECK(lexical_cast( static_cast(zero + 1)) == static_cast(1) ); + BOOST_CHECK(lexical_cast( static_cast(zero + 2)) == static_cast(2) ); + BOOST_CHECK(lexical_cast( static_cast(zero + 3)) == static_cast(3) ); + BOOST_CHECK(lexical_cast( static_cast(zero + 4)) == static_cast(4) ); + BOOST_CHECK(lexical_cast( static_cast(zero + 5)) == static_cast(5) ); + BOOST_CHECK(lexical_cast( static_cast(zero + 6)) == static_cast(6) ); + BOOST_CHECK(lexical_cast( static_cast(zero + 7)) == static_cast(7) ); + BOOST_CHECK(lexical_cast( static_cast(zero + 8)) == static_cast(8) ); + BOOST_CHECK(lexical_cast( static_cast(zero + 9)) == static_cast(9) ); + + BOOST_CHECK_THROW(lexical_cast( static_cast(zero + 10)), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast( static_cast(zero - 1)), bad_lexical_cast); +} + template void test_conversion_from_integral_to_integral() { @@ -625,13 +649,36 @@ void test_conversion_from_to_integral() signed char const szero = '0'; unsigned char const uzero = '0'; test_conversion_from_integral_to_char(zero); + test_conversion_from_char_to_integral(zero); test_conversion_from_integral_to_char(szero); + test_conversion_from_char_to_integral(szero); test_conversion_from_integral_to_char(uzero); + test_conversion_from_char_to_integral(uzero); #if !defined(BOOST_LCAST_NO_WCHAR_T) && !defined(BOOST_NO_INTRINSIC_WCHAR_T) wchar_t const wzero = L'0'; test_conversion_from_integral_to_char(wzero); + test_conversion_from_char_to_integral(wzero); #endif + BOOST_CHECK(lexical_cast("-1") == static_cast(-1)); + BOOST_CHECK(lexical_cast("-9") == static_cast(-9)); + BOOST_CHECK(lexical_cast(-1) == static_cast(-1)); + BOOST_CHECK(lexical_cast(-9) == static_cast(-9)); + + BOOST_CHECK_THROW(lexical_cast("-1.0"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("-9.0"), bad_lexical_cast); + BOOST_CHECK(lexical_cast(-1.0) == static_cast(-1)); + BOOST_CHECK(lexical_cast(-9.0) == static_cast(-9)); + + BOOST_CHECK(lexical_cast(static_cast(1)) == static_cast(1)); + BOOST_CHECK(lexical_cast(static_cast(9)) == static_cast(9)); + BOOST_CHECK_THROW(lexical_cast(1.1f), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(1.1), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(1.1L), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(1.0001f), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(1.0001), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(1.0001L), bad_lexical_cast); + // test_conversion_from_to_integral_for_locale typedef std::numpunct numpunct; @@ -665,6 +712,27 @@ void test_conversion_from_to_integral() BOOST_TEST_MESSAGE("Formatting with thousands_sep has not been tested"); } +template +void test_conversion_from_to_float() +{ + char const zero = '0'; + signed char const szero = '0'; + unsigned char const uzero = '0'; + test_conversion_from_integral_to_char(zero); + test_conversion_from_char_to_integral(zero); + test_conversion_from_integral_to_char(szero); + test_conversion_from_char_to_integral(szero); + test_conversion_from_integral_to_char(uzero); + test_conversion_from_char_to_integral(uzero); +#if !defined(BOOST_LCAST_NO_WCHAR_T) && !defined(BOOST_NO_INTRINSIC_WCHAR_T) + wchar_t const wzero = L'0'; + test_conversion_from_integral_to_char(wzero); + test_conversion_from_char_to_integral(wzero); +#endif + + test_conversion_from_integral_to_integral(); +} + void test_conversion_from_to_short() { test_conversion_from_to_integral(); @@ -717,6 +785,19 @@ void test_conversion_from_to_ulonglong() test_conversion_from_to_integral(); } +void test_conversion_from_to_float() +{ + test_conversion_from_to_float(); +} +void test_conversion_from_to_double() +{ + test_conversion_from_to_float(); +} +void test_conversion_from_to_long_double() +{ + test_conversion_from_to_float(); +} + #elif defined(LCAST_TEST_LONGLONG) void test_conversion_from_to_longlong() From dc9b364d6f3033712a93cae14d15ca3736dd39da Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Fri, 20 May 2011 17:11:53 +0000 Subject: [PATCH 04/39] Fixes #5417. Much better performance on casts to integral types. Adds more tests for overflow detection. Workaround for bugs of vc8 (lexical_cast_vc8_bug_test.cpp now passes) Fixes some inspection errors. [SVN r72056] --- include/boost/lexical_cast.hpp | 228 ++++++++++++++++++++++++++--- lexical_cast.htm | 5 +- lexical_cast_test.cpp | 93 ++++++++---- test/lexical_cast_vc8_bug_test.cpp | 14 ++ 4 files changed, 296 insertions(+), 44 deletions(-) diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index 7a4a5ee..00d0c4c 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -577,6 +577,84 @@ namespace boost } } + namespace detail // lcast_ret_unsigned + { + template + inline bool lcast_ret_unsigned(T& value, const CharT* const begin, const CharT* end) + { +#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS + BOOST_STATIC_ASSERT(!std::numeric_limits::is_signed); +#endif + typedef typename Traits::int_type int_type; + CharT const czero = lcast_char_constants::zero; + --end; + value = 0; + + if ( *end < czero || *end >= czero + 10 || begin > end) + return false; + value = *end - czero; + --end; + T multiplier = 1; + +#ifndef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE + // TODO: use BOOST_NO_STD_LOCALE + std::locale loc; + typedef std::numpunct numpunct; + numpunct const& np = BOOST_USE_FACET(numpunct, loc); + std::string const& grouping = np.grouping(); + std::string::size_type const grouping_size = grouping.size(); + + /* According to [22.2.2.1.2] of Programming languages — C++ we MUST check for correct grouping */ + if (grouping_size) + { + unsigned char current_grouping = 0; + CharT const thousands_sep = grouping_size ? np.thousands_sep() : 0; + char remained = grouping[current_grouping] - 1; + + for(;end>=begin; --end) + { + if (remained) { + T const new_sub_value = multiplier * 10 * (*end - czero); + + if (*end < czero || *end >= czero + 10 + /* detecting overflow */ + || new_sub_value/10 != multiplier * (*end - czero) + || static_cast((std::numeric_limits::max)()-new_sub_value) < value + ) + return false; + + value += new_sub_value; + multiplier *= 10; + --remained; + } else { + if ( !Traits::eq(*end, thousands_sep) || begin == end ) return false; + if (current_grouping < grouping_size-1 ) ++current_grouping; + remained = grouping[current_grouping]; + } + } + } else +#endif + { + while ( begin <= end ) + { + T const new_sub_value = multiplier * 10 * (*end - czero); + + if (*end < czero || *end >= czero + 10 + /* detecting overflow */ + || new_sub_value/10 != multiplier * (*end - czero) + || static_cast((std::numeric_limits::max)()-new_sub_value) < value + ) + return false; + + value += new_sub_value; + multiplier *= 10; + --end; + } + } + return true; + } + } + namespace detail // stream wrapper for handling lexical conversions { template @@ -762,8 +840,130 @@ namespace boost bool operator<<(double); bool operator<<(long double); + private: + + template + bool input_operator_helper_unsigned(Type& output) + { + CharT const minus = lcast_char_constants::minus; + bool const has_minus = Traits::eq(minus,*start); + bool const succeed = lcast_ret_unsigned(output, has_minus ? start+1 : start, finish); +#if (defined _MSC_VER) +# pragma warning( push ) +// C4146: unary minus operator applied to unsigned type, result still unsigned +# pragma warning( disable : 4146 ) +#elif defined( __BORLANDC__ ) +# pragma option push -w-8041 +#endif + if (has_minus) output = static_cast(-output); +#if (defined _MSC_VER) +# pragma warning( pop ) +#elif defined( __BORLANDC__ ) +# pragma option pop +#endif + return succeed; + } + + template + bool input_operator_helper_signed(Type& output) + { + CharT const minus = lcast_char_constants::minus; + typedef BOOST_DEDUCED_TYPENAME make_unsigned::type utype; + utype out_tmp =0; + bool const has_minus = Traits::eq(minus,*start); + bool succeed = lcast_ret_unsigned(out_tmp, has_minus ? start+1 : start, finish); + if (has_minus) { +#if (defined _MSC_VER) +# pragma warning( push ) +// C4146: unary minus operator applied to unsigned type, result still unsigned +# pragma warning( disable : 4146 ) +#elif defined( __BORLANDC__ ) +# pragma option push -w-8041 +#endif + utype const comp_val = static_cast(-(std::numeric_limits::min)()); + succeed = succeed && out_tmp<=comp_val; + output = -out_tmp; +#if (defined _MSC_VER) +# pragma warning( pop ) +#elif defined( __BORLANDC__ ) +# pragma option pop +#endif + } else { + utype const comp_val = static_cast((std::numeric_limits::max)()); + succeed = succeed && out_tmp<=comp_val; + output = out_tmp; + } + return succeed; + } + public: // input + bool operator>>(unsigned short& output) + { + return input_operator_helper_unsigned(output); + } + + bool operator>>(unsigned int& output) + { + return input_operator_helper_unsigned(output); + } + + bool operator>>(unsigned long int& output) + { + return input_operator_helper_unsigned(output); + } + + bool operator>>(short& output) + { + return input_operator_helper_signed(output); + } + + bool operator>>(int& output) + { + return input_operator_helper_signed(output); + } + + bool operator>>(long int& output) + { + return input_operator_helper_signed(output); + } + + +#if defined(BOOST_HAS_LONG_LONG) + bool operator>>( boost::ulong_long_type& output) + { + return input_operator_helper_unsigned(output); + } + + bool operator>>(boost::long_long_type& output) + { + return input_operator_helper_signed(output); + } + +#elif defined(BOOST_HAS_MS_INT64) + bool operator>>(unsigned __int64& output) + { + return input_operator_helper_unsigned(output); + } + + bool operator>>(__int64& output) + { + return input_operator_helper_signed(output); + } + +#endif + + bool operator>>(bool& output) + { + output = (start[0] == lcast_char_constants::zero + 1); + return finish-start==1 + && ( + start[0] == lcast_char_constants::zero + || start[0] == lcast_char_constants::zero + 1 + ); + } + + // Generic istream-based algorithm. // lcast_streambuf_for_target::value is true. template @@ -1059,23 +1259,17 @@ namespace boost template struct lcast_streambuf_for_target { - BOOST_STATIC_CONSTANT(bool, value = true); + BOOST_STATIC_CONSTANT(bool, value = + ( + ::boost::type_traits::ice_or< + ::boost::type_traits::ice_not< is_integral::value >::value, + is_same::value, + is_same::value + >::value + ) + ); }; - template<> - struct lcast_streambuf_for_target - { - BOOST_STATIC_CONSTANT(bool, value = false); - }; - -#if !defined(BOOST_LCAST_NO_WCHAR_T) && !defined(BOOST_NO_INTRINSIC_WCHAR_T) - template<> - struct lcast_streambuf_for_target - { - BOOST_STATIC_CONSTANT(bool, value = false); - }; -#endif - #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION template struct lcast_streambuf_for_target< @@ -1328,7 +1522,7 @@ namespace boost > Converter ; return Converter::convert(arg); - } catch(...) { + } catch( ::boost::numeric::bad_numeric_cast const& ) { BOOST_LCAST_THROW_BAD_CAST(Source, Target); } } @@ -1354,7 +1548,7 @@ namespace boost } else { return Converter::convert(arg); } - } catch(...) { + } catch( ::boost::numeric::bad_numeric_cast const& ) { BOOST_LCAST_THROW_BAD_CAST(Source, Target); } } diff --git a/lexical_cast.htm b/lexical_cast.htm index 268684e..3372618 100644 --- a/lexical_cast.htm +++ b/lexical_cast.htm @@ -267,7 +267,8 @@ Eliminate an overhead of std::locale if your program runs in the "C

    Changes

    May 2011:

      -
    • Better performance for conversions from arithmetic type to arithmetic type.
    • +
    • Better performance and less memory usage for conversions to arithmetic types.
    • +
    • Better performance and less memory usage for conversions from arithmetic type to arithmetic type.
    • Directly construct Target from Source on some conversions (like conversions from string to string, from char array to string, from char to char and others).

    August, October 2006:

    @@ -317,7 +318,7 @@ Eliminate an overhead of std::locale if your program runs in the "C
    Copyright © Antony Polukhin, 2011
    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) + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
    diff --git a/lexical_cast_test.cpp b/lexical_cast_test.cpp index 3f0991b..317c3fd 100644 --- a/lexical_cast_test.cpp +++ b/lexical_cast_test.cpp @@ -4,6 +4,7 @@ // // Copyright Terje Sletteb and Kevlin Henney, 2005. // Copyright Alexander Nasonov, 2006. +// Copyright Antony Polukhin, 2011. // // Distributed under the Boost // Software License, Version 1.0. (See accompanying file @@ -32,6 +33,7 @@ #include #include +#include #include #include @@ -235,6 +237,14 @@ void test_conversion_to_bool() BOOST_CHECK_EQUAL(false, lexical_cast("0")); BOOST_CHECK_EQUAL(true, lexical_cast(std::string("1"))); BOOST_CHECK_EQUAL(false, lexical_cast(std::string("0"))); + + BOOST_CHECK_THROW(lexical_cast(1.0001L), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(2), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(2u), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(-1), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(-2), bad_lexical_cast); + + BOOST_CHECK_THROW( lexical_cast(std::string("")), bad_lexical_cast); BOOST_CHECK_THROW( @@ -564,25 +574,46 @@ void test_conversion_from_string_to_integral(CharT) BOOST_CHECK_EQUAL(lexical_cast(s), min_val); if(limits::is_signed) { -#if defined(BOOST_MSVC) && BOOST_MSVC == 1400 - // VC++ 8.0 bug, see libs/conversion/test/lexical_cast_vc8_bug_test.cpp - if(sizeof(T) < sizeof(boost::intmax_t)) -#endif - { - BOOST_CHECK_THROW(lexical_cast(s + zero), bad_lexical_cast); - BOOST_CHECK_THROW(lexical_cast(s + nine), bad_lexical_cast); - } + BOOST_CHECK_THROW(lexical_cast(s + zero), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(s + nine), bad_lexical_cast); } s = to_str(max_val); BOOST_CHECK_EQUAL(lexical_cast(s), max_val); -#if defined(BOOST_MSVC) && BOOST_MSVC == 1400 - // VC++ 8.0 bug, see libs/conversion/test/lexical_cast_vc8_bug_test.cpp - if(sizeof(T) != sizeof(boost::intmax_t)) -#endif { BOOST_CHECK_THROW(lexical_cast(s + zero), bad_lexical_cast); BOOST_CHECK_THROW(lexical_cast(s + nine), bad_lexical_cast); + + s = to_str(max_val); + for (int i =1; i <=10; ++i) { + s[s.size()-1] += 1; + BOOST_CHECK_THROW(lexical_cast( s ), bad_lexical_cast); + } + + s = to_str(max_val); + std::locale loc; + typedef std::numpunct numpunct; + if ( BOOST_USE_FACET(numpunct, loc).grouping().empty() ) { + // Following tests work well for locale C + BOOST_CHECK_EQUAL(lexical_cast(to_str(0)+s), max_val); + BOOST_CHECK_EQUAL(lexical_cast(to_str(0)+to_str(0)+s), max_val); + BOOST_CHECK_EQUAL(lexical_cast(to_str(0)+to_str(0)+to_str(0)+s), max_val); + } + + for (int i =1; i <=256; ++i) { + BOOST_CHECK_THROW(lexical_cast( to_str(i)+s ), bad_lexical_cast); + } + + typedef BOOST_DEDUCED_TYPENAME boost::integral_promotion::type promoted; + if ( !(boost::is_same::value) ) + { + promoted prom = max_val; + s = to_str(max_val); + for (int i =1; i <=256; ++i) { + BOOST_CHECK_THROW(lexical_cast( to_str(prom+i) ), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast( to_str(i)+s ), bad_lexical_cast); + } + } } if(limits::digits <= 16 && lcast_test_small_integral_types_completely) @@ -627,6 +658,18 @@ void test_conversion_from_string_to_integral(CharT) template void test_conversion_from_to_integral_for_locale() { + std::locale current_locale; + typedef std::numpunct numpunct; + numpunct const& np = BOOST_USE_FACET(numpunct, current_locale); + if ( !np.grouping().empty() ) + { + BOOST_CHECK_THROW( + lexical_cast( std::string("100") + np.thousands_sep() + np.thousands_sep() + "0" ) + , bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast( std::string("100") + np.thousands_sep() ), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast( np.thousands_sep() + std::string("100") ), bad_lexical_cast); + } + test_conversion_from_integral_to_integral(); test_conversion_from_integral_to_string('0'); test_conversion_from_string_to_integral('0'); @@ -773,18 +816,6 @@ void test_conversion_from_to_uintmax_t() test_conversion_from_to_integral(); } -#if defined(BOOST_HAS_LONG_LONG) - -void test_conversion_from_to_longlong() -{ - test_conversion_from_to_integral(); -} - -void test_conversion_from_to_ulonglong() -{ - test_conversion_from_to_integral(); -} - void test_conversion_from_to_float() { test_conversion_from_to_float(); @@ -798,7 +829,19 @@ void test_conversion_from_to_long_double() test_conversion_from_to_float(); } -#elif defined(LCAST_TEST_LONGLONG) +#if defined(BOOST_HAS_LONG_LONG) + +void test_conversion_from_to_longlong() +{ + test_conversion_from_to_integral(); +} + +void test_conversion_from_to_ulonglong() +{ + test_conversion_from_to_integral(); +} + +#elif defined(BOOST_HAS_MS_INT64) void test_conversion_from_to_longlong() { diff --git a/test/lexical_cast_vc8_bug_test.cpp b/test/lexical_cast_vc8_bug_test.cpp index 843bea8..151e4f8 100644 --- a/test/lexical_cast_vc8_bug_test.cpp +++ b/test/lexical_cast_vc8_bug_test.cpp @@ -1,3 +1,17 @@ +// Unit test for boost::lexical_cast. +// +// See http://www.boost.org for most recent version, including documentation. +// +// Copyright Alexander Nasonov, 2007. +// +// 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). +// +// This tests now must pass on vc8, because lexical_cast +// implementation has changed and it does not use stringstream for casts +// to integral types + #include #include #include From 920e36f6ba7ef26d1a80902b84cfeaa94cd03a0a Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Sun, 22 May 2011 11:35:00 +0000 Subject: [PATCH 05/39] Fixes #5557. Adds tests on #5557 [SVN r72071] --- include/boost/lexical_cast.hpp | 79 ++++++++++++++++++++++++++++------ lexical_cast_test.cpp | 11 +++++ 2 files changed, 77 insertions(+), 13 deletions(-) diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index 00d0c4c..6875b16 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -463,7 +463,7 @@ namespace boost #endif // #ifndef BOOST_LCAST_NO_COMPILE_TIME_PRECISION } - namespace detail // '0' and '-' constants + namespace detail // '0', '+' and '-' constants { template struct lcast_char_constants; @@ -472,6 +472,7 @@ namespace boost { BOOST_STATIC_CONSTANT(char, zero = '0'); BOOST_STATIC_CONSTANT(char, minus = '-'); + BOOST_STATIC_CONSTANT(char, plus = '+'); }; #ifndef BOOST_LCAST_NO_WCHAR_T @@ -480,6 +481,7 @@ namespace boost { BOOST_STATIC_CONSTANT(wchar_t, zero = L'0'); BOOST_STATIC_CONSTANT(wchar_t, minus = L'-'); + BOOST_STATIC_CONSTANT(wchar_t, plus = L'+'); }; #endif } @@ -604,7 +606,9 @@ namespace boost std::string const& grouping = np.grouping(); std::string::size_type const grouping_size = grouping.size(); - /* According to [22.2.2.1.2] of Programming languages — C++ we MUST check for correct grouping */ + /* According to [22.2.2.1.2] of Programming languages - C++ + * we MUST check for correct grouping + */ if (grouping_size) { unsigned char current_grouping = 0; @@ -846,8 +850,20 @@ namespace boost bool input_operator_helper_unsigned(Type& output) { CharT const minus = lcast_char_constants::minus; - bool const has_minus = Traits::eq(minus,*start); - bool const succeed = lcast_ret_unsigned(output, has_minus ? start+1 : start, finish); + CharT const plus = lcast_char_constants::plus; + bool has_minus = false; + + /* We won`t use `start' any more, so no need in decrementing it after */ + if ( Traits::eq(minus,*start) ) + { + ++start; + has_minus = true; + } else if ( Traits::eq( plus, *start ) ) + { + ++start; + } + + bool const succeed = lcast_ret_unsigned(output, start, finish); #if (defined _MSC_VER) # pragma warning( push ) // C4146: unary minus operator applied to unsigned type, result still unsigned @@ -868,10 +884,22 @@ namespace boost bool input_operator_helper_signed(Type& output) { CharT const minus = lcast_char_constants::minus; + CharT const plus = lcast_char_constants::plus; typedef BOOST_DEDUCED_TYPENAME make_unsigned::type utype; utype out_tmp =0; - bool const has_minus = Traits::eq(minus,*start); - bool succeed = lcast_ret_unsigned(out_tmp, has_minus ? start+1 : start, finish); + bool has_minus = false; + + /* We won`t use `start' any more, so no need in decrementing it after */ + if ( Traits::eq(minus,*start) ) + { + ++start; + has_minus = true; + } else if ( Traits::eq(plus, *start) ) + { + ++start; + } + + bool succeed = lcast_ret_unsigned(out_tmp, start, finish); if (has_minus) { #if (defined _MSC_VER) # pragma warning( push ) @@ -953,14 +981,38 @@ namespace boost #endif + /* + * case "-0" || "0" || "+0" : output = false; return true; + * case "1" || "+1": output = true; return true; + * default: return false; + */ bool operator>>(bool& output) { - output = (start[0] == lcast_char_constants::zero + 1); - return finish-start==1 - && ( - start[0] == lcast_char_constants::zero - || start[0] == lcast_char_constants::zero + 1 - ); + CharT const zero = lcast_char_constants::zero; + CharT const plus = lcast_char_constants::plus; + CharT const minus = lcast_char_constants::minus; + + switch(finish-start) + { + case 1: + output = Traits::eq(start[0], zero+1); + return output || Traits::eq(start[0], zero ); + case 2: + if ( Traits::eq( plus, *start) ) + { + ++start; + output = Traits::eq(start[0], zero +1); + return output || Traits::eq(start[0], zero ); + } else + { + output = false; + return Traits::eq( minus, *start) + && Traits::eq( zero, start[1]); + } + default: + output = false; // Suppress warning about uninitalized variable + return false; + } } @@ -1614,7 +1666,8 @@ namespace boost >::value > do_copy_type; - typedef BOOST_DEDUCED_TYPENAME detail::is_arithmetic_and_not_xchars do_copy_with_dynamic_check_type; + typedef BOOST_DEDUCED_TYPENAME + detail::is_arithmetic_and_not_xchars do_copy_with_dynamic_check_type; typedef BOOST_DEDUCED_TYPENAME ::boost::mpl::if_c< do_copy_type::value, diff --git a/lexical_cast_test.cpp b/lexical_cast_test.cpp index 317c3fd..f366eb2 100644 --- a/lexical_cast_test.cpp +++ b/lexical_cast_test.cpp @@ -249,6 +249,12 @@ void test_conversion_to_bool() lexical_cast(std::string("")), bad_lexical_cast); BOOST_CHECK_THROW( lexical_cast(std::string("Test")), bad_lexical_cast); + + BOOST_CHECK(lexical_cast("+1") == true ); + BOOST_CHECK(lexical_cast("+0") == false ); + BOOST_CHECK(lexical_cast("-0") == false ); + BOOST_CHECK_THROW(lexical_cast("--0"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("-+-0"), bad_lexical_cast); } void test_conversion_to_string() @@ -722,6 +728,8 @@ void test_conversion_from_to_integral() BOOST_CHECK_THROW(lexical_cast(1.0001), bad_lexical_cast); BOOST_CHECK_THROW(lexical_cast(1.0001L), bad_lexical_cast); + BOOST_CHECK(lexical_cast("+1") == static_cast(1) ); + BOOST_CHECK(lexical_cast("+9") == static_cast(9) ); // test_conversion_from_to_integral_for_locale typedef std::numpunct numpunct; @@ -774,6 +782,9 @@ void test_conversion_from_to_float() #endif test_conversion_from_integral_to_integral(); + + BOOST_CHECK_CLOSE(lexical_cast("+1"), 1, std::numeric_limits::epsilon() ); + BOOST_CHECK_CLOSE(lexical_cast("+9"), 9, std::numeric_limits::epsilon()*9 ); } void test_conversion_from_to_short() From 98d24e04f408e86a8cf6675b5fff93c902bf3960 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Fri, 27 May 2011 04:22:18 +0000 Subject: [PATCH 06/39] Fixes #5564. Adds tests on #5564 and more tests on #5557 [SVN r72203] --- include/boost/lexical_cast.hpp | 138 ++++++++++++++++++++++++++++----- lexical_cast.htm | 1 + lexical_cast_test.cpp | 54 +++++++++++++ 3 files changed, 174 insertions(+), 19 deletions(-) diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index 6875b16..d185852 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -247,13 +247,42 @@ namespace boost static void check_coverage() {} }; - // No specializations for: - // lcast_src_length - // lcast_src_length - // lcast_src_length - // lcast_src_length - // lcast_src_length - // lcast_src_length + template<> + struct lcast_src_length + { + BOOST_STATIC_CONSTANT(std::size_t, value = 1); + static void check_coverage() {} + }; + template<> + struct lcast_src_length + { + BOOST_STATIC_CONSTANT(std::size_t, value = 1); + static void check_coverage() {} + }; + template<> + struct lcast_src_length + { + BOOST_STATIC_CONSTANT(std::size_t, value = 1); + static void check_coverage() {} + }; + template<> + struct lcast_src_length + { + BOOST_STATIC_CONSTANT(std::size_t, value = 1); + static void check_coverage() {} + }; + template<> + struct lcast_src_length + { + BOOST_STATIC_CONSTANT(std::size_t, value = 1); + static void check_coverage() {} + }; + template<> + struct lcast_src_length + { + BOOST_STATIC_CONSTANT(std::size_t, value = 1); + static void check_coverage() {} + }; #ifndef BOOST_LCAST_NO_WCHAR_T template<> @@ -821,9 +850,13 @@ namespace boost bool operator<<(bool); bool operator<<(char); + bool operator<<(unsigned char); + bool operator<<(signed char); #if !defined(BOOST_LCAST_NO_WCHAR_T) && !defined(BOOST_NO_INTRINSIC_WCHAR_T) bool operator<<(wchar_t); #endif + bool operator<<(unsigned char const*); + bool operator<<(signed char const*); bool operator<<(CharT const*); bool operator<<(short); bool operator<<(int); @@ -1050,6 +1083,8 @@ namespace boost } bool operator>>(CharT&); + bool operator>>(unsigned char&); + bool operator>>(signed char&); #ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION // This #if is in sync with lcast_streambuf_for_target @@ -1091,6 +1126,34 @@ namespace boost return true; } + template + inline bool lexical_stream_limited_src::operator<<( + unsigned char ch) + { + return ((*this) << static_cast(ch)); + } + + template + inline bool lexical_stream_limited_src::operator<<( + signed char ch) + { + return ((*this) << static_cast(ch)); + } + + template + inline bool lexical_stream_limited_src::operator<<( + unsigned char const* ch) + { + return ((*this) << reinterpret_cast(ch)); + } + + template + inline bool lexical_stream_limited_src::operator<<( + signed char const* ch) + { + return ((*this) << reinterpret_cast(ch)); + } + #if !defined(BOOST_LCAST_NO_WCHAR_T) && !defined(BOOST_NO_INTRINSIC_WCHAR_T) template inline bool lexical_stream_limited_src::operator<<( @@ -1256,6 +1319,34 @@ namespace boost return ok; } + template + inline bool lexical_stream_limited_src::operator>>( + unsigned char& output) + { + BOOST_STATIC_ASSERT( sizeof(CharT) == sizeof(unsigned char) ); + bool const ok = (finish - start == 1); + if(ok) { + CharT out; + Traits::assign(out, *start); + output = static_cast(out); + } + return ok; + } + + template + inline bool lexical_stream_limited_src::operator>>( + signed char& output) + { + BOOST_STATIC_ASSERT( sizeof(CharT) == sizeof(signed char) ); + bool const ok = (finish - start == 1); + if(ok) { + CharT out; + Traits::assign(out, *start); + output = static_cast(out); + } + return ok; + } + #ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION template inline bool lexical_stream_limited_src::operator>>( @@ -1312,13 +1403,9 @@ namespace boost struct lcast_streambuf_for_target { BOOST_STATIC_CONSTANT(bool, value = - ( - ::boost::type_traits::ice_or< - ::boost::type_traits::ice_not< is_integral::value >::value, - is_same::value, - is_same::value - >::value - ) + ( + ::boost::type_traits::ice_not< is_integral::value >::value + ) ); }; @@ -1472,16 +1559,29 @@ namespace boost ); }; + /* + * is_xchar_to_xchar::value is true, when + * Target and Souce are the same char types, or when + * Target and Souce are char types of the same size. + */ template struct is_xchar_to_xchar { BOOST_STATIC_CONSTANT(bool, value = - ( - ::boost::type_traits::ice_and< - is_same::value, - is_char_or_wchar::value + ( + ::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, + is_char_or_wchar::value, + is_char_or_wchar::value + >::value >::value - ) + ) ); }; diff --git a/lexical_cast.htm b/lexical_cast.htm index 3372618..03625b4 100644 --- a/lexical_cast.htm +++ b/lexical_cast.htm @@ -267,6 +267,7 @@ Eliminate an overhead of std::locale if your program runs in the "C

    Changes

    May 2011:

      +
    • Better performance and less memory usage for unsigned char and signed char conversions.
    • Better performance and less memory usage for conversions to arithmetic types.
    • Better performance and less memory usage for conversions from arithmetic type to arithmetic type.
    • Directly construct Target from Source on some conversions (like conversions from string to string, from char array to string, from char to char and others).
    • diff --git a/lexical_cast_test.cpp b/lexical_cast_test.cpp index f366eb2..75d12ff 100644 --- a/lexical_cast_test.cpp +++ b/lexical_cast_test.cpp @@ -95,6 +95,7 @@ void test_wtraits(); void test_allocator(); void test_wallocator(); #endif +void test_char_types_conversions(); unit_test::test_suite *init_unit_test_suite(int, char *[]) { @@ -137,6 +138,8 @@ unit_test::test_suite *init_unit_test_suite(int, char *[]) suite->add(BOOST_TEST_CASE(&test_wallocator)); #endif + suite->add(BOOST_TEST_CASE(&test_char_types_conversions)); + return suite; } @@ -730,6 +733,12 @@ void test_conversion_from_to_integral() BOOST_CHECK(lexical_cast("+1") == static_cast(1) ); BOOST_CHECK(lexical_cast("+9") == static_cast(9) ); + BOOST_CHECK(lexical_cast("+10") == static_cast(10) ); + BOOST_CHECK(lexical_cast("+90") == static_cast(90) ); + BOOST_CHECK_THROW(lexical_cast("++1"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("-+9"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("--1"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("+-9"), bad_lexical_cast); // test_conversion_from_to_integral_for_locale typedef std::numpunct numpunct; @@ -785,6 +794,11 @@ void test_conversion_from_to_float() BOOST_CHECK_CLOSE(lexical_cast("+1"), 1, std::numeric_limits::epsilon() ); BOOST_CHECK_CLOSE(lexical_cast("+9"), 9, std::numeric_limits::epsilon()*9 ); + + BOOST_CHECK_THROW(lexical_cast("++1"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("-+9"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("--1"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("+-9"), bad_lexical_cast); } void test_conversion_from_to_short() @@ -923,3 +937,43 @@ void test_wallocator() #endif +#include +void test_char_types_conversions() +{ + 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"; + + BOOST_CHECK(boost::lexical_cast(c_arr) == std::string(c_arr)); + BOOST_CHECK(boost::lexical_cast(uc_arr) == std::string(c_arr)); + BOOST_CHECK(boost::lexical_cast(sc_arr) == std::string(c_arr)); + + BOOST_CHECK(boost::lexical_cast(c_arr[0]) == c_arr[0]); + BOOST_CHECK(boost::lexical_cast(uc_arr[0]) == c_arr[0]); + BOOST_CHECK(boost::lexical_cast(sc_arr[0]) == c_arr[0]); + + BOOST_CHECK(boost::lexical_cast(c_arr[0]) == uc_arr[0]); + BOOST_CHECK(boost::lexical_cast(uc_arr[0]) == uc_arr[0]); + BOOST_CHECK(boost::lexical_cast(sc_arr[0]) == uc_arr[0]); + + BOOST_CHECK(boost::lexical_cast(c_arr[0]) == sc_arr[0]); + BOOST_CHECK(boost::lexical_cast(uc_arr[0]) == sc_arr[0]); + BOOST_CHECK(boost::lexical_cast(sc_arr[0]) == sc_arr[0]); + +#ifndef BOOST_LCAST_NO_WCHAR_T + const wchar_t wc_arr[]=L"Test array of chars"; + + BOOST_CHECK(boost::lexical_cast(wc_arr) == std::wstring(wc_arr)); + BOOST_CHECK(boost::lexical_cast(c_arr) == std::wstring(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(c_arr[0]) == wc_arr[0]); + BOOST_CHECK(boost::lexical_cast(wc_arr[0]) == wc_arr[0]); + + BOOST_CHECK_THROW(boost::lexical_cast(uc_arr[0]), bad_lexical_cast); + BOOST_CHECK_THROW(boost::lexical_cast(sc_arr[0]), bad_lexical_cast); + +#endif +} From b0b1ce9453445af00649f6ec7beee5d0beb5edf9 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Fri, 27 May 2011 18:19:38 +0000 Subject: [PATCH 07/39] Fixes #5576, adds performance section to the lexical_cast documentation, fixes misprint in tests/ [SVN r72224] --- include/boost/lexical_cast.hpp | 73 +++++++++++++++++++--------------- lexical_cast.htm | 34 +++++++++++++++- lexical_cast_test.cpp | 1 - 3 files changed, 74 insertions(+), 34 deletions(-) diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index d185852..c1b083b 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -555,6 +555,10 @@ namespace boost BOOST_STATIC_ASSERT(!std::numeric_limits::is_signed); #endif + typedef typename Traits::int_type int_type; + CharT const czero = lcast_char_constants::zero; + int_type const zero = Traits::to_int_type(czero); + #ifndef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE // TODO: use BOOST_NO_STD_LOCALE std::locale loc; @@ -562,47 +566,54 @@ namespace boost numpunct const& np = BOOST_USE_FACET(numpunct, loc); std::string const& grouping = np.grouping(); std::string::size_type const grouping_size = grouping.size(); - CharT thousands_sep = grouping_size ? np.thousands_sep() : 0; - std::string::size_type group = 0; // current group number - char last_grp_size = - grouping_size == 0 || grouping[0] <= 0 ? CHAR_MAX : grouping[0]; + + if ( grouping_size && grouping[0] > 0 ) + { + #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS // Check that ulimited group is unreachable: BOOST_STATIC_ASSERT(std::numeric_limits::digits10 < CHAR_MAX); #endif + CharT thousands_sep = np.thousands_sep(); + std::string::size_type group = 0; // current group number + char last_grp_size = grouping[0]; + char left = last_grp_size; - char left = last_grp_size; -#endif - - typedef typename Traits::int_type int_type; - CharT const czero = lcast_char_constants::zero; - int_type const zero = Traits::to_int_type(czero); - - do - { -#ifndef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE - if(left == 0) + do { - ++group; - if(group < grouping_size) + if(left == 0) { - char const grp_size = grouping[group]; - last_grp_size = grp_size <= 0 ? CHAR_MAX : grp_size; + ++group; + if(group < grouping_size) + { + char const grp_size = grouping[group]; + last_grp_size = grp_size <= 0 ? CHAR_MAX : grp_size; + } + + left = last_grp_size; + --finish; + Traits::assign(*finish, thousands_sep); } - left = last_grp_size; + --left; + --finish; - Traits::assign(*finish, thousands_sep); - } + int_type const digit = static_cast(n % 10U); + Traits::assign(*finish, Traits::to_char_type(zero + digit)); + n /= 10; + } while(n); - --left; + } else #endif - - --finish; - int_type const digit = static_cast(n % 10U); - Traits::assign(*finish, Traits::to_char_type(zero + digit)); - n /= 10; - } while(n); + { + do + { + --finish; + int_type const digit = static_cast(n % 10U); + Traits::assign(*finish, Traits::to_char_type(zero + digit)); + n /= 10; + } while(n); + } return finish; } @@ -638,10 +649,10 @@ namespace boost /* According to [22.2.2.1.2] of Programming languages - C++ * we MUST check for correct grouping */ - if (grouping_size) + if (grouping_size && grouping[0] > 0) { unsigned char current_grouping = 0; - CharT const thousands_sep = grouping_size ? np.thousands_sep() : 0; + CharT const thousands_sep = np.thousands_sep(); char remained = grouping[current_grouping] - 1; for(;end>=begin; --end) diff --git a/lexical_cast.htm b/lexical_cast.htm index 03625b4..2292d2a 100644 --- a/lexical_cast.htm +++ b/lexical_cast.htm @@ -26,6 +26,8 @@ References
    • Changes
    • +
    • + Performance

    Motivation

    @@ -87,7 +89,7 @@ For a good discussion of the options and issues involved in string-based formatting, including comparison of stringstream, lexical_cast, and others, see Herb Sutter's article, - The String Formatters of Manor Farm. + The String Formatters of Manor Farm. Also, take a look at the Performance section.


    Examples

    @@ -267,6 +269,7 @@ Eliminate an overhead of std::locale if your program runs in the "C

    Changes

    May 2011:

      +
    • Optimizations for "C" and other locales without number grouping.
    • Better performance and less memory usage for unsigned char and signed char conversions.
    • Better performance and less memory usage for conversions to arithmetic types.
    • Better performance and less memory usage for conversions from arithmetic type to arithmetic type.
    • @@ -313,7 +316,34 @@ Eliminate an overhead of std::locale if your program runs in the "C


    - + +

    Performance

    +This table shows the execution speed for 100000 iterations in milliseconds of the following code blocks: + + + + + + + + + + + + + + + + + + + + +
    From->To target = lexical_cast<Target>(source); std::stringstream ss;
    ss << source;
    ss >> target;
    ss << source;
    ss >> target;
    ss.str(std::string());
    ss.clear();
    sscanf( (const char*)source, <...>, &target);
    OR
    sprintf( (char*)buffer, <...>, source);
    + target = buffer;
    string->char<191710
    string->int71152318
    string->unsigned int71172217
    string->bool<11041910
    string->float851726033
    char->string71051612
    int->string151312117
    unsigned int->string141252117
    bool->string71222412
    float->string12422311548
    char*->string912320---
    int->int<112026---
    float->float<1262142---
    + +Fastest results are highlitened with green. +
    Copyright © Kevlin Henney, 2000-2005
    Copyright © Alexander Nasonov, 2006-2010
    Copyright © Antony Polukhin, 2011
    diff --git a/lexical_cast_test.cpp b/lexical_cast_test.cpp index 75d12ff..f88017f 100644 --- a/lexical_cast_test.cpp +++ b/lexical_cast_test.cpp @@ -937,7 +937,6 @@ void test_wallocator() #endif -#include void test_char_types_conversions() { const char c_arr[] = "Test array of chars"; From ccaa3059e88a1acc7bbac40343a491c0d69cef8d Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Fri, 27 May 2011 18:32:57 +0000 Subject: [PATCH 08/39] Improved english and documentation design for #5576. [SVN r72225] --- lexical_cast.htm | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/lexical_cast.htm b/lexical_cast.htm index 2292d2a..7929dd4 100644 --- a/lexical_cast.htm +++ b/lexical_cast.htm @@ -318,15 +318,11 @@ Eliminate an overhead of std::locale if your program runs in the "C

    Performance

    -This table shows the execution speed for 100000 iterations in milliseconds of the following code blocks: +This table shows the execution time in milliseconds for 100000 calls of the following string formatters: - - - - + From cd0167d6b8bc3cadab3b674e7f5304d8322c77d8 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Tue, 31 May 2011 20:46:37 +0000 Subject: [PATCH 09/39] Fixes #5585 and adds test on it [SVN r72315] --- include/boost/lexical_cast.hpp | 28 ++++++++++++++++++++++++---- lexical_cast_test.cpp | 3 +++ 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index c1b083b..ddd7398 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -654,6 +654,7 @@ namespace boost unsigned char current_grouping = 0; CharT const thousands_sep = np.thousands_sep(); char remained = grouping[current_grouping] - 1; + bool shall_we_return = true; for(;end>=begin; --end) { @@ -671,12 +672,31 @@ namespace boost multiplier *= 10; --remained; } else { - if ( !Traits::eq(*end, thousands_sep) || begin == end ) return false; - if (current_grouping < grouping_size-1 ) ++current_grouping; - remained = grouping[current_grouping]; + if ( !Traits::eq(*end, thousands_sep) ) //|| begin == end ) return false; + { + /* + * According to Programming languages - C++ + * Digit grouping is checked. That is, the positions of discarded + * separators is examined for consistency with + * use_facet >(loc ).grouping() + * + * BUT what if there is no separators at all and grouping() + * is not empty? Well, we have no extraced separators, so we + * won`t check them for consistency. This will allow us to + * work with "C" locale from other locales + */ + shall_we_return = false; + break; + } else { + if ( begin == end ) return false; + if (current_grouping < grouping_size-1 ) ++current_grouping; + remained = grouping[current_grouping]; + } } } - } else + + if (shall_we_return) return true; + } #endif { while ( begin <= end ) diff --git a/lexical_cast_test.cpp b/lexical_cast_test.cpp index f88017f..f20994e 100644 --- a/lexical_cast_test.cpp +++ b/lexical_cast_test.cpp @@ -677,6 +677,9 @@ void test_conversion_from_to_integral_for_locale() , bad_lexical_cast); BOOST_CHECK_THROW(lexical_cast( std::string("100") + np.thousands_sep() ), bad_lexical_cast); BOOST_CHECK_THROW(lexical_cast( np.thousands_sep() + std::string("100") ), bad_lexical_cast); + + // Exception must not be thrown, when we are using no separators at all + BOOST_CHECK( lexical_cast("10000") == static_cast(10000) ); } test_conversion_from_integral_to_integral(); From 6a8c22d5c31df22424cbcfcb7b56ea4cb3643ce8 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Wed, 6 Jul 2011 15:43:04 +0000 Subject: [PATCH 10/39] Partial fix for #5660. Better performance and less memory usage for conversions to float type (and to double type, if sizeof(double) < sizeof(long double)). New test suits. Documentation update. [SVN r72925] --- include/boost/lexical_cast.hpp | 318 ++++++++++++++- lexical_cast.htm | 4 + lexical_cast_test.cpp | 65 +-- test/Jamfile.v2 | 2 + test/lexical_cast_float_types_test.cpp | 527 +++++++++++++++++++++++++ test/lexical_cast_loopback_test.cpp | 6 - test/lexical_cast_wchars_test.cpp | 56 +++ 7 files changed, 918 insertions(+), 60 deletions(-) create mode 100755 test/lexical_cast_float_types_test.cpp create mode 100755 test/lexical_cast_wchars_test.cpp diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index ddd7398..d9b73af 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -1,6 +1,12 @@ #ifndef BOOST_LEXICAL_CAST_INCLUDED #define BOOST_LEXICAL_CAST_INCLUDED +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + // Boost lexical_cast.hpp header -------------------------------------------// // // See http://www.boost.org/libs/conversion for documentation. @@ -502,6 +508,9 @@ namespace boost BOOST_STATIC_CONSTANT(char, zero = '0'); BOOST_STATIC_CONSTANT(char, minus = '-'); BOOST_STATIC_CONSTANT(char, plus = '+'); + BOOST_STATIC_CONSTANT(char, lowercase_e = 'e'); + BOOST_STATIC_CONSTANT(char, capital_e = 'E'); + BOOST_STATIC_CONSTANT(char, c_decimal_separator = '.'); }; #ifndef BOOST_LCAST_NO_WCHAR_T @@ -511,6 +520,9 @@ namespace boost BOOST_STATIC_CONSTANT(wchar_t, zero = L'0'); BOOST_STATIC_CONSTANT(wchar_t, minus = L'-'); BOOST_STATIC_CONSTANT(wchar_t, plus = L'+'); + BOOST_STATIC_CONSTANT(wchar_t, lowercase_e = L'e'); + BOOST_STATIC_CONSTANT(wchar_t, capital_e = L'E'); + BOOST_STATIC_CONSTANT(wchar_t, c_decimal_separator = L'.'); }; #endif } @@ -646,7 +658,7 @@ namespace boost std::string const& grouping = np.grouping(); std::string::size_type const grouping_size = grouping.size(); - /* According to [22.2.2.1.2] of Programming languages - C++ + /* According to Programming languages - C++ * we MUST check for correct grouping */ if (grouping_size && grouping[0] > 0) @@ -719,6 +731,246 @@ namespace boost } } + namespace detail // lcast_ret_float + { + template + struct mantissa_holder_type + { + /* Can not be used with this type */ + }; + + template <> + struct mantissa_holder_type + { + typedef unsigned int type; + }; + + template <> + struct mantissa_holder_type + { +#if defined(BOOST_HAS_LONG_LONG) + typedef boost::ulong_long_type type; +#elif defined(BOOST_HAS_MS_INT64) + typedef unsigned __int64 type; +#endif + }; + + template + inline bool lcast_ret_float(T& value, const CharT* begin, const CharT* end) + { + +#ifndef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE + // TODO: use BOOST_NO_STD_LOCALE + std::locale loc; + typedef std::numpunct numpunct; + numpunct const& np = BOOST_USE_FACET(numpunct, loc); + std::string const& grouping = np.grouping(); + std::string::size_type const grouping_size = grouping.size(); + CharT const thousands_sep = grouping_size ? np.thousands_sep() : 0; + CharT const decimal_point = np.decimal_point(); + bool found_grouping = false; + unsigned int last_grouping_pos = grouping_size - 1; +#else + CharT const decimal_point = lcast_char_constants::c_decimal_separator; +#endif + + CharT const czero = lcast_char_constants::zero; + CharT const minus = lcast_char_constants::minus; + CharT const plus = lcast_char_constants::plus; + CharT const capital_e = lcast_char_constants::capital_e; + CharT const lowercase_e = lcast_char_constants::lowercase_e; + + value = 0.0; + + typedef typename Traits::int_type int_type; + typedef BOOST_DEDUCED_TYPENAME mantissa_holder_type::type mantissa_type; + int_type const zero = Traits::to_int_type(czero); + if (begin == end) return false; + + /* Getting the plus/minus sign */ + bool has_minus = false; + if ( *begin == minus ) { + ++ begin; + has_minus = true; + if (begin == end) return false; + } else if ( *begin == plus ) { + ++begin; + if (begin == end) return false; + } + + if ( *begin < czero || *begin >= czero + 10 ) { + return false; + } + + + bool found_decimal = false; + int pow_of_10 = 0; + mantissa_type mantissa=0; + bool is_mantissa_full = false; + + char length_since_last_delim = 0; + + while ( begin != end ) + { + if (found_decimal) { + /* We allow no thousand_separators after decimal point */ + + mantissa_type tmp_mantissa = mantissa * 10u; + if ( *begin == lowercase_e || *begin == capital_e ) break; + if ( *begin < czero || *begin >= czero + 10 ) return false; + if ( is_mantissa_full + || tmp_mantissa / 10u != mantissa + || (std::numeric_limits::max)()-(*begin - zero) < tmp_mantissa + ) { + is_mantissa_full = true; + ++ begin; + continue; + } + + -- pow_of_10; + mantissa = tmp_mantissa; + mantissa += *begin - zero; + } else { + + if (*begin >= czero && *begin < czero + 10) { + + /* Checking for mantissa overflow. If overflow will + * occur, them we only increase multiplyer + */ + mantissa_type tmp_mantissa = mantissa * 10u; + if( !is_mantissa_full + && tmp_mantissa / 10u == mantissa + && (std::numeric_limits::max)()-(*begin - zero) >= tmp_mantissa + ) + { + mantissa = tmp_mantissa; + mantissa += *begin - zero; + } else + { + is_mantissa_full = true; + ++ pow_of_10; + } + + ++ length_since_last_delim; + } else if ( *begin == decimal_point || *begin == lowercase_e || *begin == capital_e) { +#ifndef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE + /* If ( we need to check grouping + * and ( grouping missmatches + * or grouping position is incorrect + * or we are using the grouping position 0 twice + * ) + * ) then return error + */ + if( grouping_size && found_grouping + && ( + length_since_last_delim != grouping[0] + || last_grouping_pos>1 + || (last_grouping_pos==0 && grouping_size>1) + ) + ) return false; +#endif + + if(*begin == decimal_point){ + ++ begin; + found_decimal = true; + continue; + }else break; + } +#ifndef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE + else if (grouping_size && *begin == thousands_sep){ + if(found_grouping) + { + /* It is not he first time, when we find thousands separator, + * so we need to chek, is the distance between two groupings + * equal to grouping[last_grouping_pos] */ + + if (length_since_last_delim != grouping[last_grouping_pos] ) + { + if (!last_grouping_pos) return false; + else + { + -- last_grouping_pos; + if (length_since_last_delim != grouping[last_grouping_pos]) return false; + } + } else + /* We are calling the grouping[0] twice, when grouping size is more than 1 */ + if (grouping_size>1u && last_grouping_pos+1 grouping[last_grouping_pos] ) return false; + } + + length_since_last_delim = 0; + ++ begin; + + /* Delimiter at the end '100,' */ + if (begin == end) return false; + continue; + } +#endif + else return false; + } + + ++begin; + } + + // Exponent found + if ( begin != end && ( *begin == lowercase_e || *begin == capital_e ) ) { + ++ begin; + if ( begin == end ) return false; + + bool exp_has_minus = false; + if( *begin == minus ) { + exp_has_minus = true; + ++ begin; + if ( begin == end ) return false; + } else if (*begin == plus ) { + ++ begin; + if ( begin == end ) return false; + } + + int exp_pow_of_10 = 0; + while ( begin != end ) + { + if ( *begin < czero + || *begin >= czero + 10 + || exp_pow_of_10 * 10 < exp_pow_of_10) /* Overflows are checked lower more precisely*/ + return false; + + exp_pow_of_10 *= 10; + exp_pow_of_10 += *begin - zero; + ++ begin; + }; + + if ( exp_pow_of_10 ) { + /* Overflows are checked lower */ + if ( exp_has_minus ) { + pow_of_10 -= exp_pow_of_10; + } else { + pow_of_10 += exp_pow_of_10; + } + } + } + + /* We need a more accurate algorithm... We can not use current algorithm + * with long doubles (and with doubles if sizeof(double)==sizeof(long double)). + */ + long double result = std::pow(10.0L, pow_of_10) * mantissa; + value = ( has_minus ? -1 * result : result); + + if ( value > (std::numeric_limits::max)() // is it +inf + || value < -(std::numeric_limits::max)() // is it -inf + || value != value) // is it NaN + return false; + + return true; + } + } + namespace detail // stream wrapper for handling lexical conversions { template @@ -1079,12 +1331,54 @@ namespace boost } } + bool operator>>(float& output) + { + return lcast_ret_float(output,start,finish); + } + +#if defined(BOOST_HAS_LONG_LONG) || defined(BOOST_HAS_MS_INT64) + private: + // we need workaround + bool no_long_double_80bit_realization_workaround(double& output, int) { + return convert_using_base_class(output); + } + + // we do not need a workaround + bool no_long_double_80bit_realization_workaround(double& output,char) { + return lcast_ret_float(output,start,finish); + } + public: + + bool operator>>(double& output) + { + /* + * Some compilers implement long double as double. In that case these types have + * same size, same precision, same max and min values... And it means, + * that current implementation of lcast_ret_float cannot be used for type + * double, because it will give a big precision loss. + * */ + boost::mpl::if_c< + ::boost::type_traits::ice_eq< sizeof(double), sizeof(long double) >::value, + int, + char + >::type dummy = 0; + + return no_long_double_80bit_realization_workaround(output, dummy); + } +#endif // Generic istream-based algorithm. // lcast_streambuf_for_target::value is true. template bool operator>>(InputStreamable& output) { + return convert_using_base_class(output); + } + + private: + template + bool convert_using_base_class(InputStreamable& output) + { #if (defined _MSC_VER) # pragma warning( push ) // conditional expression is constant @@ -1112,6 +1406,7 @@ namespace boost Traits::eof(); #endif } + public: bool operator>>(CharT&); bool operator>>(unsigned char&); @@ -1433,11 +1728,30 @@ namespace boost template struct lcast_streambuf_for_target { +#if defined(BOOST_HAS_LONG_LONG) || defined(BOOST_HAS_MS_INT64) BOOST_STATIC_CONSTANT(bool, value = ( - ::boost::type_traits::ice_not< is_integral::value >::value + ::boost::type_traits::ice_or< + ::boost::type_traits::ice_not< is_arithmetic::value >::value, + is_same::value, + ::boost::type_traits::ice_and< + is_same::value, + ::boost::type_traits::ice_eq::value + >::value + >::value ) ); +#else + BOOST_STATIC_CONSTANT(bool, value = + ( + ::boost::type_traits::ice_or< + ::boost::type_traits::ice_not< is_arithmetic::value >::value, + is_same::value, + is_same::value + >::value + ) + ); +#endif }; #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION diff --git a/lexical_cast.htm b/lexical_cast.htm index 7929dd4..7a1fee5 100644 --- a/lexical_cast.htm +++ b/lexical_cast.htm @@ -267,6 +267,10 @@ Eliminate an overhead of std::locale if your program runs in the "C August 2006.

    Changes

    +

    July 2011:

    +
      +
    • Better performance and less memory usage for conversions to float type (and to double type, if sizeof(double)<sizeof(long double)).
    • +

    May 2011:

    • Optimizations for "C" and other locales without number grouping.
    • diff --git a/lexical_cast_test.cpp b/lexical_cast_test.cpp index f20994e..cdf42fe 100644 --- a/lexical_cast_test.cpp +++ b/lexical_cast_test.cpp @@ -86,9 +86,6 @@ void test_conversion_from_to_uintmax_t(); void test_conversion_from_to_longlong(); void test_conversion_from_to_ulonglong(); #endif -void test_conversion_from_to_float(); -void test_conversion_from_to_double(); -void test_conversion_from_to_long_double(); #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION void test_traits(); void test_wtraits(); @@ -128,9 +125,6 @@ unit_test::test_suite *init_unit_test_suite(int, char *[]) suite->add(BOOST_TEST_CASE(&test_conversion_from_to_longlong)); suite->add(BOOST_TEST_CASE(&test_conversion_from_to_ulonglong)); #endif - suite->add(BOOST_TEST_CASE(&test_conversion_from_to_float)); - suite->add(BOOST_TEST_CASE(&test_conversion_from_to_double)); - suite->add(BOOST_TEST_CASE(&test_conversion_from_to_long_double)); #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION suite->add(BOOST_TEST_CASE(&test_traits)); suite->add(BOOST_TEST_CASE(&test_wtraits)); @@ -679,7 +673,7 @@ void test_conversion_from_to_integral_for_locale() BOOST_CHECK_THROW(lexical_cast( np.thousands_sep() + std::string("100") ), bad_lexical_cast); // Exception must not be thrown, when we are using no separators at all - BOOST_CHECK( lexical_cast("10000") == static_cast(10000) ); + BOOST_CHECK( lexical_cast("30000") == static_cast(30000) ); } test_conversion_from_integral_to_integral(); @@ -775,35 +769,6 @@ void test_conversion_from_to_integral() BOOST_TEST_MESSAGE("Formatting with thousands_sep has not been tested"); } -template -void test_conversion_from_to_float() -{ - char const zero = '0'; - signed char const szero = '0'; - unsigned char const uzero = '0'; - test_conversion_from_integral_to_char(zero); - test_conversion_from_char_to_integral(zero); - test_conversion_from_integral_to_char(szero); - test_conversion_from_char_to_integral(szero); - test_conversion_from_integral_to_char(uzero); - test_conversion_from_char_to_integral(uzero); -#if !defined(BOOST_LCAST_NO_WCHAR_T) && !defined(BOOST_NO_INTRINSIC_WCHAR_T) - wchar_t const wzero = L'0'; - test_conversion_from_integral_to_char(wzero); - test_conversion_from_char_to_integral(wzero); -#endif - - test_conversion_from_integral_to_integral(); - - BOOST_CHECK_CLOSE(lexical_cast("+1"), 1, std::numeric_limits::epsilon() ); - BOOST_CHECK_CLOSE(lexical_cast("+9"), 9, std::numeric_limits::epsilon()*9 ); - - BOOST_CHECK_THROW(lexical_cast("++1"), bad_lexical_cast); - BOOST_CHECK_THROW(lexical_cast("-+9"), bad_lexical_cast); - BOOST_CHECK_THROW(lexical_cast("--1"), bad_lexical_cast); - BOOST_CHECK_THROW(lexical_cast("+-9"), bad_lexical_cast); -} - void test_conversion_from_to_short() { test_conversion_from_to_integral(); @@ -844,19 +809,6 @@ void test_conversion_from_to_uintmax_t() test_conversion_from_to_integral(); } -void test_conversion_from_to_float() -{ - test_conversion_from_to_float(); -} -void test_conversion_from_to_double() -{ - test_conversion_from_to_float(); -} -void test_conversion_from_to_long_double() -{ - test_conversion_from_to_float(); -} - #if defined(BOOST_HAS_LONG_LONG) void test_conversion_from_to_longlong() @@ -966,16 +918,25 @@ void test_char_types_conversions() const wchar_t wc_arr[]=L"Test array of chars"; BOOST_CHECK(boost::lexical_cast(wc_arr) == std::wstring(wc_arr)); + BOOST_CHECK(boost::lexical_cast(wc_arr[0]) == wc_arr[0]); + + // Following tests depend on realization of std::locale. + // All we need to know, is that this functions must compile + 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(sc_arr) != std::wstring(wc_arr) ); BOOST_CHECK(boost::lexical_cast(uc_arr) != std::wstring(wc_arr) ); - BOOST_CHECK(boost::lexical_cast(c_arr[0]) == wc_arr[0]); - BOOST_CHECK(boost::lexical_cast(wc_arr[0]) == wc_arr[0]); - BOOST_CHECK_THROW(boost::lexical_cast(uc_arr[0]), bad_lexical_cast); BOOST_CHECK_THROW(boost::lexical_cast(sc_arr[0]), bad_lexical_cast); #endif } + + + + + + + diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 1fea2fb..9517c63 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -25,6 +25,8 @@ test-suite conversion [ run lexical_cast_abstract_test.cpp ../../test/build//boost_unit_test_framework/static ] [ run lexical_cast_noncopyable_test.cpp ../../test/build//boost_unit_test_framework/static ] [ run lexical_cast_vc8_bug_test.cpp ../../test/build//boost_unit_test_framework/static ] + [ run lexical_cast_wchars_test.cpp ../../test/build//boost_unit_test_framework/static ] + [ run lexical_cast_float_types_test.cpp ../../test/build//boost_unit_test_framework/static ] ; diff --git a/test/lexical_cast_float_types_test.cpp b/test/lexical_cast_float_types_test.cpp new file mode 100755 index 0000000..442ed3b --- /dev/null +++ b/test/lexical_cast_float_types_test.cpp @@ -0,0 +1,527 @@ +// Unit test for boost::lexical_cast. +// +// See http://www.boost.org for most recent version, including documentation. +// +// Copyright Antony Polukhin, 2011. +// +// 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 + +#if defined(__INTEL_COMPILER) +#pragma warning(disable: 193 383 488 981 1418 1419) +#elif defined(BOOST_MSVC) +#pragma warning(disable: 4097 4100 4121 4127 4146 4244 4245 4511 4512 4701 4800) +#endif + +#include + +#include +#include +#include + +void test_conversion_from_to_float(); +void test_conversion_from_to_double(); +void test_conversion_from_to_long_double(); + +using namespace boost; + + +unit_test::test_suite *init_unit_test_suite(int, char *[]) +{ + unit_test_framework::test_suite *suite = + BOOST_TEST_SUITE("lexical_cast float types unit test"); + suite->add(BOOST_TEST_CASE(&test_conversion_from_to_float)); + suite->add(BOOST_TEST_CASE(&test_conversion_from_to_double)); + suite->add(BOOST_TEST_CASE(&test_conversion_from_to_long_double)); + + return suite; +} + + +// Replace "-,999" with "-999". +template +std::basic_string to_str_gcc_workaround(std::basic_string str) +{ + std::locale loc; + std::numpunct const& np = BOOST_USE_FACET(std::numpunct, loc); + std::ctype const& ct = BOOST_USE_FACET(std::ctype, loc); + + if(np.grouping().empty()) + return str; + + CharT prefix[3] = { ct.widen('-'), np.thousands_sep(), CharT() }; + + if(str.find(prefix) != 0) + return str; + + prefix[1] = CharT(); + str.replace(0, 2, prefix); + return str; +} + +template +std::basic_string to_str(T t) +{ + std::basic_ostringstream o; + o << t; + return to_str_gcc_workaround(o.str()); +} + + +template +void test_conversion_from_to_float_for_locale() +{ + std::locale current_locale; + typedef std::numpunct numpunct; + numpunct const& np = BOOST_USE_FACET(numpunct, current_locale); + if ( !np.grouping().empty() ) + { + BOOST_CHECK_THROW( + lexical_cast( std::string("100") + np.thousands_sep() + np.thousands_sep() + "0" ) + , bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast( std::string("100") + np.thousands_sep() ), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast( np.thousands_sep() + std::string("100") ), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast( std::string("1") + np.thousands_sep() + np.decimal_point() + "e10" ), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast( std::string("1e10") + np.thousands_sep() ), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast( std::string("1") + np.thousands_sep() + "e10" ), bad_lexical_cast); + + BOOST_CHECK_CLOSE(lexical_cast( to_str< char >(100000) ), 100000, (std::numeric_limits::epsilon()*100) ); + BOOST_CHECK_CLOSE(lexical_cast( to_str< char >(10000000u) ), 10000000u, (std::numeric_limits::epsilon()*100) ); + BOOST_CHECK_CLOSE(lexical_cast( to_str< char >(100) ), 100, (std::numeric_limits::epsilon()*100) ); +#if !defined(BOOST_LCAST_NO_WCHAR_T) && !defined(BOOST_NO_INTRINSIC_WCHAR_T) + BOOST_CHECK_CLOSE(lexical_cast( to_str< wchar_t >(100000) ), 100000, (std::numeric_limits::epsilon()*100) ); + BOOST_CHECK_CLOSE(lexical_cast( to_str< wchar_t >(10000000u) ), 10000000u, (std::numeric_limits::epsilon()*100) ); + BOOST_CHECK_CLOSE(lexical_cast( to_str< wchar_t >(100) ), 100, (std::numeric_limits::epsilon()*100) ); +#endif + // Exception must not be thrown, when we are using no separators at all + BOOST_CHECK_CLOSE( lexical_cast("30000"), static_cast(30000), (std::numeric_limits::epsilon()*100) ); + } +} + + + + +/* + * Converts char* [and wchar_t] to float number type and checks, that generated + * number is in interval [base_value-epsilon, base_value+epsilon]. + */ +#ifndef BOOST_LCAST_NO_WCHAR_T +#define CHECK_CLOSE_ABS_DIFF(VAL,PREFIX) \ + converted_val = lexical_cast(#VAL); \ + BOOST_CHECK_CLOSE( (VAL ## L? VAL ## L : std::numeric_limits::epsilon()), \ + (converted_val ? converted_val : std::numeric_limits::epsilon()), \ + std::numeric_limits::epsilon() * 100 \ + ); \ + BOOST_CHECK_EQUAL(converted_val, lexical_cast(L## #VAL) ); + +#else +#define CHECK_CLOSE_ABS_DIFF(VAL,TYPE) \ + converted_val = lexical_cast(#VAL); \ + BOOST_CHECK_CLOSE( (VAL ## L? VAL ## L : std::numeric_limits::epsilon()), \ + (converted_val ? converted_val : std::numeric_limits::epsilon()), \ + std::numeric_limits::epsilon() * 100 \ + ); +#endif + +template +void test_converion_to_float_types() +{ + typedef TestType test_t; + test_t converted_val; + + BOOST_CHECK_CLOSE(1.0, lexical_cast('1'), (std::numeric_limits::epsilon())); + BOOST_CHECK_EQUAL(0.0, lexical_cast('0')); + + unsigned char const uc_one = '1'; + unsigned char const uc_zero ='0'; + BOOST_CHECK_CLOSE(1.0, lexical_cast(uc_one), (std::numeric_limits::epsilon())); + BOOST_CHECK_EQUAL(0.0, lexical_cast(uc_zero)); + + signed char const sc_one = '1'; + signed char const sc_zero ='0'; + BOOST_CHECK_CLOSE(1.0, lexical_cast(sc_one), (std::numeric_limits::epsilon())); + BOOST_CHECK_EQUAL(0.0, lexical_cast(sc_zero)); + + BOOST_CHECK_CLOSE(1e34L, lexical_cast( "10000000000000000000000000000000000"), (std::numeric_limits::epsilon()*100) ); + +// VC failes the next test +// BOOST_CHECK_CLOSE(1e-35L, lexical_cast("0.00000000000000000000000000000000001"), (std::numeric_limits::epsilon()*100) ); + BOOST_CHECK_CLOSE( + 0.1111111111111111111111111111111111111111111111111111111111111111111111111L + , lexical_cast("0.1111111111111111111111111111111111111111111111111111111111111111111111111") + , (std::numeric_limits::epsilon()*100) ); + + CHECK_CLOSE_ABS_DIFF(1,test_t); + BOOST_CHECK_EQUAL(0,lexical_cast("0")); + CHECK_CLOSE_ABS_DIFF(-1,test_t); + + CHECK_CLOSE_ABS_DIFF(1.0, test_t); + CHECK_CLOSE_ABS_DIFF(0.0, test_t); + CHECK_CLOSE_ABS_DIFF(-1.0,test_t); + + CHECK_CLOSE_ABS_DIFF(1e1, test_t); + CHECK_CLOSE_ABS_DIFF(0e1, test_t); + CHECK_CLOSE_ABS_DIFF(-1e1,test_t); + + CHECK_CLOSE_ABS_DIFF(1.0e1, test_t); + CHECK_CLOSE_ABS_DIFF(0.0e1, test_t); + CHECK_CLOSE_ABS_DIFF(-1.0e1,test_t); + + CHECK_CLOSE_ABS_DIFF(1e-1, test_t); + CHECK_CLOSE_ABS_DIFF(0e-1, test_t); + CHECK_CLOSE_ABS_DIFF(-1e-1,test_t); + + CHECK_CLOSE_ABS_DIFF(1.0e-1, test_t); + CHECK_CLOSE_ABS_DIFF(0.0e-1, test_t); + CHECK_CLOSE_ABS_DIFF(-1.0e-1,test_t); + + CHECK_CLOSE_ABS_DIFF(1E1, test_t); + CHECK_CLOSE_ABS_DIFF(0E1, test_t); + CHECK_CLOSE_ABS_DIFF(-1E1,test_t); + + CHECK_CLOSE_ABS_DIFF(1.0E1, test_t); + CHECK_CLOSE_ABS_DIFF(0.0E1, test_t); + CHECK_CLOSE_ABS_DIFF(-1.0E1,test_t); + + CHECK_CLOSE_ABS_DIFF(1E-1, test_t); + CHECK_CLOSE_ABS_DIFF(0E-1, test_t); + CHECK_CLOSE_ABS_DIFF(-1E-1,test_t); + + CHECK_CLOSE_ABS_DIFF(1.0E-1, test_t); + CHECK_CLOSE_ABS_DIFF(0.0E-1, test_t); + CHECK_CLOSE_ABS_DIFF(-1.0E-1, test_t); + + + + CHECK_CLOSE_ABS_DIFF(10.0, test_t); + CHECK_CLOSE_ABS_DIFF(00.0, test_t); + CHECK_CLOSE_ABS_DIFF(-10.0,test_t); + + CHECK_CLOSE_ABS_DIFF(10e1, test_t); + CHECK_CLOSE_ABS_DIFF(00e1, test_t); + CHECK_CLOSE_ABS_DIFF(-10e1,test_t); + + CHECK_CLOSE_ABS_DIFF(10.0e1, test_t); + CHECK_CLOSE_ABS_DIFF(00.0e1, test_t); + CHECK_CLOSE_ABS_DIFF(-10.0e1,test_t); + + CHECK_CLOSE_ABS_DIFF(10e-1, test_t); + CHECK_CLOSE_ABS_DIFF(00e-1, test_t); + CHECK_CLOSE_ABS_DIFF(-10e-1,test_t); + + CHECK_CLOSE_ABS_DIFF(10.0e-1, test_t); + CHECK_CLOSE_ABS_DIFF(00.0e-1, test_t); + CHECK_CLOSE_ABS_DIFF(-10.0e-1,test_t); + + CHECK_CLOSE_ABS_DIFF(10E1, test_t); + CHECK_CLOSE_ABS_DIFF(00E1, test_t); + CHECK_CLOSE_ABS_DIFF(-10E1,test_t); + + CHECK_CLOSE_ABS_DIFF(10.0E1, test_t); + CHECK_CLOSE_ABS_DIFF(00.0E1, test_t); + CHECK_CLOSE_ABS_DIFF(-10.0E1,test_t); + + CHECK_CLOSE_ABS_DIFF(10E-1, test_t); + CHECK_CLOSE_ABS_DIFF(00E-1, test_t); + CHECK_CLOSE_ABS_DIFF(-10E-1,test_t); + + CHECK_CLOSE_ABS_DIFF(10.0E-1, test_t); + CHECK_CLOSE_ABS_DIFF(00.0E-1, test_t); + CHECK_CLOSE_ABS_DIFF(-10.0E-1, test_t); + + CHECK_CLOSE_ABS_DIFF(-10101.0E-011, test_t); + CHECK_CLOSE_ABS_DIFF(-10101093, test_t); + CHECK_CLOSE_ABS_DIFF(10101093, test_t); + +// BOOST_CHECK(lexical_cast("-inf") == -std::numeric_limits::infinity() ); +// BOOST_CHECK(lexical_cast("-INF") == -std::numeric_limits::infinity() ); +// BOOST_CHECK(lexical_cast("+inf") == std::numeric_limits::infinity() ); +// BOOST_CHECK(lexical_cast("infinity") == std::numeric_limits::infinity() ); +// +// BOOST_CHECK(lexical_cast("nan") == std::numeric_limits::quiet_NaN() ); +// BOOST_CHECK(lexical_cast("NaN") == std::numeric_limits::quiet_NaN() ); + + BOOST_CHECK_THROW(lexical_cast("-inf"), bad_lexical_cast ); + BOOST_CHECK_THROW(lexical_cast("-INF"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("+inf"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("infinity"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("nan"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("NaN"), bad_lexical_cast); + + + BOOST_CHECK_THROW(lexical_cast("-1.e"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("-1.E"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("1.e"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("1.E"), bad_lexical_cast); + + BOOST_CHECK_THROW(lexical_cast("1.0e"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("1.0E"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("10E"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("10e"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("1.0e-"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("1.0E-"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("10E-"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("10e-"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("e1"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("e-1"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("e-"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(".e"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(".11111111111111111111111111111111111111111111111111111111111111111111ee"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(".11111111111111111111111111111111111111111111111111111111111111111111e-"), bad_lexical_cast); + + BOOST_CHECK_THROW(lexical_cast("-B"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("0xB"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("0x0"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("--1.0"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("1.0e--1"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("1.0.0"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("1e1e1"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("1.0e-1e-1"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(" 1.0"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("1.0 "), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(""), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("-"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast('\0'), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast('-'), bad_lexical_cast); +} + +template +void test_float_typess_for_overflows() +{ + typedef T test_t; + test_t minvalue = (std::numeric_limits::min)(); + std::string s_min_value = lexical_cast(minvalue); + BOOST_CHECK_CLOSE(minvalue, lexical_cast(minvalue), (std::numeric_limits::epsilon()*100)); + BOOST_CHECK_CLOSE(minvalue, lexical_cast(s_min_value), (std::numeric_limits::epsilon()*100)); + + test_t maxvalue = (std::numeric_limits::max)(); + std::string s_max_value = lexical_cast(maxvalue); + BOOST_CHECK_CLOSE(maxvalue, lexical_cast(maxvalue), (std::numeric_limits::epsilon()*100)); + BOOST_CHECK_CLOSE(maxvalue, lexical_cast(s_max_value), (std::numeric_limits::epsilon()*100)); + + BOOST_CHECK_THROW(lexical_cast(s_max_value+"1"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(s_max_value+"9"), bad_lexical_cast); + + // VC9 can fail the fllowing tests on floats and doubles when using stingstream... + BOOST_CHECK_THROW(lexical_cast("1"+s_max_value), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("9"+s_max_value), bad_lexical_cast); + + if ( is_same::value ) + { + BOOST_CHECK_THROW(lexical_cast( (std::numeric_limits::max)() ), bad_lexical_cast); + BOOST_CHECK( + (std::numeric_limits::min)() - std::numeric_limits::epsilon() + <= lexical_cast( (std::numeric_limits::min)() ) + && lexical_cast( (std::numeric_limits::min)() ) + <= (std::numeric_limits::min)() + std::numeric_limits::epsilon() + ); + } + + if ( sizeof(test_t) < sizeof(long double) ) + { + BOOST_CHECK_THROW(lexical_cast( (std::numeric_limits::max)() ), bad_lexical_cast); + BOOST_CHECK( + (std::numeric_limits::min)() - std::numeric_limits::epsilon() + <= lexical_cast( (std::numeric_limits::min)() ) + && lexical_cast( (std::numeric_limits::min)() ) + <= (std::numeric_limits::min)() + std::numeric_limits::epsilon() + ); + } +} + +#undef CHECK_CLOSE_ABS_DIFF + +#define TEST_TO_FROM_CAST_AROUND_TYPED(VAL,STRING_TYPE) \ + test_value = VAL + std::numeric_limits::epsilon() * i ; \ + converted_val = lexical_cast( lexical_cast(test_value) ); \ + BOOST_CHECK_CLOSE( \ + test_value, \ + converted_val, \ + std::numeric_limits::epsilon()*100 \ + ); + +/* + * For interval [ from_mult*epsilon+VAL, to_mult*epsilon+VAL ], converts float type + * numbers to string[wstring] and then back to float type, then compares initial + * values and generated. + * Step is epsilon + */ +#ifndef BOOST_LCAST_NO_WCHAR_T +# define TEST_TO_FROM_CAST_AROUND(VAL) \ + for(i=from_mult; i<=to_mult; ++i) { \ + TEST_TO_FROM_CAST_AROUND_TYPED(VAL, std::string) \ + TEST_TO_FROM_CAST_AROUND_TYPED(VAL, std::wstring) \ + } +#else +# define TEST_TO_FROM_CAST_AROUND(VAL) \ + for(i=from_mult; i<=to_mult; ++i) { \ + TEST_TO_FROM_CAST_AROUND_TYPED(VAL, std::string) \ + } +#endif + +template +void test_converion_from_to_float_types() +{ + typedef TestType test_t; + test_t test_value; + test_t converted_val; + + int i; + int from_mult = -50; + int to_mult = 50; + + TEST_TO_FROM_CAST_AROUND( 0.0 ); + +// TEST_TO_FROM_CAST_AROUND( std::numeric_limits::infinity() ); +// TEST_TO_FROM_CAST_AROUND( -std::numeric_limits::infinity() ); +// TEST_TO_FROM_CAST_AROUND( std::numeric_limits::quiet_NaN() ); + + long double val1; + for(val1 = 1.0e-10L; val1 < 1e11; val1*=10 ) + TEST_TO_FROM_CAST_AROUND( val1 ); + + long double val2; + for(val2 = -1.0e-10L; val2 > -1e11; val2*=10 ) + TEST_TO_FROM_CAST_AROUND( val2 ); + + from_mult = -100; + to_mult = 0; + TEST_TO_FROM_CAST_AROUND( (std::numeric_limits::max)() ); + + from_mult = 0; + to_mult = 100; + TEST_TO_FROM_CAST_AROUND( (std::numeric_limits::min)() ); +} + +#undef TEST_TO_FROM_CAST_AROUND +#undef TEST_TO_FROM_CAST_AROUND_TYPED + + +template +void test_conversion_from_float_to_char(CharT zero) +{ + BOOST_CHECK(lexical_cast(static_cast(0)) == zero + 0); + BOOST_CHECK(lexical_cast(static_cast(1)) == zero + 1); + BOOST_CHECK(lexical_cast(static_cast(2)) == zero + 2); + BOOST_CHECK(lexical_cast(static_cast(3)) == zero + 3); + BOOST_CHECK(lexical_cast(static_cast(4)) == zero + 4); + BOOST_CHECK(lexical_cast(static_cast(5)) == zero + 5); + BOOST_CHECK(lexical_cast(static_cast(6)) == zero + 6); + BOOST_CHECK(lexical_cast(static_cast(7)) == zero + 7); + BOOST_CHECK(lexical_cast(static_cast(8)) == zero + 8); + BOOST_CHECK(lexical_cast(static_cast(9)) == zero + 9); + + BOOST_CHECK_THROW(lexical_cast(static_cast(10)), bad_lexical_cast); + + T t = (std::numeric_limits::max)(); + BOOST_CHECK_THROW(lexical_cast(t), bad_lexical_cast); +} + +template +void test_conversion_from_char_to_float(CharT zero) +{ + BOOST_CHECK_CLOSE(lexical_cast( static_cast(zero + 0)), static_cast(0), (std::numeric_limits::epsilon()*100) ); + BOOST_CHECK_CLOSE(lexical_cast( static_cast(zero + 1)), static_cast(1), (std::numeric_limits::epsilon()*100) ); + BOOST_CHECK_CLOSE(lexical_cast( static_cast(zero + 2)), static_cast(2), (std::numeric_limits::epsilon()*100) ); + BOOST_CHECK_CLOSE(lexical_cast( static_cast(zero + 3)), static_cast(3), (std::numeric_limits::epsilon()*100) ); + BOOST_CHECK_CLOSE(lexical_cast( static_cast(zero + 4)), static_cast(4), (std::numeric_limits::epsilon()*100) ); + BOOST_CHECK_CLOSE(lexical_cast( static_cast(zero + 5)), static_cast(5), (std::numeric_limits::epsilon()*100) ); + BOOST_CHECK_CLOSE(lexical_cast( static_cast(zero + 6)), static_cast(6), (std::numeric_limits::epsilon()*100) ); + BOOST_CHECK_CLOSE(lexical_cast( static_cast(zero + 7)), static_cast(7), (std::numeric_limits::epsilon()*100) ); + BOOST_CHECK_CLOSE(lexical_cast( static_cast(zero + 8)), static_cast(8), (std::numeric_limits::epsilon()*100) ); + BOOST_CHECK_CLOSE(lexical_cast( static_cast(zero + 9)), static_cast(9), (std::numeric_limits::epsilon()*100) ); + + BOOST_CHECK_THROW(lexical_cast( static_cast(zero + 10)), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast( static_cast(zero - 1)), bad_lexical_cast); +} + +struct restore_oldloc +{ + std::locale oldloc; + ~restore_oldloc() { std::locale::global(oldloc); } +}; + +template +void test_conversion_from_to_float() +{ char const zero = '0'; + signed char const szero = '0'; + unsigned char const uzero = '0'; + test_conversion_from_float_to_char(zero); + test_conversion_from_char_to_float(zero); + test_conversion_from_float_to_char(szero); + test_conversion_from_char_to_float(szero); + test_conversion_from_float_to_char(uzero); + test_conversion_from_char_to_float(uzero); + #if !defined(BOOST_LCAST_NO_WCHAR_T) && !defined(BOOST_NO_INTRINSIC_WCHAR_T) + wchar_t const wzero = L'0'; + test_conversion_from_float_to_char(wzero); + test_conversion_from_char_to_float(wzero); + #endif + + BOOST_CHECK_CLOSE(lexical_cast("+1"), 1, std::numeric_limits::epsilon() ); + BOOST_CHECK_CLOSE(lexical_cast("+9"), 9, std::numeric_limits::epsilon()*9 ); + + BOOST_CHECK_THROW(lexical_cast("++1"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("-+9"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("--1"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("+-9"), bad_lexical_cast); + + test_converion_to_float_types(); + test_float_typess_for_overflows(); + test_converion_from_to_float_types(); + + + typedef std::numpunct numpunct; + + restore_oldloc guard; + std::locale const& oldloc = guard.oldloc; + + std::string grouping1 = BOOST_USE_FACET(numpunct, oldloc).grouping(); + std::string grouping2(grouping1); + + test_conversion_from_to_float_for_locale(); + + try + { + std::locale newloc(""); + std::locale::global(newloc); + + grouping2 = BOOST_USE_FACET(numpunct, newloc).grouping(); + } + catch(std::exception const& ex) + { + std::string msg("Failed to set system locale: "); + msg += ex.what(); + BOOST_TEST_MESSAGE(msg); + } + + if(grouping1 != grouping2) + test_conversion_from_to_float_for_locale(); + + if(grouping1.empty() && grouping2.empty()) + BOOST_TEST_MESSAGE("Formatting with thousands_sep has not been tested"); +} + + +void test_conversion_from_to_float() +{ + test_conversion_from_to_float(); +} +void test_conversion_from_to_double() +{ + test_conversion_from_to_float(); +} +void test_conversion_from_to_long_double() +{ + test_conversion_from_to_float(); +} + + + + + + + diff --git a/test/lexical_cast_loopback_test.cpp b/test/lexical_cast_loopback_test.cpp index cd058fe..5787996 100644 --- a/test/lexical_cast_loopback_test.cpp +++ b/test/lexical_cast_loopback_test.cpp @@ -64,7 +64,6 @@ void test_round_conversion() } -#if defined(BOOST_MSVC) // See bug http://tinyurl.com/vhpvo template void test_msvc_magic_values() @@ -73,7 +72,6 @@ void test_msvc_magic_values() std::string magic_msvc_s = boost::lexical_cast(magic_msvc); BOOST_CHECK(magic_msvc == lexical_cast(magic_msvc_s)); } -#endif void test_round_conversion_float() { @@ -83,16 +81,12 @@ void test_round_conversion_float() void test_round_conversion_double() { test_round_conversion(); -#if defined(BOOST_MSVC) test_msvc_magic_values(); -#endif } void test_round_conversion_long_double() { test_round_conversion(); -#if defined(BOOST_MSVC) test_msvc_magic_values(); -#endif } diff --git a/test/lexical_cast_wchars_test.cpp b/test/lexical_cast_wchars_test.cpp new file mode 100755 index 0000000..547f226 --- /dev/null +++ b/test/lexical_cast_wchars_test.cpp @@ -0,0 +1,56 @@ +// Unit test for boost::lexical_cast. +// +// See http://www.boost.org for most recent version, including documentation. +// +// Copyright Antony Polukhin, 2011. +// +// 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 + +#if defined(__INTEL_COMPILER) +#pragma warning(disable: 193 383 488 981 1418 1419) +#elif defined(BOOST_MSVC) +#pragma warning(disable: 4097 4100 4121 4127 4146 4244 4245 4511 4512 4701 4800) +#endif + +#include + +#include +#include +#include + +using namespace boost; + +void test_char_types_conversions() +{ +#ifndef BOOST_LCAST_NO_WCHAR_T + 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(sc_arr) != std::wstring(wc_arr) ); + BOOST_CHECK(boost::lexical_cast(uc_arr) != std::wstring(wc_arr) ); + + BOOST_CHECK_THROW(boost::lexical_cast(uc_arr[0]), boost::bad_lexical_cast); + BOOST_CHECK_THROW(boost::lexical_cast(sc_arr[0]), boost::bad_lexical_cast); +#endif + BOOST_CHECK(1); +} + +unit_test::test_suite *init_unit_test_suite(int, char *[]) +{ + unit_test_framework::test_suite *suite = + BOOST_TEST_SUITE("lexical_cast char<->wchar_t unit test"); + suite->add(BOOST_TEST_CASE(&test_char_types_conversions)); + + return suite; +} From 0e2235dc75a588e60e22859e683ab177d480e2eb Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Thu, 7 Jul 2011 11:31:25 +0000 Subject: [PATCH 11/39] Fixes #5675. Adds tests on #5675. Updates #5660. Updates performance section of documentation [SVN r72954] --- include/boost/lexical_cast.hpp | 14 ++++++++------ lexical_cast.htm | 2 +- test/lexical_cast_float_types_test.cpp | 8 +++++++- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index d9b73af..044354f 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -798,12 +798,8 @@ namespace boost if (begin == end) return false; } - if ( *begin < czero || *begin >= czero + 10 ) { - return false; - } - - bool found_decimal = false; + bool found_number_before_exp = false; int pow_of_10 = 0; mantissa_type mantissa=0; bool is_mantissa_full = false; @@ -830,6 +826,8 @@ namespace boost -- pow_of_10; mantissa = tmp_mantissa; mantissa += *begin - zero; + + found_number_before_exp = true; } else { if (*begin >= czero && *begin < czero + 10) { @@ -851,6 +849,7 @@ namespace boost ++ pow_of_10; } + found_number_before_exp = true; ++ length_since_last_delim; } else if ( *begin == decimal_point || *begin == lowercase_e || *begin == capital_e) { #ifndef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE @@ -874,7 +873,10 @@ namespace boost ++ begin; found_decimal = true; continue; - }else break; + }else { + if (!found_number_before_exp) return false; + break; + } } #ifndef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE else if (grouping_size && *begin == thousands_sep){ diff --git a/lexical_cast.htm b/lexical_cast.htm index 7a1fee5..2079a0f 100644 --- a/lexical_cast.htm +++ b/lexical_cast.htm @@ -331,7 +331,7 @@ This table shows the execution time in milliseconds for 100000 calls of the foll
    - + diff --git a/test/lexical_cast_float_types_test.cpp b/test/lexical_cast_float_types_test.cpp index 442ed3b..66f6d67 100755 --- a/test/lexical_cast_float_types_test.cpp +++ b/test/lexical_cast_float_types_test.cpp @@ -194,7 +194,9 @@ void test_converion_to_float_types() CHECK_CLOSE_ABS_DIFF(0.0E-1, test_t); CHECK_CLOSE_ABS_DIFF(-1.0E-1, test_t); - + CHECK_CLOSE_ABS_DIFF(.0E-1, test_t); + CHECK_CLOSE_ABS_DIFF(.0E-1, test_t); + CHECK_CLOSE_ABS_DIFF(-.0E-1, test_t); CHECK_CLOSE_ABS_DIFF(10.0, test_t); CHECK_CLOSE_ABS_DIFF(00.0, test_t); @@ -235,6 +237,10 @@ void test_converion_to_float_types() CHECK_CLOSE_ABS_DIFF(-10101.0E-011, test_t); CHECK_CLOSE_ABS_DIFF(-10101093, test_t); CHECK_CLOSE_ABS_DIFF(10101093, test_t); + + CHECK_CLOSE_ABS_DIFF(-.34, test_t); + CHECK_CLOSE_ABS_DIFF(.34, test_t); + CHECK_CLOSE_ABS_DIFF(.34e10, test_t); // BOOST_CHECK(lexical_cast("-inf") == -std::numeric_limits::infinity() ); // BOOST_CHECK(lexical_cast("-INF") == -std::numeric_limits::infinity() ); From fff0066392bfbb4cebb6f1366ea301e7bc74ae15 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Thu, 7 Jul 2011 16:04:32 +0000 Subject: [PATCH 12/39] Fixes #5676. Tests for float types are now more accurate [SVN r72955] --- lexical_cast_test.cpp | 17 +++--- test/lexical_cast_float_types_test.cpp | 72 +++++++++++++------------- 2 files changed, 45 insertions(+), 44 deletions(-) diff --git a/lexical_cast_test.cpp b/lexical_cast_test.cpp index cdf42fe..62449ea 100644 --- a/lexical_cast_test.cpp +++ b/lexical_cast_test.cpp @@ -197,17 +197,18 @@ void test_conversion_to_int() void test_conversion_to_double() { - BOOST_CHECK_CLOSE(1.0, lexical_cast('1'), (std::numeric_limits::epsilon())); + BOOST_CHECK_CLOSE_FRACTION(1.0, lexical_cast('1'), (std::numeric_limits::epsilon())); BOOST_CHECK_THROW(lexical_cast('A'), bad_lexical_cast); - BOOST_CHECK_CLOSE(1.0, lexical_cast(1), (std::numeric_limits::epsilon())); - BOOST_CHECK_CLOSE(1.23, lexical_cast(1.23), (std::numeric_limits::epsilon())); - BOOST_CHECK_CLOSE(1.234567890, 1.234567890, std::numeric_limits::epsilon()); - BOOST_CHECK_CLOSE(1.0, lexical_cast(true), (std::numeric_limits::epsilon())); - BOOST_CHECK_CLOSE(0.0, lexical_cast(false), (std::numeric_limits::epsilon())); - BOOST_CHECK_CLOSE(1.23, lexical_cast("1.23"), (std::numeric_limits::epsilon())); + BOOST_CHECK_CLOSE_FRACTION(1.0, lexical_cast(1), (std::numeric_limits::epsilon())); + BOOST_CHECK_CLOSE_FRACTION(1.23, lexical_cast(1.23), (std::numeric_limits::epsilon())); + BOOST_CHECK_CLOSE_FRACTION(1.234567890, lexical_cast(1.234567890), std::numeric_limits::epsilon()); + BOOST_CHECK_CLOSE_FRACTION(1.234567890, lexical_cast("1.234567890"), std::numeric_limits::epsilon()); + BOOST_CHECK_CLOSE_FRACTION(1.0, lexical_cast(true), (std::numeric_limits::epsilon())); + BOOST_CHECK_CLOSE_FRACTION(0.0, lexical_cast(false), (std::numeric_limits::epsilon())); + BOOST_CHECK_CLOSE_FRACTION(1.23, lexical_cast("1.23"), (std::numeric_limits::epsilon())); BOOST_CHECK_THROW(lexical_cast(""), bad_lexical_cast); BOOST_CHECK_THROW(lexical_cast("Test"), bad_lexical_cast); - BOOST_CHECK_CLOSE(1.23, lexical_cast(std::string("1.23")), (std::numeric_limits::epsilon())); + BOOST_CHECK_CLOSE_FRACTION(1.23, lexical_cast(std::string("1.23")), (std::numeric_limits::epsilon())); BOOST_CHECK_THROW( lexical_cast(std::string("")), bad_lexical_cast); BOOST_CHECK_THROW( diff --git a/test/lexical_cast_float_types_test.cpp b/test/lexical_cast_float_types_test.cpp index 66f6d67..10074d4 100755 --- a/test/lexical_cast_float_types_test.cpp +++ b/test/lexical_cast_float_types_test.cpp @@ -88,16 +88,16 @@ void test_conversion_from_to_float_for_locale() BOOST_CHECK_THROW(lexical_cast( std::string("1e10") + np.thousands_sep() ), bad_lexical_cast); BOOST_CHECK_THROW(lexical_cast( std::string("1") + np.thousands_sep() + "e10" ), bad_lexical_cast); - BOOST_CHECK_CLOSE(lexical_cast( to_str< char >(100000) ), 100000, (std::numeric_limits::epsilon()*100) ); - BOOST_CHECK_CLOSE(lexical_cast( to_str< char >(10000000u) ), 10000000u, (std::numeric_limits::epsilon()*100) ); - BOOST_CHECK_CLOSE(lexical_cast( to_str< char >(100) ), 100, (std::numeric_limits::epsilon()*100) ); + BOOST_CHECK_CLOSE_FRACTION(lexical_cast( to_str< char >(100000) ), 100000, (std::numeric_limits::epsilon()) ); + BOOST_CHECK_CLOSE_FRACTION(lexical_cast( to_str< char >(10000000u) ), 10000000u, (std::numeric_limits::epsilon()) ); + BOOST_CHECK_CLOSE_FRACTION(lexical_cast( to_str< char >(100) ), 100, (std::numeric_limits::epsilon()) ); #if !defined(BOOST_LCAST_NO_WCHAR_T) && !defined(BOOST_NO_INTRINSIC_WCHAR_T) - BOOST_CHECK_CLOSE(lexical_cast( to_str< wchar_t >(100000) ), 100000, (std::numeric_limits::epsilon()*100) ); - BOOST_CHECK_CLOSE(lexical_cast( to_str< wchar_t >(10000000u) ), 10000000u, (std::numeric_limits::epsilon()*100) ); - BOOST_CHECK_CLOSE(lexical_cast( to_str< wchar_t >(100) ), 100, (std::numeric_limits::epsilon()*100) ); + BOOST_CHECK_CLOSE_FRACTION(lexical_cast( to_str< wchar_t >(100000) ), 100000, (std::numeric_limits::epsilon()) ); + BOOST_CHECK_CLOSE_FRACTION(lexical_cast( to_str< wchar_t >(10000000u) ), 10000000u, (std::numeric_limits::epsilon()) ); + BOOST_CHECK_CLOSE_FRACTION(lexical_cast( to_str< wchar_t >(100) ), 100, (std::numeric_limits::epsilon()) ); #endif // Exception must not be thrown, when we are using no separators at all - BOOST_CHECK_CLOSE( lexical_cast("30000"), static_cast(30000), (std::numeric_limits::epsilon()*100) ); + BOOST_CHECK_CLOSE_FRACTION( lexical_cast("30000"), static_cast(30000), (std::numeric_limits::epsilon()) ); } } @@ -111,18 +111,18 @@ void test_conversion_from_to_float_for_locale() #ifndef BOOST_LCAST_NO_WCHAR_T #define CHECK_CLOSE_ABS_DIFF(VAL,PREFIX) \ converted_val = lexical_cast(#VAL); \ - BOOST_CHECK_CLOSE( (VAL ## L? VAL ## L : std::numeric_limits::epsilon()), \ + BOOST_CHECK_CLOSE_FRACTION( (VAL ## L? VAL ## L : std::numeric_limits::epsilon()), \ (converted_val ? converted_val : std::numeric_limits::epsilon()), \ - std::numeric_limits::epsilon() * 100 \ + std::numeric_limits::epsilon() \ ); \ BOOST_CHECK_EQUAL(converted_val, lexical_cast(L## #VAL) ); #else #define CHECK_CLOSE_ABS_DIFF(VAL,TYPE) \ converted_val = lexical_cast(#VAL); \ - BOOST_CHECK_CLOSE( (VAL ## L? VAL ## L : std::numeric_limits::epsilon()), \ + BOOST_CHECK_CLOSE_FRACTION( (VAL ## L? VAL ## L : std::numeric_limits::epsilon()), \ (converted_val ? converted_val : std::numeric_limits::epsilon()), \ - std::numeric_limits::epsilon() * 100 \ + std::numeric_limits::epsilon() \ ); #endif @@ -132,27 +132,27 @@ void test_converion_to_float_types() typedef TestType test_t; test_t converted_val; - BOOST_CHECK_CLOSE(1.0, lexical_cast('1'), (std::numeric_limits::epsilon())); + BOOST_CHECK_CLOSE_FRACTION(1.0, lexical_cast('1'), (std::numeric_limits::epsilon())); BOOST_CHECK_EQUAL(0.0, lexical_cast('0')); unsigned char const uc_one = '1'; unsigned char const uc_zero ='0'; - BOOST_CHECK_CLOSE(1.0, lexical_cast(uc_one), (std::numeric_limits::epsilon())); + BOOST_CHECK_CLOSE_FRACTION(1.0, lexical_cast(uc_one), (std::numeric_limits::epsilon())); BOOST_CHECK_EQUAL(0.0, lexical_cast(uc_zero)); signed char const sc_one = '1'; signed char const sc_zero ='0'; - BOOST_CHECK_CLOSE(1.0, lexical_cast(sc_one), (std::numeric_limits::epsilon())); + BOOST_CHECK_CLOSE_FRACTION(1.0, lexical_cast(sc_one), (std::numeric_limits::epsilon())); BOOST_CHECK_EQUAL(0.0, lexical_cast(sc_zero)); - BOOST_CHECK_CLOSE(1e34L, lexical_cast( "10000000000000000000000000000000000"), (std::numeric_limits::epsilon()*100) ); + BOOST_CHECK_CLOSE_FRACTION(1e34L, lexical_cast( "10000000000000000000000000000000000"), (std::numeric_limits::epsilon()) ); // VC failes the next test -// BOOST_CHECK_CLOSE(1e-35L, lexical_cast("0.00000000000000000000000000000000001"), (std::numeric_limits::epsilon()*100) ); - BOOST_CHECK_CLOSE( +// BOOST_CHECK_CLOSE_FRACTION(1e-35L, lexical_cast("0.00000000000000000000000000000000001"), (std::numeric_limits::epsilon()) ); + BOOST_CHECK_CLOSE_FRACTION( 0.1111111111111111111111111111111111111111111111111111111111111111111111111L , lexical_cast("0.1111111111111111111111111111111111111111111111111111111111111111111111111") - , (std::numeric_limits::epsilon()*100) ); + , (std::numeric_limits::epsilon()) ); CHECK_CLOSE_ABS_DIFF(1,test_t); BOOST_CHECK_EQUAL(0,lexical_cast("0")); @@ -300,13 +300,13 @@ void test_float_typess_for_overflows() typedef T test_t; test_t minvalue = (std::numeric_limits::min)(); std::string s_min_value = lexical_cast(minvalue); - BOOST_CHECK_CLOSE(minvalue, lexical_cast(minvalue), (std::numeric_limits::epsilon()*100)); - BOOST_CHECK_CLOSE(minvalue, lexical_cast(s_min_value), (std::numeric_limits::epsilon()*100)); + BOOST_CHECK_CLOSE_FRACTION(minvalue, lexical_cast(minvalue), (std::numeric_limits::epsilon())); + BOOST_CHECK_CLOSE_FRACTION(minvalue, lexical_cast(s_min_value), (std::numeric_limits::epsilon())); test_t maxvalue = (std::numeric_limits::max)(); std::string s_max_value = lexical_cast(maxvalue); - BOOST_CHECK_CLOSE(maxvalue, lexical_cast(maxvalue), (std::numeric_limits::epsilon()*100)); - BOOST_CHECK_CLOSE(maxvalue, lexical_cast(s_max_value), (std::numeric_limits::epsilon()*100)); + BOOST_CHECK_CLOSE_FRACTION(maxvalue, lexical_cast(maxvalue), (std::numeric_limits::epsilon())); + BOOST_CHECK_CLOSE_FRACTION(maxvalue, lexical_cast(s_max_value), (std::numeric_limits::epsilon())); BOOST_CHECK_THROW(lexical_cast(s_max_value+"1"), bad_lexical_cast); BOOST_CHECK_THROW(lexical_cast(s_max_value+"9"), bad_lexical_cast); @@ -343,10 +343,10 @@ void test_float_typess_for_overflows() #define TEST_TO_FROM_CAST_AROUND_TYPED(VAL,STRING_TYPE) \ test_value = VAL + std::numeric_limits::epsilon() * i ; \ converted_val = lexical_cast( lexical_cast(test_value) ); \ - BOOST_CHECK_CLOSE( \ + BOOST_CHECK_CLOSE_FRACTION( \ test_value, \ converted_val, \ - std::numeric_limits::epsilon()*100 \ + std::numeric_limits::epsilon() \ ); /* @@ -429,16 +429,16 @@ void test_conversion_from_float_to_char(CharT zero) template void test_conversion_from_char_to_float(CharT zero) { - BOOST_CHECK_CLOSE(lexical_cast( static_cast(zero + 0)), static_cast(0), (std::numeric_limits::epsilon()*100) ); - BOOST_CHECK_CLOSE(lexical_cast( static_cast(zero + 1)), static_cast(1), (std::numeric_limits::epsilon()*100) ); - BOOST_CHECK_CLOSE(lexical_cast( static_cast(zero + 2)), static_cast(2), (std::numeric_limits::epsilon()*100) ); - BOOST_CHECK_CLOSE(lexical_cast( static_cast(zero + 3)), static_cast(3), (std::numeric_limits::epsilon()*100) ); - BOOST_CHECK_CLOSE(lexical_cast( static_cast(zero + 4)), static_cast(4), (std::numeric_limits::epsilon()*100) ); - BOOST_CHECK_CLOSE(lexical_cast( static_cast(zero + 5)), static_cast(5), (std::numeric_limits::epsilon()*100) ); - BOOST_CHECK_CLOSE(lexical_cast( static_cast(zero + 6)), static_cast(6), (std::numeric_limits::epsilon()*100) ); - BOOST_CHECK_CLOSE(lexical_cast( static_cast(zero + 7)), static_cast(7), (std::numeric_limits::epsilon()*100) ); - BOOST_CHECK_CLOSE(lexical_cast( static_cast(zero + 8)), static_cast(8), (std::numeric_limits::epsilon()*100) ); - BOOST_CHECK_CLOSE(lexical_cast( static_cast(zero + 9)), static_cast(9), (std::numeric_limits::epsilon()*100) ); + BOOST_CHECK_CLOSE_FRACTION(lexical_cast( static_cast(zero + 0)), static_cast(0), (std::numeric_limits::epsilon()) ); + BOOST_CHECK_CLOSE_FRACTION(lexical_cast( static_cast(zero + 1)), static_cast(1), (std::numeric_limits::epsilon()) ); + BOOST_CHECK_CLOSE_FRACTION(lexical_cast( static_cast(zero + 2)), static_cast(2), (std::numeric_limits::epsilon()) ); + BOOST_CHECK_CLOSE_FRACTION(lexical_cast( static_cast(zero + 3)), static_cast(3), (std::numeric_limits::epsilon()) ); + BOOST_CHECK_CLOSE_FRACTION(lexical_cast( static_cast(zero + 4)), static_cast(4), (std::numeric_limits::epsilon()) ); + BOOST_CHECK_CLOSE_FRACTION(lexical_cast( static_cast(zero + 5)), static_cast(5), (std::numeric_limits::epsilon()) ); + BOOST_CHECK_CLOSE_FRACTION(lexical_cast( static_cast(zero + 6)), static_cast(6), (std::numeric_limits::epsilon()) ); + BOOST_CHECK_CLOSE_FRACTION(lexical_cast( static_cast(zero + 7)), static_cast(7), (std::numeric_limits::epsilon()) ); + BOOST_CHECK_CLOSE_FRACTION(lexical_cast( static_cast(zero + 8)), static_cast(8), (std::numeric_limits::epsilon()) ); + BOOST_CHECK_CLOSE_FRACTION(lexical_cast( static_cast(zero + 9)), static_cast(9), (std::numeric_limits::epsilon()) ); BOOST_CHECK_THROW(lexical_cast( static_cast(zero + 10)), bad_lexical_cast); BOOST_CHECK_THROW(lexical_cast( static_cast(zero - 1)), bad_lexical_cast); @@ -467,8 +467,8 @@ void test_conversion_from_to_float() test_conversion_from_char_to_float(wzero); #endif - BOOST_CHECK_CLOSE(lexical_cast("+1"), 1, std::numeric_limits::epsilon() ); - BOOST_CHECK_CLOSE(lexical_cast("+9"), 9, std::numeric_limits::epsilon()*9 ); + BOOST_CHECK_CLOSE_FRACTION(lexical_cast("+1"), 1, std::numeric_limits::epsilon()); + BOOST_CHECK_CLOSE_FRACTION(lexical_cast("+9"), 9, std::numeric_limits::epsilon()); BOOST_CHECK_THROW(lexical_cast("++1"), bad_lexical_cast); BOOST_CHECK_THROW(lexical_cast("-+9"), bad_lexical_cast); From 27a7fac22ed34d464e274eb08141037101b5056e Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Fri, 8 Jul 2011 17:23:31 +0000 Subject: [PATCH 13/39] Updates #5660. Removed duplicate tests. Unified behaviour for float conversions on different compillers [SVN r72972] --- include/boost/lexical_cast.hpp | 51 ++++++++++++++++++++++++++++------ lexical_cast_test.cpp | 11 -------- 2 files changed, 42 insertions(+), 20 deletions(-) diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index 044354f..4878b32 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -1338,15 +1338,39 @@ namespace boost return lcast_ret_float(output,start,finish); } -#if defined(BOOST_HAS_LONG_LONG) || defined(BOOST_HAS_MS_INT64) private: - // we need workaround - bool no_long_double_80bit_realization_workaround(double& output, int) { - return convert_using_base_class(output); + // Not optimised converter + template + bool float_types_converter_internal(T& output, int /*tag*/) { + bool return_value = convert_using_base_class(output); + + /* Some compilers and libraries successfully + * parse 'inf', 'INFINITY', '1.0E', '1.0E-'... + * We are trying to provide a unified behaviour, + * so we just forbid such conversions (as some + * of the most popular compilers/libraries do) + * */ + CharT const minus = lcast_char_constants::minus; + CharT const plus = lcast_char_constants::plus; + CharT const capital_e = lcast_char_constants::capital_e; + CharT const lowercase_e = lcast_char_constants::lowercase_e; + if ( return_value && + ( + output > (std::numeric_limits::max)() // +inf + || output < -(std::numeric_limits::max)() // -inf + || output != output // NaN + || *(finish-1) == lowercase_e // 1.0e + || *(finish-1) == capital_e // 1.0E + || *(finish-1) == minus // 1.0e- or 1.0E- + || *(finish-1) == plus // 1.0e+ or 1.0E+ + ) + ) return false; + + return return_value; } - // we do not need a workaround - bool no_long_double_80bit_realization_workaround(double& output,char) { + // Optimised converter + bool float_types_converter_internal(double& output,char /*tag*/) { return lcast_ret_float(output,start,finish); } public: @@ -1360,14 +1384,23 @@ namespace boost * double, because it will give a big precision loss. * */ 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, +#else + 0 +#endif int, char - >::type dummy = 0; + >::type tag = 0; - return no_long_double_80bit_realization_workaround(output, dummy); + return float_types_converter_internal(output, tag); + } + + bool operator>>(long double& output) + { + int tag = 0; + return float_types_converter_internal(output, tag); } -#endif // Generic istream-based algorithm. // lcast_streambuf_for_target::value is true. diff --git a/lexical_cast_test.cpp b/lexical_cast_test.cpp index 62449ea..afa16a6 100644 --- a/lexical_cast_test.cpp +++ b/lexical_cast_test.cpp @@ -921,17 +921,6 @@ void test_char_types_conversions() BOOST_CHECK(boost::lexical_cast(wc_arr) == std::wstring(wc_arr)); BOOST_CHECK(boost::lexical_cast(wc_arr[0]) == wc_arr[0]); - // Following tests depend on realization of std::locale. - // All we need to know, is that this functions must compile - 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(sc_arr) != std::wstring(wc_arr) ); - BOOST_CHECK(boost::lexical_cast(uc_arr) != std::wstring(wc_arr) ); - - BOOST_CHECK_THROW(boost::lexical_cast(uc_arr[0]), bad_lexical_cast); - BOOST_CHECK_THROW(boost::lexical_cast(sc_arr[0]), bad_lexical_cast); - #endif } From de3df54f809d6721a704eac29335feefbe7168a9 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Fri, 15 Jul 2011 11:20:11 +0000 Subject: [PATCH 14/39] Fixes #5689. Added code to work with Inf and NaN on any platform [SVN r73118] --- include/boost/lexical_cast.hpp | 144 ++++++++++++++++++++++++- lexical_cast.htm | 1 + lexical_cast_test.cpp | 4 + test/Jamfile.v2 | 1 + test/lexical_cast_float_types_test.cpp | 20 ---- test/lexical_cast_inf_nan_test.cpp | 109 +++++++++++++++++++ 6 files changed, 254 insertions(+), 25 deletions(-) create mode 100755 test/lexical_cast_inf_nan_test.cpp diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index 4878b32..b4728f3 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -731,6 +732,136 @@ namespace boost } } + namespace detail + { + /* Returns true and sets the correct value if found NaN or Inf. */ + template + inline bool parse_inf_nan_impl(const CharT* begin, const CharT* end, T& value + , const CharT* lc_NAN, const CharT* lc_nan + , const CharT* lc_INFINITY, const CharT* lc_infinity + , const CharT opening_brace, const CharT closing_brace) + { + using namespace std; + const wchar_t minus = lcast_char_constants::minus; + const wchar_t plus = lcast_char_constants::plus; + const int inifinity_size = 8; + + bool has_minus = false; + /* Parsing +/- */ + if( *begin == minus) + { + ++ begin; + has_minus = true; + } + else if( *begin == plus ) ++begin; + + if( end-begin < 3 ) return false; + if( !memcmp(begin, lc_nan, 3*sizeof(CharT)) || !memcmp(begin, lc_NAN, 3*sizeof(CharT)) ) + { + begin += 3; + if (end != begin) /* It is 'nan(...)' or some bad input*/ + { + if(end-begin<2) return false; // bad input + -- end; + if( *begin != opening_brace || *end != closing_brace) return false; // bad input + } + + if( !has_minus ) value = std::numeric_limits::quiet_NaN(); + else value = -std::numeric_limits::quiet_NaN(); + return true; + } else + if (( /* 'INF' or 'inf' */ + end-begin==3 + && + (!memcmp(begin, lc_infinity, 3*sizeof(CharT)) || !memcmp(begin, lc_INFINITY, 3*sizeof(CharT))) + ) + || + ( /* 'INFINITY' or 'infinity' */ + end-begin==inifinity_size + && + (!memcmp(begin, lc_infinity, inifinity_size)|| !memcmp(begin, lc_INFINITY, inifinity_size)) + ) + ) + { + if( !has_minus ) value = std::numeric_limits::infinity(); + else value = -std::numeric_limits::infinity(); + return true; + } + + return false; + } + +#ifndef BOOST_LCAST_NO_WCHAR_T + template + bool parse_inf_nan(const wchar_t* begin, const wchar_t* end, T& value) + { + return parse_inf_nan_impl(begin, end, value + , L"NAN", L"nan" + , L"INFINITY", L"infinity" + , L'(', L')'); + } +#endif + + template + bool parse_inf_nan(const CharT* begin, const CharT* end, T& value) + { + return parse_inf_nan_impl(begin, end, value + , "NAN", "nan" + , "INFINITY", "infinity" + , '(', ')'); + } + + template + bool put_inf_nan(wchar_t* begin, wchar_t*& end, const T& value) + { + using namespace std; + if (value != value) + { + memcpy(begin,L"nan", sizeof(L"nan")); + end = begin + 3; + return true; + } else if ( value > numeric_limits::max() ) + { + memcpy(begin,L"inf", sizeof(L"inf")); + end = begin + 3; + return true; + } else if ( value < -numeric_limits::max() ) + { + memcpy(begin,L"-inf", sizeof(L"-inf")); + end = begin + 4; + return true; + } + + return false; + } + + template + bool put_inf_nan(CharT* begin, CharT*& end, const T& value) + { + using namespace std; + if (value != value) + { + memcpy(begin,"nan", sizeof("nan")); + end = begin + 3; + return true; + } else if ( value > numeric_limits::max() ) + { + memcpy(begin,"inf", sizeof("inf")); + end = begin + 3; + return true; + } else if ( value < -numeric_limits::max() ) + { + memcpy(begin,"-inf", sizeof("-inf")); + end = begin + 4; + return true; + } + + return false; + } + + } + + namespace detail // lcast_ret_float { template @@ -782,6 +913,8 @@ namespace boost value = 0.0; + if (parse_inf_nan(begin, end, value)) return true; + typedef typename Traits::int_type int_type; typedef BOOST_DEDUCED_TYPENAME mantissa_holder_type::type mantissa_type; int_type const zero = Traits::to_int_type(czero); @@ -1104,6 +1237,7 @@ namespace boost template bool lcast_put(const OutputStreamable& input) { + if(put_inf_nan(start, finish, input)) return true; this->setp(start, finish); std::basic_ostream stream(static_cast(this)); lcast_set_precision(stream, static_cast(0)); @@ -1342,10 +1476,13 @@ namespace boost // Not optimised converter template bool float_types_converter_internal(T& output, int /*tag*/) { + + if (parse_inf_nan(start, finish, output)) return true; + bool return_value = convert_using_base_class(output); /* Some compilers and libraries successfully - * parse 'inf', 'INFINITY', '1.0E', '1.0E-'... + * parse '1.0E', '1.0E-'... * We are trying to provide a unified behaviour, * so we just forbid such conversions (as some * of the most popular compilers/libraries do) @@ -1356,10 +1493,7 @@ namespace boost CharT const lowercase_e = lcast_char_constants::lowercase_e; if ( return_value && ( - output > (std::numeric_limits::max)() // +inf - || output < -(std::numeric_limits::max)() // -inf - || output != output // NaN - || *(finish-1) == lowercase_e // 1.0e + *(finish-1) == lowercase_e // 1.0e || *(finish-1) == capital_e // 1.0E || *(finish-1) == minus // 1.0e- or 1.0E- || *(finish-1) == plus // 1.0e+ or 1.0E+ diff --git a/lexical_cast.htm b/lexical_cast.htm index 2079a0f..35c6e58 100644 --- a/lexical_cast.htm +++ b/lexical_cast.htm @@ -269,6 +269,7 @@ Eliminate an overhead of std::locale if your program runs in the "C

    Changes

    July 2011:

      +
    • Added code to work with Inf and NaN on any platform.
    • Better performance and less memory usage for conversions to float type (and to double type, if sizeof(double)<sizeof(long double)).

    May 2011:

    diff --git a/lexical_cast_test.cpp b/lexical_cast_test.cpp index afa16a6..244addb 100644 --- a/lexical_cast_test.cpp +++ b/lexical_cast_test.cpp @@ -42,6 +42,10 @@ #define LCAST_TEST_LONGLONG #endif +#if defined(BOOST_NO_STRINGSTREAM) || defined(BOOST_NO_STD_WSTRING) +#define BOOST_LCAST_NO_WCHAR_T +#endif + template struct my_traits : std::char_traits { diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 9517c63..2dd3500 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -27,6 +27,7 @@ test-suite conversion [ run lexical_cast_vc8_bug_test.cpp ../../test/build//boost_unit_test_framework/static ] [ run lexical_cast_wchars_test.cpp ../../test/build//boost_unit_test_framework/static ] [ run lexical_cast_float_types_test.cpp ../../test/build//boost_unit_test_framework/static ] + [ run lexical_cast_inf_nan_test.cpp ../../test/build//boost_unit_test_framework/static ] ; diff --git a/test/lexical_cast_float_types_test.cpp b/test/lexical_cast_float_types_test.cpp index 10074d4..72279bb 100755 --- a/test/lexical_cast_float_types_test.cpp +++ b/test/lexical_cast_float_types_test.cpp @@ -242,22 +242,6 @@ void test_converion_to_float_types() CHECK_CLOSE_ABS_DIFF(.34, test_t); CHECK_CLOSE_ABS_DIFF(.34e10, test_t); -// BOOST_CHECK(lexical_cast("-inf") == -std::numeric_limits::infinity() ); -// BOOST_CHECK(lexical_cast("-INF") == -std::numeric_limits::infinity() ); -// BOOST_CHECK(lexical_cast("+inf") == std::numeric_limits::infinity() ); -// BOOST_CHECK(lexical_cast("infinity") == std::numeric_limits::infinity() ); -// -// BOOST_CHECK(lexical_cast("nan") == std::numeric_limits::quiet_NaN() ); -// BOOST_CHECK(lexical_cast("NaN") == std::numeric_limits::quiet_NaN() ); - - BOOST_CHECK_THROW(lexical_cast("-inf"), bad_lexical_cast ); - BOOST_CHECK_THROW(lexical_cast("-INF"), bad_lexical_cast); - BOOST_CHECK_THROW(lexical_cast("+inf"), bad_lexical_cast); - BOOST_CHECK_THROW(lexical_cast("infinity"), bad_lexical_cast); - BOOST_CHECK_THROW(lexical_cast("nan"), bad_lexical_cast); - BOOST_CHECK_THROW(lexical_cast("NaN"), bad_lexical_cast); - - BOOST_CHECK_THROW(lexical_cast("-1.e"), bad_lexical_cast); BOOST_CHECK_THROW(lexical_cast("-1.E"), bad_lexical_cast); BOOST_CHECK_THROW(lexical_cast("1.e"), bad_lexical_cast); @@ -381,10 +365,6 @@ void test_converion_from_to_float_types() TEST_TO_FROM_CAST_AROUND( 0.0 ); -// TEST_TO_FROM_CAST_AROUND( std::numeric_limits::infinity() ); -// TEST_TO_FROM_CAST_AROUND( -std::numeric_limits::infinity() ); -// TEST_TO_FROM_CAST_AROUND( std::numeric_limits::quiet_NaN() ); - long double val1; for(val1 = 1.0e-10L; val1 < 1e11; val1*=10 ) TEST_TO_FROM_CAST_AROUND( val1 ); diff --git a/test/lexical_cast_inf_nan_test.cpp b/test/lexical_cast_inf_nan_test.cpp new file mode 100755 index 0000000..64a4957 --- /dev/null +++ b/test/lexical_cast_inf_nan_test.cpp @@ -0,0 +1,109 @@ +// Unit test for boost::lexical_cast. +// +// See http://www.boost.org for most recent version, including documentation. +// +// Copyright Antony Polukhin, 2011. +// +// 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 + +#if defined(__INTEL_COMPILER) +#pragma warning(disable: 193 383 488 981 1418 1419) +#elif defined(BOOST_MSVC) +#pragma warning(disable: 4097 4100 4121 4127 4146 4244 4245 4511 4512 4701 4800) +#endif + +#include + +#include +#include +#include + +#if defined(BOOST_NO_STRINGSTREAM) || defined(BOOST_NO_STD_WSTRING) +#define BOOST_LCAST_NO_WCHAR_T +#endif + +using namespace boost; + +template +void test_inf_nan_templated() +{ + typedef T test_t; + + BOOST_CHECK(lexical_cast("inf") > (std::numeric_limits::max)() ); + BOOST_CHECK(lexical_cast("INF") > (std::numeric_limits::max)() ); + + BOOST_CHECK(lexical_cast("-inf") < -(std::numeric_limits::max)() ); + BOOST_CHECK(lexical_cast("-INF") < -(std::numeric_limits::max)() ); + + BOOST_CHECK(lexical_cast("+inf") > (std::numeric_limits::max)() ); + BOOST_CHECK(lexical_cast("+INF") > (std::numeric_limits::max)() ); + + BOOST_CHECK(lexical_cast("infinity") > (std::numeric_limits::max)() ); + BOOST_CHECK(lexical_cast("INFINITY") > (std::numeric_limits::max)() ); + + BOOST_CHECK(lexical_cast("-infinity") < -(std::numeric_limits::max)() ); + BOOST_CHECK(lexical_cast("-INFINITY") < -(std::numeric_limits::max)() ); + + BOOST_CHECK(lexical_cast("+infinity") > (std::numeric_limits::max)() ); + BOOST_CHECK(lexical_cast("+INFINITY") > (std::numeric_limits::max)() ); + + BOOST_CHECK( lexical_cast("nan") != lexical_cast("nan") ); + BOOST_CHECK( lexical_cast("NAN") != lexical_cast("NAN") ); + + BOOST_CHECK( lexical_cast("-nan") != lexical_cast("-nan") ); + BOOST_CHECK( lexical_cast("-NAN") != lexical_cast("-NAN") ); + + BOOST_CHECK( lexical_cast("+nan") != lexical_cast("+nan") ); + BOOST_CHECK( lexical_cast("+NAN") != lexical_cast("+NAN") ); + + BOOST_CHECK( lexical_cast("nan()") != lexical_cast("nan()") ); + BOOST_CHECK( lexical_cast("NAN(some string)") != lexical_cast("NAN(some string)") ); + BOOST_CHECK_THROW( lexical_cast("NAN(some string"), bad_lexical_cast ); + + BOOST_CHECK(lexical_cast( -std::numeric_limits::infinity()) == "-inf" ); + BOOST_CHECK(lexical_cast( std::numeric_limits::infinity()) == "inf" ); + BOOST_CHECK(lexical_cast( std::numeric_limits::quiet_NaN()) == "nan" ); + +#ifndef BOOST_LCAST_NO_WCHAR_T + BOOST_CHECK(lexical_cast(L"inf") > (std::numeric_limits::max)() ); + BOOST_CHECK(lexical_cast(L"INF") > (std::numeric_limits::max)() ); + + BOOST_CHECK( lexical_cast(L"nan") != lexical_cast(L"nan") ); + BOOST_CHECK( lexical_cast(L"NAN") != lexical_cast(L"NAN") ); + + BOOST_CHECK(lexical_cast( -std::numeric_limits::infinity()) == L"-inf" ); + BOOST_CHECK(lexical_cast( std::numeric_limits::infinity()) == L"inf" ); + BOOST_CHECK(lexical_cast( std::numeric_limits::quiet_NaN()) == L"nan" ); + +#endif +} + +void test_inf_nan_float() +{ + test_inf_nan_templated(); +} + +void test_inf_nan_double() +{ + test_inf_nan_templated(); +} + +void test_inf_nan_long_double() +{ + test_inf_nan_templated(); +} + +unit_test::test_suite *init_unit_test_suite(int, char *[]) +{ + unit_test_framework::test_suite *suite = + BOOST_TEST_SUITE("lexical_cast inf anf nan parsing unit test"); + suite->add(BOOST_TEST_CASE(&test_inf_nan_float)); + suite->add(BOOST_TEST_CASE(&test_inf_nan_double)); + suite->add(BOOST_TEST_CASE(&test_inf_nan_long_double)); + + return suite; +} From c6c501c7693c838eac10763a619e77d9d3de0fb8 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Sat, 16 Jul 2011 21:02:32 +0000 Subject: [PATCH 15/39] Fixes #5689. Added code to work -NaN on any platform. Removed some warnings [SVN r73155] --- include/boost/lexical_cast.hpp | 79 ++++++++++++-------- test/lexical_cast_inf_nan_test.cpp | 114 ++++++++++++++++++++++------- 2 files changed, 134 insertions(+), 59 deletions(-) diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index b4728f3..99aeb24 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -40,6 +40,8 @@ #include #include #include +#include +#include #include #include #include @@ -767,7 +769,7 @@ namespace boost } if( !has_minus ) value = std::numeric_limits::quiet_NaN(); - else value = -std::numeric_limits::quiet_NaN(); + else value = (boost::math::changesign) (std::numeric_limits::quiet_NaN()); return true; } else if (( /* 'INF' or 'inf' */ @@ -784,7 +786,7 @@ namespace boost ) { if( !has_minus ) value = std::numeric_limits::infinity(); - else value = -std::numeric_limits::infinity(); + else value = (boost::math::changesign) (std::numeric_limits::infinity()); return true; } @@ -810,49 +812,67 @@ namespace boost , "INFINITY", "infinity" , '(', ')'); } - +#ifndef BOOST_LCAST_NO_WCHAR_T template bool put_inf_nan(wchar_t* begin, wchar_t*& end, const T& value) { using namespace std; - if (value != value) + if ( (boost::math::isnan)(value) ) { - memcpy(begin,L"nan", sizeof(L"nan")); - end = begin + 3; + if ( (boost::math::signbit)(value) ) + { + memcpy(begin,L"-nan", sizeof(L"-nan")); + end = begin + 4; + } else + { + memcpy(begin,L"nan", sizeof(L"nan")); + end = begin + 3; + } return true; - } else if ( value > numeric_limits::max() ) + } else if ( (boost::math::isinf)(value) ) { - memcpy(begin,L"inf", sizeof(L"inf")); - end = begin + 3; - return true; - } else if ( value < -numeric_limits::max() ) - { - memcpy(begin,L"-inf", sizeof(L"-inf")); - end = begin + 4; + if ( (boost::math::signbit)(value) ) + { + memcpy(begin,L"-inf", sizeof(L"-inf")); + end = begin + 4; + } else + { + memcpy(begin,L"inf", sizeof(L"inf")); + end = begin + 3; + } return true; } return false; } - +#endif template bool put_inf_nan(CharT* begin, CharT*& end, const T& value) { using namespace std; - if (value != value) + if ( (boost::math::isnan)(value) ) { - memcpy(begin,"nan", sizeof("nan")); - end = begin + 3; + if ( (boost::math::signbit)(value) ) + { + memcpy(begin,"-nan", sizeof("-nan")); + end = begin + 4; + } else + { + memcpy(begin,"nan", sizeof("nan")); + end = begin + 3; + } return true; - } else if ( value > numeric_limits::max() ) + } else if ( (boost::math::isinf)(value) ) { - memcpy(begin,"inf", sizeof("inf")); - end = begin + 3; - return true; - } else if ( value < -numeric_limits::max() ) - { - memcpy(begin,"-inf", sizeof("-inf")); - end = begin + 4; + if ( (boost::math::signbit)(value) ) + { + memcpy(begin,"-inf", sizeof("-inf")); + end = begin + 4; + } else + { + memcpy(begin,"inf", sizeof("inf")); + end = begin + 3; + } return true; } @@ -1095,12 +1115,9 @@ namespace boost * with long doubles (and with doubles if sizeof(double)==sizeof(long double)). */ long double result = std::pow(10.0L, pow_of_10) * mantissa; - value = ( has_minus ? -1 * result : result); + value = static_cast( has_minus ? -1 * result : result); - if ( value > (std::numeric_limits::max)() // is it +inf - || value < -(std::numeric_limits::max)() // is it -inf - || value != value) // is it NaN - return false; + if ( (boost::math::isinf)(value) || (boost::math::isnan)(value) ) return false; return true; } diff --git a/test/lexical_cast_inf_nan_test.cpp b/test/lexical_cast_inf_nan_test.cpp index 64a4957..ee50dee 100755 --- a/test/lexical_cast_inf_nan_test.cpp +++ b/test/lexical_cast_inf_nan_test.cpp @@ -18,7 +18,9 @@ #include -#include + +#include +#include #include #include @@ -28,57 +30,113 @@ using namespace boost; +template +bool is_pos_inf(T value) +{ + return (boost::math::isinf)(value) && !(boost::math::signbit)(value); +} + +template +bool is_neg_inf(T value) +{ + return (boost::math::isinf)(value) && (boost::math::signbit)(value); +} + +template +bool is_pos_nan(T value) +{ + return (boost::math::isnan)(value) && !(boost::math::signbit)(value); +} + +template +bool is_neg_nan(T value) +{ + return (boost::math::isnan)(value) && (boost::math::signbit)(value); +} + template void test_inf_nan_templated() { typedef T test_t; - BOOST_CHECK(lexical_cast("inf") > (std::numeric_limits::max)() ); - BOOST_CHECK(lexical_cast("INF") > (std::numeric_limits::max)() ); + BOOST_CHECK( is_pos_inf( lexical_cast("inf") ) ); + BOOST_CHECK( is_pos_inf( lexical_cast("INF") ) ); - BOOST_CHECK(lexical_cast("-inf") < -(std::numeric_limits::max)() ); - BOOST_CHECK(lexical_cast("-INF") < -(std::numeric_limits::max)() ); + BOOST_CHECK( is_neg_inf( lexical_cast("-inf") ) ); + BOOST_CHECK( is_neg_inf( lexical_cast("-INF") ) ); - BOOST_CHECK(lexical_cast("+inf") > (std::numeric_limits::max)() ); - BOOST_CHECK(lexical_cast("+INF") > (std::numeric_limits::max)() ); + BOOST_CHECK( is_pos_inf( lexical_cast("+inf") ) ); + BOOST_CHECK( is_pos_inf( lexical_cast("+INF") ) ); - BOOST_CHECK(lexical_cast("infinity") > (std::numeric_limits::max)() ); - BOOST_CHECK(lexical_cast("INFINITY") > (std::numeric_limits::max)() ); + BOOST_CHECK( is_pos_inf( lexical_cast("infinity") ) ); + BOOST_CHECK( is_pos_inf( lexical_cast("INFINITY") ) ); - BOOST_CHECK(lexical_cast("-infinity") < -(std::numeric_limits::max)() ); - BOOST_CHECK(lexical_cast("-INFINITY") < -(std::numeric_limits::max)() ); + BOOST_CHECK( is_neg_inf( lexical_cast("-infinity") ) ); + BOOST_CHECK( is_neg_inf( lexical_cast("-INFINITY") ) ); - BOOST_CHECK(lexical_cast("+infinity") > (std::numeric_limits::max)() ); - BOOST_CHECK(lexical_cast("+INFINITY") > (std::numeric_limits::max)() ); + BOOST_CHECK( is_pos_inf( lexical_cast("+infinity") ) ); + BOOST_CHECK( is_pos_inf( lexical_cast("+INFINITY") ) ); - BOOST_CHECK( lexical_cast("nan") != lexical_cast("nan") ); - BOOST_CHECK( lexical_cast("NAN") != lexical_cast("NAN") ); + BOOST_CHECK( is_pos_nan( lexical_cast("nan") ) ); + BOOST_CHECK( is_pos_nan( lexical_cast("NAN") ) ); - BOOST_CHECK( lexical_cast("-nan") != lexical_cast("-nan") ); - BOOST_CHECK( lexical_cast("-NAN") != lexical_cast("-NAN") ); + BOOST_CHECK( is_neg_nan( lexical_cast("-nan") ) ); + BOOST_CHECK( is_neg_nan( lexical_cast("-NAN") ) ); - BOOST_CHECK( lexical_cast("+nan") != lexical_cast("+nan") ); - BOOST_CHECK( lexical_cast("+NAN") != lexical_cast("+NAN") ); + BOOST_CHECK( is_pos_nan( lexical_cast("+nan") ) ); + BOOST_CHECK( is_pos_nan( lexical_cast("+NAN") ) ); - BOOST_CHECK( lexical_cast("nan()") != lexical_cast("nan()") ); - BOOST_CHECK( lexical_cast("NAN(some string)") != lexical_cast("NAN(some string)") ); + BOOST_CHECK( is_pos_nan( lexical_cast("nan()") ) ); + BOOST_CHECK( is_pos_nan( lexical_cast("NAN(some string)") ) ); BOOST_CHECK_THROW( lexical_cast("NAN(some string"), bad_lexical_cast ); - BOOST_CHECK(lexical_cast( -std::numeric_limits::infinity()) == "-inf" ); + BOOST_CHECK(lexical_cast( (boost::math::changesign)(std::numeric_limits::infinity())) + == "-inf" ); BOOST_CHECK(lexical_cast( std::numeric_limits::infinity()) == "inf" ); BOOST_CHECK(lexical_cast( std::numeric_limits::quiet_NaN()) == "nan" ); + BOOST_CHECK(lexical_cast( + (boost::math::changesign)(std::numeric_limits::quiet_NaN())) + == "-nan" ); #ifndef BOOST_LCAST_NO_WCHAR_T - BOOST_CHECK(lexical_cast(L"inf") > (std::numeric_limits::max)() ); - BOOST_CHECK(lexical_cast(L"INF") > (std::numeric_limits::max)() ); + BOOST_CHECK( is_pos_inf( lexical_cast(L"inf") ) ); + BOOST_CHECK( is_pos_inf( lexical_cast(L"INF") ) ); - BOOST_CHECK( lexical_cast(L"nan") != lexical_cast(L"nan") ); - BOOST_CHECK( lexical_cast(L"NAN") != lexical_cast(L"NAN") ); + BOOST_CHECK( is_neg_inf( lexical_cast(L"-inf") ) ); + BOOST_CHECK( is_neg_inf( lexical_cast(L"-INF") ) ); - BOOST_CHECK(lexical_cast( -std::numeric_limits::infinity()) == L"-inf" ); + BOOST_CHECK( is_pos_inf( lexical_cast(L"+inf") ) ); + BOOST_CHECK( is_pos_inf( lexical_cast(L"+INF") ) ); + + BOOST_CHECK( is_pos_inf( lexical_cast(L"infinity") ) ); + BOOST_CHECK( is_pos_inf( lexical_cast(L"INFINITY") ) ); + + BOOST_CHECK( is_neg_inf( lexical_cast(L"-infinity") ) ); + BOOST_CHECK( is_neg_inf( lexical_cast(L"-INFINITY") ) ); + + BOOST_CHECK( is_pos_inf( lexical_cast(L"+infinity") ) ); + BOOST_CHECK( is_pos_inf( lexical_cast(L"+INFINITY") ) ); + + BOOST_CHECK( is_pos_nan( lexical_cast(L"nan") ) ); + BOOST_CHECK( is_pos_nan( lexical_cast(L"NAN") ) ); + + BOOST_CHECK( is_neg_nan( lexical_cast(L"-nan") ) ); + BOOST_CHECK( is_neg_nan( lexical_cast(L"-NAN") ) ); + + BOOST_CHECK( is_pos_nan( lexical_cast(L"+nan") ) ); + BOOST_CHECK( is_pos_nan( lexical_cast(L"+NAN") ) ); + + BOOST_CHECK( is_pos_nan( lexical_cast(L"nan()") ) ); + BOOST_CHECK( is_pos_nan( lexical_cast(L"NAN(some string)") ) ); + BOOST_CHECK_THROW( lexical_cast(L"NAN(some string"), bad_lexical_cast ); + + BOOST_CHECK(lexical_cast( (boost::math::changesign)(std::numeric_limits::infinity())) + == L"-inf" ); BOOST_CHECK(lexical_cast( std::numeric_limits::infinity()) == L"inf" ); BOOST_CHECK(lexical_cast( std::numeric_limits::quiet_NaN()) == L"nan" ); - + BOOST_CHECK(lexical_cast( + (boost::math::changesign)(std::numeric_limits::quiet_NaN())) + == L"-nan" ); #endif } From 272e92ba7f7c34e82b8a1f8f6fe39ddf139112b2 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Wed, 20 Jul 2011 11:50:46 +0000 Subject: [PATCH 16/39] Fixes #5723. Updates lexical_cast maintainer info [SVN r73256] --- doc/Jamfile.v2 | 16 + doc/lexical_cast.qbk | 685 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 701 insertions(+) create mode 100644 doc/Jamfile.v2 create mode 100644 doc/lexical_cast.qbk diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 new file mode 100644 index 0000000..b629c6a --- /dev/null +++ b/doc/Jamfile.v2 @@ -0,0 +1,16 @@ +# Copyright Antony Polukhin 2011. Use, modification, and distribution are +# subject to 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) + +using quickbook ; +import boostbook : boostbook ; + +xml lexical_cast : lexical_cast.qbk ; +boostbook standalone + : + lexical_cast + : + boost.root=../../../.. + pdf:boost.url.prefix=http://www.boost.org/doc/libs/release/doc/html + ; + diff --git a/doc/lexical_cast.qbk b/doc/lexical_cast.qbk new file mode 100644 index 0000000..8ce54cb --- /dev/null +++ b/doc/lexical_cast.qbk @@ -0,0 +1,685 @@ +[library Boost.Lexical_Cast + [quickbook 1.5] + [version 1.0] + [copyright 2000-2005 Kevlin Henney] + [copyright 2006-2010 Alexander Nasonov] + [copyright 2011 Antony Polukhin] + [category String and text processing] + [category Miscellaneous] + [license + 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]) + ] +] + +[def __numericcast__ [@http://www.boost.org/libs/numeric/conversion/doc/html/boost_numericconversion/improved_numeric_cast__.html `boost::numeric_cast`]] +[def __proposallong__ [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1973.html Lexical Conversion Library Proposal for TR2, N1973 by Kevlin Henney and Beman Dawes]] +[def __proposalshort__ [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1973.html Lexical Conversion Library Proposal for TR2, N1973]] + +[section Motivation] +Sometimes a value must be converted to a literal text form, such as an [c++] `int` represented as a `std::string`, or vice-versa, when a `std::string` is interpreted as an `int`. Such examples are common when converting between data types internal to a program and representation external to a program, such as windows and configuration files. + +The standard C and C++ libraries offer a number of facilities for performing such conversions. However, they vary with their ease of use, extensibility, and safety. + +For instance, there are a number of limitations with the family of standard C functions typified by `atoi`: + +* Conversion is supported in one direction only: from text to internal data type. Converting the other way using the C library requires either the inconvenience and compromised safety of the `sprintf` function, or the loss of portability associated with non-standard functions such as `itoa`. +* The range of types supported is only a subset of the built-in numeric types, namely `int`, `long`, and `double`. +* The range of types cannot be extended in a uniform manner. For instance, conversion from string representation to complex or rational. + +The standard C functions typified by `strtol` have the same basic limitations, but offer finer control over the conversion process. However, for the common case such control is often either not required or not used. The `scanf` family of functions offer even greater control, but also lack safety and ease of use. + +The standard C++ library offers `stringstream` for the kind of in-core formatting being discussed. It offers a great deal of control over the formatting and conversion of I/O to and from arbitrary types through text. However, for simple conversions direct use of `stringstream` can be either clumsy (with the introduction of extra local variables and the loss of infix-expression convenience) or obscure (where `stringstream` objects are created as temporary objects in an expression). Facets provide a comprehensive concept and facility for controlling textual representation, but their perceived complexity and high entry level requires an extreme degree of involvement for simple conversions, and excludes all but a few programmers. + +The `lexical_cast` function template offers a convenient and consistent form for supporting common conversions to and from arbitrary types when they are represented as text. The simplification it offers is in expression-level convenience for such conversions. For more involved conversions, such as where precision or formatting need tighter control than is offered by the default behavior of `lexical_cast`, the conventional `std::stringstream` approach is recommended. Where the conversions are numeric to numeric, __numericcast__ may offer more reasonable behavior than `lexical_cast`. + +For a good discussion of the options and issues involved in string-based formatting, including comparison of `stringstream`, `lexical_cast`, and others, see Herb Sutter's article, [@http://www.gotw.ca/publications/mill19.htm The String Formatters of Manor Farm]. Also, take a look at the [link boost_lexical_cast.performance Performance] section. +[endsect] + +[section Examples] +The following example treats command line arguments as a sequence of numeric data: +`` + int main(int argc, char * argv[]) + { + using boost::lexical_cast; + using boost::bad_lexical_cast; + + std::vector args; + + while(*++argv) + { + try + { + args.push_back(lexical_cast(*argv)); + } + catch(bad_lexical_cast &) + { + args.push_back(0); + } + } + ... + } +`` +The following example uses numeric data in a string expression: +`` + void log_message(const std::string &); + + void log_errno(int yoko) + { + log_message("Error " + boost::lexical_cast(yoko) + ": " + strerror(yoko)); + } +`` +[endsect] + +[section Synopsis] +Library features defined in [@../../boost/lexical_cast.hpp boost/lexical_cast.hpp]: +`` + namespace boost + { + class bad_lexical_cast; + template + Target lexical_cast(const Source& arg); + } +`` + +[section lexical_cast] +`` + template + Target lexical_cast(const Source& arg); +`` +Returns the result of streaming arg into a standard library string-based stream and then out as a Target object. Where Target is either `std::string` or `std::wstring`, stream extraction takes the whole content of the string, including spaces, rather than relying on the default `operator>>` behavior. If the conversion is unsuccessful, a `bad_lexical_cast` exception is thrown. + +The requirements on the argument and result types are: + +* Source is OutputStreamable, meaning that an `operator<<` is defined that takes a `std::ostream` or `std::wostream` object on the left hand side and an instance of the argument type on the right. +* Target is InputStreamable, meaning that an `operator>>` is defined that takes a `std::istream` or `std::wistream` object on the left hand side and an instance of the result type on the right. +* 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`. + +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] + +[section bad_lexical_cast] +`` + class bad_lexical_cast : public std::bad_cast + { + public: + ... // same member function interface as std::exception + }; +`` +Exception used to indicate runtime lexical_cast failure. +[endsect] + +[endsect] + +[section Frequently Asked Questions] + +* [*Question:] Why does `lexical_cast("127")` throw `bad_lexical_cast`? + * [*Answer:] The type `int8_t` is a `typedef` to `char` or `signed char`. Lexical conversion to these types +is simply reading a byte from source but since the source has more than one byte, the exception is thrown. +Please use other integer types such as `int` or `short int`. If bounds checking is important, you can also +call __numericcast__: +`numeric_cast(lexical_cast("127"));` + + +* [*Question:] What does `lexical_cast` of an `int8_t` or `uint8_t` not do what I expect? + * [*Answer:] As above, note that int8_t and uint8_t are actually chars and are formatted as such. To avoid +this, cast to an integer type first: `lexical_cast(static_cast(n));` + + +* [*Question:] The implementation always resets the `ios_base::skipws` flag of an underlying stream object. +It breaks my `operator>>` that works only in presence of this flag. Can you remove code that resets the flag? + * [*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. +Read a good C++ book, study `std::sentry` and [@../../libs/io/doc/ios_state.html `ios_state_saver`]. + + +* [*Question:] Why `std::cout << boost::lexical_cast("-1");` does not throw, but outputs 4294967295? + * [*Answer:] `boost::lexical_cast` has the behavior of `std::stringstream`, which uses `num_get` functions of +`std::locale` to convert numbers. If we look at the Programming languages — C++, we'll see, that `num_get` uses +the rules of `scanf` for conversions. And in the C99 standard for unsigned input value minus sign is optional, so +if a negative number is read, no errors will arise and the result will be the two's complement. + +[endsect] + +[section Changes] +* [*boost 1.48.0 :] + + * Added code to work with Inf and NaN on any platform. + * Better performance and less memory usage for conversions to float type (and to double type, if `sizeof(double) < sizeof(long double)`). + +* [*boost 1.47.0 :] + + * Optimizations for "C" and other locales without number grouping. + * Better performance and less memory usage for unsigned char and signed char conversions. + * Better performance and less memory usage for conversions to arithmetic types. + * Better performance and less memory usage for conversions from arithmetic type to arithmetic type. + * Directly construct Target from Source on some conversions (like conversions from string to string, from char array to string, from char to char and others). + +* [*boost 1.34.0 :] + + * Better performance for many combinations of Source and Target types. For more details refer to Alexander Nasonovs article [@http://accu.org/index.php/journals/1375 Fine Tuning for lexical_cast, Overload #74, August 2006] [@http://www.accu.org/var/uploads/journals/overload74.pdf (PDF)]. + +* [*boost 1.33.0 :] + + * Call-by-const reference for the parameters. This requires partial specialization of class templates, so it doesn't work for MSVC 6, and it uses the original pass by value there. + * The MSVC 6 support is deprecated, and will be removed in a future Boost version. + +* [*Earlier :] + + * The previous version of lexical_cast used the default stream precision for reading and writing floating-point numbers. For numerics that have a corresponding specialization of `std::numeric_limits`, the current version now chooses a precision to match. + * The previous version of lexical_cast did not support conversion to or from any wide-character-based types. For compilers with full language and library support for wide characters, `lexical_cast` now supports conversions from `wchar_t`, `wchar_t *`, and `std::wstring` and to `wchar_t` and `std::wstring`. + * The previous version of `lexical_cast` assumed that the conventional stream extractor operators were sufficient for reading values. However, string I/O is asymmetric, with the result that spaces play the role of I/O separators rather than string content. The current version fixes this error for `std::string` and, where supported, `std::wstring`: `lexical_cast("Hello, World")` succeeds instead of failing with a `bad_lexical_cast` exception. + * The previous version of `lexical_cast` allowed unsafe and meaningless conversions to pointers. The current version now throws a `bad_lexical_cast` for conversions to pointers: `lexical_cast("Goodbye, World")` now throws an exception instead of causing undefined behavior. + +[endsect] + +[section Performance] + +In most cases `boost::lexical_cast` is faster than `scanf`, `printf`, `std::stringstream`. For more detailed info you can look at the tables below. + +[section Tests description] +All the tests measure execution speed in milliseconds for 10000 iterations of the following code blocks: +[table:legend Tests source code +[[Test name] [Code]] +[[lexical_cast] + [`` + _out = boost::lexical_cast(_in); + ``] + ] +[[std::stringstream with construction] + [`` + std::stringstream ss; + ss << _in; + if (ss.fail()) throw std::logic_error(descr); + ss >> _out; + if (ss.fail()) throw std::logic_error(descr); + ``] + ] +[[std::stringstream without construction] + [`` + ss << _in; // ss is an instance of std::stringstream + if (ss.fail()) throw std::logic_error(descr); + ss >> _out; + if (ss.fail()) throw std::logic_error(descr); + /* reseting std::stringstream to use it again */ + ss.str(std::string()); + ss.clear(); + ``] + ] +[[scanf/printf] + [`` + typename OUTTYPE::value_type buffer[500]; + sprintf( (char*)buffer, conv, _in); + _out = buffer; + ``] + ] +] +Fastest results are highlitened with "!!! *x* !!!". +Do not use this results to compare compilers, because tests were taken on different hardware. + +[endsect] + +[/ BEGIN of section, generated by performance measuring program ] + +[section clang-linux-2.8][table:id Performance Table (clang-linux-2.8) +[[From->To] [lexical_cast] [std::stringstream with construction] [std::stringstream without construction][scanf/printf]] +[[ string->char ][ !!! *<1* !!! ][ 106 ][ 11 ][ 11 ]] +[[ string->signed char ][ !!! *<1* !!! ][ 102 ][ 8 ][ 8 ]] +[[ string->unsigned char ][ !!! *<1* !!! ][ 83 ][ 7 ][ 15 ]] +[[ string->int ][ !!! *8* !!! ][ 114 ][ 21 ][ 17 ]] +[[ string->short ][ !!! *10* !!! ][ 111 ][ 20 ][ 17 ]] +[[ string->long int ][ !!! *9* !!! ][ 113 ][ 20 ][ 16 ]] +[[ string->long long ][ !!! *9* !!! ][ 112 ][ 21 ][ 16 ]] +[[ string->unsigned int ][ !!! *9* !!! ][ 115 ][ 23 ][ 17 ]] +[[ string->unsigned short ][ !!! *7* !!! ][ 111 ][ 21 ][ 16 ]] +[[ string->unsigned long int ][ !!! *9* !!! ][ 106 ][ 20 ][ 17 ]] +[[ string->unsigned long long ][ !!! *9* !!! ][ 104 ][ 21 ][ 17 ]] +[[ string->bool ][ !!! *<1* !!! ][ 101 ][ 17 ][ 10 ]] +[[ string->float ][ !!! *16* !!! ][ 175 ][ 67 ][ 33 ]] +[[ string->double ][ !!! *18* !!! ][ 196 ][ 91 ][ 56 ]] +[[ string->long double ][ 126 ][ 198 ][ 92 ][ !!! *61* !!! ]] +[[ char->string ][ !!! *12* !!! ][ 101 ][ 16 ][ 12 ]] +[[ unsigned char->string ][ !!! *10* !!! ][ 103 ][ 18 ][ 17 ]] +[[ signed char->string ][ !!! *12* !!! ][ 101 ][ 18 ][ 12 ]] +[[ int->string ][ !!! *19* !!! ][ 124 ][ 25 ][ 19 ]] +[[ short->string ][ 23 ][ 124 ][ 26 ][ !!! *17* !!! ]] +[[ long int->string ][ 20 ][ 123 ][ 23 ][ !!! *17* !!! ]] +[[ long long->string ][ 19 ][ 124 ][ 23 ][ !!! *18* !!! ]] +[[ unsigned int->string ][ 18 ][ 122 ][ 28 ][ !!! *17* !!! ]] +[[ unsigned short->string ][ 36 ][ 160 ][ 31 ][ !!! *17* !!! ]] +[[ unsigned long int->string ][ 22 ][ 123 ][ 28 ][ !!! *18* !!! ]] +[[ unsigned long long->string ][ !!! *23* !!! ][ 137 ][ 32 ][ 23 ]] +[[ bool->string ][ !!! *11* !!! ][ 124 ][ 26 ][ 17 ]] +[[ float->string ][ 178 ][ 273 ][ 124 ][ !!! *57* !!! ]] +[[ double->string ][ 227 ][ 450 ][ 241 ][ !!! *77* !!! ]] +[[ long double->string ][ 249 ][ 331 ][ 185 ][ !!! *85* !!! ]] +[[ char*->char ][ !!! *<1* !!! ][ 109 ][ 9 ][ 11 ]] +[[ char*->signed char ][ !!! *<1* !!! ][ 105 ][ 15 ][ 8 ]] +[[ char*->unsigned char ][ !!! *<1* !!! ][ 111 ][ 11 ][ 20 ]] +[[ char*->int ][ !!! *7* !!! ][ 143 ][ 25 ][ 19 ]] +[[ char*->short ][ !!! *10* !!! ][ 131 ][ 24 ][ 18 ]] +[[ char*->long int ][ !!! *12* !!! ][ 134 ][ 24 ][ 18 ]] +[[ char*->long long ][ !!! *12* !!! ][ 132 ][ 26 ][ 17 ]] +[[ char*->unsigned int ][ !!! *10* !!! ][ 133 ][ 26 ][ 19 ]] +[[ char*->unsigned short ][ !!! *11* !!! ][ 127 ][ 24 ][ 20 ]] +[[ char*->unsigned long int ][ !!! *10* !!! ][ 143 ][ 26 ][ 19 ]] +[[ char*->unsigned long long ][ !!! *12* !!! ][ 137 ][ 26 ][ 19 ]] +[[ char*->bool ][ !!! *2* !!! ][ 138 ][ 27 ][ 13 ]] +[[ char*->float ][ !!! *19* !!! ][ 186 ][ 65 ][ 31 ]] +[[ char*->double ][ !!! *19* !!! ][ 195 ][ 96 ][ 57 ]] +[[ char*->long double ][ 134 ][ 200 ][ 92 ][ !!! *61* !!! ]] +[[ unsigned char*->char ][ !!! *<1* !!! ][ 87 ][ 8 ][ 10 ]] +[[ unsigned char*->signed char ][ !!! *<1* !!! ][ 87 ][ 8 ][ 10 ]] +[[ unsigned char*->unsigned char ][ !!! *<1* !!! ][ 89 ][ 8 ][ 16 ]] +[[ unsigned char*->int ][ !!! *10* !!! ][ 117 ][ 22 ][ 17 ]] +[[ unsigned char*->short ][ !!! *11* !!! ][ 117 ][ 21 ][ 17 ]] +[[ unsigned char*->long int ][ !!! *10* !!! ][ 116 ][ 22 ][ 17 ]] +[[ unsigned char*->long long ][ !!! *9* !!! ][ 116 ][ 22 ][ 17 ]] +[[ unsigned char*->unsigned int ][ !!! *10* !!! ][ 117 ][ 24 ][ 17 ]] +[[ unsigned char*->unsigned short ][ !!! *11* !!! ][ 119 ][ 22 ][ 17 ]] +[[ unsigned char*->unsigned long int ][ !!! *10* !!! ][ 111 ][ 21 ][ 17 ]] +[[ unsigned char*->unsigned long long ][ !!! *10* !!! ][ 109 ][ 21 ][ 17 ]] +[[ unsigned char*->bool ][ !!! *<1* !!! ][ 105 ][ 18 ][ 10 ]] +[[ unsigned char*->float ][ !!! *17* !!! ][ 174 ][ 66 ][ 33 ]] +[[ unsigned char*->double ][ !!! *19* !!! ][ 198 ][ 91 ][ 56 ]] +[[ unsigned char*->long double ][ 129 ][ 200 ][ 92 ][ !!! *58* !!! ]] +[[ unsigned char*->string ][ !!! *12* !!! ][ 122 ][ 20 ][ --- ]] +[[ signed char*->char ][ !!! *<1* !!! ][ 87 ][ 8 ][ 9 ]] +[[ signed char*->signed char ][ !!! *<1* !!! ][ 86 ][ 8 ][ 10 ]] +[[ signed char*->unsigned char ][ !!! *<1* !!! ][ 93 ][ 8 ][ 16 ]] +[[ signed char*->int ][ !!! *10* !!! ][ 117 ][ 21 ][ 17 ]] +[[ signed char*->short ][ !!! *11* !!! ][ 117 ][ 22 ][ 17 ]] +[[ signed char*->long int ][ !!! *10* !!! ][ 115 ][ 21 ][ 17 ]] +[[ signed char*->long long ][ !!! *10* !!! ][ 115 ][ 24 ][ 17 ]] +[[ signed char*->unsigned int ][ !!! *10* !!! ][ 118 ][ 24 ][ 17 ]] +[[ signed char*->unsigned short ][ !!! *11* !!! ][ 139 ][ 27 ][ 20 ]] +[[ signed char*->unsigned long int ][ !!! *9* !!! ][ 144 ][ 27 ][ 19 ]] +[[ signed char*->unsigned long long ][ !!! *7* !!! ][ 127 ][ 25 ][ 22 ]] +[[ signed char*->bool ][ !!! *<1* !!! ][ 123 ][ 23 ][ 9 ]] +[[ signed char*->float ][ !!! *21* !!! ][ 207 ][ 80 ][ 41 ]] +[[ signed char*->double ][ !!! *23* !!! ][ 255 ][ 115 ][ 68 ]] +[[ signed char*->long double ][ 159 ][ 275 ][ 125 ][ !!! *72* !!! ]] +[[ signed char*->string ][ !!! *16* !!! ][ 155 ][ 27 ][ --- ]] +[[ int->int ][ !!! *<1* !!! ][ 150 ][ 32 ][ --- ]] +[[ float->double ][ !!! *<1* !!! ][ 304 ][ 162 ][ --- ]] +[[ double->double ][ !!! *<1* !!! ][ 298 ][ 168 ][ --- ]] +[[ int->int ][ !!! *<1* !!! ][ 311 ][ 154 ][ --- ]] +[[ int->int ][ !!! *<1* !!! ][ 308 ][ 154 ][ --- ]] +[[ char->unsigned char ][ !!! *<1* !!! ][ 97 ][ 9 ][ --- ]] +[[ char->signed char ][ !!! *<1* !!! ][ 94 ][ 11 ][ --- ]] +[[ unsigned char->char ][ !!! *<1* !!! ][ 106 ][ 8 ][ --- ]] +[[ signed char->char ][ !!! *<1* !!! ][ 111 ][ 8 ][ --- ]] +] +[endsect] +[section gcc-4.3][table:id Performance Table (gcc-4.3) +[[From->To] [lexical_cast] [std::stringstream with construction] [std::stringstream without construction][scanf/printf]] +[[ string->char ][ !!! *<1* !!! ][ 92 ][ 7 ][ 8 ]] +[[ string->signed char ][ !!! *<1* !!! ][ 92 ][ 7 ][ 8 ]] +[[ string->unsigned char ][ !!! *<1* !!! ][ 92 ][ 7 ][ 13 ]] +[[ string->int ][ !!! *6* !!! ][ 115 ][ 21 ][ 14 ]] +[[ string->short ][ !!! *7* !!! ][ 141 ][ 26 ][ 24 ]] +[[ string->long int ][ !!! *7* !!! ][ 141 ][ 27 ][ 18 ]] +[[ string->long long ][ !!! *7* !!! ][ 153 ][ 28 ][ 17 ]] +[[ string->unsigned int ][ !!! *7* !!! ][ 156 ][ 26 ][ 18 ]] +[[ string->unsigned short ][ !!! *8* !!! ][ 146 ][ 25 ][ 18 ]] +[[ string->unsigned long int ][ !!! *9* !!! ][ 143 ][ 29 ][ 37 ]] +[[ string->unsigned long long ][ !!! *14* !!! ][ 135 ][ 20 ][ 15 ]] +[[ string->bool ][ !!! *<1* !!! ][ 117 ][ 20 ][ 8 ]] +[[ string->float ][ !!! *15* !!! ][ 177 ][ 63 ][ 31 ]] +[[ string->double ][ !!! *15* !!! ][ 198 ][ 89 ][ 54 ]] +[[ string->long double ][ 133 ][ 198 ][ 88 ][ !!! *55* !!! ]] +[[ char->string ][ !!! *10* !!! ][ 108 ][ 16 ][ 12 ]] +[[ unsigned char->string ][ !!! *10* !!! ][ 119 ][ 18 ][ 15 ]] +[[ signed char->string ][ !!! *10* !!! ][ 111 ][ 24 ][ 11 ]] +[[ int->string ][ !!! *14* !!! ][ 129 ][ 22 ][ 15 ]] +[[ short->string ][ !!! *14* !!! ][ 128 ][ 22 ][ 17 ]] +[[ long int->string ][ !!! *14* !!! ][ 127 ][ 21 ][ 17 ]] +[[ long long->string ][ !!! *14* !!! ][ 127 ][ 22 ][ 18 ]] +[[ unsigned int->string ][ !!! *15* !!! ][ 124 ][ 22 ][ 17 ]] +[[ unsigned short->string ][ 16 ][ 125 ][ 22 ][ !!! *15* !!! ]] +[[ unsigned long int->string ][ !!! *15* !!! ][ 125 ][ 22 ][ 17 ]] +[[ unsigned long long->string ][ !!! *18* !!! ][ 138 ][ 34 ][ 23 ]] +[[ bool->string ][ !!! *7* !!! ][ 120 ][ 22 ][ 12 ]] +[[ float->string ][ 136 ][ 229 ][ 110 ][ !!! *48* !!! ]] +[[ double->string ][ 184 ][ 270 ][ 136 ][ !!! *67* !!! ]] +[[ long double->string ][ 198 ][ 264 ][ 148 ][ !!! *69* !!! ]] +[[ char*->char ][ !!! *<1* !!! ][ 98 ][ 8 ][ 8 ]] +[[ char*->signed char ][ !!! *<1* !!! ][ 99 ][ 8 ][ 8 ]] +[[ char*->unsigned char ][ !!! *<1* !!! ][ 96 ][ 8 ][ 14 ]] +[[ char*->int ][ !!! *8* !!! ][ 120 ][ 21 ][ 15 ]] +[[ char*->short ][ !!! *8* !!! ][ 122 ][ 22 ][ 16 ]] +[[ char*->long int ][ !!! *8* !!! ][ 122 ][ 24 ][ 16 ]] +[[ char*->long long ][ !!! *8* !!! ][ 120 ][ 23 ][ 14 ]] +[[ char*->unsigned int ][ !!! *7* !!! ][ 123 ][ 23 ][ 15 ]] +[[ char*->unsigned short ][ !!! *8* !!! ][ 123 ][ 24 ][ 15 ]] +[[ char*->unsigned long int ][ !!! *8* !!! ][ 121 ][ 22 ][ 14 ]] +[[ char*->unsigned long long ][ !!! *7* !!! ][ 116 ][ 20 ][ 16 ]] +[[ char*->bool ][ !!! *<1* !!! ][ 107 ][ 18 ][ 10 ]] +[[ char*->float ][ !!! *14* !!! ][ 181 ][ 67 ][ 32 ]] +[[ char*->double ][ !!! *16* !!! ][ 197 ][ 88 ][ 53 ]] +[[ char*->long double ][ 127 ][ 208 ][ 93 ][ !!! *56* !!! ]] +[[ unsigned char*->char ][ !!! *<1* !!! ][ 94 ][ 8 ][ 8 ]] +[[ unsigned char*->signed char ][ !!! *<1* !!! ][ 93 ][ 8 ][ 10 ]] +[[ unsigned char*->unsigned char ][ !!! *<1* !!! ][ 94 ][ 8 ][ 15 ]] +[[ unsigned char*->int ][ !!! *7* !!! ][ 117 ][ 21 ][ 16 ]] +[[ unsigned char*->short ][ !!! *8* !!! ][ 119 ][ 21 ][ 16 ]] +[[ unsigned char*->long int ][ !!! *7* !!! ][ 117 ][ 22 ][ 16 ]] +[[ unsigned char*->long long ][ !!! *8* !!! ][ 119 ][ 23 ][ 16 ]] +[[ unsigned char*->unsigned int ][ !!! *10* !!! ][ 123 ][ 20 ][ 15 ]] +[[ unsigned char*->unsigned short ][ !!! *8* !!! ][ 122 ][ 24 ][ 15 ]] +[[ unsigned char*->unsigned long int ][ !!! *8* !!! ][ 120 ][ 21 ][ 14 ]] +[[ unsigned char*->unsigned long long ][ !!! *8* !!! ][ 118 ][ 23 ][ 16 ]] +[[ unsigned char*->bool ][ !!! *1* !!! ][ 108 ][ 18 ][ 8 ]] +[[ unsigned char*->float ][ !!! *13* !!! ][ 182 ][ 63 ][ 30 ]] +[[ unsigned char*->double ][ !!! *16* !!! ][ 204 ][ 87 ][ 53 ]] +[[ unsigned char*->long double ][ 126 ][ 206 ][ 90 ][ !!! *60* !!! ]] +[[ unsigned char*->string ][ !!! *9* !!! ][ 123 ][ 21 ][ --- ]] +[[ signed char*->char ][ !!! *<1* !!! ][ 95 ][ 8 ][ 10 ]] +[[ signed char*->signed char ][ !!! *<1* !!! ][ 94 ][ 8 ][ 10 ]] +[[ signed char*->unsigned char ][ !!! *<1* !!! ][ 94 ][ 8 ][ 15 ]] +[[ signed char*->int ][ !!! *8* !!! ][ 117 ][ 22 ][ 16 ]] +[[ signed char*->short ][ !!! *7* !!! ][ 117 ][ 22 ][ 16 ]] +[[ signed char*->long int ][ !!! *8* !!! ][ 118 ][ 25 ][ 15 ]] +[[ signed char*->long long ][ !!! *7* !!! ][ 117 ][ 24 ][ 16 ]] +[[ signed char*->unsigned int ][ !!! *7* !!! ][ 120 ][ 20 ][ 16 ]] +[[ signed char*->unsigned short ][ !!! *8* !!! ][ 124 ][ 24 ][ 15 ]] +[[ signed char*->unsigned long int ][ !!! *8* !!! ][ 115 ][ 21 ][ 16 ]] +[[ signed char*->unsigned long long ][ !!! *9* !!! ][ 120 ][ 21 ][ 16 ]] +[[ signed char*->bool ][ !!! *1* !!! ][ 112 ][ 19 ][ 8 ]] +[[ signed char*->float ][ !!! *14* !!! ][ 183 ][ 64 ][ 31 ]] +[[ signed char*->double ][ !!! *18* !!! ][ 208 ][ 87 ][ 51 ]] +[[ signed char*->long double ][ 126 ][ 217 ][ 94 ][ !!! *55* !!! ]] +[[ signed char*->string ][ !!! *12* !!! ][ 126 ][ 22 ][ --- ]] +[[ int->int ][ !!! *<1* !!! ][ 146 ][ 23 ][ --- ]] +[[ float->double ][ !!! *<1* !!! ][ 275 ][ 139 ][ --- ]] +[[ double->double ][ !!! *<1* !!! ][ 270 ][ 142 ][ --- ]] +[[ int->int ][ !!! *<1* !!! ][ 281 ][ 145 ][ --- ]] +[[ int->int ][ !!! *<1* !!! ][ 301 ][ 145 ][ --- ]] +[[ char->unsigned char ][ !!! *<1* !!! ][ 96 ][ 7 ][ --- ]] +[[ char->signed char ][ !!! *<1* !!! ][ 95 ][ 7 ][ --- ]] +[[ unsigned char->char ][ !!! *<1* !!! ][ 96 ][ 7 ][ --- ]] +[[ signed char->char ][ !!! *<1* !!! ][ 91 ][ 7 ][ --- ]] +] +[endsect] +[section gcc-4.4][table:id Performance Table (gcc-4.4) +[[From->To] [lexical_cast] [std::stringstream with construction] [std::stringstream without construction][scanf/printf]] +[[ string->char ][ !!! *<1* !!! ][ 81 ][ 8 ][ 8 ]] +[[ string->signed char ][ !!! *<1* !!! ][ 110 ][ 7 ][ 9 ]] +[[ string->unsigned char ][ !!! *<1* !!! ][ 94 ][ 8 ][ 18 ]] +[[ string->int ][ !!! *9* !!! ][ 125 ][ 25 ][ 15 ]] +[[ string->short ][ !!! *7* !!! ][ 113 ][ 25 ][ 15 ]] +[[ string->long int ][ !!! *8* !!! ][ 112 ][ 24 ][ 15 ]] +[[ string->long long ][ !!! *8* !!! ][ 109 ][ 22 ][ 15 ]] +[[ string->unsigned int ][ !!! *8* !!! ][ 108 ][ 26 ][ 20 ]] +[[ string->unsigned short ][ !!! *9* !!! ][ 125 ][ 22 ][ 18 ]] +[[ string->unsigned long int ][ !!! *11* !!! ][ 125 ][ 32 ][ 17 ]] +[[ string->unsigned long long ][ !!! *10* !!! ][ 119 ][ 23 ][ 19 ]] +[[ string->bool ][ !!! *<1* !!! ][ 132 ][ 24 ][ 11 ]] +[[ string->float ][ !!! *18* !!! ][ 178 ][ 75 ][ 37 ]] +[[ string->double ][ !!! *24* !!! ][ 236 ][ 100 ][ 64 ]] +[[ string->long double ][ 146 ][ 233 ][ 118 ][ !!! *75* !!! ]] +[[ char->string ][ !!! *8* !!! ][ 136 ][ 22 ][ 13 ]] +[[ unsigned char->string ][ !!! *11* !!! ][ 127 ][ 22 ][ 20 ]] +[[ signed char->string ][ !!! *11* !!! ][ 128 ][ 21 ][ 15 ]] +[[ int->string ][ 25 ][ 159 ][ 30 ][ !!! *20* !!! ]] +[[ short->string ][ 25 ][ 151 ][ 30 ][ !!! *20* !!! ]] +[[ long int->string ][ !!! *20* !!! ][ 150 ][ 30 ][ 20 ]] +[[ long long->string ][ !!! *19* !!! ][ 164 ][ 26 ][ 21 ]] +[[ unsigned int->string ][ 35 ][ 147 ][ 27 ][ !!! *20* !!! ]] +[[ unsigned short->string ][ 26 ][ 149 ][ 26 ][ !!! *20* !!! ]] +[[ unsigned long int->string ][ 19 ][ 142 ][ 38 ][ !!! *17* !!! ]] +[[ unsigned long long->string ][ !!! *20* !!! ][ 139 ][ 36 ][ 26 ]] +[[ bool->string ][ !!! *10* !!! ][ 144 ][ 28 ][ 13 ]] +[[ float->string ][ 166 ][ 268 ][ 127 ][ !!! *52* !!! ]] +[[ double->string ][ 192 ][ 285 ][ 170 ][ !!! *90* !!! ]] +[[ long double->string ][ 250 ][ 344 ][ 160 ][ !!! *85* !!! ]] +[[ char*->char ][ !!! *<1* !!! ][ 90 ][ 9 ][ 8 ]] +[[ char*->signed char ][ !!! *<1* !!! ][ 82 ][ 9 ][ 8 ]] +[[ char*->unsigned char ][ !!! *<1* !!! ][ 88 ][ 8 ][ 13 ]] +[[ char*->int ][ !!! *6* !!! ][ 113 ][ 26 ][ 14 ]] +[[ char*->short ][ !!! *6* !!! ][ 114 ][ 25 ][ 14 ]] +[[ char*->long int ][ !!! *6* !!! ][ 123 ][ 38 ][ 17 ]] +[[ char*->long long ][ !!! *7* !!! ][ 126 ][ 37 ][ 17 ]] +[[ char*->unsigned int ][ !!! *6* !!! ][ 134 ][ 26 ][ 18 ]] +[[ char*->unsigned short ][ !!! *8* !!! ][ 126 ][ 24 ][ 17 ]] +[[ char*->unsigned long int ][ !!! *8* !!! ][ 121 ][ 24 ][ 17 ]] +[[ char*->unsigned long long ][ !!! *5* !!! ][ 117 ][ 24 ][ 18 ]] +[[ char*->bool ][ !!! *<1* !!! ][ 116 ][ 24 ][ 9 ]] +[[ char*->float ][ !!! *16* !!! ][ 171 ][ 67 ][ 30 ]] +[[ char*->double ][ !!! *15* !!! ][ 204 ][ 109 ][ 64 ]] +[[ char*->long double ][ 152 ][ 250 ][ 110 ][ !!! *71* !!! ]] +[[ unsigned char*->char ][ !!! *<1* !!! ][ 109 ][ 11 ][ 11 ]] +[[ unsigned char*->signed char ][ !!! *<1* !!! ][ 108 ][ 11 ][ 9 ]] +[[ unsigned char*->unsigned char ][ !!! *<1* !!! ][ 106 ][ 11 ][ 17 ]] +[[ unsigned char*->int ][ !!! *7* !!! ][ 143 ][ 31 ][ 17 ]] +[[ unsigned char*->short ][ !!! *9* !!! ][ 143 ][ 32 ][ 19 ]] +[[ unsigned char*->long int ][ !!! *8* !!! ][ 153 ][ 30 ][ 18 ]] +[[ unsigned char*->long long ][ !!! *10* !!! ][ 146 ][ 27 ][ 18 ]] +[[ unsigned char*->unsigned int ][ !!! *9* !!! ][ 144 ][ 25 ][ 18 ]] +[[ unsigned char*->unsigned short ][ !!! *9* !!! ][ 138 ][ 26 ][ 17 ]] +[[ unsigned char*->unsigned long int ][ !!! *9* !!! ][ 143 ][ 25 ][ 18 ]] +[[ unsigned char*->unsigned long long ][ !!! *10* !!! ][ 132 ][ 26 ][ 18 ]] +[[ unsigned char*->bool ][ !!! *<1* !!! ][ 102 ][ 18 ][ 9 ]] +[[ unsigned char*->float ][ !!! *13* !!! ][ 171 ][ 65 ][ 31 ]] +[[ unsigned char*->double ][ !!! *14* !!! ][ 197 ][ 89 ][ 53 ]] +[[ unsigned char*->long double ][ 122 ][ 208 ][ 89 ][ !!! *58* !!! ]] +[[ unsigned char*->string ][ !!! *8* !!! ][ 115 ][ 20 ][ --- ]] +[[ signed char*->char ][ !!! *<1* !!! ][ 93 ][ 10 ][ 9 ]] +[[ signed char*->signed char ][ !!! *<1* !!! ][ 91 ][ 8 ][ 8 ]] +[[ signed char*->unsigned char ][ !!! *<1* !!! ][ 90 ][ 10 ][ 15 ]] +[[ signed char*->int ][ !!! *7* !!! ][ 112 ][ 26 ][ 16 ]] +[[ signed char*->short ][ !!! *7* !!! ][ 112 ][ 26 ][ 16 ]] +[[ signed char*->long int ][ !!! *6* !!! ][ 118 ][ 25 ][ 14 ]] +[[ signed char*->long long ][ !!! *13* !!! ][ 114 ][ 25 ][ 14 ]] +[[ signed char*->unsigned int ][ !!! *7* !!! ][ 114 ][ 23 ][ 16 ]] +[[ signed char*->unsigned short ][ !!! *7* !!! ][ 107 ][ 25 ][ 16 ]] +[[ signed char*->unsigned long int ][ !!! *7* !!! ][ 106 ][ 23 ][ 14 ]] +[[ signed char*->unsigned long long ][ !!! *7* !!! ][ 103 ][ 22 ][ 16 ]] +[[ signed char*->bool ][ !!! *<1* !!! ][ 110 ][ 20 ][ 9 ]] +[[ signed char*->float ][ !!! *13* !!! ][ 175 ][ 66 ][ 32 ]] +[[ signed char*->double ][ !!! *14* !!! ][ 203 ][ 90 ][ 53 ]] +[[ signed char*->long double ][ 124 ][ 205 ][ 87 ][ !!! *55* !!! ]] +[[ signed char*->string ][ !!! *8* !!! ][ 120 ][ 20 ][ --- ]] +[[ int->int ][ !!! *<1* !!! ][ 116 ][ 28 ][ --- ]] +[[ float->double ][ !!! *<1* !!! ][ 264 ][ 135 ][ --- ]] +[[ double->double ][ !!! *<1* !!! ][ 260 ][ 140 ][ --- ]] +[[ int->int ][ !!! *<1* !!! ][ 275 ][ 135 ][ --- ]] +[[ int->int ][ !!! *<1* !!! ][ 274 ][ 135 ][ --- ]] +[[ char->unsigned char ][ !!! *<1* !!! ][ 77 ][ 7 ][ --- ]] +[[ char->signed char ][ !!! *<1* !!! ][ 79 ][ 7 ][ --- ]] +[[ unsigned char->char ][ !!! *<1* !!! ][ 78 ][ 8 ][ --- ]] +[[ signed char->char ][ !!! *<1* !!! ][ 83 ][ 7 ][ --- ]] +] +[endsect] +[section gcc-4.5][table:id Performance Table (gcc-4.5) +[[From->To] [lexical_cast] [std::stringstream with construction] [std::stringstream without construction][scanf/printf]] +[[ string->char ][ !!! *<1* !!! ][ 86 ][ 8 ][ 9 ]] +[[ string->signed char ][ !!! *<1* !!! ][ 88 ][ 9 ][ 9 ]] +[[ string->unsigned char ][ !!! *<1* !!! ][ 87 ][ 8 ][ 15 ]] +[[ string->int ][ !!! *6* !!! ][ 107 ][ 23 ][ 16 ]] +[[ string->short ][ !!! *7* !!! ][ 108 ][ 25 ][ 15 ]] +[[ string->long int ][ !!! *6* !!! ][ 110 ][ 26 ][ 15 ]] +[[ string->long long ][ !!! *7* !!! ][ 110 ][ 26 ][ 15 ]] +[[ string->unsigned int ][ !!! *6* !!! ][ 108 ][ 26 ][ 16 ]] +[[ string->unsigned short ][ !!! *7* !!! ][ 105 ][ 24 ][ 15 ]] +[[ string->unsigned long int ][ !!! *6* !!! ][ 108 ][ 23 ][ 15 ]] +[[ string->unsigned long long ][ !!! *10* !!! ][ 104 ][ 24 ][ 15 ]] +[[ string->bool ][ !!! *<1* !!! ][ 102 ][ 21 ][ 9 ]] +[[ string->float ][ !!! *13* !!! ][ 173 ][ 64 ][ 34 ]] +[[ string->double ][ !!! *15* !!! ][ 196 ][ 89 ][ 53 ]] +[[ string->long double ][ 126 ][ 211 ][ 90 ][ !!! *56* !!! ]] +[[ char->string ][ !!! *8* !!! ][ 107 ][ 20 ][ 10 ]] +[[ unsigned char->string ][ !!! *8* !!! ][ 107 ][ 17 ][ 15 ]] +[[ signed char->string ][ !!! *8* !!! ][ 108 ][ 19 ][ 10 ]] +[[ int->string ][ 16 ][ 129 ][ 25 ][ !!! *15* !!! ]] +[[ short->string ][ !!! *14* !!! ][ 128 ][ 25 ][ 17 ]] +[[ long int->string ][ 20 ][ 128 ][ 24 ][ !!! *15* !!! ]] +[[ long long->string ][ !!! *16* !!! ][ 128 ][ 25 ][ 16 ]] +[[ unsigned int->string ][ !!! *15* !!! ][ 125 ][ 25 ][ 15 ]] +[[ unsigned short->string ][ !!! *14* !!! ][ 125 ][ 24 ][ 15 ]] +[[ unsigned long int->string ][ 16 ][ 125 ][ 25 ][ !!! *15* !!! ]] +[[ unsigned long long->string ][ !!! *18* !!! ][ 140 ][ 32 ][ 22 ]] +[[ bool->string ][ !!! *8* !!! ][ 121 ][ 24 ][ 10 ]] +[[ float->string ][ 137 ][ 226 ][ 108 ][ !!! *48* !!! ]] +[[ double->string ][ 174 ][ 255 ][ 141 ][ !!! *71* !!! ]] +[[ long double->string ][ 208 ][ 268 ][ 144 ][ !!! *72* !!! ]] +[[ char*->char ][ !!! *<1* !!! ][ 93 ][ 8 ][ 9 ]] +[[ char*->signed char ][ !!! *<1* !!! ][ 94 ][ 9 ][ 9 ]] +[[ char*->unsigned char ][ !!! *<1* !!! ][ 94 ][ 8 ][ 15 ]] +[[ char*->int ][ !!! *7* !!! ][ 115 ][ 26 ][ 16 ]] +[[ char*->short ][ !!! *8* !!! ][ 114 ][ 26 ][ 15 ]] +[[ char*->long int ][ !!! *7* !!! ][ 115 ][ 27 ][ 16 ]] +[[ char*->long long ][ !!! *7* !!! ][ 114 ][ 26 ][ 16 ]] +[[ char*->unsigned int ][ !!! *8* !!! ][ 115 ][ 25 ][ 16 ]] +[[ char*->unsigned short ][ !!! *7* !!! ][ 113 ][ 24 ][ 16 ]] +[[ char*->unsigned long int ][ !!! *8* !!! ][ 117 ][ 23 ][ 16 ]] +[[ char*->unsigned long long ][ !!! *8* !!! ][ 107 ][ 25 ][ 16 ]] +[[ char*->bool ][ !!! *<1* !!! ][ 110 ][ 21 ][ 9 ]] +[[ char*->float ][ !!! *17* !!! ][ 170 ][ 67 ][ 34 ]] +[[ char*->double ][ !!! *14* !!! ][ 197 ][ 91 ][ 52 ]] +[[ char*->long double ][ 127 ][ 206 ][ 89 ][ !!! *56* !!! ]] +[[ unsigned char*->char ][ !!! *<1* !!! ][ 83 ][ 8 ][ 9 ]] +[[ unsigned char*->signed char ][ !!! *<1* !!! ][ 83 ][ 10 ][ 9 ]] +[[ unsigned char*->unsigned char ][ !!! *<1* !!! ][ 83 ][ 8 ][ 15 ]] +[[ unsigned char*->int ][ !!! *7* !!! ][ 113 ][ 26 ][ 16 ]] +[[ unsigned char*->short ][ !!! *7* !!! ][ 112 ][ 24 ][ 16 ]] +[[ unsigned char*->long int ][ !!! *8* !!! ][ 114 ][ 26 ][ 16 ]] +[[ unsigned char*->long long ][ !!! *8* !!! ][ 113 ][ 26 ][ 16 ]] +[[ unsigned char*->unsigned int ][ !!! *8* !!! ][ 114 ][ 25 ][ 16 ]] +[[ unsigned char*->unsigned short ][ !!! *8* !!! ][ 109 ][ 24 ][ 16 ]] +[[ unsigned char*->unsigned long int ][ !!! *8* !!! ][ 111 ][ 23 ][ 16 ]] +[[ unsigned char*->unsigned long long ][ !!! *7* !!! ][ 106 ][ 25 ][ 16 ]] +[[ unsigned char*->bool ][ !!! *<1* !!! ][ 106 ][ 20 ][ 9 ]] +[[ unsigned char*->float ][ !!! *14* !!! ][ 169 ][ 65 ][ 34 ]] +[[ unsigned char*->double ][ !!! *16* !!! ][ 198 ][ 91 ][ 52 ]] +[[ unsigned char*->long double ][ 127 ][ 205 ][ 88 ][ !!! *56* !!! ]] +[[ unsigned char*->string ][ !!! *10* !!! ][ 123 ][ 21 ][ --- ]] +[[ signed char*->char ][ !!! *<1* !!! ][ 90 ][ 9 ][ 9 ]] +[[ signed char*->signed char ][ !!! *<1* !!! ][ 91 ][ 8 ][ 9 ]] +[[ signed char*->unsigned char ][ !!! *<1* !!! ][ 92 ][ 8 ][ 15 ]] +[[ signed char*->int ][ !!! *7* !!! ][ 116 ][ 26 ][ 16 ]] +[[ signed char*->short ][ !!! *8* !!! ][ 113 ][ 26 ][ 15 ]] +[[ signed char*->long int ][ !!! *8* !!! ][ 113 ][ 24 ][ 16 ]] +[[ signed char*->long long ][ !!! *8* !!! ][ 113 ][ 27 ][ 16 ]] +[[ signed char*->unsigned int ][ !!! *8* !!! ][ 113 ][ 25 ][ 16 ]] +[[ signed char*->unsigned short ][ !!! *7* !!! ][ 107 ][ 24 ][ 16 ]] +[[ signed char*->unsigned long int ][ !!! *7* !!! ][ 111 ][ 23 ][ 17 ]] +[[ signed char*->unsigned long long ][ !!! *8* !!! ][ 105 ][ 25 ][ 16 ]] +[[ signed char*->bool ][ !!! *<1* !!! ][ 106 ][ 21 ][ 9 ]] +[[ signed char*->float ][ !!! *13* !!! ][ 169 ][ 63 ][ 34 ]] +[[ signed char*->double ][ !!! *16* !!! ][ 196 ][ 90 ][ 52 ]] +[[ signed char*->long double ][ 127 ][ 211 ][ 91 ][ !!! *60* !!! ]] +[[ signed char*->string ][ !!! *9* !!! ][ 123 ][ 21 ][ --- ]] +[[ int->int ][ !!! *<1* !!! ][ 120 ][ 29 ][ --- ]] +[[ float->double ][ !!! *<1* !!! ][ 258 ][ 147 ][ --- ]] +[[ double->double ][ !!! *<1* !!! ][ 261 ][ 140 ][ --- ]] +[[ int->int ][ !!! *<1* !!! ][ 266 ][ 138 ][ --- ]] +[[ int->int ][ !!! *<1* !!! ][ 266 ][ 137 ][ --- ]] +[[ char->unsigned char ][ !!! *<1* !!! ][ 89 ][ 8 ][ --- ]] +[[ char->signed char ][ !!! *<1* !!! ][ 91 ][ 8 ][ --- ]] +[[ unsigned char->char ][ !!! *<1* !!! ][ 90 ][ 9 ][ --- ]] +[[ signed char->char ][ !!! *<1* !!! ][ 89 ][ 8 ][ --- ]] +] +[endsect] +[section intel-12-linux][table:id Performance Table (intel-12-linux) +[[From->To] [lexical_cast] [std::stringstream with construction] [std::stringstream without construction][scanf/printf]] +[[ string->char ][ !!! *1* !!! ][ 87 ][ 9 ][ 8 ]] +[[ string->signed char ][ !!! *<1* !!! ][ 90 ][ 9 ][ 8 ]] +[[ string->unsigned char ][ !!! *<1* !!! ][ 99 ][ 9 ][ 20 ]] +[[ string->int ][ !!! *8* !!! ][ 112 ][ 24 ][ 16 ]] +[[ string->short ][ !!! *8* !!! ][ 110 ][ 26 ][ 16 ]] +[[ string->long int ][ !!! *7* !!! ][ 110 ][ 23 ][ 16 ]] +[[ string->long long ][ !!! *10* !!! ][ 114 ][ 31 ][ 16 ]] +[[ string->unsigned int ][ !!! *7* !!! ][ 122 ][ 25 ][ 16 ]] +[[ string->unsigned short ][ !!! *7* !!! ][ 120 ][ 27 ][ 16 ]] +[[ string->unsigned long int ][ !!! *7* !!! ][ 114 ][ 25 ][ 16 ]] +[[ string->unsigned long long ][ !!! *7* !!! ][ 128 ][ 23 ][ 25 ]] +[[ string->bool ][ !!! *1* !!! ][ 103 ][ 20 ][ 9 ]] +[[ string->float ][ !!! *15* !!! ][ 166 ][ 73 ][ 31 ]] +[[ string->double ][ !!! *19* !!! ][ 206 ][ 103 ][ 56 ]] +[[ string->long double ][ 142 ][ 205 ][ 106 ][ !!! *61* !!! ]] +[[ char->string ][ !!! *10* !!! ][ 111 ][ 19 ][ 12 ]] +[[ unsigned char->string ][ !!! *12* !!! ][ 109 ][ 19 ][ 16 ]] +[[ signed char->string ][ !!! *9* !!! ][ 110 ][ 18 ][ 12 ]] +[[ int->string ][ 19 ][ 126 ][ 23 ][ !!! *17* !!! ]] +[[ short->string ][ 20 ][ 127 ][ 23 ][ !!! *18* !!! ]] +[[ long int->string ][ 20 ][ 128 ][ 24 ][ !!! *18* !!! ]] +[[ long long->string ][ !!! *16* !!! ][ 129 ][ 23 ][ 22 ]] +[[ unsigned int->string ][ 20 ][ 126 ][ 23 ][ !!! *17* !!! ]] +[[ unsigned short->string ][ 20 ][ 126 ][ 23 ][ !!! *17* !!! ]] +[[ unsigned long int->string ][ 20 ][ 126 ][ 23 ][ !!! *17* !!! ]] +[[ unsigned long long->string ][ !!! *24* !!! ][ 134 ][ 35 ][ 24 ]] +[[ bool->string ][ !!! *9* !!! ][ 124 ][ 29 ][ 12 ]] +[[ float->string ][ 147 ][ 218 ][ 104 ][ !!! *48* !!! ]] +[[ double->string ][ 202 ][ 245 ][ 128 ][ !!! *68* !!! ]] +[[ long double->string ][ 199 ][ 236 ][ 128 ][ !!! *69* !!! ]] +[[ char*->char ][ !!! *1* !!! ][ 91 ][ 10 ][ 9 ]] +[[ char*->signed char ][ !!! *1* !!! ][ 98 ][ 10 ][ 9 ]] +[[ char*->unsigned char ][ !!! *1* !!! ][ 97 ][ 14 ][ 15 ]] +[[ char*->int ][ !!! *8* !!! ][ 114 ][ 24 ][ 16 ]] +[[ char*->short ][ !!! *8* !!! ][ 112 ][ 27 ][ 15 ]] +[[ char*->long int ][ !!! *8* !!! ][ 117 ][ 28 ][ 16 ]] +[[ char*->long long ][ !!! *8* !!! ][ 123 ][ 30 ][ 16 ]] +[[ char*->unsigned int ][ !!! *8* !!! ][ 120 ][ 26 ][ 16 ]] +[[ char*->unsigned short ][ !!! *8* !!! ][ 122 ][ 30 ][ 16 ]] +[[ char*->unsigned long int ][ !!! *10* !!! ][ 119 ][ 25 ][ 16 ]] +[[ char*->unsigned long long ][ !!! *8* !!! ][ 140 ][ 54 ][ 34 ]] +[[ char*->bool ][ !!! *1* !!! ][ 108 ][ 21 ][ 8 ]] +[[ char*->float ][ !!! *16* !!! ][ 177 ][ 76 ][ 33 ]] +[[ char*->double ][ !!! *18* !!! ][ 271 ][ 104 ][ 56 ]] +[[ char*->long double ][ 142 ][ 207 ][ 106 ][ !!! *61* !!! ]] +[[ unsigned char*->char ][ !!! *1* !!! ][ 91 ][ 10 ][ 9 ]] +[[ unsigned char*->signed char ][ !!! *1* !!! ][ 92 ][ 10 ][ 8 ]] +[[ unsigned char*->unsigned char ][ !!! *1* !!! ][ 92 ][ 10 ][ 15 ]] +[[ unsigned char*->int ][ !!! *8* !!! ][ 111 ][ 24 ][ 16 ]] +[[ unsigned char*->short ][ !!! *9* !!! ][ 113 ][ 27 ][ 16 ]] +[[ unsigned char*->long int ][ !!! *7* !!! ][ 113 ][ 28 ][ 16 ]] +[[ unsigned char*->long long ][ !!! *7* !!! ][ 120 ][ 29 ][ 15 ]] +[[ unsigned char*->unsigned int ][ !!! *7* !!! ][ 119 ][ 24 ][ 15 ]] +[[ unsigned char*->unsigned short ][ !!! *8* !!! ][ 116 ][ 28 ][ 15 ]] +[[ unsigned char*->unsigned long int ][ !!! *7* !!! ][ 118 ][ 25 ][ 16 ]] +[[ unsigned char*->unsigned long long ][ !!! *7* !!! ][ 116 ][ 25 ][ 16 ]] +[[ unsigned char*->bool ][ !!! *1* !!! ][ 102 ][ 20 ][ 9 ]] +[[ unsigned char*->float ][ !!! *16* !!! ][ 167 ][ 74 ][ 31 ]] +[[ unsigned char*->double ][ !!! *19* !!! ][ 231 ][ 109 ][ 55 ]] +[[ unsigned char*->long double ][ 141 ][ 214 ][ 109 ][ !!! *61* !!! ]] +[[ unsigned char*->string ][ !!! *12* !!! ][ 122 ][ 23 ][ --- ]] +[[ signed char*->char ][ !!! *1* !!! ][ 91 ][ 10 ][ 8 ]] +[[ signed char*->signed char ][ !!! *1* !!! ][ 92 ][ 10 ][ 9 ]] +[[ signed char*->unsigned char ][ !!! *1* !!! ][ 92 ][ 10 ][ 15 ]] +[[ signed char*->int ][ !!! *7* !!! ][ 117 ][ 34 ][ 16 ]] +[[ signed char*->short ][ !!! *8* !!! ][ 117 ][ 25 ][ 15 ]] +[[ signed char*->long int ][ !!! *7* !!! ][ 115 ][ 28 ][ 16 ]] +[[ signed char*->long long ][ !!! *8* !!! ][ 116 ][ 31 ][ 15 ]] +[[ signed char*->unsigned int ][ !!! *8* !!! ][ 123 ][ 27 ][ 16 ]] +[[ signed char*->unsigned short ][ !!! *8* !!! ][ 120 ][ 27 ][ 16 ]] +[[ signed char*->unsigned long int ][ !!! *7* !!! ][ 119 ][ 26 ][ 16 ]] +[[ signed char*->unsigned long long ][ !!! *7* !!! ][ 118 ][ 26 ][ 17 ]] +[[ signed char*->bool ][ !!! *1* !!! ][ 108 ][ 26 ][ 9 ]] +[[ signed char*->float ][ !!! *16* !!! ][ 170 ][ 73 ][ 31 ]] +[[ signed char*->double ][ !!! *18* !!! ][ 210 ][ 112 ][ 55 ]] +[[ signed char*->long double ][ 137 ][ 210 ][ 107 ][ !!! *61* !!! ]] +[[ signed char*->string ][ !!! *14* !!! ][ 121 ][ 23 ][ --- ]] +[[ int->int ][ !!! *<1* !!! ][ 115 ][ 26 ][ --- ]] +[[ float->double ][ !!! *<1* !!! ][ 266 ][ 155 ][ --- ]] +[[ double->double ][ !!! *<1* !!! ][ 267 ][ 157 ][ --- ]] +[[ int->int ][ !!! *<1* !!! ][ 261 ][ 153 ][ --- ]] +[[ int->int ][ !!! *<1* !!! ][ 264 ][ 152 ][ --- ]] +[[ char->unsigned char ][ !!! *<1* !!! ][ 96 ][ 9 ][ --- ]] +[[ char->signed char ][ !!! *<1* !!! ][ 96 ][ 9 ][ --- ]] +[[ unsigned char->char ][ !!! *<1* !!! ][ 93 ][ 9 ][ --- ]] +[[ signed char->char ][ !!! *<1* !!! ][ 87 ][ 9 ][ --- ]] +] +[endsect] + + + +[/ END of section, generated by performance measuring program ] +[endsect] + From fa7f4ba7a729b6d42258ba7db9173d9b5d8e5e29 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 21 Jul 2011 07:35:29 +0000 Subject: [PATCH 17/39] Link up the new lexical cast documentation. [SVN r73267] --- index.html | 2 +- lexical_cast.htm | 362 ++--------------------------------------------- 2 files changed, 12 insertions(+), 352 deletions(-) diff --git a/index.html b/index.html index cf8527f..133680c 100644 --- a/index.html +++ b/index.html @@ -24,7 +24,7 @@ supplied by several headers:

    and polymorphic_downcast<> to perform safe casting between polymorphic types.
    -
  • The boost/lexical_cast header provides lexical_cast<> +
  • The boost/lexical_cast header provides lexical_cast<> general literal text conversions, such as an int represented as a string, or vice-versa.
  • diff --git a/lexical_cast.htm b/lexical_cast.htm index 35c6e58..73b6ba5 100644 --- a/lexical_cast.htm +++ b/lexical_cast.htm @@ -1,356 +1,16 @@ - - - - - lexical_cast - - - - -

    boost.png (6897 bytes)Header - boost/lexical_cast.hpp

    - -
    -

    Motivation

    - Sometimes a value must be converted to a literal text form, such as an int - represented as a string, or vice-versa, when a string - is interpreted as an int. Such examples are common when converting - between data types internal to a program and representation external to a - program, such as windows and configuration files. -

    - The standard C and C++ libraries offer a number of facilities for performing - such conversions. However, they vary with their ease of use, extensibility, and - safety. -

    - For instance, there are a number of limitations with the family of standard C - functions typified by atoi: -

      -
    • - Conversion is supported in one direction only: from text to internal data type. - Converting the other way using the C library requires either the inconvenience - and compromised safety of the sprintf function, or the loss of - portability associated with non-standard functions such as itoa. -
    • -
    • - The range of types supported is only a subset of the built-in numeric types, - namely int, long, and double. -
    • -
    • - The range of types cannot be extended in a uniform manner. For instance, - conversion from string representation to complex or rational. -
    • -
    - The standard C functions typified by strtol have the same basic - limitations, but offer finer control over the conversion process. However, for - the common case such control is often either not required or not used. The scanf - family of functions offer even greater control, but also lack safety and ease - of use. -

    - The standard C++ library offers stringstream for the kind of - in-core formatting being discussed. It offers a great deal of control over the - formatting and conversion of I/O to and from arbitrary types through text. - However, for simple conversions direct use of stringstream can be - either clumsy (with the introduction of extra local variables and the loss of - infix-expression convenience) or obscure (where stringstream - objects are created as temporary objects in an expression). Facets provide a - comprehensive concept and facility for controlling textual representation, but - their perceived complexity and high entry level requires an extreme degree of - involvement for simple conversions, and excludes all but a few programmers. -

    - The lexical_cast function template offers a convenient and - consistent form for supporting common conversions to and from arbitrary types - when they are represented as text. The simplification it offers is in - expression-level convenience for such conversions. For more involved - conversions, such as where precision or formatting need tighter control than is - offered by the default behavior of lexical_cast, the conventional - stringstream approach is recommended. Where the conversions are - numeric to numeric, numeric_cast - may offer more reasonable behavior than lexical_cast. -

    - For a good discussion of the options and issues involved in string-based - formatting, including comparison of stringstream, lexical_cast, - and others, see Herb Sutter's article, - The String Formatters of Manor Farm. Also, take a look at the Performance section. -

    -


    -

    Examples

    - The following example treats command line arguments as a sequence of numeric - data:
    -
    int main(int argc, char * argv[])
    -{
    -    using boost::lexical_cast;
    -    using boost::bad_lexical_cast;
     
    -    std::vector<short> args;
    -
    -    while(*++argv)
    -    {
    -        try
    -        {
    -            args.push_back(lexical_cast<short>(*argv));
    -        }
    -        catch(bad_lexical_cast &)
    -        {
    -            args.push_back(0);
    -        }
    -    }
    -    ...
    -}
    -
    -
    The following example uses numeric data in a string expression:
    -
    void log_message(const std::string &);
    -
    -void log_errno(int yoko)
    -{
    -    log_message("Error " + boost::lexical_cast<std::string>(yoko) + ": " + strerror(yoko));
    -}
    -
    -
    -
    -

    Synopsis

    - Library features defined in "boost/lexical_cast.hpp": -
    -
    namespace boost
    -{
    -    class bad_lexical_cast;
    -    template<typename Target, typename Source>
    -      Target lexical_cast(const Source& arg);
    -}
    -
    -
    Unit test defined in "lexical_cast_test.cpp". -

    -


    -

    lexical_cast

    -
    -
    template<typename Target, typename Source>
    -  Target lexical_cast(const Source& arg);
    -
    -
    Returns the result of streaming arg into a - standard library string-based stream and then out as a Target object. - Where Target is either std::string - or std::wstring, stream extraction takes the whole content - of the string, including spaces, rather than relying on the default - operator>> behavior. - If the conversion is unsuccessful, a - bad_lexical_cast exception is thrown. -

    - The requirements on the argument and result types are: -

      -
    • - Source is OutputStreamable, meaning that an operator<< - is defined that takes a std::ostream or std::wostream object on the - left hand side and an instance of the argument type on the right. -
    • -
    • - Target is InputStreamable, meaning that an operator>> - is defined that takes a std::istream or std::wistream object on the left hand side - and an instance of the result type on the right. -
    • -
    • - 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. -

    - 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. -

    -


    -

    bad_lexical_cast

    -
    -
    class bad_lexical_cast : public std::bad_cast
    -{
    -public:
    -    ... // same member function interface as std::exception
    -};
    -
    -
    Exception used to indicate runtime lexical_cast - failure. - -
    - - -

    Frequently Asked Questions

    -
    From->To target = lexical_cast<Target>(source); std::stringstream ss;
    ss << source;
    ss >> target;
    ss << source;
    ss >> target;
    ss.str(std::string());
    ss.clear();
    sscanf( (const char*)source, <...>, &target);
    OR
    sprintf( (char*)buffer, <...>, source);
    - target = buffer;
    From->To lexical_cast std::stringstream
    with construction
    std::stringstream
    without construction
    sscanf/sprintf
    string->char<191710
    string->int71152318
    string->unsigned int71172217
    string->int71152318
    string->unsigned int71172217
    string->bool<11041910
    string->float851726033
    string->float131726033
    char->string71051612
    int->string151312117
    unsigned int->string141252117
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Question:Why does lexical_cast<int8_t>("127") throw bad_lexical_cast?
    Answer:The type int8_t is a typedef to char or signed char. - Lexical conversion to these types is simply reading a byte from source but since the source has - more than one byte, the exception is thrown. - Please use other integer types such as int or short int. If bounds checking - is important, you can also call numeric_cast: -
    numeric_cast<int8_t>(lexical_cast<int>("127"));
    -
    Question:What does lexical_cast<std::string> of an int8_t or uint8_t not do what I expect?
    Answer:As above, note that int8_t and uint8_t are actually chars and are formatted as such. To avoid this, cast to an integer type first: -
    lexical_cast<std::string>(static_cast<int>(n));
    -
    Question:The implementation always resets the ios_base::skipws flag of an underlying stream object. It breaks my operator>> that works only in presence of this flag. Can you remove code that resets the flag?
    Answer:May be in a future version. There is no requirement in [N1973] to reset the flag but remember that [N1973] is not yet accepted by the committee. By the way, it's a great opportunity to make your operator>> conform to the standard. Read a good C++ book, study std::sentry and ios_state_saver. -
    Question:Why std::cout << boost::lexical_cast<unsigned int>("-1"); does not throw, but outputs 4294967295?
    Answer:boost::lexical_cast has the behavior of stringstream, which uses num_get functions of std::locale to convert numbers. If we look at the [22.2.2.1.2] of Programming languages — C++, we'll see, that num_get uses the rules of scanf for conversions. And in the C99 standard for unsigned input value minus sign is optional, so if a negative number is read, no errors will arise and the result will be the two's complement. -
    - -

    References

    -
      -
    • [N1973] Kevlin Henney, Beman Dawes, Lexical Conversion Library Proposal for TR2, - N1973. -
    • [Tuning] Alexander Nasonov, Fine Tuning for lexical_cast, - Overload #74 (PDF), - August 2006.
    • -
    -

    Changes

    -

    July 2011:

    -
      -
    • Added code to work with Inf and NaN on any platform.
    • -
    • Better performance and less memory usage for conversions to float type (and to double type, if sizeof(double)<sizeof(long double)).
    • -
    -

    May 2011:

    -
      -
    • Optimizations for "C" and other locales without number grouping.
    • -
    • Better performance and less memory usage for unsigned char and signed char conversions.
    • -
    • Better performance and less memory usage for conversions to arithmetic types.
    • -
    • Better performance and less memory usage for conversions from arithmetic type to arithmetic type.
    • -
    • Directly construct Target from Source on some conversions (like conversions from string to string, from char array to string, from char to char and others).
    • -
    -

    August, October 2006:

    -
      -
    • Better performance for many combinations of Source and Target - types. Refer to [Tuning] for more details. -
    • -
    -

    June 2005:

    -
      -
    • Call-by-const reference for the parameters. This requires partial specialization - of class templates, so it doesn't work for MSVC 6, and it uses the original - pass by value there.
      -
    • -
    • The MSVC 6 support is deprecated, and will be removed in a future Boost - version.
    • -
    -

    Earlier:

    - -
      -
    • The previous version of lexical_cast used the default stream - precision for reading and writing floating-point numbers. For numerics that - have a corresponding specialization of std::numeric_limits, the - current version now chooses a precision to match.
      -
    • The previous version of lexical_cast did not support conversion - to or from any wide-character-based types. For compilers with full language - and library support for wide characters, lexical_cast now supports - conversions from wchar_t, wchar_t *, and std::wstring - and to wchar_t and std::wstring.
      -
    • The previous version of lexical_cast assumed that the conventional - stream extractor operators were sufficient for reading values. However, string - I/O is asymmetric, with the result that spaces play the role of I/O separators - rather than string content. The current version fixes this error for std::string - and, where supported, std::wstring: lexical_cast<std::string>("Hello, - World") succeeds instead of failing with a bad_lexical_cast - exception.
      -
    • The previous version of lexical_cast allowed unsafe and meaningless - conversions to pointers. The current version now throws a bad_lexical_cast - for conversions to pointers: lexical_cast<char *>("Goodbye, World") - now throws an exception instead of causing undefined behavior. -
    -

    -


    - -

    Performance

    -This table shows the execution time in milliseconds for 100000 calls of the following string formatters: - - - - - - - - - - - - - - - - - -
    From->To lexical_cast std::stringstream
    with construction
    std::stringstream
    without construction
    sscanf/sprintf
    string->char<191710
    string->int71152318
    string->unsigned int71172217
    string->bool<11041910
    string->float131726033
    char->string71051612
    int->string151312117
    unsigned int->string141252117
    bool->string71222412
    float->string12422311548
    char*->string912320---
    int->int<112026---
    float->float<1262142---
    - -Fastest results are highlitened with green. -
    -
    Copyright © Kevlin Henney, 2000-2005
    -
    Copyright © Alexander Nasonov, 2006-2010
    -
    Copyright © Antony Polukhin, 2011
    -
    - 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) -
    - + + + + + +Automatic redirection failed, please go to +../../doc/html/boost_lexical_cast.html + From c372f482a2e583d53a996669e6b3a415e9242d93 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Thu, 21 Jul 2011 08:20:35 +0000 Subject: [PATCH 18/39] Fixes #5723. Fixes broken link [SVN r73269] --- doc/lexical_cast.qbk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/lexical_cast.qbk b/doc/lexical_cast.qbk index 8ce54cb..f8a9b7c 100644 --- a/doc/lexical_cast.qbk +++ b/doc/lexical_cast.qbk @@ -73,7 +73,7 @@ The following example uses numeric data in a string expression: [endsect] [section Synopsis] -Library features defined in [@../../boost/lexical_cast.hpp boost/lexical_cast.hpp]: +Library features defined in [@http://www.boost.org/boost/lexical_cast.hpp boost/lexical_cast.hpp]: `` namespace boost { From c1c8485cb43559a069e02cfdad93bb786b52a7e2 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Thu, 21 Jul 2011 15:35:11 +0000 Subject: [PATCH 19/39] Fixes #5723. Links in documentation are now implemented via [@boost: ] [SVN r73277] --- doc/lexical_cast.qbk | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/lexical_cast.qbk b/doc/lexical_cast.qbk index f8a9b7c..f5beec7 100644 --- a/doc/lexical_cast.qbk +++ b/doc/lexical_cast.qbk @@ -13,7 +13,7 @@ ] ] -[def __numericcast__ [@http://www.boost.org/libs/numeric/conversion/doc/html/boost_numericconversion/improved_numeric_cast__.html `boost::numeric_cast`]] +[def __numericcast__ [@boost:libs/numeric/conversion/doc/html/boost_numericconversion/improved_numeric_cast__.html `boost::numeric_cast`]] [def __proposallong__ [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1973.html Lexical Conversion Library Proposal for TR2, N1973 by Kevlin Henney and Beman Dawes]] [def __proposalshort__ [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1973.html Lexical Conversion Library Proposal for TR2, N1973]] @@ -73,7 +73,7 @@ The following example uses numeric data in a string expression: [endsect] [section Synopsis] -Library features defined in [@http://www.boost.org/boost/lexical_cast.hpp boost/lexical_cast.hpp]: +Library features defined in [@boost:boost/lexical_cast.hpp boost/lexical_cast.hpp]: `` namespace boost { @@ -136,7 +136,7 @@ It breaks my `operator>>` that works only in presence of this flag. Can you remo __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. -Read a good C++ book, study `std::sentry` and [@../../libs/io/doc/ios_state.html `ios_state_saver`]. +Read a good C++ book, study `std::sentry` and [@boost:libs/io/doc/ios_state.html `ios_state_saver`]. * [*Question:] Why `std::cout << boost::lexical_cast("-1");` does not throw, but outputs 4294967295? From 8a756eae7bba379765c17aebbe5ae7596b339e2e Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Sat, 23 Jul 2011 15:55:54 +0000 Subject: [PATCH 20/39] Fixes #5732. * reduces templates count * leaves only one lexical converting class (at least for modern compilers) * fixes small TODOs and XXXs from source code * makes lexical_stream_limited_src more readable * updates status/explicit-failures-markup.xml * makes lexical_cast_inf_nan_test.cpp pass on Itanium pltform * makes lexical_cast able to convert signed and unsigned chars to wchar_t and updates lexical_cast_wchars_test [SVN r73313] --- include/boost/lexical_cast.hpp | 1162 ++++++++-------------------- test/lexical_cast_inf_nan_test.cpp | 13 + test/lexical_cast_wchars_test.cpp | 8 +- 3 files changed, 356 insertions(+), 827 deletions(-) diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index 99aeb24..58fdea8 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -39,7 +39,6 @@ #include #include #include -#include #include #include #include @@ -47,7 +46,12 @@ #include #ifndef BOOST_NO_STD_LOCALE -#include +# include +#else +# ifndef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE +# warning "Unable to use header. boost::lexical_cast will use the 'C' locale." +# define BOOST_LEXICAL_CAST_ASSUME_C_LOCALE +# endif #endif #ifdef BOOST_NO_STRINGSTREAM @@ -223,156 +227,17 @@ namespace boost namespace detail // lcast_src_length { // Return max. length of string representation of Source; - // 0 if unlimited (with exceptions for some types, see below). - // Values with limited string representation are placed to - // the buffer locally defined in lexical_cast function. - // 1 is returned for few types such as CharT const* or - // std::basic_string that already have an internal - // buffer ready to be reused by lexical_stream_limited_src. - // Each specialization should have a correspondent operator<< - // defined in lexical_stream_limited_src. template< class CharT // A result of widest_char transformation. , class Source // Source type of lexical_cast. > struct lcast_src_length { - BOOST_STATIC_CONSTANT(std::size_t, value = 0); + BOOST_STATIC_CONSTANT(std::size_t, value = 1); // To check coverage, build the test with // bjam --v2 profile optimization=off static void check_coverage() {} }; - template<> - struct lcast_src_length - { - BOOST_STATIC_CONSTANT(std::size_t, value = 1); - static void check_coverage() {} - }; - - template<> - struct lcast_src_length - { - BOOST_STATIC_CONSTANT(std::size_t, value = 1); - static void check_coverage() {} - }; - - template<> - struct lcast_src_length - { - BOOST_STATIC_CONSTANT(std::size_t, value = 1); - static void check_coverage() {} - }; - template<> - struct lcast_src_length - { - BOOST_STATIC_CONSTANT(std::size_t, value = 1); - static void check_coverage() {} - }; - template<> - struct lcast_src_length - { - BOOST_STATIC_CONSTANT(std::size_t, value = 1); - static void check_coverage() {} - }; - template<> - struct lcast_src_length - { - BOOST_STATIC_CONSTANT(std::size_t, value = 1); - static void check_coverage() {} - }; - template<> - struct lcast_src_length - { - BOOST_STATIC_CONSTANT(std::size_t, value = 1); - static void check_coverage() {} - }; - template<> - struct lcast_src_length - { - BOOST_STATIC_CONSTANT(std::size_t, value = 1); - static void check_coverage() {} - }; - -#ifndef BOOST_LCAST_NO_WCHAR_T - template<> - struct lcast_src_length - { - BOOST_STATIC_CONSTANT(std::size_t, value = 1); - static void check_coverage() {} - }; - - template<> - struct lcast_src_length - { - BOOST_STATIC_CONSTANT(std::size_t, value = 1); - static void check_coverage() {} - }; - -#ifndef BOOST_NO_INTRINSIC_WCHAR_T - template<> - struct lcast_src_length - { - BOOST_STATIC_CONSTANT(std::size_t, value = 1); - static void check_coverage() {} - }; -#endif -#endif - - template<> - struct lcast_src_length - { - BOOST_STATIC_CONSTANT(std::size_t, value = 1); - static void check_coverage() {} - }; - - template<> - struct lcast_src_length - { - BOOST_STATIC_CONSTANT(std::size_t, value = 1); - static void check_coverage() {} - }; - -#ifndef BOOST_LCAST_NO_WCHAR_T - template<> - struct lcast_src_length - { - BOOST_STATIC_CONSTANT(std::size_t, value = 1); - static void check_coverage() {} - }; - - template<> - struct lcast_src_length - { - BOOST_STATIC_CONSTANT(std::size_t, value = 1); - static void check_coverage() {} - }; -#endif - -#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION - template - struct lcast_src_length< CharT, std::basic_string > - { - BOOST_STATIC_CONSTANT(std::size_t, value = 1); - static void check_coverage() {} - }; -#else - template<> - struct lcast_src_length< char, std::basic_string > - { - BOOST_STATIC_CONSTANT(std::size_t, value = 1); - static void check_coverage() {} - }; - -#ifndef BOOST_LCAST_NO_WCHAR_T - template<> - struct lcast_src_length< wchar_t, std::basic_string > - { - BOOST_STATIC_CONSTANT(std::size_t, value = 1); - static void check_coverage() {} - }; -#endif -#endif - // Helper for integral types. // Notes on length calculation: // Max length for 32bit int with grouping "\1" and thousands_sep ',': @@ -530,13 +395,6 @@ namespace boost #endif } - namespace detail // lexical_streambuf_fake - { - struct lexical_streambuf_fake - { - }; - } - namespace detail // lcast_to_unsigned { #if (defined _MSC_VER) @@ -575,7 +433,6 @@ namespace boost int_type const zero = Traits::to_int_type(czero); #ifndef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE - // TODO: use BOOST_NO_STD_LOCALE std::locale loc; typedef std::numpunct numpunct; numpunct const& np = BOOST_USE_FACET(numpunct, loc); @@ -654,7 +511,6 @@ namespace boost T multiplier = 1; #ifndef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE - // TODO: use BOOST_NO_STD_LOCALE std::locale loc; typedef std::numpunct numpunct; numpunct const& np = BOOST_USE_FACET(numpunct, loc); @@ -911,7 +767,6 @@ namespace boost { #ifndef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE - // TODO: use BOOST_NO_STD_LOCALE std::locale loc; typedef std::numpunct numpunct; numpunct const& np = BOOST_USE_FACET(numpunct, loc); @@ -1115,7 +970,7 @@ namespace boost * with long doubles (and with doubles if sizeof(double)==sizeof(long double)). */ long double result = std::pow(10.0L, pow_of_10) * mantissa; - value = static_cast( has_minus ? -1 * result : result); + value = static_cast( has_minus ? (boost::math::changesign)(result) : result); if ( (boost::math::isinf)(value) || (boost::math::isnan)(value) ) return false; @@ -1123,92 +978,23 @@ namespace boost } } - namespace detail // stream wrapper for handling lexical conversions + namespace detail // stl_buf_unlocker { - template - class lexical_stream - { - private: - typedef typename widest_char< - typename stream_char::type, - typename stream_char::type>::type char_type; - - typedef Traits traits_type; - + template< class BufferType, class CharT > + class stl_buf_unlocker: public BufferType{ public: - lexical_stream(char_type* = 0, char_type* = 0) - { - stream.unsetf(std::ios::skipws); - lcast_set_precision(stream, static_cast(0), static_cast(0) ); - } - ~lexical_stream() - { - #if defined(BOOST_NO_STRINGSTREAM) - stream.freeze(false); - #endif - } - bool operator<<(const Source &input) - { - return !(stream << input).fail(); - } - template - bool operator>>(InputStreamable &output) - { - return !is_pointer::value && - stream >> output && - stream.get() == -#if defined(__GNUC__) && (__GNUC__<3) && defined(BOOST_NO_STD_WSTRING) -// GCC 2.9x lacks std::char_traits<>::eof(). -// We use BOOST_NO_STD_WSTRING to filter out STLport and libstdc++-v3 -// configurations, which do provide std::char_traits<>::eof(). - - EOF; + typedef BufferType base_class; +#ifndef BOOST_NO_USING_TEMPLATE + using base_class::pptr; + using base_class::pbase; + using base_class::setg; + using base_class::setp; #else - traits_type::eof(); + CharT* pptr() const { return base_class::pptr(); } + CharT* pbase() const { return base_class::pbase(); } + void setg(CharT* gbeg, CharT* gnext, CharT* gend){ return base_class::setg(gbeg, gnext, gend); } + void setp(CharT* pbeg, CharT* pend) { return setp(pbeg, pend); } #endif - } - -#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION - - bool operator>>(std::string &output) - { - #if defined(BOOST_NO_STRINGSTREAM) - stream << '\0'; - #endif - stream.str().swap(output); - return true; - } - #ifndef BOOST_LCAST_NO_WCHAR_T - bool operator>>(std::wstring &output) - { - stream.str().swap(output); - return true; - } - #endif - -#else - bool operator>>(std::basic_string& output) - { - stream.str().swap(output); - return true; - } - - template - bool operator>>(std::basic_string& out) - { - std::basic_string str(stream.str()); - out.assign(str.begin(), str.end()); - return true; - } -#endif - private: - #if defined(BOOST_NO_STRINGSTREAM) - std::strstream stream; - #elif defined(BOOST_NO_STD_LOCALE) - std::stringstream stream; - #else - std::basic_stringstream stream; - #endif }; } @@ -1216,66 +1002,133 @@ namespace boost { // String representation of Source has an upper limit. template< class CharT // a result of widest_char transformation - , class Base // lexical_streambuf_fake or basic_streambuf , class Traits // usually char_traits > - class lexical_stream_limited_src : public Base + class lexical_stream_limited_src { + typedef stl_buf_unlocker, CharT > local_streambuffer_t; + +#if defined(BOOST_NO_STRINGSTREAM) + typedef stl_buf_unlocker local_stringbuffer_t; +#elif defined(BOOST_NO_STD_LOCALE) + typedef stl_buf_unlocker local_stringbuffer_t; +#else + typedef stl_buf_unlocker, CharT > local_stringbuffer_t; +#endif // A string representation of Source is written to [start, finish). // Currently, it is assumed that [start, finish) is big enough // to hold a string representation of any Source value. CharT* start; CharT* finish; + local_stringbuffer_t *stringbuf; + + public: + lexical_stream_limited_src(CharT* sta, CharT* fin) + : start(sta) + , finish(fin) + , stringbuf(NULL) + {} + + ~lexical_stream_limited_src() + { + if (stringbuf) delete stringbuf; + } private: - - static void widen_and_assign(char*p, char ch) - { - Traits::assign(*p, ch); - } - -#ifndef BOOST_LCAST_NO_WCHAR_T - static void widen_and_assign(wchar_t* p, char ch) - { - // TODO: use BOOST_NO_STD_LOCALE - std::locale loc; - wchar_t w = BOOST_USE_FACET(std::ctype, loc).widen(ch); - Traits::assign(*p, w); - } - - static void widen_and_assign(wchar_t* p, wchar_t ch) - { - Traits::assign(*p, ch); - } - - static void widen_and_assign(char*, wchar_t ch); // undefined -#endif - - template - bool lcast_put(const OutputStreamable& input) - { - if(put_inf_nan(start, finish, input)) return true; - this->setp(start, finish); - std::basic_ostream stream(static_cast(this)); - lcast_set_precision(stream, static_cast(0)); - bool const result = !(stream << input).fail(); - finish = this->pptr(); - return result; - } - // Undefined: lexical_stream_limited_src(lexical_stream_limited_src const&); void operator=(lexical_stream_limited_src const&); +/************************************ HELPER FUNCTIONS FOR OPERATORS << ( ... ) ********************************/ + bool shl_char(CharT ch) + { + Traits::assign(*start, ch); + finish = start + 1; + return true; + } + +#ifndef BOOST_LCAST_NO_WCHAR_T + template + bool shl_char(T ch) + { + BOOST_STATIC_ASSERT_MSG(( sizeof(T) <= sizeof(CharT)) , + "boost::lexical_cast does not support conversions from whar_t to char types." + "Use boost::locale instead" ); +#ifndef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE + std::locale loc; + wchar_t w = BOOST_USE_FACET(std::ctype, loc).widen(ch); +#else + wchar_t w = ch; +#endif + Traits::assign(*start, w); + finish = start + 1; + return true; + } +#endif + + bool shl_char_array(CharT const* str) + { + start = const_cast(str); + finish = start + Traits::length(str); + return true; + } + +#ifndef BOOST_LCAST_NO_WCHAR_T + template + bool shl_char_array(T const* str) + { + BOOST_STATIC_ASSERT_MSG(( sizeof(T) <= sizeof(CharT)), + "boost::lexical_cast does not support conversions from whar_t to char types." + "Use boost::locale instead" ); + return shl_input_streamable(str); + } +#endif + + template + bool shl_input_streamable(InputStreamable& input) + { + /* No one will call this function twice, + * so we do not need `if (!stringbuf)' */ + stringbuf = new local_stringbuffer_t(); + + std::basic_ostream stream(stringbuf); + lcast_set_precision(stream, static_cast(0)); + bool const result = !(stream << input).fail(); + start = stringbuf->pbase(); + finish = stringbuf->pptr(); + return result; + } + + template + inline bool shl_signed(T n) + { + start = lcast_put_unsigned(lcast_to_unsigned(n), finish); + if(n < 0) + { + --start; + CharT const minus = lcast_char_constants::minus; + Traits::assign(*start, minus); + } + return true; + } + +#ifndef BOOST_LCAST_NO_COMPILE_TIME_PRECISION + template + bool shl_float_types(T val) + { + if (put_inf_nan(start, finish, val)) return true; + local_streambuffer_t bb; + bb.setp(start, finish); + std::basic_ostream stream(&bb); + lcast_set_precision(stream, &val); + bool const result = !(stream << val).fail(); + finish = bb.pptr(); + return result; + } +#endif + +/************************************ OPERATORS << ( ... ) ********************************/ public: - - lexical_stream_limited_src(CharT* sta, CharT* fin) - : start(sta) - , finish(fin) - {} - - public: // output - template bool operator<<(std::basic_string const& str) { @@ -1284,39 +1137,53 @@ namespace boost return true; } - bool operator<<(bool); - bool operator<<(char); - bool operator<<(unsigned char); - bool operator<<(signed char); -#if !defined(BOOST_LCAST_NO_WCHAR_T) && !defined(BOOST_NO_INTRINSIC_WCHAR_T) - bool operator<<(wchar_t); + bool operator<<(bool value) + { + CharT const czero = lcast_char_constants::zero; + Traits::assign(*start, Traits::to_char_type(czero + value)); + finish = start + 1; + return true; + } + + bool operator<<(char ch) { return shl_char(ch); } + bool operator<<(unsigned char ch) { return ((*this) << static_cast(ch)); } + bool operator<<(signed char ch) { return ((*this) << static_cast(ch)); } +#if !defined(BOOST_LCAST_NO_WCHAR_T) + bool operator<<(wchar_t const* str) { return shl_char_array(str); } +#ifndef BOOST_NO_INTRINSIC_WCHAR_T + bool operator<<(wchar_t ch) { return shl_char(ch); } #endif - bool operator<<(unsigned char const*); - bool operator<<(signed char const*); - bool operator<<(CharT const*); - bool operator<<(short); - bool operator<<(int); - bool operator<<(long); - bool operator<<(unsigned short); - bool operator<<(unsigned int); - bool operator<<(unsigned long); +#endif + bool operator<<(unsigned char const* ch) { return ((*this) << reinterpret_cast(ch)); } + bool operator<<(signed char const* ch) { return ((*this) << reinterpret_cast(ch)); } + bool operator<<(char const* str) { return shl_char_array(str); } + bool operator<<(short n) { return shl_signed(n); } + bool operator<<(int n) { return shl_signed(n); } + bool operator<<(long n) { return shl_signed(n); } + bool operator<<(unsigned short n) { start = lcast_put_unsigned(n, finish); return true; } + bool operator<<(unsigned int n) { start = lcast_put_unsigned(n, finish); return true; } + bool operator<<(unsigned long n) { start = lcast_put_unsigned(n, finish); return true; } + #if defined(BOOST_HAS_LONG_LONG) - bool operator<<(boost::ulong_long_type); - bool operator<<(boost::long_long_type ); + bool operator<<(boost::ulong_long_type n) { start = lcast_put_unsigned(n, finish); return true; } + bool operator<<(boost::long_long_type n) { return shl_signed(n); } #elif defined(BOOST_HAS_MS_INT64) - bool operator<<(unsigned __int64); - bool operator<<( __int64); + bool operator<<(unsigned __int64 n) { start = lcast_put_unsigned(n, finish); return true; } + bool operator<<( __int64 n) { return shl_signed(n); } #endif - // These three operators use ostream and streambuf. - // lcast_streambuf_for_source::value is true. - bool operator<<(float); - bool operator<<(double); - bool operator<<(long double); +#ifndef BOOST_LCAST_NO_COMPILE_TIME_PRECISION + bool operator<<(float val) { return shl_float_types(val); } + bool operator<<(double val) { return shl_float_types(val); } + bool operator<<(long double val) { return shl_float_types(val); } +#endif // BOOST_LCAST_NO_COMPILE_TIME_PRECISION + template + bool operator<<(const InStreamable& input) { return shl_input_streamable(input); } + +/************************************ HELPER FUNCTIONS FOR OPERATORS >> ( ... ) ********************************/ private: - template - bool input_operator_helper_unsigned(Type& output) + bool shr_unsigned(Type& output) { CharT const minus = lcast_char_constants::minus; CharT const plus = lcast_char_constants::plus; @@ -1350,7 +1217,7 @@ namespace boost } template - bool input_operator_helper_signed(Type& output) + bool shr_signed(Type& output) { CharT const minus = lcast_char_constants::minus; CharT const plus = lcast_char_constants::plus; @@ -1393,63 +1260,81 @@ namespace boost return succeed; } - public: // input - - bool operator>>(unsigned short& output) + template + bool shr_using_base_class(InputStreamable& output) { - return input_operator_helper_unsigned(output); +#if (defined _MSC_VER) +# pragma warning( push ) + // conditional expression is constant +# pragma warning( disable : 4127 ) +#endif + if(is_pointer::value) + return false; + + local_streambuffer_t bb; + bb.setg(start, start, finish); + std::basic_istream stream(&bb); + stream.unsetf(std::ios::skipws); + lcast_set_precision(stream, static_cast(0)); +#if (defined _MSC_VER) +# pragma warning( pop ) +#endif + return stream >> output && + stream.get() == +#if defined(__GNUC__) && (__GNUC__<3) && defined(BOOST_NO_STD_WSTRING) + // GCC 2.9x lacks std::char_traits<>::eof(). + // We use BOOST_NO_STD_WSTRING to filter out STLport and libstdc++-v3 + // configurations, which do provide std::char_traits<>::eof(). + + EOF; +#else + Traits::eof(); +#endif } - bool operator>>(unsigned int& output) + template + inline bool shr_xchar(T& output) { - return input_operator_helper_unsigned(output); + BOOST_STATIC_ASSERT_MSG(( sizeof(CharT) == sizeof(T) ), + "boost::lexical_cast does not support conversions from whar_t to char types." + "Use boost::locale instead" ); + bool const ok = (finish - start == 1); + if(ok) { + CharT out; + Traits::assign(out, *start); + output = static_cast(out); + } + return ok; } - bool operator>>(unsigned long int& output) - { - return input_operator_helper_unsigned(output); - } - - bool operator>>(short& output) - { - return input_operator_helper_signed(output); - } - - bool operator>>(int& output) - { - return input_operator_helper_signed(output); - } - - bool operator>>(long int& output) - { - return input_operator_helper_signed(output); - } - - +/************************************ OPERATORS >> ( ... ) ********************************/ + public: + bool operator>>(unsigned short& output) { return shr_unsigned(output); } + bool operator>>(unsigned int& output) { return shr_unsigned(output); } + bool operator>>(unsigned long int& output) { return shr_unsigned(output); } + bool operator>>(short& output) { return shr_signed(output); } + bool operator>>(int& output) { return shr_signed(output); } + bool operator>>(long int& output) { return shr_signed(output); } #if defined(BOOST_HAS_LONG_LONG) - bool operator>>( boost::ulong_long_type& output) - { - return input_operator_helper_unsigned(output); - } - - bool operator>>(boost::long_long_type& output) - { - return input_operator_helper_signed(output); - } - + bool operator>>(boost::ulong_long_type& output) { return shr_unsigned(output); } + bool operator>>(boost::long_long_type& output) { return shr_signed(output); } #elif defined(BOOST_HAS_MS_INT64) - bool operator>>(unsigned __int64& output) - { - return input_operator_helper_unsigned(output); - } - - bool operator>>(__int64& output) - { - return input_operator_helper_signed(output); - } + bool operator>>(unsigned __int64& output) { return shr_unsigned(output); } + bool operator>>(__int64& output) { return shr_signed(output); } #endif - + bool operator>>(CharT& output) { return shr_xchar(output); } + bool operator>>(unsigned char& output) { return shr_xchar(output); } + bool operator>>(signed char& output) { return shr_xchar(output); } +#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; } +#endif /* * case "-0" || "0" || "+0" : output = false; return true; * case "1" || "+1": output = true; return true; @@ -1484,22 +1369,17 @@ namespace boost } } - bool operator>>(float& output) - { - return lcast_ret_float(output,start,finish); - } + bool operator>>(float& output) { return lcast_ret_float(output,start,finish); } private: // Not optimised converter template bool float_types_converter_internal(T& output, int /*tag*/) { - if (parse_inf_nan(start, finish, output)) return true; - - bool return_value = convert_using_base_class(output); + bool return_value = shr_using_base_class(output); /* Some compilers and libraries successfully - * parse '1.0E', '1.0E-'... + * parse 'inf', 'INFINITY', '1.0E', '1.0E-'... * We are trying to provide a unified behaviour, * so we just forbid such conversions (as some * of the most popular compilers/libraries do) @@ -1556,424 +1436,11 @@ namespace boost // Generic istream-based algorithm. // lcast_streambuf_for_target::value is true. template - bool operator>>(InputStreamable& output) - { - return convert_using_base_class(output); - } - - private: - template - bool convert_using_base_class(InputStreamable& output) - { -#if (defined _MSC_VER) -# pragma warning( push ) - // conditional expression is constant -# pragma warning( disable : 4127 ) -#endif - if(is_pointer::value) - return false; - - this->setg(start, start, finish); - std::basic_istream stream(static_cast(this)); - stream.unsetf(std::ios::skipws); - lcast_set_precision(stream, static_cast(0)); -#if (defined _MSC_VER) -# pragma warning( pop ) -#endif - return stream >> output && - stream.get() == -#if defined(__GNUC__) && (__GNUC__<3) && defined(BOOST_NO_STD_WSTRING) - // GCC 2.9x lacks std::char_traits<>::eof(). - // We use BOOST_NO_STD_WSTRING to filter out STLport and libstdc++-v3 - // configurations, which do provide std::char_traits<>::eof(). - - EOF; -#else - Traits::eof(); -#endif - } - public: - - bool operator>>(CharT&); - bool operator>>(unsigned char&); - bool operator>>(signed char&); - -#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION -// This #if is in sync with lcast_streambuf_for_target - - bool operator>>(std::string&); - -#ifndef BOOST_LCAST_NO_WCHAR_T - bool operator>>(std::wstring&); -#endif - -#else - template - bool operator>>(std::basic_string& str) - { - str.assign(start, finish); - return true; - } -#endif - }; - - template - inline bool lexical_stream_limited_src::operator<<( - bool value) - { - typedef typename Traits::int_type int_type; - CharT const czero = lcast_char_constants::zero; - int_type const zero = Traits::to_int_type(czero); - Traits::assign(*start, Traits::to_char_type(zero + value)); - finish = start + 1; - return true; - } - - template - inline bool lexical_stream_limited_src::operator<<( - char ch) - { - widen_and_assign(start, ch); - finish = start + 1; - return true; - } - - template - inline bool lexical_stream_limited_src::operator<<( - unsigned char ch) - { - return ((*this) << static_cast(ch)); - } - - template - inline bool lexical_stream_limited_src::operator<<( - signed char ch) - { - return ((*this) << static_cast(ch)); - } - - template - inline bool lexical_stream_limited_src::operator<<( - unsigned char const* ch) - { - return ((*this) << reinterpret_cast(ch)); - } - - template - inline bool lexical_stream_limited_src::operator<<( - signed char const* ch) - { - return ((*this) << reinterpret_cast(ch)); - } - -#if !defined(BOOST_LCAST_NO_WCHAR_T) && !defined(BOOST_NO_INTRINSIC_WCHAR_T) - template - inline bool lexical_stream_limited_src::operator<<( - wchar_t ch) - { - widen_and_assign(start, ch); - finish = start + 1; - return true; - } -#endif - - template - inline bool lexical_stream_limited_src::operator<<( - short n) - { - start = lcast_put_unsigned(lcast_to_unsigned(n), finish); - if(n < 0) - { - --start; - CharT const minus = lcast_char_constants::minus; - Traits::assign(*start, minus); - } - return true; - } - - template - inline bool lexical_stream_limited_src::operator<<( - int n) - { - start = lcast_put_unsigned(lcast_to_unsigned(n), finish); - if(n < 0) - { - --start; - CharT const minus = lcast_char_constants::minus; - Traits::assign(*start, minus); - } - return true; - } - - template - inline bool lexical_stream_limited_src::operator<<( - long n) - { - start = lcast_put_unsigned(lcast_to_unsigned(n), finish); - if(n < 0) - { - --start; - CharT const minus = lcast_char_constants::minus; - Traits::assign(*start, minus); - } - return true; - } - -#if defined(BOOST_HAS_LONG_LONG) - template - inline bool lexical_stream_limited_src::operator<<( - boost::long_long_type n) - { - start = lcast_put_unsigned(lcast_to_unsigned(n), finish); - if(n < 0) - { - --start; - CharT const minus = lcast_char_constants::minus; - Traits::assign(*start, minus); - } - return true; - } -#elif defined(BOOST_HAS_MS_INT64) - template - inline bool lexical_stream_limited_src::operator<<( - __int64 n) - { - start = lcast_put_unsigned(lcast_to_unsigned(n), finish); - if(n < 0) - { - --start; - CharT const minus = lcast_char_constants::minus; - Traits::assign(*start, minus); - } - return true; - } -#endif - - template - inline bool lexical_stream_limited_src::operator<<( - unsigned short n) - { - start = lcast_put_unsigned(n, finish); - return true; - } - - template - inline bool lexical_stream_limited_src::operator<<( - unsigned int n) - { - start = lcast_put_unsigned(n, finish); - return true; - } - - template - inline bool lexical_stream_limited_src::operator<<( - unsigned long n) - { - start = lcast_put_unsigned(n, finish); - return true; - } - -#if defined(BOOST_HAS_LONG_LONG) - template - inline bool lexical_stream_limited_src::operator<<( - boost::ulong_long_type n) - { - start = lcast_put_unsigned(n, finish); - return true; - } -#elif defined(BOOST_HAS_MS_INT64) - template - inline bool lexical_stream_limited_src::operator<<( - unsigned __int64 n) - { - start = lcast_put_unsigned(n, finish); - return true; - } -#endif - - template - inline bool lexical_stream_limited_src::operator<<( - float val) - { - return this->lcast_put(val); - } - - template - inline bool lexical_stream_limited_src::operator<<( - double val) - { - return this->lcast_put(val); - } - - template - inline bool lexical_stream_limited_src::operator<<( - long double val) - { - return this->lcast_put(val); - } - - template - inline bool lexical_stream_limited_src::operator<<( - CharT const* str) - { - start = const_cast(str); - finish = start + Traits::length(str); - return true; - } - - template - inline bool lexical_stream_limited_src::operator>>( - CharT& output) - { - bool const ok = (finish - start == 1); - if(ok) - Traits::assign(output, *start); - return ok; - } - - template - inline bool lexical_stream_limited_src::operator>>( - unsigned char& output) - { - BOOST_STATIC_ASSERT( sizeof(CharT) == sizeof(unsigned char) ); - bool const ok = (finish - start == 1); - if(ok) { - CharT out; - Traits::assign(out, *start); - output = static_cast(out); - } - return ok; - } - - template - inline bool lexical_stream_limited_src::operator>>( - signed char& output) - { - BOOST_STATIC_ASSERT( sizeof(CharT) == sizeof(signed char) ); - bool const ok = (finish - start == 1); - if(ok) { - CharT out; - Traits::assign(out, *start); - output = static_cast(out); - } - return ok; - } - -#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION - template - inline bool lexical_stream_limited_src::operator>>( - std::string& str) - { - str.assign(start, finish); - return true; - } - -#ifndef BOOST_LCAST_NO_WCHAR_T - template - inline bool lexical_stream_limited_src::operator>>( - std::wstring& str) - { - str.assign(start, finish); - return true; - } -#endif -#endif - } - - namespace detail // lcast_streambuf_for_source - { - // Returns true if optimized stream wrapper needs ostream for writing. - template - struct lcast_streambuf_for_source - { - BOOST_STATIC_CONSTANT(bool, value = false); - }; - - template<> - struct lcast_streambuf_for_source - { - BOOST_STATIC_CONSTANT(bool, value = true); - }; - - template<> - struct lcast_streambuf_for_source - { - BOOST_STATIC_CONSTANT(bool, value = true); - }; - - template<> - struct lcast_streambuf_for_source - { - BOOST_STATIC_CONSTANT(bool, value = true); + bool operator>>(InputStreamable& output) { return shr_using_base_class(output); } }; } - namespace detail // lcast_streambuf_for_target - { - // Returns true if optimized stream wrapper needs istream for reading. - template - struct lcast_streambuf_for_target - { -#if defined(BOOST_HAS_LONG_LONG) || defined(BOOST_HAS_MS_INT64) - BOOST_STATIC_CONSTANT(bool, value = - ( - ::boost::type_traits::ice_or< - ::boost::type_traits::ice_not< is_arithmetic::value >::value, - is_same::value, - ::boost::type_traits::ice_and< - is_same::value, - ::boost::type_traits::ice_eq::value - >::value - >::value - ) - ); -#else - BOOST_STATIC_CONSTANT(bool, value = - ( - ::boost::type_traits::ice_or< - ::boost::type_traits::ice_not< is_arithmetic::value >::value, - is_same::value, - is_same::value - >::value - ) - ); -#endif - }; - #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION - template - struct lcast_streambuf_for_target< - std::basic_string > - { - BOOST_STATIC_CONSTANT(bool, value = false); - }; - -#ifndef BOOST_LCAST_NO_WCHAR_T - template - struct lcast_streambuf_for_target< - std::basic_string > - { - BOOST_STATIC_CONSTANT(bool, value = false); - }; -#endif -#else - template<> - struct lcast_streambuf_for_target - { - BOOST_STATIC_CONSTANT(bool, value = false); - }; - -#ifndef BOOST_LCAST_NO_WCHAR_T - template<> - struct lcast_streambuf_for_target - { - BOOST_STATIC_CONSTANT(bool, value = false); - }; -#endif -#endif - } - - #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION // call-by-const reference version @@ -1991,47 +1458,6 @@ namespace boost typedef const T * type; }; -#if (defined _MSC_VER) -# pragma warning( push ) -# pragma warning( disable : 4701 ) // possible use of ... before initialization -# pragma warning( disable : 4702 ) // unreachable code -# pragma warning( disable : 4267 ) // conversion from 'size_t' to 'unsigned int' -#endif - - template< typename Target - , typename Source - , bool Unlimited // string representation of Source is unlimited - , typename CharT - > - Target lexical_cast( - BOOST_DEDUCED_TYPENAME boost::call_traits::param_type arg, - CharT* buf, std::size_t src_len) - { - typedef BOOST_DEDUCED_TYPENAME - deduce_char_traits::type traits; - - typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_c< - lcast_streambuf_for_target::value || - lcast_streambuf_for_source::value - , std::basic_streambuf - , lexical_streambuf_fake - >::type base; - - BOOST_DEDUCED_TYPENAME boost::mpl::if_c< - Unlimited - , detail::lexical_stream - , detail::lexical_stream_limited_src - >::type interpreter(buf, buf + src_len); - - Target result; - if(!(interpreter << arg && interpreter >> result)) - BOOST_LCAST_THROW_BAD_CAST(Source, Target); - return result; - } -#if (defined _MSC_VER) -# pragma warning( pop ) -#endif - template struct is_stdstring { @@ -2134,25 +1560,43 @@ namespace boost BOOST_STATIC_CONSTANT(bool, value = true ); }; +#if (defined _MSC_VER) +# pragma warning( push ) +# pragma warning( disable : 4701 ) // possible use of ... before initialization +# pragma warning( disable : 4702 ) // unreachable code +# pragma warning( disable : 4267 ) // conversion from 'size_t' to 'unsigned int' +#endif template struct lexical_cast_do_cast { - static inline Target lexical_cast_impl(const Source &arg) + static inline Target lexical_cast_impl(const Source& arg) { - typedef typename detail::array_to_pointer_decay::type src; + typedef BOOST_DEDUCED_TYPENAME detail::array_to_pointer_decay::type src; - typedef typename detail::widest_char< - typename detail::stream_char::type - , typename detail::stream_char::type + typedef BOOST_DEDUCED_TYPENAME detail::widest_char< + BOOST_DEDUCED_TYPENAME detail::stream_char::type + , BOOST_DEDUCED_TYPENAME detail::stream_char::type >::type char_type; 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(); - return detail::lexical_cast(arg, buf, src_len); + + typedef BOOST_DEDUCED_TYPENAME + deduce_char_traits::type traits; + + detail::lexical_stream_limited_src interpreter(buf, buf + src_len); + + Target result; + if(!(interpreter << arg && interpreter >> result)) + BOOST_LCAST_THROW_BAD_CAST(Source, Target); + return result; } }; +#if (defined _MSC_VER) +# pragma warning( pop ) +#endif template struct lexical_cast_copy @@ -2315,6 +1759,78 @@ namespace boost #else + namespace detail // stream wrapper for handling lexical conversions + { + template + class lexical_stream + { + private: + typedef typename widest_char< + typename stream_char::type, + typename stream_char::type>::type char_type; + + typedef Traits traits_type; + + public: + lexical_stream(char_type* = 0, char_type* = 0) + { + stream.unsetf(std::ios::skipws); + lcast_set_precision(stream, static_cast(0), static_cast(0) ); + } + ~lexical_stream() + { + #if defined(BOOST_NO_STRINGSTREAM) + stream.freeze(false); + #endif + } + bool operator<<(const Source &input) + { + return !(stream << input).fail(); + } + template + bool operator>>(InputStreamable &output) + { + return !is_pointer::value && + stream >> output && + stream.get() == +#if defined(__GNUC__) && (__GNUC__<3) && defined(BOOST_NO_STD_WSTRING) +// GCC 2.9x lacks std::char_traits<>::eof(). +// We use BOOST_NO_STD_WSTRING to filter out STLport and libstdc++-v3 +// configurations, which do provide std::char_traits<>::eof(). + + EOF; +#else + traits_type::eof(); +#endif + } + + bool operator>>(std::string &output) + { + #if defined(BOOST_NO_STRINGSTREAM) + stream << '\0'; + #endif + stream.str().swap(output); + return true; + } + #ifndef BOOST_LCAST_NO_WCHAR_T + bool operator>>(std::wstring &output) + { + stream.str().swap(output); + return true; + } + #endif + + private: + #if defined(BOOST_NO_STRINGSTREAM) + std::strstream stream; + #elif defined(BOOST_NO_STD_LOCALE) + std::stringstream stream; + #else + std::basic_stringstream stream; + #endif + }; + } + // call-by-value fallback version (deprecated) template diff --git a/test/lexical_cast_inf_nan_test.cpp b/test/lexical_cast_inf_nan_test.cpp index ee50dee..4617d5e 100755 --- a/test/lexical_cast_inf_nan_test.cpp +++ b/test/lexical_cast_inf_nan_test.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -51,7 +52,14 @@ bool is_pos_nan(T value) template bool is_neg_nan(T value) { + /* There is some strange behaviour on Itanium platform with -nan nuber for long double. + * It is a IA64 feature, or it is a boost::math feature, not a lexical_cast bug */ +#if defined(__ia64__) || defined(_M_IA64) + return (boost::math::isnan)(value) + && ( boost::is_same::value || (boost::math::signbit)(value) ); +#else return (boost::math::isnan)(value) && (boost::math::signbit)(value); +#endif } template @@ -94,9 +102,11 @@ void test_inf_nan_templated() == "-inf" ); BOOST_CHECK(lexical_cast( std::numeric_limits::infinity()) == "inf" ); BOOST_CHECK(lexical_cast( std::numeric_limits::quiet_NaN()) == "nan" ); +#if !defined(__ia64__) && !defined(_M_IA64) BOOST_CHECK(lexical_cast( (boost::math::changesign)(std::numeric_limits::quiet_NaN())) == "-nan" ); +#endif #ifndef BOOST_LCAST_NO_WCHAR_T BOOST_CHECK( is_pos_inf( lexical_cast(L"inf") ) ); @@ -134,10 +144,13 @@ void test_inf_nan_templated() == L"-inf" ); BOOST_CHECK(lexical_cast( std::numeric_limits::infinity()) == L"inf" ); BOOST_CHECK(lexical_cast( std::numeric_limits::quiet_NaN()) == L"nan" ); +#if !defined(__ia64__) && !defined(_M_IA64) BOOST_CHECK(lexical_cast( (boost::math::changesign)(std::numeric_limits::quiet_NaN())) == L"-nan" ); #endif + +#endif } void test_inf_nan_float() diff --git a/test/lexical_cast_wchars_test.cpp b/test/lexical_cast_wchars_test.cpp index 547f226..14ac461 100755 --- a/test/lexical_cast_wchars_test.cpp +++ b/test/lexical_cast_wchars_test.cpp @@ -37,11 +37,11 @@ void test_char_types_conversions() 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(sc_arr) != std::wstring(wc_arr) ); - BOOST_CHECK(boost::lexical_cast(uc_arr) != std::wstring(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_THROW(boost::lexical_cast(uc_arr[0]), boost::bad_lexical_cast); - BOOST_CHECK_THROW(boost::lexical_cast(sc_arr[0]), boost::bad_lexical_cast); + BOOST_CHECK_EQUAL(boost::lexical_cast(uc_arr[0]), wc_arr[0]); + BOOST_CHECK_EQUAL(boost::lexical_cast(sc_arr[0]), wc_arr[0]); #endif BOOST_CHECK(1); } From fd264b05837d83fc602d8c27e7b44111e8c3a12b Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Sun, 24 Jul 2011 09:42:06 +0000 Subject: [PATCH 21/39] Fixes #5732. * fixes performance regression, that was added by previous commit * fixes float types preformance regression for old compilers [SVN r73323] --- include/boost/lexical_cast.hpp | 108 ++++++++++++++++++++++----------- 1 file changed, 73 insertions(+), 35 deletions(-) diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index 58fdea8..e3e0632 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -35,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -1003,6 +1005,7 @@ namespace boost // String representation of Source has an upper limit. template< class CharT // a result of widest_char transformation , class Traits // usually char_traits + , bool RequiresStringbuffer > class lexical_stream_limited_src { @@ -1015,25 +1018,23 @@ namespace boost #else typedef stl_buf_unlocker, CharT > local_stringbuffer_t; #endif + typedef BOOST_DEDUCED_TYPENAME ::boost::mpl::if_c< + RequiresStringbuffer, + local_stringbuffer_t, + char + >::type deduced_stringbuffer_t; + // A string representation of Source is written to [start, finish). - // Currently, it is assumed that [start, finish) is big enough - // to hold a string representation of any Source value. CharT* start; CharT* finish; - local_stringbuffer_t *stringbuf; + deduced_stringbuffer_t stringbuffer; public: lexical_stream_limited_src(CharT* sta, CharT* fin) : start(sta) , finish(fin) - , stringbuf(NULL) {} - ~lexical_stream_limited_src() - { - if (stringbuf) delete stringbuf; - } - private: // Undefined: lexical_stream_limited_src(lexical_stream_limited_src const&); @@ -1078,7 +1079,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 whar_t to char types." + "boost::lexical_cast does not support conversions from wchar_t to char types." "Use boost::locale instead" ); return shl_input_streamable(str); } @@ -1087,15 +1088,10 @@ namespace boost template bool shl_input_streamable(InputStreamable& input) { - /* No one will call this function twice, - * so we do not need `if (!stringbuf)' */ - stringbuf = new local_stringbuffer_t(); - - std::basic_ostream stream(stringbuf); - lcast_set_precision(stream, static_cast(0)); + std::basic_ostream stream(&stringbuffer); bool const result = !(stream << input).fail(); - start = stringbuf->pbase(); - finish = stringbuf->pptr(); + start = stringbuffer.pbase(); + finish = stringbuffer.pptr(); return result; } @@ -1112,18 +1108,44 @@ namespace boost return true; } -#ifndef BOOST_LCAST_NO_COMPILE_TIME_PRECISION template - bool shl_float_types(T val) - { - if (put_inf_nan(start, finish, val)) return true; - local_streambuffer_t bb; - bb.setp(start, finish); - std::basic_ostream stream(&bb); - lcast_set_precision(stream, &val); - bool const result = !(stream << val).fail(); - finish = bb.pptr(); - return result; + bool shl_float(float val,T* out) + { using namespace std; + finish = start + sprintf(out,"%.*g", static_cast(boost::detail::lcast_get_precision()), val ); + return finish > start; + } + + template + bool shl_double(double val,T* out) + { using namespace std; + finish = start + sprintf(out,"%.*lg", static_cast(boost::detail::lcast_get_precision()), val ); + return finish > start; + } + + template + bool shl_long_double(long double val,T* out) + { using namespace std; + finish = start + sprintf(out,"%.*Lg", static_cast(boost::detail::lcast_get_precision()), val ); + return finish > start; + } + +#ifndef BOOST_LCAST_NO_WCHAR_T + bool shl_float(float val,wchar_t* out) + { using namespace std; + finish = start + swprintf(out,finish-start,L"%.*g", static_cast(boost::detail::lcast_get_precision()), val ); + return finish > start; + } + + bool shl_double(double val,wchar_t* out) + { using namespace std; + finish = start + swprintf(out,finish-start,L"%.*lg", static_cast(boost::detail::lcast_get_precision()), val ); + return finish > start; + } + + bool shl_long_double(long double val,wchar_t* out) + { using namespace std; + finish = start + swprintf(out,finish-start,L"%.*Lg", static_cast(boost::detail::lcast_get_precision()), val ); + return finish > start; } #endif @@ -1171,11 +1193,9 @@ namespace boost bool operator<<(unsigned __int64 n) { start = lcast_put_unsigned(n, finish); return true; } bool operator<<( __int64 n) { return shl_signed(n); } #endif -#ifndef BOOST_LCAST_NO_COMPILE_TIME_PRECISION - bool operator<<(float val) { return shl_float_types(val); } - bool operator<<(double val) { return shl_float_types(val); } - bool operator<<(long double val) { return shl_float_types(val); } -#endif // BOOST_LCAST_NO_COMPILE_TIME_PRECISION + bool operator<<(float val) { return shl_float(val,start); } + bool operator<<(double val) { return shl_double(val,start); } + bool operator<<(long double val) { return shl_long_double(val,start); } template bool operator<<(const InStreamable& input) { return shl_input_streamable(input); } @@ -1586,7 +1606,25 @@ namespace boost typedef BOOST_DEDUCED_TYPENAME deduce_char_traits::type traits; - detail::lexical_stream_limited_src interpreter(buf, buf + src_len); + typedef BOOST_DEDUCED_TYPENAME remove_pointer::type removed_ptr_t; + const bool requires_stringbuf = + !( + ::boost::type_traits::ice_or< + is_stdstring::value, + is_arithmetic::value, + ::boost::type_traits::ice_and< + is_pointer::value, + is_char_or_wchar::value, + ::boost::type_traits::ice_eq< + sizeof(char_type), + sizeof(removed_ptr_t) + >::value + >::value + >::value + ); + + detail::lexical_stream_limited_src + interpreter(buf, buf + src_len); Target result; if(!(interpreter << arg && interpreter >> result)) From 0ee6400d5ea89e6f4aa4e2508b6700a55a3e3006 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Sun, 24 Jul 2011 10:56:54 +0000 Subject: [PATCH 22/39] Fixes #5732. * fixes some warnings and bugs for VC [SVN r73328] --- include/boost/lexical_cast.hpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index e3e0632..5d85a5d 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -1108,9 +1108,16 @@ namespace boost return true; } +#if (defined _MSC_VER) +# pragma warning( push ) +// C4996: This function or variable may be unsafe. Consider using sprintf_s instead +# pragma warning( disable : 4996 ) +#endif + template bool shl_float(float val,T* out) { using namespace std; + if (put_inf_nan(start,finish,val)) return true; finish = start + sprintf(out,"%.*g", static_cast(boost::detail::lcast_get_precision()), val ); return finish > start; } @@ -1118,6 +1125,7 @@ namespace boost template bool shl_double(double val,T* out) { using namespace std; + if (put_inf_nan(start,finish,val)) return true; finish = start + sprintf(out,"%.*lg", static_cast(boost::detail::lcast_get_precision()), val ); return finish > start; } @@ -1125,25 +1133,34 @@ namespace boost template bool shl_long_double(long double val,T* out) { using namespace std; + if (put_inf_nan(start,finish,val)) return true; finish = start + sprintf(out,"%.*Lg", static_cast(boost::detail::lcast_get_precision()), val ); return finish > start; } +#if (defined _MSC_VER) +# pragma warning( pop ) +#endif + + #ifndef BOOST_LCAST_NO_WCHAR_T bool shl_float(float val,wchar_t* out) { using namespace std; + if (put_inf_nan(start,finish,val)) return true; finish = start + swprintf(out,finish-start,L"%.*g", static_cast(boost::detail::lcast_get_precision()), val ); return finish > start; } bool shl_double(double val,wchar_t* out) { using namespace std; + if (put_inf_nan(start,finish,val)) return true; finish = start + swprintf(out,finish-start,L"%.*lg", static_cast(boost::detail::lcast_get_precision()), val ); return finish > start; } bool shl_long_double(long double val,wchar_t* out) { using namespace std; + if (put_inf_nan(start,finish,val)) return true; finish = start + swprintf(out,finish-start,L"%.*Lg", static_cast(boost::detail::lcast_get_precision()), val ); return finish > start; } From 2b76f558c10fb965b2bad902f9d49a3fbb8b8c7c Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Mon, 25 Jul 2011 05:02:07 +0000 Subject: [PATCH 23/39] #5732. Adds workaround for MinGW bugs [SVN r73347] --- include/boost/lexical_cast.hpp | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index 5d85a5d..7874743 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -1147,21 +1147,42 @@ namespace boost bool shl_float(float val,wchar_t* out) { using namespace std; if (put_inf_nan(start,finish,val)) return true; - finish = start + swprintf(out,finish-start,L"%.*g", static_cast(boost::detail::lcast_get_precision()), val ); + finish = start + swprintf(out, +#ifndef __MINGW32__ + finish-start, +#endif + L"%.*g", static_cast(boost::detail::lcast_get_precision()), val ); + return finish > start; } + bool shl_double(double val,wchar_t* out) { using namespace std; if (put_inf_nan(start,finish,val)) return true; - finish = start + swprintf(out,finish-start,L"%.*lg", static_cast(boost::detail::lcast_get_precision()), val ); + /* __MINGW32__ is defined for both mingw.org and for mingw-w64. + * For mingw-w64, __MINGW64__ is defined, too, when targetting + * 64 bits. + * + * swprintf realization in MinGW does not conform to the ISO C + * Standard. + */ + finish = start + swprintf(out, +#ifndef __MINGW32__ + finish-start, +#endif + L"%.*lg", static_cast(boost::detail::lcast_get_precision()), val ); return finish > start; } bool shl_long_double(long double val,wchar_t* out) { using namespace std; if (put_inf_nan(start,finish,val)) return true; - finish = start + swprintf(out,finish-start,L"%.*Lg", static_cast(boost::detail::lcast_get_precision()), val ); + finish = start + swprintf(out, +#ifndef __MINGW32__ + finish-start, +#endif + L"%.*Lg", static_cast(boost::detail::lcast_get_precision()), val ); return finish > start; } #endif From 9ac4e2bef184f81a420da369f52ff4307b9ec7c6 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Mon, 25 Jul 2011 15:13:36 +0000 Subject: [PATCH 24/39] Fixes #5732. * fixes compilation errors for nonconst char arrays [SVN r73357] --- include/boost/lexical_cast.hpp | 11 ++++++++++- lexical_cast_test.cpp | 28 ++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index 7874743..9e0a7af 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -1000,6 +1000,11 @@ namespace boost }; } + namespace detail + { + struct do_not_construct_stringbuffer_t{}; + } + namespace detail // optimized stream wrapper { // String representation of Source has an upper limit. @@ -1021,7 +1026,7 @@ namespace boost typedef BOOST_DEDUCED_TYPENAME ::boost::mpl::if_c< RequiresStringbuffer, local_stringbuffer_t, - char + do_not_construct_stringbuffer_t >::type deduced_stringbuffer_t; // A string representation of Source is written to [start, finish). @@ -1210,13 +1215,17 @@ namespace boost bool operator<<(signed char ch) { return ((*this) << static_cast(ch)); } #if !defined(BOOST_LCAST_NO_WCHAR_T) bool operator<<(wchar_t const* str) { return shl_char_array(str); } + bool operator<<(wchar_t * str) { return shl_char_array(str); } #ifndef BOOST_NO_INTRINSIC_WCHAR_T bool operator<<(wchar_t ch) { return shl_char(ch); } #endif #endif bool operator<<(unsigned char const* ch) { return ((*this) << reinterpret_cast(ch)); } + bool operator<<(unsigned char * ch) { return ((*this) << reinterpret_cast(ch)); } bool operator<<(signed char const* ch) { return ((*this) << reinterpret_cast(ch)); } + bool operator<<(signed char * ch) { return ((*this) << reinterpret_cast(ch)); } bool operator<<(char const* str) { return shl_char_array(str); } + bool operator<<(char* str) { return shl_char_array(str); } bool operator<<(short n) { return shl_signed(n); } bool operator<<(int n) { return shl_signed(n); } bool operator<<(long n) { return shl_signed(n); } diff --git a/lexical_cast_test.cpp b/lexical_cast_test.cpp index 244addb..37753ca 100644 --- a/lexical_cast_test.cpp +++ b/lexical_cast_test.cpp @@ -35,6 +35,7 @@ #include #include +#include #include #if (defined(BOOST_HAS_LONG_LONG) || defined(BOOST_HAS_MS_INT64)) \ @@ -69,6 +70,7 @@ void test_conversion_to_char(); void test_conversion_to_int(); void test_conversion_to_double(); void test_conversion_to_bool(); +void test_conversion_with_nonconst_char(); void test_conversion_to_string(); void test_conversion_from_to_wchar_t_alias(); void test_conversion_to_pointer(); @@ -109,6 +111,7 @@ unit_test::test_suite *init_unit_test_suite(int, char *[]) suite->add(BOOST_TEST_CASE(test_conversion_from_to_wchar_t_alias)); suite->add(BOOST_TEST_CASE(test_conversion_to_pointer)); suite->add(BOOST_TEST_CASE(test_conversion_to_string)); + suite->add(BOOST_TEST_CASE(test_conversion_with_nonconst_char)); #ifndef BOOST_LCAST_NO_WCHAR_T suite->add(BOOST_TEST_CASE(test_conversion_from_wchar_t)); suite->add(BOOST_TEST_CASE(test_conversion_to_wchar_t)); @@ -199,6 +202,31 @@ void test_conversion_to_int() lexical_cast(std::string("Test")), bad_lexical_cast); } +void test_conversion_with_nonconst_char() +{ + std::vector buffer; + buffer.push_back('1'); + buffer.push_back('\0'); + BOOST_CHECK_EQUAL(boost::lexical_cast(&buffer[0]), 1); + + std::vector buffer2; + buffer2.push_back('1'); + buffer2.push_back('\0'); + BOOST_CHECK_EQUAL(boost::lexical_cast(&buffer2[0]), 1); + + std::vector buffer3; + buffer3.push_back('1'); + buffer3.push_back('\0'); + BOOST_CHECK_EQUAL(boost::lexical_cast(&buffer3[0]), 1); + +#ifndef BOOST_LCAST_NO_WCHAR_T + std::vector buffer4; + buffer4.push_back(L'1'); + buffer4.push_back(L'\0'); + BOOST_CHECK_EQUAL(boost::lexical_cast(&buffer4[0]), 1); +#endif +} + void test_conversion_to_double() { BOOST_CHECK_CLOSE_FRACTION(1.0, lexical_cast('1'), (std::numeric_limits::epsilon())); From 19f316f768a20c45365e87e075b431c951def6d4 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Tue, 26 Jul 2011 18:51:39 +0000 Subject: [PATCH 25/39] Fixes #5732. * fixes compilation errors pgi compiler * fixes some bugs for MinGW compiler [SVN r73384] --- include/boost/lexical_cast.hpp | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index 9e0a7af..5987908 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -47,6 +47,10 @@ #include #include +#ifdef __PGI +#include +#endif + #ifndef BOOST_NO_STD_LOCALE # include #else @@ -1134,7 +1138,7 @@ namespace boost finish = start + sprintf(out,"%.*lg", static_cast(boost::detail::lcast_get_precision()), val ); return finish > start; } - +#ifndef __MINGW32__ template bool shl_long_double(long double val,T* out) { using namespace std; @@ -1142,6 +1146,7 @@ namespace boost finish = start + sprintf(out,"%.*Lg", static_cast(boost::detail::lcast_get_precision()), val ); return finish > start; } +#endif #if (defined _MSC_VER) # pragma warning( pop ) @@ -1180,16 +1185,16 @@ namespace boost return finish > start; } +#ifndef __MINGW32__ bool shl_long_double(long double val,wchar_t* out) { using namespace std; if (put_inf_nan(start,finish,val)) return true; - finish = start + swprintf(out, -#ifndef __MINGW32__ - finish-start, -#endif - L"%.*Lg", static_cast(boost::detail::lcast_get_precision()), val ); + finish = start + swprintf(out,finish-start, + L"%.*Lg", static_cast(boost::detail::lcast_get_precision()), val ); return finish > start; } + #endif + #endif /************************************ OPERATORS << ( ... ) ********************************/ @@ -1242,7 +1247,13 @@ namespace boost #endif bool operator<<(float val) { return shl_float(val,start); } bool operator<<(double val) { return shl_double(val,start); } - bool operator<<(long double val) { return shl_long_double(val,start); } + bool operator<<(long double val) { +#ifndef __MINGW32__ + return shl_long_double(val,start); +#else + return shl_double(val,start); +#endif + } template bool operator<<(const InStreamable& input) { return shl_input_streamable(input); } From 30e4efd062c698a24f3f943bf4f1340357de2dd7 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Wed, 27 Jul 2011 15:56:49 +0000 Subject: [PATCH 26/39] Fixes #5732. * one more try to fix compilation errors on pgi compiler [SVN r73401] --- include/boost/lexical_cast.hpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index 5987908..4690a9e 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -46,10 +46,8 @@ #include #include #include - -#ifdef __PGI #include -#endif + #ifndef BOOST_NO_STD_LOCALE # include From aba423d425b6e8eed4aa70c82a674cac9cc9f038 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Fri, 29 Jul 2011 19:33:18 +0000 Subject: [PATCH 27/39] Fixes #5732. * one more try to fix compilation errors on pgi compiler [SVN r73435] --- include/boost/lexical_cast.hpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index 4690a9e..48fdda7 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -1156,7 +1156,7 @@ namespace boost { using namespace std; if (put_inf_nan(start,finish,val)) return true; finish = start + swprintf(out, -#ifndef __MINGW32__ +#if !defined(__MINGW32__) && !defined(__PGIC__) finish-start, #endif L"%.*g", static_cast(boost::detail::lcast_get_precision()), val ); @@ -1176,7 +1176,7 @@ namespace boost * Standard. */ finish = start + swprintf(out, -#ifndef __MINGW32__ +#if !defined(__MINGW32__) && !defined(__PGIC__) finish-start, #endif L"%.*lg", static_cast(boost::detail::lcast_get_precision()), val ); @@ -1187,7 +1187,10 @@ namespace boost bool shl_long_double(long double val,wchar_t* out) { using namespace std; if (put_inf_nan(start,finish,val)) return true; - finish = start + swprintf(out,finish-start, + finish = start + swprintf(out, +#if !defined(__PGIC__) + finish-start, +#endif L"%.*Lg", static_cast(boost::detail::lcast_get_precision()), val ); return finish > start; } From a9778ad460659ea5d1d1960e710101b3e914e282 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Sat, 30 Jul 2011 16:47:30 +0000 Subject: [PATCH 28/39] Fixes #5732. * at least compiles on pgi [SVN r73446] --- include/boost/lexical_cast.hpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index 48fdda7..25884b6 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -1156,7 +1156,7 @@ namespace boost { using namespace std; if (put_inf_nan(start,finish,val)) return true; finish = start + swprintf(out, -#if !defined(__MINGW32__) && !defined(__PGIC__) +#if !defined(__MINGW32__) finish-start, #endif L"%.*g", static_cast(boost::detail::lcast_get_precision()), val ); @@ -1176,7 +1176,7 @@ namespace boost * Standard. */ finish = start + swprintf(out, -#if !defined(__MINGW32__) && !defined(__PGIC__) +#if !defined(__MINGW32__) finish-start, #endif L"%.*lg", static_cast(boost::detail::lcast_get_precision()), val ); @@ -1187,11 +1187,7 @@ namespace boost bool shl_long_double(long double val,wchar_t* out) { using namespace std; if (put_inf_nan(start,finish,val)) return true; - finish = start + swprintf(out, -#if !defined(__PGIC__) - finish-start, -#endif - L"%.*Lg", static_cast(boost::detail::lcast_get_precision()), val ); + finish = start + swprintf(out, finish-start, L"%.*Lg", static_cast(boost::detail::lcast_get_precision()), val ); return finish > start; } #endif From e8108e50668cac57209d4f0e2b2afc80f8463d7a Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Sun, 7 Aug 2011 17:38:33 +0000 Subject: [PATCH 29/39] Fixes #5732. * some fixes for WinCE * updated explicit failures markup [SVN r73601] --- include/boost/lexical_cast.hpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index 25884b6..34a0aed 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -1156,7 +1156,7 @@ namespace boost { using namespace std; if (put_inf_nan(start,finish,val)) return true; finish = start + swprintf(out, -#if !defined(__MINGW32__) +#if !defined(__MINGW32__) && !defined(UNDER_CE) finish-start, #endif L"%.*g", static_cast(boost::detail::lcast_get_precision()), val ); @@ -1172,11 +1172,12 @@ namespace boost * For mingw-w64, __MINGW64__ is defined, too, when targetting * 64 bits. * - * swprintf realization in MinGW does not conform to the ISO C + * swprintf realization in MinGW and under WinCE does not conform + * to the ISO C * Standard. */ finish = start + swprintf(out, -#if !defined(__MINGW32__) +#if !defined(__MINGW32__) && !defined(UNDER_CE) finish-start, #endif L"%.*lg", static_cast(boost::detail::lcast_get_precision()), val ); @@ -1187,10 +1188,14 @@ namespace boost bool shl_long_double(long double val,wchar_t* out) { using namespace std; if (put_inf_nan(start,finish,val)) return true; - finish = start + swprintf(out, finish-start, L"%.*Lg", static_cast(boost::detail::lcast_get_precision()), val ); + finish = start + swprintf(out, +#if !defined(UNDER_CE) + finish-start, +#endif + L"%.*Lg", static_cast(boost::detail::lcast_get_precision()), val ); return finish > start; } - #endif +#endif #endif From 9955dcce51f746710b1fc67cda1026b2f41e60d4 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Wed, 10 Aug 2011 18:58:06 +0000 Subject: [PATCH 30/39] Fixes #5732. * suppress compilation warnings, if the compiler requires a return, even when it can never be reached [SVN r73640] --- include/boost/lexical_cast.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index 34a0aed..686b9f5 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -1750,6 +1750,7 @@ namespace boost } catch( ::boost::numeric::bad_numeric_cast const& ) { BOOST_LCAST_THROW_BAD_CAST(Source, Target); } + BOOST_UNREACHABLE_RETURN(static_cast(0)); } }; @@ -1776,6 +1777,7 @@ namespace boost } catch( ::boost::numeric::bad_numeric_cast const& ) { BOOST_LCAST_THROW_BAD_CAST(Source, Target); } + BOOST_UNREACHABLE_RETURN(static_cast(0)); } }; From 4a4150d0be5f09bae17efc9e194cf80bb0fbfff0 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Fri, 12 Aug 2011 17:04:31 +0000 Subject: [PATCH 31/39] Fixes #5746 Updates FAQ section of documentation [SVN r73705] --- doc/lexical_cast.qbk | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/doc/lexical_cast.qbk b/doc/lexical_cast.qbk index f5beec7..360534a 100644 --- a/doc/lexical_cast.qbk +++ b/doc/lexical_cast.qbk @@ -118,17 +118,29 @@ Exception used to indicate runtime lexical_cast failure. [section Frequently Asked Questions] * [*Question:] Why does `lexical_cast("127")` throw `bad_lexical_cast`? - * [*Answer:] The type `int8_t` is a `typedef` to `char` or `signed char`. Lexical conversion to these types -is simply reading a byte from source but since the source has more than one byte, the exception is thrown. + * [*Answer:] The type `int8_t` is a `typedef` to `char` or `signed char`. Lexical conversion to these types is simply reading a byte from source but since the source has more than one byte, the exception is thrown. Please use other integer types such as `int` or `short int`. If bounds checking is important, you can also call __numericcast__: `numeric_cast(lexical_cast("127"));` +[pre +] + +* [*Question:] Why does `lexical_cast("127")` throw `bad_lexical_cast`? + * [*Answer:] Lexical conversion to any char type is simply reading a byte from source. But since the source has more than one byte, the exception is thrown. +Please use other integer types such as `int` or `short int`. If bounds checking is important, you can also +call __numericcast__: +`numeric_cast(lexical_cast("127"));` + +[pre +] * [*Question:] What does `lexical_cast` of an `int8_t` or `uint8_t` not do what I expect? * [*Answer:] As above, note that int8_t and uint8_t are actually chars and are formatted as such. To avoid this, cast to an integer type first: `lexical_cast(static_cast(n));` +[pre +] * [*Question:] The implementation always resets the `ios_base::skipws` flag of an underlying stream object. It breaks my `operator>>` that works only in presence of this flag. Can you remove code that resets the flag? @@ -138,6 +150,8 @@ remember that __proposalshort__ is not yet accepted by the committee. By the way make your `operator>>` conform to the standard. Read a good C++ book, study `std::sentry` and [@boost:libs/io/doc/ios_state.html `ios_state_saver`]. +[pre +] * [*Question:] Why `std::cout << boost::lexical_cast("-1");` does not throw, but outputs 4294967295? * [*Answer:] `boost::lexical_cast` has the behavior of `std::stringstream`, which uses `num_get` functions of From 5ebb13bbad64b7e2e2b44e7ca6593d0b81e13961 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Fri, 12 Aug 2011 17:08:17 +0000 Subject: [PATCH 32/39] Very small update for FAQ section of documentation [SVN r73706] --- doc/lexical_cast.qbk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/lexical_cast.qbk b/doc/lexical_cast.qbk index 360534a..9fb6cdf 100644 --- a/doc/lexical_cast.qbk +++ b/doc/lexical_cast.qbk @@ -130,7 +130,7 @@ call __numericcast__: * [*Answer:] Lexical conversion to any char type is simply reading a byte from source. But since the source has more than one byte, the exception is thrown. Please use other integer types such as `int` or `short int`. If bounds checking is important, you can also call __numericcast__: -`numeric_cast(lexical_cast("127"));` +`numeric_cast(lexical_cast("127"));` [pre ] From eb66b40e6729fca3971fd87d37a1dcbcfd74d984 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Fri, 12 Aug 2011 17:35:56 +0000 Subject: [PATCH 33/39] FIxes #5631 Workaround for nvcc bug [SVN r73707] --- include/boost/lexical_cast.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index 686b9f5..3ac3cc9 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -261,7 +261,7 @@ namespace boost #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS BOOST_STATIC_CONSTANT(std::size_t, value = std::numeric_limits::is_signed + - std::numeric_limits::is_specialized + // == 1 + std::numeric_limits::is_specialized + /* == 1 */ std::numeric_limits::digits10 * 2 ); #else From 2f5d0c847bba655e5391d55bdc43d18c9cb3592f Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Tue, 16 Aug 2011 17:09:25 +0000 Subject: [PATCH 34/39] Fixes #5783 Fixes ambiguities with operators >> and <<. Adds tests for such cases. [SVN r73818] --- include/boost/lexical_cast.hpp | 3 ++- lexical_cast_test.cpp | 28 ++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index 3ac3cc9..6479e5d 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -1687,7 +1687,8 @@ namespace boost interpreter(buf, buf + src_len); Target result; - if(!(interpreter << arg && interpreter >> result)) + // Disabling ADL, by directly specifying operators. + if(!(interpreter.operator <<(arg) && interpreter.operator >>(result))) BOOST_LCAST_THROW_BAD_CAST(Source, Target); return result; } diff --git a/lexical_cast_test.cpp b/lexical_cast_test.cpp index 37753ca..f07926b 100644 --- a/lexical_cast_test.cpp +++ b/lexical_cast_test.cpp @@ -99,6 +99,7 @@ void test_allocator(); void test_wallocator(); #endif void test_char_types_conversions(); +void operators_overload_test(); unit_test::test_suite *init_unit_test_suite(int, char *[]) { @@ -140,6 +141,7 @@ unit_test::test_suite *init_unit_test_suite(int, char *[]) #endif suite->add(BOOST_TEST_CASE(&test_char_types_conversions)); + suite->add(BOOST_TEST_CASE(&operators_overload_test)); return suite; } @@ -958,7 +960,33 @@ void test_char_types_conversions() +struct foo_operators_test +{ + foo_operators_test() : f(2) {} + int f; +}; +template +OStream& operator<<(OStream& ostr, const foo_operators_test& foo) +{ + ostr << foo.f; + return ostr; +} +template +IStream& operator>>(IStream& istr, foo_operators_test& foo) +{ + istr >> foo.f; + return istr; +} +void operators_overload_test() +{ + foo_operators_test foo; + BOOST_CHECK_EQUAL(boost::lexical_cast(foo), "2"); + BOOST_CHECK_EQUAL((boost::lexical_cast("2")).f, 2); + + // Must compile + (void)boost::lexical_cast(foo); +} From 2acef7aa443b2cb448197b98289905b22e321746 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Mon, 5 Sep 2011 19:00:29 +0000 Subject: [PATCH 35/39] Basic support for char16_t and char32_t [SVN r74243] --- include/boost/lexical_cast.hpp | 223 ++++++++++++++++++++------------- lexical_cast_test.cpp | 34 ++++- 2 files changed, 166 insertions(+), 91 deletions(-) diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index 6479e5d..e536ac5 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -133,60 +133,102 @@ namespace boost namespace detail // selectors for choosing stream character type { - template - struct stream_char - { - typedef char type; - }; + template + struct stream_char + { + typedef char type; + }; #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION - template - struct stream_char< std::basic_string > - { - typedef CharT type; - }; + template + struct stream_char< std::basic_string > + { + typedef CharT type; + }; #endif #ifndef BOOST_LCAST_NO_WCHAR_T #ifndef BOOST_NO_INTRINSIC_WCHAR_T - template<> - struct stream_char - { - typedef wchar_t type; - }; + 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; - }; + template<> + struct stream_char + { + typedef wchar_t type; + }; #ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION - template<> - struct stream_char - { - typedef wchar_t type; - }; + 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 struct widest_char { - typedef TargetChar type; - }; - - template<> - struct widest_char - { - typedef wchar_t type; + typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_c< + (sizeof(TargetChar) > sizeof(SourceChar)) + , TargetChar + , SourceChar >::type type; }; } @@ -231,8 +273,7 @@ namespace boost namespace detail // lcast_src_length { // Return max. length of string representation of Source; - template< class CharT // A result of widest_char transformation. - , class Source // Source type of lexical_cast. + template< class Source // Source type of lexical_cast. > struct lcast_src_length { @@ -269,20 +310,12 @@ namespace boost BOOST_STATIC_ASSERT(sizeof(Source) * CHAR_BIT <= 256); #endif }; - -#define BOOST_LCAST_DEF1(CharT, T) \ - template<> struct lcast_src_length \ +// 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 \ { static void check_coverage() {} }; -#ifdef BOOST_LCAST_NO_WCHAR_T -#define BOOST_LCAST_DEF(T) BOOST_LCAST_DEF1(char, T) -#else -#define BOOST_LCAST_DEF(T) \ - BOOST_LCAST_DEF1(char, T) \ - BOOST_LCAST_DEF1(wchar_t, T) -#endif - BOOST_LCAST_DEF(short) BOOST_LCAST_DEF(unsigned short) BOOST_LCAST_DEF(int) @@ -298,7 +331,6 @@ namespace boost #endif #undef BOOST_LCAST_DEF -#undef BOOST_LCAST_DEF1 #ifndef BOOST_LCAST_NO_COMPILE_TIME_PRECISION // Helper for floating point types. @@ -324,49 +356,26 @@ namespace boost }; template<> - struct lcast_src_length + struct lcast_src_length : lcast_src_length_floating { static void check_coverage() {} }; template<> - struct lcast_src_length + struct lcast_src_length : lcast_src_length_floating { static void check_coverage() {} }; template<> - struct lcast_src_length + struct lcast_src_length : lcast_src_length_floating { static void check_coverage() {} }; -#ifndef BOOST_LCAST_NO_WCHAR_T - template<> - struct lcast_src_length - : lcast_src_length_floating - { - static void check_coverage() {} - }; - - template<> - struct lcast_src_length - : lcast_src_length_floating - { - static void check_coverage() {} - }; - - template<> - struct lcast_src_length - : lcast_src_length_floating - { - static void check_coverage() {} - }; - -#endif // #ifndef BOOST_LCAST_NO_WCHAR_T #endif // #ifndef BOOST_LCAST_NO_COMPILE_TIME_PRECISION } @@ -397,6 +406,32 @@ namespace boost BOOST_STATIC_CONSTANT(wchar_t, c_decimal_separator = L'.'); }; #endif + +#ifndef BOOST_NO_CHAR16_T + template<> + struct lcast_char_constants + { + BOOST_STATIC_CONSTANT(char16_t, zero = u'0'); + BOOST_STATIC_CONSTANT(char16_t, minus = u'-'); + BOOST_STATIC_CONSTANT(char16_t, plus = u'+'); + BOOST_STATIC_CONSTANT(char16_t, lowercase_e = u'e'); + BOOST_STATIC_CONSTANT(char16_t, capital_e = u'E'); + BOOST_STATIC_CONSTANT(char16_t, c_decimal_separator = u'.'); + }; +#endif + +#ifndef BOOST_NO_CHAR32_T + template<> + struct lcast_char_constants + { + BOOST_STATIC_CONSTANT(char32_t, zero = U'0'); + BOOST_STATIC_CONSTANT(char32_t, minus = U'-'); + BOOST_STATIC_CONSTANT(char32_t, plus = U'+'); + BOOST_STATIC_CONSTANT(char32_t, lowercase_e = U'e'); + BOOST_STATIC_CONSTANT(char32_t, capital_e = U'E'); + BOOST_STATIC_CONSTANT(char32_t, c_decimal_separator = U'.'); + }; +#endif } namespace detail // lcast_to_unsigned @@ -1553,28 +1588,38 @@ namespace boost template struct is_char_or_wchar { + private: #ifndef BOOST_LCAST_NO_WCHAR_T - BOOST_STATIC_CONSTANT(bool, value = - ( - ::boost::type_traits::ice_or< - is_same< T, char >::value, - is_same< T, wchar_t >::value, - is_same< T, unsigned char >::value, - is_same< T, signed char >::value - >::value - ) - ); + 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 ) ); -#endif }; template @@ -1658,7 +1703,7 @@ namespace boost , BOOST_DEDUCED_TYPENAME detail::stream_char::type >::type char_type; - 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(); diff --git a/lexical_cast_test.cpp b/lexical_cast_test.cpp index f07926b..47381cd 100644 --- a/lexical_cast_test.cpp +++ b/lexical_cast_test.cpp @@ -100,6 +100,13 @@ void test_wallocator(); #endif void test_char_types_conversions(); void operators_overload_test(); +#ifndef BOOST_NO_CHAR16_T +void test_char16_conversions(); +#endif +#ifndef BOOST_NO_CHAR32_T +void test_char32_conversions(); +#endif + unit_test::test_suite *init_unit_test_suite(int, char *[]) { @@ -142,6 +149,12 @@ 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)); +#ifndef BOOST_NO_CHAR16_T + suite->add(BOOST_TEST_CASE(&test_char16_conversions)); +#endif +#ifndef BOOST_NO_CHAR32_T + suite->add(BOOST_TEST_CASE(&test_char32_conversions)); +#endif return suite; } @@ -582,7 +595,7 @@ void test_conversion_from_integral_to_string(CharT) // Test values around zero: if(limits::is_signed) - for(t = -counter; t < static_cast(counter); ++t) + for(t = static_cast(-counter); t < static_cast(counter); ++t) BOOST_CHECK(lexical_cast(t) == to_str(t)); // Test values around 100, 1000, 10000, ... @@ -679,7 +692,7 @@ void test_conversion_from_string_to_integral(CharT) // Test values around zero: if(limits::is_signed) - for(t = -counter; t < static_cast(counter); ++t) + for(t = static_cast(-counter); t < static_cast(counter); ++t) BOOST_CHECK(lexical_cast(to_str(t)) == t); // Test values around 100, 1000, 10000, ... @@ -990,3 +1003,20 @@ void operators_overload_test() (void)boost::lexical_cast(foo); } + +#ifndef BOOST_NO_CHAR16_T +void test_char16_conversions() +{ + BOOST_CHECK(u"100" == lexical_cast(u"100")); + BOOST_CHECK(u"1" == lexical_cast(u'1')); +} +#endif + +#ifndef BOOST_NO_CHAR32_T +void test_char32_conversions() +{ + BOOST_CHECK(U"100" == lexical_cast(U"100")); + BOOST_CHECK(U"1" == lexical_cast(U'1')); +} +#endif + From d2ae7fdbd7578ac43427b2962d8f8a3d44f22718 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Sat, 17 Sep 2011 09:09:27 +0000 Subject: [PATCH 36/39] char16_t and char32_t conversions now work on gcc for C locale Optimizations for C locale Performance section of documentation updated [SVN r74432] --- doc/lexical_cast.qbk | 780 +++++++++++++++------------------ include/boost/lexical_cast.hpp | 175 ++++---- lexical_cast_test.cpp | 10 + 3 files changed, 448 insertions(+), 517 deletions(-) diff --git a/doc/lexical_cast.qbk b/doc/lexical_cast.qbk index 9fb6cdf..b540267 100644 --- a/doc/lexical_cast.qbk +++ b/doc/lexical_cast.qbk @@ -243,457 +243,365 @@ Do not use this results to compare compilers, because tests were taken on differ [section clang-linux-2.8][table:id Performance Table (clang-linux-2.8) [[From->To] [lexical_cast] [std::stringstream with construction] [std::stringstream without construction][scanf/printf]] -[[ string->char ][ !!! *<1* !!! ][ 106 ][ 11 ][ 11 ]] -[[ string->signed char ][ !!! *<1* !!! ][ 102 ][ 8 ][ 8 ]] -[[ string->unsigned char ][ !!! *<1* !!! ][ 83 ][ 7 ][ 15 ]] -[[ string->int ][ !!! *8* !!! ][ 114 ][ 21 ][ 17 ]] -[[ string->short ][ !!! *10* !!! ][ 111 ][ 20 ][ 17 ]] -[[ string->long int ][ !!! *9* !!! ][ 113 ][ 20 ][ 16 ]] -[[ string->long long ][ !!! *9* !!! ][ 112 ][ 21 ][ 16 ]] -[[ string->unsigned int ][ !!! *9* !!! ][ 115 ][ 23 ][ 17 ]] -[[ string->unsigned short ][ !!! *7* !!! ][ 111 ][ 21 ][ 16 ]] -[[ string->unsigned long int ][ !!! *9* !!! ][ 106 ][ 20 ][ 17 ]] -[[ string->unsigned long long ][ !!! *9* !!! ][ 104 ][ 21 ][ 17 ]] -[[ string->bool ][ !!! *<1* !!! ][ 101 ][ 17 ][ 10 ]] -[[ string->float ][ !!! *16* !!! ][ 175 ][ 67 ][ 33 ]] -[[ string->double ][ !!! *18* !!! ][ 196 ][ 91 ][ 56 ]] -[[ string->long double ][ 126 ][ 198 ][ 92 ][ !!! *61* !!! ]] -[[ char->string ][ !!! *12* !!! ][ 101 ][ 16 ][ 12 ]] -[[ unsigned char->string ][ !!! *10* !!! ][ 103 ][ 18 ][ 17 ]] -[[ signed char->string ][ !!! *12* !!! ][ 101 ][ 18 ][ 12 ]] -[[ int->string ][ !!! *19* !!! ][ 124 ][ 25 ][ 19 ]] -[[ short->string ][ 23 ][ 124 ][ 26 ][ !!! *17* !!! ]] -[[ long int->string ][ 20 ][ 123 ][ 23 ][ !!! *17* !!! ]] -[[ long long->string ][ 19 ][ 124 ][ 23 ][ !!! *18* !!! ]] -[[ unsigned int->string ][ 18 ][ 122 ][ 28 ][ !!! *17* !!! ]] -[[ unsigned short->string ][ 36 ][ 160 ][ 31 ][ !!! *17* !!! ]] -[[ unsigned long int->string ][ 22 ][ 123 ][ 28 ][ !!! *18* !!! ]] -[[ unsigned long long->string ][ !!! *23* !!! ][ 137 ][ 32 ][ 23 ]] -[[ bool->string ][ !!! *11* !!! ][ 124 ][ 26 ][ 17 ]] -[[ float->string ][ 178 ][ 273 ][ 124 ][ !!! *57* !!! ]] -[[ double->string ][ 227 ][ 450 ][ 241 ][ !!! *77* !!! ]] -[[ long double->string ][ 249 ][ 331 ][ 185 ][ !!! *85* !!! ]] -[[ char*->char ][ !!! *<1* !!! ][ 109 ][ 9 ][ 11 ]] -[[ char*->signed char ][ !!! *<1* !!! ][ 105 ][ 15 ][ 8 ]] -[[ char*->unsigned char ][ !!! *<1* !!! ][ 111 ][ 11 ][ 20 ]] -[[ char*->int ][ !!! *7* !!! ][ 143 ][ 25 ][ 19 ]] -[[ char*->short ][ !!! *10* !!! ][ 131 ][ 24 ][ 18 ]] -[[ char*->long int ][ !!! *12* !!! ][ 134 ][ 24 ][ 18 ]] -[[ char*->long long ][ !!! *12* !!! ][ 132 ][ 26 ][ 17 ]] -[[ char*->unsigned int ][ !!! *10* !!! ][ 133 ][ 26 ][ 19 ]] -[[ char*->unsigned short ][ !!! *11* !!! ][ 127 ][ 24 ][ 20 ]] -[[ char*->unsigned long int ][ !!! *10* !!! ][ 143 ][ 26 ][ 19 ]] -[[ char*->unsigned long long ][ !!! *12* !!! ][ 137 ][ 26 ][ 19 ]] -[[ char*->bool ][ !!! *2* !!! ][ 138 ][ 27 ][ 13 ]] -[[ char*->float ][ !!! *19* !!! ][ 186 ][ 65 ][ 31 ]] -[[ char*->double ][ !!! *19* !!! ][ 195 ][ 96 ][ 57 ]] -[[ char*->long double ][ 134 ][ 200 ][ 92 ][ !!! *61* !!! ]] -[[ unsigned char*->char ][ !!! *<1* !!! ][ 87 ][ 8 ][ 10 ]] -[[ unsigned char*->signed char ][ !!! *<1* !!! ][ 87 ][ 8 ][ 10 ]] -[[ unsigned char*->unsigned char ][ !!! *<1* !!! ][ 89 ][ 8 ][ 16 ]] -[[ unsigned char*->int ][ !!! *10* !!! ][ 117 ][ 22 ][ 17 ]] -[[ unsigned char*->short ][ !!! *11* !!! ][ 117 ][ 21 ][ 17 ]] -[[ unsigned char*->long int ][ !!! *10* !!! ][ 116 ][ 22 ][ 17 ]] -[[ unsigned char*->long long ][ !!! *9* !!! ][ 116 ][ 22 ][ 17 ]] -[[ unsigned char*->unsigned int ][ !!! *10* !!! ][ 117 ][ 24 ][ 17 ]] -[[ unsigned char*->unsigned short ][ !!! *11* !!! ][ 119 ][ 22 ][ 17 ]] -[[ unsigned char*->unsigned long int ][ !!! *10* !!! ][ 111 ][ 21 ][ 17 ]] -[[ unsigned char*->unsigned long long ][ !!! *10* !!! ][ 109 ][ 21 ][ 17 ]] -[[ unsigned char*->bool ][ !!! *<1* !!! ][ 105 ][ 18 ][ 10 ]] -[[ unsigned char*->float ][ !!! *17* !!! ][ 174 ][ 66 ][ 33 ]] -[[ unsigned char*->double ][ !!! *19* !!! ][ 198 ][ 91 ][ 56 ]] -[[ unsigned char*->long double ][ 129 ][ 200 ][ 92 ][ !!! *58* !!! ]] -[[ unsigned char*->string ][ !!! *12* !!! ][ 122 ][ 20 ][ --- ]] -[[ signed char*->char ][ !!! *<1* !!! ][ 87 ][ 8 ][ 9 ]] -[[ signed char*->signed char ][ !!! *<1* !!! ][ 86 ][ 8 ][ 10 ]] -[[ signed char*->unsigned char ][ !!! *<1* !!! ][ 93 ][ 8 ][ 16 ]] -[[ signed char*->int ][ !!! *10* !!! ][ 117 ][ 21 ][ 17 ]] -[[ signed char*->short ][ !!! *11* !!! ][ 117 ][ 22 ][ 17 ]] -[[ signed char*->long int ][ !!! *10* !!! ][ 115 ][ 21 ][ 17 ]] -[[ signed char*->long long ][ !!! *10* !!! ][ 115 ][ 24 ][ 17 ]] -[[ signed char*->unsigned int ][ !!! *10* !!! ][ 118 ][ 24 ][ 17 ]] -[[ signed char*->unsigned short ][ !!! *11* !!! ][ 139 ][ 27 ][ 20 ]] -[[ signed char*->unsigned long int ][ !!! *9* !!! ][ 144 ][ 27 ][ 19 ]] -[[ signed char*->unsigned long long ][ !!! *7* !!! ][ 127 ][ 25 ][ 22 ]] -[[ signed char*->bool ][ !!! *<1* !!! ][ 123 ][ 23 ][ 9 ]] -[[ signed char*->float ][ !!! *21* !!! ][ 207 ][ 80 ][ 41 ]] -[[ signed char*->double ][ !!! *23* !!! ][ 255 ][ 115 ][ 68 ]] -[[ signed char*->long double ][ 159 ][ 275 ][ 125 ][ !!! *72* !!! ]] -[[ signed char*->string ][ !!! *16* !!! ][ 155 ][ 27 ][ --- ]] -[[ int->int ][ !!! *<1* !!! ][ 150 ][ 32 ][ --- ]] -[[ float->double ][ !!! *<1* !!! ][ 304 ][ 162 ][ --- ]] -[[ double->double ][ !!! *<1* !!! ][ 298 ][ 168 ][ --- ]] -[[ int->int ][ !!! *<1* !!! ][ 311 ][ 154 ][ --- ]] -[[ int->int ][ !!! *<1* !!! ][ 308 ][ 154 ][ --- ]] -[[ char->unsigned char ][ !!! *<1* !!! ][ 97 ][ 9 ][ --- ]] -[[ char->signed char ][ !!! *<1* !!! ][ 94 ][ 11 ][ --- ]] -[[ unsigned char->char ][ !!! *<1* !!! ][ 106 ][ 8 ][ --- ]] -[[ signed char->char ][ !!! *<1* !!! ][ 111 ][ 8 ][ --- ]] -] -[endsect] -[section gcc-4.3][table:id Performance Table (gcc-4.3) -[[From->To] [lexical_cast] [std::stringstream with construction] [std::stringstream without construction][scanf/printf]] -[[ string->char ][ !!! *<1* !!! ][ 92 ][ 7 ][ 8 ]] -[[ string->signed char ][ !!! *<1* !!! ][ 92 ][ 7 ][ 8 ]] -[[ string->unsigned char ][ !!! *<1* !!! ][ 92 ][ 7 ][ 13 ]] -[[ string->int ][ !!! *6* !!! ][ 115 ][ 21 ][ 14 ]] -[[ string->short ][ !!! *7* !!! ][ 141 ][ 26 ][ 24 ]] -[[ string->long int ][ !!! *7* !!! ][ 141 ][ 27 ][ 18 ]] -[[ string->long long ][ !!! *7* !!! ][ 153 ][ 28 ][ 17 ]] -[[ string->unsigned int ][ !!! *7* !!! ][ 156 ][ 26 ][ 18 ]] -[[ string->unsigned short ][ !!! *8* !!! ][ 146 ][ 25 ][ 18 ]] -[[ string->unsigned long int ][ !!! *9* !!! ][ 143 ][ 29 ][ 37 ]] -[[ string->unsigned long long ][ !!! *14* !!! ][ 135 ][ 20 ][ 15 ]] -[[ string->bool ][ !!! *<1* !!! ][ 117 ][ 20 ][ 8 ]] -[[ string->float ][ !!! *15* !!! ][ 177 ][ 63 ][ 31 ]] -[[ string->double ][ !!! *15* !!! ][ 198 ][ 89 ][ 54 ]] -[[ string->long double ][ 133 ][ 198 ][ 88 ][ !!! *55* !!! ]] -[[ char->string ][ !!! *10* !!! ][ 108 ][ 16 ][ 12 ]] -[[ unsigned char->string ][ !!! *10* !!! ][ 119 ][ 18 ][ 15 ]] -[[ signed char->string ][ !!! *10* !!! ][ 111 ][ 24 ][ 11 ]] -[[ int->string ][ !!! *14* !!! ][ 129 ][ 22 ][ 15 ]] -[[ short->string ][ !!! *14* !!! ][ 128 ][ 22 ][ 17 ]] -[[ long int->string ][ !!! *14* !!! ][ 127 ][ 21 ][ 17 ]] -[[ long long->string ][ !!! *14* !!! ][ 127 ][ 22 ][ 18 ]] -[[ unsigned int->string ][ !!! *15* !!! ][ 124 ][ 22 ][ 17 ]] -[[ unsigned short->string ][ 16 ][ 125 ][ 22 ][ !!! *15* !!! ]] -[[ unsigned long int->string ][ !!! *15* !!! ][ 125 ][ 22 ][ 17 ]] -[[ unsigned long long->string ][ !!! *18* !!! ][ 138 ][ 34 ][ 23 ]] -[[ bool->string ][ !!! *7* !!! ][ 120 ][ 22 ][ 12 ]] -[[ float->string ][ 136 ][ 229 ][ 110 ][ !!! *48* !!! ]] -[[ double->string ][ 184 ][ 270 ][ 136 ][ !!! *67* !!! ]] -[[ long double->string ][ 198 ][ 264 ][ 148 ][ !!! *69* !!! ]] -[[ char*->char ][ !!! *<1* !!! ][ 98 ][ 8 ][ 8 ]] -[[ char*->signed char ][ !!! *<1* !!! ][ 99 ][ 8 ][ 8 ]] -[[ char*->unsigned char ][ !!! *<1* !!! ][ 96 ][ 8 ][ 14 ]] -[[ char*->int ][ !!! *8* !!! ][ 120 ][ 21 ][ 15 ]] -[[ char*->short ][ !!! *8* !!! ][ 122 ][ 22 ][ 16 ]] -[[ char*->long int ][ !!! *8* !!! ][ 122 ][ 24 ][ 16 ]] -[[ char*->long long ][ !!! *8* !!! ][ 120 ][ 23 ][ 14 ]] -[[ char*->unsigned int ][ !!! *7* !!! ][ 123 ][ 23 ][ 15 ]] -[[ char*->unsigned short ][ !!! *8* !!! ][ 123 ][ 24 ][ 15 ]] -[[ char*->unsigned long int ][ !!! *8* !!! ][ 121 ][ 22 ][ 14 ]] -[[ char*->unsigned long long ][ !!! *7* !!! ][ 116 ][ 20 ][ 16 ]] -[[ char*->bool ][ !!! *<1* !!! ][ 107 ][ 18 ][ 10 ]] -[[ char*->float ][ !!! *14* !!! ][ 181 ][ 67 ][ 32 ]] -[[ char*->double ][ !!! *16* !!! ][ 197 ][ 88 ][ 53 ]] -[[ char*->long double ][ 127 ][ 208 ][ 93 ][ !!! *56* !!! ]] -[[ unsigned char*->char ][ !!! *<1* !!! ][ 94 ][ 8 ][ 8 ]] -[[ unsigned char*->signed char ][ !!! *<1* !!! ][ 93 ][ 8 ][ 10 ]] -[[ unsigned char*->unsigned char ][ !!! *<1* !!! ][ 94 ][ 8 ][ 15 ]] -[[ unsigned char*->int ][ !!! *7* !!! ][ 117 ][ 21 ][ 16 ]] -[[ unsigned char*->short ][ !!! *8* !!! ][ 119 ][ 21 ][ 16 ]] -[[ unsigned char*->long int ][ !!! *7* !!! ][ 117 ][ 22 ][ 16 ]] -[[ unsigned char*->long long ][ !!! *8* !!! ][ 119 ][ 23 ][ 16 ]] -[[ unsigned char*->unsigned int ][ !!! *10* !!! ][ 123 ][ 20 ][ 15 ]] -[[ unsigned char*->unsigned short ][ !!! *8* !!! ][ 122 ][ 24 ][ 15 ]] -[[ unsigned char*->unsigned long int ][ !!! *8* !!! ][ 120 ][ 21 ][ 14 ]] -[[ unsigned char*->unsigned long long ][ !!! *8* !!! ][ 118 ][ 23 ][ 16 ]] -[[ unsigned char*->bool ][ !!! *1* !!! ][ 108 ][ 18 ][ 8 ]] -[[ unsigned char*->float ][ !!! *13* !!! ][ 182 ][ 63 ][ 30 ]] -[[ unsigned char*->double ][ !!! *16* !!! ][ 204 ][ 87 ][ 53 ]] -[[ unsigned char*->long double ][ 126 ][ 206 ][ 90 ][ !!! *60* !!! ]] -[[ unsigned char*->string ][ !!! *9* !!! ][ 123 ][ 21 ][ --- ]] -[[ signed char*->char ][ !!! *<1* !!! ][ 95 ][ 8 ][ 10 ]] -[[ signed char*->signed char ][ !!! *<1* !!! ][ 94 ][ 8 ][ 10 ]] -[[ signed char*->unsigned char ][ !!! *<1* !!! ][ 94 ][ 8 ][ 15 ]] -[[ signed char*->int ][ !!! *8* !!! ][ 117 ][ 22 ][ 16 ]] -[[ signed char*->short ][ !!! *7* !!! ][ 117 ][ 22 ][ 16 ]] -[[ signed char*->long int ][ !!! *8* !!! ][ 118 ][ 25 ][ 15 ]] -[[ signed char*->long long ][ !!! *7* !!! ][ 117 ][ 24 ][ 16 ]] -[[ signed char*->unsigned int ][ !!! *7* !!! ][ 120 ][ 20 ][ 16 ]] -[[ signed char*->unsigned short ][ !!! *8* !!! ][ 124 ][ 24 ][ 15 ]] -[[ signed char*->unsigned long int ][ !!! *8* !!! ][ 115 ][ 21 ][ 16 ]] -[[ signed char*->unsigned long long ][ !!! *9* !!! ][ 120 ][ 21 ][ 16 ]] -[[ signed char*->bool ][ !!! *1* !!! ][ 112 ][ 19 ][ 8 ]] -[[ signed char*->float ][ !!! *14* !!! ][ 183 ][ 64 ][ 31 ]] -[[ signed char*->double ][ !!! *18* !!! ][ 208 ][ 87 ][ 51 ]] -[[ signed char*->long double ][ 126 ][ 217 ][ 94 ][ !!! *55* !!! ]] -[[ signed char*->string ][ !!! *12* !!! ][ 126 ][ 22 ][ --- ]] -[[ int->int ][ !!! *<1* !!! ][ 146 ][ 23 ][ --- ]] -[[ float->double ][ !!! *<1* !!! ][ 275 ][ 139 ][ --- ]] -[[ double->double ][ !!! *<1* !!! ][ 270 ][ 142 ][ --- ]] -[[ int->int ][ !!! *<1* !!! ][ 281 ][ 145 ][ --- ]] -[[ int->int ][ !!! *<1* !!! ][ 301 ][ 145 ][ --- ]] -[[ char->unsigned char ][ !!! *<1* !!! ][ 96 ][ 7 ][ --- ]] -[[ char->signed char ][ !!! *<1* !!! ][ 95 ][ 7 ][ --- ]] -[[ unsigned char->char ][ !!! *<1* !!! ][ 96 ][ 7 ][ --- ]] -[[ signed char->char ][ !!! *<1* !!! ][ 91 ][ 7 ][ --- ]] +[[ string->char ][ !!! *<1* !!! ][ 148 ][ 14 ][ 12 ]] +[[ string->signed char ][ !!! *<1* !!! ][ 97 ][ 8 ][ 7 ]] +[[ string->unsigned char ][ !!! *<1* !!! ][ 90 ][ 8 ][ 13 ]] +[[ string->int ][ !!! *4* !!! ][ 102 ][ 19 ][ 15 ]] +[[ string->short ][ !!! *4* !!! ][ 105 ][ 20 ][ 15 ]] +[[ string->long int ][ !!! *4* !!! ][ 105 ][ 19 ][ 15 ]] +[[ string->long long ][ !!! *4* !!! ][ 115 ][ 19 ][ 14 ]] +[[ string->unsigned int ][ !!! *4* !!! ][ 102 ][ 18 ][ 14 ]] +[[ string->unsigned short ][ !!! *4* !!! ][ 101 ][ 19 ][ 15 ]] +[[ string->unsigned long int ][ !!! *3* !!! ][ 107 ][ 20 ][ 14 ]] +[[ string->unsigned long long ][ !!! *3* !!! ][ 103 ][ 20 ][ 14 ]] +[[ string->bool ][ !!! *<1* !!! ][ 97 ][ 16 ][ 8 ]] +[[ string->float ][ !!! *21* !!! ][ 170 ][ 61 ][ 32 ]] +[[ string->double ][ !!! *18* !!! ][ 206 ][ 93 ][ 58 ]] +[[ string->long double ][ 135 ][ 221 ][ 94 ][ !!! *57* !!! ]] +[[ char->string ][ !!! *7* !!! ][ 100 ][ 17 ][ 13 ]] +[[ unsigned char->string ][ !!! *7* !!! ][ 99 ][ 18 ][ 16 ]] +[[ signed char->string ][ !!! *7* !!! ][ 101 ][ 17 ][ 12 ]] +[[ int->string ][ !!! *13* !!! ][ 110 ][ 23 ][ 15 ]] +[[ short->string ][ !!! *13* !!! ][ 112 ][ 24 ][ 18 ]] +[[ long int->string ][ !!! *13* !!! ][ 119 ][ 23 ][ 17 ]] +[[ long long->string ][ !!! *13* !!! ][ 110 ][ 23 ][ 18 ]] +[[ unsigned int->string ][ !!! *14* !!! ][ 113 ][ 24 ][ 17 ]] +[[ unsigned short->string ][ !!! *13* !!! ][ 108 ][ 24 ][ 17 ]] +[[ unsigned long int->string ][ !!! *13* !!! ][ 109 ][ 24 ][ 16 ]] +[[ unsigned long long->string ][ !!! *13* !!! ][ 110 ][ 23 ][ 17 ]] +[[ bool->string ][ !!! *7* !!! ][ 105 ][ 24 ][ 12 ]] +[[ float->string ][ 70 ][ 192 ][ 94 ][ !!! *49* !!! ]] +[[ double->string ][ 106 ][ 217 ][ 122 ][ !!! *76* !!! ]] +[[ long double->string ][ 120 ][ 219 ][ 123 ][ !!! *80* !!! ]] +[[ char*->char ][ !!! *2* !!! ][ 90 ][ 9 ][ 8 ]] +[[ char*->signed char ][ !!! *2* !!! ][ 87 ][ 10 ][ 7 ]] +[[ char*->unsigned char ][ !!! *3* !!! ][ 90 ][ 10 ][ 13 ]] +[[ char*->int ][ !!! *6* !!! ][ 107 ][ 21 ][ 15 ]] +[[ char*->short ][ !!! *6* !!! ][ 110 ][ 19 ][ 14 ]] +[[ char*->long int ][ !!! *6* !!! ][ 103 ][ 19 ][ 14 ]] +[[ char*->long long ][ !!! *7* !!! ][ 104 ][ 20 ][ 15 ]] +[[ char*->unsigned int ][ !!! *6* !!! ][ 101 ][ 20 ][ 15 ]] +[[ char*->unsigned short ][ !!! *7* !!! ][ 100 ][ 20 ][ 14 ]] +[[ char*->unsigned long int ][ !!! *6* !!! ][ 105 ][ 22 ][ 15 ]] +[[ char*->unsigned long long ][ !!! *7* !!! ][ 106 ][ 21 ][ 14 ]] +[[ char*->bool ][ !!! *2* !!! ][ 99 ][ 18 ][ 7 ]] +[[ char*->float ][ !!! *22* !!! ][ 159 ][ 67 ][ 33 ]] +[[ char*->double ][ !!! *20* !!! ][ 205 ][ 94 ][ 58 ]] +[[ char*->long double ][ 140 ][ 214 ][ 95 ][ !!! *58* !!! ]] +[[ unsigned char*->char ][ !!! *2* !!! ][ 92 ][ 9 ][ 7 ]] +[[ unsigned char*->signed char ][ !!! *2* !!! ][ 89 ][ 10 ][ 7 ]] +[[ unsigned char*->unsigned char ][ !!! *2* !!! ][ 89 ][ 10 ][ 14 ]] +[[ unsigned char*->int ][ !!! *6* !!! ][ 104 ][ 20 ][ 14 ]] +[[ unsigned char*->short ][ !!! *6* !!! ][ 106 ][ 21 ][ 14 ]] +[[ unsigned char*->long int ][ !!! *6* !!! ][ 105 ][ 19 ][ 14 ]] +[[ unsigned char*->long long ][ !!! *6* !!! ][ 106 ][ 20 ][ 15 ]] +[[ unsigned char*->unsigned int ][ !!! *7* !!! ][ 105 ][ 19 ][ 14 ]] +[[ unsigned char*->unsigned short ][ !!! *6* !!! ][ 103 ][ 19 ][ 14 ]] +[[ unsigned char*->unsigned long int ][ !!! *6* !!! ][ 106 ][ 19 ][ 14 ]] +[[ unsigned char*->unsigned long long ][ !!! *6* !!! ][ 104 ][ 21 ][ 15 ]] +[[ unsigned char*->bool ][ !!! *2* !!! ][ 102 ][ 18 ][ 7 ]] +[[ unsigned char*->float ][ !!! *23* !!! ][ 160 ][ 66 ][ 32 ]] +[[ unsigned char*->double ][ !!! *20* !!! ][ 201 ][ 95 ][ 58 ]] +[[ unsigned char*->long double ][ 144 ][ 221 ][ 95 ][ !!! *60* !!! ]] +[[ unsigned char*->string ][ !!! *12* !!! ][ 104 ][ 23 ][ --- ]] +[[ signed char*->char ][ !!! *2* !!! ][ 90 ][ 9 ][ 7 ]] +[[ signed char*->signed char ][ !!! *2* !!! ][ 89 ][ 9 ][ 7 ]] +[[ signed char*->unsigned char ][ !!! *2* !!! ][ 89 ][ 10 ][ 13 ]] +[[ signed char*->int ][ !!! *6* !!! ][ 106 ][ 19 ][ 15 ]] +[[ signed char*->short ][ !!! *6* !!! ][ 107 ][ 20 ][ 15 ]] +[[ signed char*->long int ][ !!! *6* !!! ][ 103 ][ 19 ][ 14 ]] +[[ signed char*->long long ][ !!! *6* !!! ][ 103 ][ 19 ][ 14 ]] +[[ signed char*->unsigned int ][ !!! *6* !!! ][ 101 ][ 19 ][ 15 ]] +[[ signed char*->unsigned short ][ !!! *6* !!! ][ 101 ][ 19 ][ 16 ]] +[[ signed char*->unsigned long int ][ !!! *6* !!! ][ 105 ][ 22 ][ 15 ]] +[[ signed char*->unsigned long long ][ !!! *6* !!! ][ 104 ][ 21 ][ 15 ]] +[[ signed char*->bool ][ !!! *2* !!! ][ 100 ][ 18 ][ 7 ]] +[[ signed char*->float ][ !!! *23* !!! ][ 161 ][ 62 ][ 32 ]] +[[ signed char*->double ][ !!! *20* !!! ][ 207 ][ 102 ][ 57 ]] +[[ signed char*->long double ][ 144 ][ 216 ][ 96 ][ !!! *63* !!! ]] +[[ signed char*->string ][ !!! *12* !!! ][ 104 ][ 23 ][ --- ]] +[[ int->int ][ !!! *<1* !!! ][ 110 ][ 22 ][ --- ]] +[[ float->double ][ !!! *<1* !!! ][ 223 ][ 113 ][ --- ]] +[[ double->double ][ !!! *<1* !!! ][ 227 ][ 111 ][ --- ]] +[[ int->int ][ !!! *<1* !!! ][ 231 ][ 122 ][ --- ]] +[[ int->int ][ !!! *<1* !!! ][ 229 ][ 121 ][ --- ]] +[[ char->unsigned char ][ !!! *<1* !!! ][ 90 ][ 8 ][ --- ]] +[[ char->signed char ][ !!! *<1* !!! ][ 88 ][ 8 ][ --- ]] +[[ unsigned char->char ][ !!! *<1* !!! ][ 89 ][ 8 ][ --- ]] +[[ signed char->char ][ !!! *<1* !!! ][ 91 ][ 9 ][ --- ]] ] [endsect] [section gcc-4.4][table:id Performance Table (gcc-4.4) [[From->To] [lexical_cast] [std::stringstream with construction] [std::stringstream without construction][scanf/printf]] -[[ string->char ][ !!! *<1* !!! ][ 81 ][ 8 ][ 8 ]] -[[ string->signed char ][ !!! *<1* !!! ][ 110 ][ 7 ][ 9 ]] -[[ string->unsigned char ][ !!! *<1* !!! ][ 94 ][ 8 ][ 18 ]] -[[ string->int ][ !!! *9* !!! ][ 125 ][ 25 ][ 15 ]] -[[ string->short ][ !!! *7* !!! ][ 113 ][ 25 ][ 15 ]] -[[ string->long int ][ !!! *8* !!! ][ 112 ][ 24 ][ 15 ]] -[[ string->long long ][ !!! *8* !!! ][ 109 ][ 22 ][ 15 ]] -[[ string->unsigned int ][ !!! *8* !!! ][ 108 ][ 26 ][ 20 ]] -[[ string->unsigned short ][ !!! *9* !!! ][ 125 ][ 22 ][ 18 ]] -[[ string->unsigned long int ][ !!! *11* !!! ][ 125 ][ 32 ][ 17 ]] -[[ string->unsigned long long ][ !!! *10* !!! ][ 119 ][ 23 ][ 19 ]] -[[ string->bool ][ !!! *<1* !!! ][ 132 ][ 24 ][ 11 ]] -[[ string->float ][ !!! *18* !!! ][ 178 ][ 75 ][ 37 ]] -[[ string->double ][ !!! *24* !!! ][ 236 ][ 100 ][ 64 ]] -[[ string->long double ][ 146 ][ 233 ][ 118 ][ !!! *75* !!! ]] -[[ char->string ][ !!! *8* !!! ][ 136 ][ 22 ][ 13 ]] -[[ unsigned char->string ][ !!! *11* !!! ][ 127 ][ 22 ][ 20 ]] -[[ signed char->string ][ !!! *11* !!! ][ 128 ][ 21 ][ 15 ]] -[[ int->string ][ 25 ][ 159 ][ 30 ][ !!! *20* !!! ]] -[[ short->string ][ 25 ][ 151 ][ 30 ][ !!! *20* !!! ]] -[[ long int->string ][ !!! *20* !!! ][ 150 ][ 30 ][ 20 ]] -[[ long long->string ][ !!! *19* !!! ][ 164 ][ 26 ][ 21 ]] -[[ unsigned int->string ][ 35 ][ 147 ][ 27 ][ !!! *20* !!! ]] -[[ unsigned short->string ][ 26 ][ 149 ][ 26 ][ !!! *20* !!! ]] -[[ unsigned long int->string ][ 19 ][ 142 ][ 38 ][ !!! *17* !!! ]] -[[ unsigned long long->string ][ !!! *20* !!! ][ 139 ][ 36 ][ 26 ]] -[[ bool->string ][ !!! *10* !!! ][ 144 ][ 28 ][ 13 ]] -[[ float->string ][ 166 ][ 268 ][ 127 ][ !!! *52* !!! ]] -[[ double->string ][ 192 ][ 285 ][ 170 ][ !!! *90* !!! ]] -[[ long double->string ][ 250 ][ 344 ][ 160 ][ !!! *85* !!! ]] -[[ char*->char ][ !!! *<1* !!! ][ 90 ][ 9 ][ 8 ]] -[[ char*->signed char ][ !!! *<1* !!! ][ 82 ][ 9 ][ 8 ]] -[[ char*->unsigned char ][ !!! *<1* !!! ][ 88 ][ 8 ][ 13 ]] -[[ char*->int ][ !!! *6* !!! ][ 113 ][ 26 ][ 14 ]] -[[ char*->short ][ !!! *6* !!! ][ 114 ][ 25 ][ 14 ]] -[[ char*->long int ][ !!! *6* !!! ][ 123 ][ 38 ][ 17 ]] -[[ char*->long long ][ !!! *7* !!! ][ 126 ][ 37 ][ 17 ]] -[[ char*->unsigned int ][ !!! *6* !!! ][ 134 ][ 26 ][ 18 ]] -[[ char*->unsigned short ][ !!! *8* !!! ][ 126 ][ 24 ][ 17 ]] -[[ char*->unsigned long int ][ !!! *8* !!! ][ 121 ][ 24 ][ 17 ]] -[[ char*->unsigned long long ][ !!! *5* !!! ][ 117 ][ 24 ][ 18 ]] -[[ char*->bool ][ !!! *<1* !!! ][ 116 ][ 24 ][ 9 ]] -[[ char*->float ][ !!! *16* !!! ][ 171 ][ 67 ][ 30 ]] -[[ char*->double ][ !!! *15* !!! ][ 204 ][ 109 ][ 64 ]] -[[ char*->long double ][ 152 ][ 250 ][ 110 ][ !!! *71* !!! ]] -[[ unsigned char*->char ][ !!! *<1* !!! ][ 109 ][ 11 ][ 11 ]] -[[ unsigned char*->signed char ][ !!! *<1* !!! ][ 108 ][ 11 ][ 9 ]] -[[ unsigned char*->unsigned char ][ !!! *<1* !!! ][ 106 ][ 11 ][ 17 ]] -[[ unsigned char*->int ][ !!! *7* !!! ][ 143 ][ 31 ][ 17 ]] -[[ unsigned char*->short ][ !!! *9* !!! ][ 143 ][ 32 ][ 19 ]] -[[ unsigned char*->long int ][ !!! *8* !!! ][ 153 ][ 30 ][ 18 ]] -[[ unsigned char*->long long ][ !!! *10* !!! ][ 146 ][ 27 ][ 18 ]] -[[ unsigned char*->unsigned int ][ !!! *9* !!! ][ 144 ][ 25 ][ 18 ]] -[[ unsigned char*->unsigned short ][ !!! *9* !!! ][ 138 ][ 26 ][ 17 ]] -[[ unsigned char*->unsigned long int ][ !!! *9* !!! ][ 143 ][ 25 ][ 18 ]] -[[ unsigned char*->unsigned long long ][ !!! *10* !!! ][ 132 ][ 26 ][ 18 ]] -[[ unsigned char*->bool ][ !!! *<1* !!! ][ 102 ][ 18 ][ 9 ]] -[[ unsigned char*->float ][ !!! *13* !!! ][ 171 ][ 65 ][ 31 ]] -[[ unsigned char*->double ][ !!! *14* !!! ][ 197 ][ 89 ][ 53 ]] -[[ unsigned char*->long double ][ 122 ][ 208 ][ 89 ][ !!! *58* !!! ]] -[[ unsigned char*->string ][ !!! *8* !!! ][ 115 ][ 20 ][ --- ]] -[[ signed char*->char ][ !!! *<1* !!! ][ 93 ][ 10 ][ 9 ]] -[[ signed char*->signed char ][ !!! *<1* !!! ][ 91 ][ 8 ][ 8 ]] -[[ signed char*->unsigned char ][ !!! *<1* !!! ][ 90 ][ 10 ][ 15 ]] -[[ signed char*->int ][ !!! *7* !!! ][ 112 ][ 26 ][ 16 ]] -[[ signed char*->short ][ !!! *7* !!! ][ 112 ][ 26 ][ 16 ]] -[[ signed char*->long int ][ !!! *6* !!! ][ 118 ][ 25 ][ 14 ]] -[[ signed char*->long long ][ !!! *13* !!! ][ 114 ][ 25 ][ 14 ]] -[[ signed char*->unsigned int ][ !!! *7* !!! ][ 114 ][ 23 ][ 16 ]] -[[ signed char*->unsigned short ][ !!! *7* !!! ][ 107 ][ 25 ][ 16 ]] -[[ signed char*->unsigned long int ][ !!! *7* !!! ][ 106 ][ 23 ][ 14 ]] -[[ signed char*->unsigned long long ][ !!! *7* !!! ][ 103 ][ 22 ][ 16 ]] -[[ signed char*->bool ][ !!! *<1* !!! ][ 110 ][ 20 ][ 9 ]] -[[ signed char*->float ][ !!! *13* !!! ][ 175 ][ 66 ][ 32 ]] -[[ signed char*->double ][ !!! *14* !!! ][ 203 ][ 90 ][ 53 ]] -[[ signed char*->long double ][ 124 ][ 205 ][ 87 ][ !!! *55* !!! ]] -[[ signed char*->string ][ !!! *8* !!! ][ 120 ][ 20 ][ --- ]] -[[ int->int ][ !!! *<1* !!! ][ 116 ][ 28 ][ --- ]] -[[ float->double ][ !!! *<1* !!! ][ 264 ][ 135 ][ --- ]] -[[ double->double ][ !!! *<1* !!! ][ 260 ][ 140 ][ --- ]] -[[ int->int ][ !!! *<1* !!! ][ 275 ][ 135 ][ --- ]] -[[ int->int ][ !!! *<1* !!! ][ 274 ][ 135 ][ --- ]] -[[ char->unsigned char ][ !!! *<1* !!! ][ 77 ][ 7 ][ --- ]] -[[ char->signed char ][ !!! *<1* !!! ][ 79 ][ 7 ][ --- ]] -[[ unsigned char->char ][ !!! *<1* !!! ][ 78 ][ 8 ][ --- ]] -[[ signed char->char ][ !!! *<1* !!! ][ 83 ][ 7 ][ --- ]] +[[ string->char ][ !!! *<1* !!! ][ 90 ][ 7 ][ 7 ]] +[[ string->signed char ][ !!! *<1* !!! ][ 88 ][ 7 ][ 8 ]] +[[ string->unsigned char ][ !!! *<1* !!! ][ 88 ][ 8 ][ 14 ]] +[[ string->int ][ !!! *3* !!! ][ 103 ][ 18 ][ 15 ]] +[[ string->short ][ !!! *3* !!! ][ 105 ][ 20 ][ 15 ]] +[[ string->long int ][ !!! *3* !!! ][ 101 ][ 18 ][ 16 ]] +[[ string->long long ][ !!! *3* !!! ][ 101 ][ 18 ][ 15 ]] +[[ string->unsigned int ][ !!! *3* !!! ][ 98 ][ 23 ][ 14 ]] +[[ string->unsigned short ][ !!! *3* !!! ][ 100 ][ 17 ][ 14 ]] +[[ string->unsigned long int ][ !!! *3* !!! ][ 100 ][ 21 ][ 15 ]] +[[ string->unsigned long long ][ !!! *3* !!! ][ 99 ][ 19 ][ 15 ]] +[[ string->bool ][ !!! *<1* !!! ][ 95 ][ 16 ][ 8 ]] +[[ string->float ][ !!! *13* !!! ][ 160 ][ 61 ][ 33 ]] +[[ string->double ][ !!! *14* !!! ][ 206 ][ 93 ][ 59 ]] +[[ string->long double ][ 128 ][ 217 ][ 96 ][ !!! *61* !!! ]] +[[ char->string ][ !!! *7* !!! ][ 100 ][ 17 ][ 12 ]] +[[ unsigned char->string ][ !!! *7* !!! ][ 109 ][ 17 ][ 16 ]] +[[ signed char->string ][ !!! *7* !!! ][ 99 ][ 17 ][ 12 ]] +[[ int->string ][ !!! *13* !!! ][ 110 ][ 21 ][ 15 ]] +[[ short->string ][ !!! *14* !!! ][ 110 ][ 22 ][ 17 ]] +[[ long int->string ][ !!! *14* !!! ][ 109 ][ 21 ][ 16 ]] +[[ long long->string ][ !!! *13* !!! ][ 114 ][ 20 ][ 17 ]] +[[ unsigned int->string ][ !!! *13* !!! ][ 109 ][ 23 ][ 15 ]] +[[ unsigned short->string ][ !!! *14* !!! ][ 109 ][ 23 ][ 17 ]] +[[ unsigned long int->string ][ !!! *13* !!! ][ 112 ][ 23 ][ 16 ]] +[[ unsigned long long->string ][ !!! *14* !!! ][ 109 ][ 21 ][ 17 ]] +[[ bool->string ][ !!! *7* !!! ][ 108 ][ 23 ][ 11 ]] +[[ float->string ][ 63 ][ 185 ][ 92 ][ !!! *50* !!! ]] +[[ double->string ][ 106 ][ 216 ][ 116 ][ !!! *75* !!! ]] +[[ long double->string ][ 118 ][ 219 ][ 119 ][ !!! *80* !!! ]] +[[ char*->char ][ !!! *1* !!! ][ 93 ][ 9 ][ 9 ]] +[[ char*->signed char ][ !!! *1* !!! ][ 92 ][ 9 ][ 9 ]] +[[ char*->unsigned char ][ !!! *1* !!! ][ 92 ][ 9 ][ 14 ]] +[[ char*->int ][ !!! *4* !!! ][ 107 ][ 19 ][ 15 ]] +[[ char*->short ][ !!! *5* !!! ][ 109 ][ 19 ][ 15 ]] +[[ char*->long int ][ !!! *4* !!! ][ 113 ][ 19 ][ 15 ]] +[[ char*->long long ][ !!! *4* !!! ][ 108 ][ 20 ][ 15 ]] +[[ char*->unsigned int ][ !!! *4* !!! ][ 106 ][ 19 ][ 15 ]] +[[ char*->unsigned short ][ !!! *4* !!! ][ 106 ][ 18 ][ 15 ]] +[[ char*->unsigned long int ][ !!! *4* !!! ][ 103 ][ 22 ][ 15 ]] +[[ char*->unsigned long long ][ !!! *4* !!! ][ 105 ][ 20 ][ 15 ]] +[[ char*->bool ][ !!! *1* !!! ][ 104 ][ 18 ][ 8 ]] +[[ char*->float ][ !!! *15* !!! ][ 164 ][ 62 ][ 33 ]] +[[ char*->double ][ !!! *16* !!! ][ 203 ][ 97 ][ 58 ]] +[[ char*->long double ][ 132 ][ 223 ][ 98 ][ !!! *60* !!! ]] +[[ unsigned char*->char ][ !!! *2* !!! ][ 90 ][ 9 ][ 8 ]] +[[ unsigned char*->signed char ][ !!! *2* !!! ][ 92 ][ 10 ][ 8 ]] +[[ unsigned char*->unsigned char ][ !!! *2* !!! ][ 91 ][ 9 ][ 14 ]] +[[ unsigned char*->int ][ !!! *6* !!! ][ 106 ][ 20 ][ 15 ]] +[[ unsigned char*->short ][ !!! *6* !!! ][ 106 ][ 21 ][ 15 ]] +[[ unsigned char*->long int ][ !!! *6* !!! ][ 111 ][ 19 ][ 15 ]] +[[ unsigned char*->long long ][ !!! *6* !!! ][ 107 ][ 20 ][ 15 ]] +[[ unsigned char*->unsigned int ][ !!! *6* !!! ][ 105 ][ 19 ][ 15 ]] +[[ unsigned char*->unsigned short ][ !!! *6* !!! ][ 103 ][ 18 ][ 15 ]] +[[ unsigned char*->unsigned long int ][ !!! *6* !!! ][ 106 ][ 22 ][ 14 ]] +[[ unsigned char*->unsigned long long ][ !!! *6* !!! ][ 105 ][ 20 ][ 14 ]] +[[ unsigned char*->bool ][ !!! *2* !!! ][ 106 ][ 18 ][ 8 ]] +[[ unsigned char*->float ][ !!! *15* !!! ][ 167 ][ 68 ][ 33 ]] +[[ unsigned char*->double ][ !!! *17* !!! ][ 203 ][ 99 ][ 58 ]] +[[ unsigned char*->long double ][ 129 ][ 216 ][ 97 ][ !!! *61* !!! ]] +[[ unsigned char*->string ][ !!! *13* !!! ][ 111 ][ 23 ][ --- ]] +[[ signed char*->char ][ !!! *2* !!! ][ 92 ][ 9 ][ 8 ]] +[[ signed char*->signed char ][ !!! *2* !!! ][ 91 ][ 9 ][ 8 ]] +[[ signed char*->unsigned char ][ !!! *2* !!! ][ 91 ][ 9 ][ 14 ]] +[[ signed char*->int ][ !!! *6* !!! ][ 107 ][ 19 ][ 15 ]] +[[ signed char*->short ][ !!! *6* !!! ][ 109 ][ 24 ][ 14 ]] +[[ signed char*->long int ][ !!! *6* !!! ][ 112 ][ 19 ][ 15 ]] +[[ signed char*->long long ][ !!! *5* !!! ][ 107 ][ 20 ][ 15 ]] +[[ signed char*->unsigned int ][ !!! *6* !!! ][ 108 ][ 20 ][ 15 ]] +[[ signed char*->unsigned short ][ !!! *6* !!! ][ 104 ][ 18 ][ 15 ]] +[[ signed char*->unsigned long int ][ !!! *6* !!! ][ 102 ][ 22 ][ 15 ]] +[[ signed char*->unsigned long long ][ !!! *6* !!! ][ 104 ][ 20 ][ 15 ]] +[[ signed char*->bool ][ !!! *2* !!! ][ 104 ][ 18 ][ 8 ]] +[[ signed char*->float ][ !!! *16* !!! ][ 165 ][ 63 ][ 33 ]] +[[ signed char*->double ][ !!! *16* !!! ][ 203 ][ 98 ][ 59 ]] +[[ signed char*->long double ][ 129 ][ 215 ][ 98 ][ !!! *61* !!! ]] +[[ signed char*->string ][ !!! *13* !!! ][ 109 ][ 21 ][ --- ]] +[[ int->int ][ !!! *<1* !!! ][ 109 ][ 21 ][ --- ]] +[[ float->double ][ !!! *<1* !!! ][ 221 ][ 102 ][ --- ]] +[[ double->double ][ !!! *<1* !!! ][ 223 ][ 103 ][ --- ]] +[[ int->int ][ !!! *<1* !!! ][ 231 ][ 115 ][ --- ]] +[[ int->int ][ !!! *<1* !!! ][ 231 ][ 115 ][ --- ]] +[[ char->unsigned char ][ !!! *<1* !!! ][ 92 ][ 8 ][ --- ]] +[[ char->signed char ][ !!! *<1* !!! ][ 88 ][ 8 ][ --- ]] +[[ unsigned char->char ][ !!! *<1* !!! ][ 88 ][ 7 ][ --- ]] +[[ signed char->char ][ !!! *<1* !!! ][ 89 ][ 8 ][ --- ]] ] [endsect] [section gcc-4.5][table:id Performance Table (gcc-4.5) [[From->To] [lexical_cast] [std::stringstream with construction] [std::stringstream without construction][scanf/printf]] -[[ string->char ][ !!! *<1* !!! ][ 86 ][ 8 ][ 9 ]] -[[ string->signed char ][ !!! *<1* !!! ][ 88 ][ 9 ][ 9 ]] -[[ string->unsigned char ][ !!! *<1* !!! ][ 87 ][ 8 ][ 15 ]] -[[ string->int ][ !!! *6* !!! ][ 107 ][ 23 ][ 16 ]] -[[ string->short ][ !!! *7* !!! ][ 108 ][ 25 ][ 15 ]] -[[ string->long int ][ !!! *6* !!! ][ 110 ][ 26 ][ 15 ]] -[[ string->long long ][ !!! *7* !!! ][ 110 ][ 26 ][ 15 ]] -[[ string->unsigned int ][ !!! *6* !!! ][ 108 ][ 26 ][ 16 ]] -[[ string->unsigned short ][ !!! *7* !!! ][ 105 ][ 24 ][ 15 ]] -[[ string->unsigned long int ][ !!! *6* !!! ][ 108 ][ 23 ][ 15 ]] -[[ string->unsigned long long ][ !!! *10* !!! ][ 104 ][ 24 ][ 15 ]] -[[ string->bool ][ !!! *<1* !!! ][ 102 ][ 21 ][ 9 ]] -[[ string->float ][ !!! *13* !!! ][ 173 ][ 64 ][ 34 ]] -[[ string->double ][ !!! *15* !!! ][ 196 ][ 89 ][ 53 ]] -[[ string->long double ][ 126 ][ 211 ][ 90 ][ !!! *56* !!! ]] -[[ char->string ][ !!! *8* !!! ][ 107 ][ 20 ][ 10 ]] -[[ unsigned char->string ][ !!! *8* !!! ][ 107 ][ 17 ][ 15 ]] -[[ signed char->string ][ !!! *8* !!! ][ 108 ][ 19 ][ 10 ]] -[[ int->string ][ 16 ][ 129 ][ 25 ][ !!! *15* !!! ]] -[[ short->string ][ !!! *14* !!! ][ 128 ][ 25 ][ 17 ]] -[[ long int->string ][ 20 ][ 128 ][ 24 ][ !!! *15* !!! ]] -[[ long long->string ][ !!! *16* !!! ][ 128 ][ 25 ][ 16 ]] -[[ unsigned int->string ][ !!! *15* !!! ][ 125 ][ 25 ][ 15 ]] -[[ unsigned short->string ][ !!! *14* !!! ][ 125 ][ 24 ][ 15 ]] -[[ unsigned long int->string ][ 16 ][ 125 ][ 25 ][ !!! *15* !!! ]] -[[ unsigned long long->string ][ !!! *18* !!! ][ 140 ][ 32 ][ 22 ]] -[[ bool->string ][ !!! *8* !!! ][ 121 ][ 24 ][ 10 ]] -[[ float->string ][ 137 ][ 226 ][ 108 ][ !!! *48* !!! ]] -[[ double->string ][ 174 ][ 255 ][ 141 ][ !!! *71* !!! ]] -[[ long double->string ][ 208 ][ 268 ][ 144 ][ !!! *72* !!! ]] -[[ char*->char ][ !!! *<1* !!! ][ 93 ][ 8 ][ 9 ]] -[[ char*->signed char ][ !!! *<1* !!! ][ 94 ][ 9 ][ 9 ]] -[[ char*->unsigned char ][ !!! *<1* !!! ][ 94 ][ 8 ][ 15 ]] -[[ char*->int ][ !!! *7* !!! ][ 115 ][ 26 ][ 16 ]] -[[ char*->short ][ !!! *8* !!! ][ 114 ][ 26 ][ 15 ]] -[[ char*->long int ][ !!! *7* !!! ][ 115 ][ 27 ][ 16 ]] -[[ char*->long long ][ !!! *7* !!! ][ 114 ][ 26 ][ 16 ]] -[[ char*->unsigned int ][ !!! *8* !!! ][ 115 ][ 25 ][ 16 ]] -[[ char*->unsigned short ][ !!! *7* !!! ][ 113 ][ 24 ][ 16 ]] -[[ char*->unsigned long int ][ !!! *8* !!! ][ 117 ][ 23 ][ 16 ]] -[[ char*->unsigned long long ][ !!! *8* !!! ][ 107 ][ 25 ][ 16 ]] -[[ char*->bool ][ !!! *<1* !!! ][ 110 ][ 21 ][ 9 ]] -[[ char*->float ][ !!! *17* !!! ][ 170 ][ 67 ][ 34 ]] -[[ char*->double ][ !!! *14* !!! ][ 197 ][ 91 ][ 52 ]] -[[ char*->long double ][ 127 ][ 206 ][ 89 ][ !!! *56* !!! ]] -[[ unsigned char*->char ][ !!! *<1* !!! ][ 83 ][ 8 ][ 9 ]] -[[ unsigned char*->signed char ][ !!! *<1* !!! ][ 83 ][ 10 ][ 9 ]] -[[ unsigned char*->unsigned char ][ !!! *<1* !!! ][ 83 ][ 8 ][ 15 ]] -[[ unsigned char*->int ][ !!! *7* !!! ][ 113 ][ 26 ][ 16 ]] -[[ unsigned char*->short ][ !!! *7* !!! ][ 112 ][ 24 ][ 16 ]] -[[ unsigned char*->long int ][ !!! *8* !!! ][ 114 ][ 26 ][ 16 ]] -[[ unsigned char*->long long ][ !!! *8* !!! ][ 113 ][ 26 ][ 16 ]] -[[ unsigned char*->unsigned int ][ !!! *8* !!! ][ 114 ][ 25 ][ 16 ]] -[[ unsigned char*->unsigned short ][ !!! *8* !!! ][ 109 ][ 24 ][ 16 ]] -[[ unsigned char*->unsigned long int ][ !!! *8* !!! ][ 111 ][ 23 ][ 16 ]] -[[ unsigned char*->unsigned long long ][ !!! *7* !!! ][ 106 ][ 25 ][ 16 ]] -[[ unsigned char*->bool ][ !!! *<1* !!! ][ 106 ][ 20 ][ 9 ]] -[[ unsigned char*->float ][ !!! *14* !!! ][ 169 ][ 65 ][ 34 ]] -[[ unsigned char*->double ][ !!! *16* !!! ][ 198 ][ 91 ][ 52 ]] -[[ unsigned char*->long double ][ 127 ][ 205 ][ 88 ][ !!! *56* !!! ]] -[[ unsigned char*->string ][ !!! *10* !!! ][ 123 ][ 21 ][ --- ]] -[[ signed char*->char ][ !!! *<1* !!! ][ 90 ][ 9 ][ 9 ]] -[[ signed char*->signed char ][ !!! *<1* !!! ][ 91 ][ 8 ][ 9 ]] -[[ signed char*->unsigned char ][ !!! *<1* !!! ][ 92 ][ 8 ][ 15 ]] -[[ signed char*->int ][ !!! *7* !!! ][ 116 ][ 26 ][ 16 ]] -[[ signed char*->short ][ !!! *8* !!! ][ 113 ][ 26 ][ 15 ]] -[[ signed char*->long int ][ !!! *8* !!! ][ 113 ][ 24 ][ 16 ]] -[[ signed char*->long long ][ !!! *8* !!! ][ 113 ][ 27 ][ 16 ]] -[[ signed char*->unsigned int ][ !!! *8* !!! ][ 113 ][ 25 ][ 16 ]] -[[ signed char*->unsigned short ][ !!! *7* !!! ][ 107 ][ 24 ][ 16 ]] -[[ signed char*->unsigned long int ][ !!! *7* !!! ][ 111 ][ 23 ][ 17 ]] -[[ signed char*->unsigned long long ][ !!! *8* !!! ][ 105 ][ 25 ][ 16 ]] -[[ signed char*->bool ][ !!! *<1* !!! ][ 106 ][ 21 ][ 9 ]] -[[ signed char*->float ][ !!! *13* !!! ][ 169 ][ 63 ][ 34 ]] -[[ signed char*->double ][ !!! *16* !!! ][ 196 ][ 90 ][ 52 ]] -[[ signed char*->long double ][ 127 ][ 211 ][ 91 ][ !!! *60* !!! ]] -[[ signed char*->string ][ !!! *9* !!! ][ 123 ][ 21 ][ --- ]] -[[ int->int ][ !!! *<1* !!! ][ 120 ][ 29 ][ --- ]] -[[ float->double ][ !!! *<1* !!! ][ 258 ][ 147 ][ --- ]] -[[ double->double ][ !!! *<1* !!! ][ 261 ][ 140 ][ --- ]] -[[ int->int ][ !!! *<1* !!! ][ 266 ][ 138 ][ --- ]] -[[ int->int ][ !!! *<1* !!! ][ 266 ][ 137 ][ --- ]] -[[ char->unsigned char ][ !!! *<1* !!! ][ 89 ][ 8 ][ --- ]] -[[ char->signed char ][ !!! *<1* !!! ][ 91 ][ 8 ][ --- ]] -[[ unsigned char->char ][ !!! *<1* !!! ][ 90 ][ 9 ][ --- ]] +[[ string->char ][ !!! *<1* !!! ][ 91 ][ 8 ][ 7 ]] +[[ string->signed char ][ !!! *<1* !!! ][ 91 ][ 8 ][ 7 ]] +[[ string->unsigned char ][ !!! *<1* !!! ][ 90 ][ 8 ][ 13 ]] +[[ string->int ][ !!! *3* !!! ][ 100 ][ 20 ][ 14 ]] +[[ string->short ][ !!! *3* !!! ][ 106 ][ 20 ][ 14 ]] +[[ string->long int ][ !!! *3* !!! ][ 100 ][ 18 ][ 14 ]] +[[ string->long long ][ !!! *9* !!! ][ 100 ][ 18 ][ 15 ]] +[[ string->unsigned int ][ !!! *3* !!! ][ 97 ][ 20 ][ 14 ]] +[[ string->unsigned short ][ !!! *3* !!! ][ 102 ][ 17 ][ 14 ]] +[[ string->unsigned long int ][ !!! *3* !!! ][ 97 ][ 21 ][ 14 ]] +[[ string->unsigned long long ][ !!! *3* !!! ][ 97 ][ 19 ][ 14 ]] +[[ string->bool ][ !!! *<1* !!! ][ 95 ][ 16 ][ 7 ]] +[[ string->float ][ !!! *15* !!! ][ 157 ][ 63 ][ 32 ]] +[[ string->double ][ !!! *17* !!! ][ 203 ][ 95 ][ 59 ]] +[[ string->long double ][ 129 ][ 216 ][ 93 ][ !!! *58* !!! ]] +[[ char->string ][ !!! *8* !!! ][ 100 ][ 17 ][ 10 ]] +[[ unsigned char->string ][ !!! *8* !!! ][ 96 ][ 18 ][ 16 ]] +[[ signed char->string ][ !!! *8* !!! ][ 96 ][ 18 ][ 10 ]] +[[ int->string ][ !!! *14* !!! ][ 105 ][ 22 ][ 15 ]] +[[ short->string ][ !!! *14* !!! ][ 107 ][ 23 ][ 17 ]] +[[ long int->string ][ !!! *14* !!! ][ 109 ][ 22 ][ 17 ]] +[[ long long->string ][ !!! *14* !!! ][ 105 ][ 22 ][ 18 ]] +[[ unsigned int->string ][ !!! *14* !!! ][ 105 ][ 25 ][ 15 ]] +[[ unsigned short->string ][ !!! *15* !!! ][ 105 ][ 23 ][ 17 ]] +[[ unsigned long int->string ][ !!! *14* !!! ][ 109 ][ 24 ][ 17 ]] +[[ unsigned long long->string ][ !!! *14* !!! ][ 102 ][ 23 ][ 17 ]] +[[ bool->string ][ !!! *8* !!! ][ 104 ][ 23 ][ 12 ]] +[[ float->string ][ 66 ][ 181 ][ 92 ][ !!! *49* !!! ]] +[[ double->string ][ 107 ][ 215 ][ 120 ][ !!! *75* !!! ]] +[[ long double->string ][ 117 ][ 221 ][ 125 ][ !!! *79* !!! ]] +[[ char*->char ][ !!! *1* !!! ][ 89 ][ 9 ][ 7 ]] +[[ char*->signed char ][ !!! *1* !!! ][ 90 ][ 9 ][ 7 ]] +[[ char*->unsigned char ][ !!! *2* !!! ][ 90 ][ 9 ][ 13 ]] +[[ char*->int ][ !!! *7* !!! ][ 103 ][ 20 ][ 15 ]] +[[ char*->short ][ !!! *6* !!! ][ 102 ][ 29 ][ 14 ]] +[[ char*->long int ][ !!! *7* !!! ][ 101 ][ 20 ][ 15 ]] +[[ char*->long long ][ !!! *6* !!! ][ 102 ][ 20 ][ 14 ]] +[[ char*->unsigned int ][ !!! *6* !!! ][ 99 ][ 19 ][ 14 ]] +[[ char*->unsigned short ][ !!! *6* !!! ][ 101 ][ 18 ][ 14 ]] +[[ char*->unsigned long int ][ !!! *6* !!! ][ 102 ][ 22 ][ 14 ]] +[[ char*->unsigned long long ][ !!! *6* !!! ][ 101 ][ 21 ][ 14 ]] +[[ char*->bool ][ !!! *3* !!! ][ 98 ][ 18 ][ 7 ]] +[[ char*->float ][ !!! *18* !!! ][ 162 ][ 63 ][ 31 ]] +[[ char*->double ][ !!! *17* !!! ][ 203 ][ 96 ][ 58 ]] +[[ char*->long double ][ 135 ][ 214 ][ 98 ][ !!! *58* !!! ]] +[[ unsigned char*->char ][ !!! *2* !!! ][ 87 ][ 9 ][ 7 ]] +[[ unsigned char*->signed char ][ !!! *2* !!! ][ 87 ][ 9 ][ 7 ]] +[[ unsigned char*->unsigned char ][ !!! *3* !!! ][ 87 ][ 9 ][ 13 ]] +[[ unsigned char*->int ][ !!! *6* !!! ][ 105 ][ 20 ][ 14 ]] +[[ unsigned char*->short ][ !!! *6* !!! ][ 102 ][ 21 ][ 14 ]] +[[ unsigned char*->long int ][ !!! *6* !!! ][ 101 ][ 20 ][ 14 ]] +[[ unsigned char*->long long ][ !!! *6* !!! ][ 102 ][ 20 ][ 14 ]] +[[ unsigned char*->unsigned int ][ !!! *6* !!! ][ 99 ][ 19 ][ 14 ]] +[[ unsigned char*->unsigned short ][ !!! *6* !!! ][ 100 ][ 18 ][ 14 ]] +[[ unsigned char*->unsigned long int ][ !!! *6* !!! ][ 101 ][ 24 ][ 14 ]] +[[ unsigned char*->unsigned long long ][ !!! *6* !!! ][ 100 ][ 20 ][ 14 ]] +[[ unsigned char*->bool ][ !!! *3* !!! ][ 99 ][ 18 ][ 8 ]] +[[ unsigned char*->float ][ !!! *17* !!! ][ 164 ][ 64 ][ 32 ]] +[[ unsigned char*->double ][ !!! *18* !!! ][ 201 ][ 94 ][ 58 ]] +[[ unsigned char*->long double ][ 133 ][ 217 ][ 95 ][ !!! *60* !!! ]] +[[ unsigned char*->string ][ !!! *14* !!! ][ 103 ][ 23 ][ --- ]] +[[ signed char*->char ][ !!! *3* !!! ][ 88 ][ 10 ][ 8 ]] +[[ signed char*->signed char ][ !!! *2* !!! ][ 87 ][ 10 ][ 7 ]] +[[ signed char*->unsigned char ][ !!! *3* !!! ][ 87 ][ 9 ][ 13 ]] +[[ signed char*->int ][ !!! *6* !!! ][ 104 ][ 20 ][ 14 ]] +[[ signed char*->short ][ !!! *6* !!! ][ 105 ][ 21 ][ 14 ]] +[[ signed char*->long int ][ !!! *6* !!! ][ 104 ][ 20 ][ 15 ]] +[[ signed char*->long long ][ !!! *6* !!! ][ 106 ][ 20 ][ 14 ]] +[[ signed char*->unsigned int ][ !!! *6* !!! ][ 99 ][ 20 ][ 14 ]] +[[ signed char*->unsigned short ][ !!! *6* !!! ][ 100 ][ 18 ][ 14 ]] +[[ signed char*->unsigned long int ][ !!! *6* !!! ][ 102 ][ 23 ][ 14 ]] +[[ signed char*->unsigned long long ][ !!! *6* !!! ][ 103 ][ 20 ][ 14 ]] +[[ signed char*->bool ][ !!! *3* !!! ][ 99 ][ 18 ][ 7 ]] +[[ signed char*->float ][ !!! *18* !!! ][ 159 ][ 60 ][ 32 ]] +[[ signed char*->double ][ !!! *18* !!! ][ 203 ][ 95 ][ 57 ]] +[[ signed char*->long double ][ 129 ][ 213 ][ 97 ][ !!! *56* !!! ]] +[[ signed char*->string ][ !!! *14* !!! ][ 105 ][ 22 ][ --- ]] +[[ int->int ][ !!! *<1* !!! ][ 109 ][ 22 ][ --- ]] +[[ float->double ][ !!! *<1* !!! ][ 226 ][ 104 ][ --- ]] +[[ double->double ][ !!! *<1* !!! ][ 229 ][ 103 ][ --- ]] +[[ int->int ][ !!! *<1* !!! ][ 225 ][ 115 ][ --- ]] +[[ int->int ][ !!! *<1* !!! ][ 227 ][ 115 ][ --- ]] +[[ char->unsigned char ][ !!! *<1* !!! ][ 90 ][ 8 ][ --- ]] +[[ char->signed char ][ !!! *<1* !!! ][ 84 ][ 8 ][ --- ]] +[[ unsigned char->char ][ !!! *<1* !!! ][ 88 ][ 8 ][ --- ]] [[ signed char->char ][ !!! *<1* !!! ][ 89 ][ 8 ][ --- ]] ] [endsect] -[section intel-12-linux][table:id Performance Table (intel-12-linux) +[section gcc-4.6][table:id Performance Table (gcc-4.6) [[From->To] [lexical_cast] [std::stringstream with construction] [std::stringstream without construction][scanf/printf]] -[[ string->char ][ !!! *1* !!! ][ 87 ][ 9 ][ 8 ]] -[[ string->signed char ][ !!! *<1* !!! ][ 90 ][ 9 ][ 8 ]] -[[ string->unsigned char ][ !!! *<1* !!! ][ 99 ][ 9 ][ 20 ]] -[[ string->int ][ !!! *8* !!! ][ 112 ][ 24 ][ 16 ]] -[[ string->short ][ !!! *8* !!! ][ 110 ][ 26 ][ 16 ]] -[[ string->long int ][ !!! *7* !!! ][ 110 ][ 23 ][ 16 ]] -[[ string->long long ][ !!! *10* !!! ][ 114 ][ 31 ][ 16 ]] -[[ string->unsigned int ][ !!! *7* !!! ][ 122 ][ 25 ][ 16 ]] -[[ string->unsigned short ][ !!! *7* !!! ][ 120 ][ 27 ][ 16 ]] -[[ string->unsigned long int ][ !!! *7* !!! ][ 114 ][ 25 ][ 16 ]] -[[ string->unsigned long long ][ !!! *7* !!! ][ 128 ][ 23 ][ 25 ]] -[[ string->bool ][ !!! *1* !!! ][ 103 ][ 20 ][ 9 ]] -[[ string->float ][ !!! *15* !!! ][ 166 ][ 73 ][ 31 ]] -[[ string->double ][ !!! *19* !!! ][ 206 ][ 103 ][ 56 ]] -[[ string->long double ][ 142 ][ 205 ][ 106 ][ !!! *61* !!! ]] -[[ char->string ][ !!! *10* !!! ][ 111 ][ 19 ][ 12 ]] -[[ unsigned char->string ][ !!! *12* !!! ][ 109 ][ 19 ][ 16 ]] -[[ signed char->string ][ !!! *9* !!! ][ 110 ][ 18 ][ 12 ]] -[[ int->string ][ 19 ][ 126 ][ 23 ][ !!! *17* !!! ]] -[[ short->string ][ 20 ][ 127 ][ 23 ][ !!! *18* !!! ]] -[[ long int->string ][ 20 ][ 128 ][ 24 ][ !!! *18* !!! ]] -[[ long long->string ][ !!! *16* !!! ][ 129 ][ 23 ][ 22 ]] -[[ unsigned int->string ][ 20 ][ 126 ][ 23 ][ !!! *17* !!! ]] -[[ unsigned short->string ][ 20 ][ 126 ][ 23 ][ !!! *17* !!! ]] -[[ unsigned long int->string ][ 20 ][ 126 ][ 23 ][ !!! *17* !!! ]] -[[ unsigned long long->string ][ !!! *24* !!! ][ 134 ][ 35 ][ 24 ]] -[[ bool->string ][ !!! *9* !!! ][ 124 ][ 29 ][ 12 ]] -[[ float->string ][ 147 ][ 218 ][ 104 ][ !!! *48* !!! ]] -[[ double->string ][ 202 ][ 245 ][ 128 ][ !!! *68* !!! ]] -[[ long double->string ][ 199 ][ 236 ][ 128 ][ !!! *69* !!! ]] -[[ char*->char ][ !!! *1* !!! ][ 91 ][ 10 ][ 9 ]] -[[ char*->signed char ][ !!! *1* !!! ][ 98 ][ 10 ][ 9 ]] -[[ char*->unsigned char ][ !!! *1* !!! ][ 97 ][ 14 ][ 15 ]] -[[ char*->int ][ !!! *8* !!! ][ 114 ][ 24 ][ 16 ]] -[[ char*->short ][ !!! *8* !!! ][ 112 ][ 27 ][ 15 ]] -[[ char*->long int ][ !!! *8* !!! ][ 117 ][ 28 ][ 16 ]] -[[ char*->long long ][ !!! *8* !!! ][ 123 ][ 30 ][ 16 ]] -[[ char*->unsigned int ][ !!! *8* !!! ][ 120 ][ 26 ][ 16 ]] -[[ char*->unsigned short ][ !!! *8* !!! ][ 122 ][ 30 ][ 16 ]] -[[ char*->unsigned long int ][ !!! *10* !!! ][ 119 ][ 25 ][ 16 ]] -[[ char*->unsigned long long ][ !!! *8* !!! ][ 140 ][ 54 ][ 34 ]] -[[ char*->bool ][ !!! *1* !!! ][ 108 ][ 21 ][ 8 ]] -[[ char*->float ][ !!! *16* !!! ][ 177 ][ 76 ][ 33 ]] -[[ char*->double ][ !!! *18* !!! ][ 271 ][ 104 ][ 56 ]] -[[ char*->long double ][ 142 ][ 207 ][ 106 ][ !!! *61* !!! ]] -[[ unsigned char*->char ][ !!! *1* !!! ][ 91 ][ 10 ][ 9 ]] -[[ unsigned char*->signed char ][ !!! *1* !!! ][ 92 ][ 10 ][ 8 ]] -[[ unsigned char*->unsigned char ][ !!! *1* !!! ][ 92 ][ 10 ][ 15 ]] -[[ unsigned char*->int ][ !!! *8* !!! ][ 111 ][ 24 ][ 16 ]] -[[ unsigned char*->short ][ !!! *9* !!! ][ 113 ][ 27 ][ 16 ]] -[[ unsigned char*->long int ][ !!! *7* !!! ][ 113 ][ 28 ][ 16 ]] -[[ unsigned char*->long long ][ !!! *7* !!! ][ 120 ][ 29 ][ 15 ]] -[[ unsigned char*->unsigned int ][ !!! *7* !!! ][ 119 ][ 24 ][ 15 ]] -[[ unsigned char*->unsigned short ][ !!! *8* !!! ][ 116 ][ 28 ][ 15 ]] -[[ unsigned char*->unsigned long int ][ !!! *7* !!! ][ 118 ][ 25 ][ 16 ]] -[[ unsigned char*->unsigned long long ][ !!! *7* !!! ][ 116 ][ 25 ][ 16 ]] -[[ unsigned char*->bool ][ !!! *1* !!! ][ 102 ][ 20 ][ 9 ]] -[[ unsigned char*->float ][ !!! *16* !!! ][ 167 ][ 74 ][ 31 ]] -[[ unsigned char*->double ][ !!! *19* !!! ][ 231 ][ 109 ][ 55 ]] -[[ unsigned char*->long double ][ 141 ][ 214 ][ 109 ][ !!! *61* !!! ]] -[[ unsigned char*->string ][ !!! *12* !!! ][ 122 ][ 23 ][ --- ]] -[[ signed char*->char ][ !!! *1* !!! ][ 91 ][ 10 ][ 8 ]] -[[ signed char*->signed char ][ !!! *1* !!! ][ 92 ][ 10 ][ 9 ]] -[[ signed char*->unsigned char ][ !!! *1* !!! ][ 92 ][ 10 ][ 15 ]] -[[ signed char*->int ][ !!! *7* !!! ][ 117 ][ 34 ][ 16 ]] -[[ signed char*->short ][ !!! *8* !!! ][ 117 ][ 25 ][ 15 ]] -[[ signed char*->long int ][ !!! *7* !!! ][ 115 ][ 28 ][ 16 ]] -[[ signed char*->long long ][ !!! *8* !!! ][ 116 ][ 31 ][ 15 ]] -[[ signed char*->unsigned int ][ !!! *8* !!! ][ 123 ][ 27 ][ 16 ]] -[[ signed char*->unsigned short ][ !!! *8* !!! ][ 120 ][ 27 ][ 16 ]] -[[ signed char*->unsigned long int ][ !!! *7* !!! ][ 119 ][ 26 ][ 16 ]] -[[ signed char*->unsigned long long ][ !!! *7* !!! ][ 118 ][ 26 ][ 17 ]] -[[ signed char*->bool ][ !!! *1* !!! ][ 108 ][ 26 ][ 9 ]] -[[ signed char*->float ][ !!! *16* !!! ][ 170 ][ 73 ][ 31 ]] -[[ signed char*->double ][ !!! *18* !!! ][ 210 ][ 112 ][ 55 ]] -[[ signed char*->long double ][ 137 ][ 210 ][ 107 ][ !!! *61* !!! ]] -[[ signed char*->string ][ !!! *14* !!! ][ 121 ][ 23 ][ --- ]] -[[ int->int ][ !!! *<1* !!! ][ 115 ][ 26 ][ --- ]] -[[ float->double ][ !!! *<1* !!! ][ 266 ][ 155 ][ --- ]] -[[ double->double ][ !!! *<1* !!! ][ 267 ][ 157 ][ --- ]] -[[ int->int ][ !!! *<1* !!! ][ 261 ][ 153 ][ --- ]] -[[ int->int ][ !!! *<1* !!! ][ 264 ][ 152 ][ --- ]] -[[ char->unsigned char ][ !!! *<1* !!! ][ 96 ][ 9 ][ --- ]] -[[ char->signed char ][ !!! *<1* !!! ][ 96 ][ 9 ][ --- ]] -[[ unsigned char->char ][ !!! *<1* !!! ][ 93 ][ 9 ][ --- ]] -[[ signed char->char ][ !!! *<1* !!! ][ 87 ][ 9 ][ --- ]] +[[ string->char ][ !!! *<1* !!! ][ 94 ][ 8 ][ 7 ]] +[[ string->signed char ][ !!! *<1* !!! ][ 96 ][ 9 ][ 7 ]] +[[ string->unsigned char ][ !!! *<1* !!! ][ 96 ][ 8 ][ 13 ]] +[[ string->int ][ !!! *3* !!! ][ 110 ][ 18 ][ 16 ]] +[[ string->short ][ !!! *3* !!! ][ 111 ][ 18 ][ 16 ]] +[[ string->long int ][ !!! *3* !!! ][ 109 ][ 18 ][ 15 ]] +[[ string->long long ][ !!! *3* !!! ][ 111 ][ 18 ][ 15 ]] +[[ string->unsigned int ][ !!! *3* !!! ][ 110 ][ 20 ][ 15 ]] +[[ string->unsigned short ][ !!! *3* !!! ][ 111 ][ 18 ][ 15 ]] +[[ string->unsigned long int ][ !!! *3* !!! ][ 109 ][ 18 ][ 15 ]] +[[ string->unsigned long long ][ !!! *3* !!! ][ 114 ][ 19 ][ 15 ]] +[[ string->bool ][ !!! *<1* !!! ][ 106 ][ 17 ][ 8 ]] +[[ string->float ][ !!! *13* !!! ][ 175 ][ 70 ][ 33 ]] +[[ string->double ][ !!! *14* !!! ][ 182 ][ 81 ][ 58 ]] +[[ string->long double ][ 118 ][ 190 ][ 87 ][ !!! *58* !!! ]] +[[ char->string ][ !!! *8* !!! ][ 118 ][ 21 ][ 12 ]] +[[ unsigned char->string ][ !!! *8* !!! ][ 109 ][ 18 ][ 16 ]] +[[ signed char->string ][ !!! *8* !!! ][ 108 ][ 18 ][ 12 ]] +[[ int->string ][ 20 ][ 121 ][ 21 ][ !!! *16* !!! ]] +[[ short->string ][ !!! *15* !!! ][ 120 ][ 22 ][ 17 ]] +[[ long int->string ][ !!! *15* !!! ][ 120 ][ 22 ][ 16 ]] +[[ long long->string ][ !!! *15* !!! ][ 120 ][ 22 ][ 17 ]] +[[ unsigned int->string ][ !!! *15* !!! ][ 120 ][ 22 ][ 16 ]] +[[ unsigned short->string ][ !!! *15* !!! ][ 120 ][ 22 ][ 18 ]] +[[ unsigned long int->string ][ 16 ][ 118 ][ 22 ][ !!! *15* !!! ]] +[[ unsigned long long->string ][ !!! *15* !!! ][ 117 ][ 21 ][ 17 ]] +[[ bool->string ][ !!! *8* !!! ][ 117 ][ 23 ][ 10 ]] +[[ float->string ][ 77 ][ 218 ][ 105 ][ !!! *50* !!! ]] +[[ double->string ][ 108 ][ 247 ][ 129 ][ !!! *73* !!! ]] +[[ long double->string ][ 120 ][ 250 ][ 131 ][ !!! *79* !!! ]] +[[ char*->char ][ !!! *2* !!! ][ 99 ][ 9 ][ 7 ]] +[[ char*->signed char ][ !!! *2* !!! ][ 98 ][ 9 ][ 8 ]] +[[ char*->unsigned char ][ !!! *2* !!! ][ 98 ][ 9 ][ 13 ]] +[[ char*->int ][ !!! *6* !!! ][ 115 ][ 22 ][ 15 ]] +[[ char*->short ][ !!! *6* !!! ][ 114 ][ 22 ][ 15 ]] +[[ char*->long int ][ !!! *6* !!! ][ 114 ][ 22 ][ 16 ]] +[[ char*->long long ][ !!! *6* !!! ][ 119 ][ 22 ][ 15 ]] +[[ char*->unsigned int ][ !!! *6* !!! ][ 114 ][ 20 ][ 15 ]] +[[ char*->unsigned short ][ !!! *6* !!! ][ 116 ][ 20 ][ 15 ]] +[[ char*->unsigned long int ][ !!! *6* !!! ][ 117 ][ 22 ][ 15 ]] +[[ char*->unsigned long long ][ !!! *6* !!! ][ 118 ][ 22 ][ 15 ]] +[[ char*->bool ][ !!! *3* !!! ][ 113 ][ 18 ][ 8 ]] +[[ char*->float ][ !!! *15* !!! ][ 180 ][ 78 ][ 32 ]] +[[ char*->double ][ !!! *16* !!! ][ 185 ][ 89 ][ 58 ]] +[[ char*->long double ][ 119 ][ 193 ][ 91 ][ !!! *60* !!! ]] +[[ unsigned char*->char ][ !!! *2* !!! ][ 99 ][ 9 ][ 8 ]] +[[ unsigned char*->signed char ][ !!! *2* !!! ][ 99 ][ 10 ][ 8 ]] +[[ unsigned char*->unsigned char ][ !!! *2* !!! ][ 100 ][ 9 ][ 15 ]] +[[ unsigned char*->int ][ !!! *6* !!! ][ 118 ][ 22 ][ 15 ]] +[[ unsigned char*->short ][ !!! *6* !!! ][ 117 ][ 26 ][ 15 ]] +[[ unsigned char*->long int ][ !!! *6* !!! ][ 119 ][ 21 ][ 15 ]] +[[ unsigned char*->long long ][ !!! *6* !!! ][ 118 ][ 21 ][ 14 ]] +[[ unsigned char*->unsigned int ][ !!! *6* !!! ][ 115 ][ 22 ][ 14 ]] +[[ unsigned char*->unsigned short ][ !!! *6* !!! ][ 117 ][ 20 ][ 15 ]] +[[ unsigned char*->unsigned long int ][ !!! *6* !!! ][ 115 ][ 21 ][ 15 ]] +[[ unsigned char*->unsigned long long ][ !!! *6* !!! ][ 117 ][ 22 ][ 15 ]] +[[ unsigned char*->bool ][ !!! *3* !!! ][ 112 ][ 18 ][ 8 ]] +[[ unsigned char*->float ][ !!! *15* !!! ][ 181 ][ 78 ][ 33 ]] +[[ unsigned char*->double ][ !!! *16* !!! ][ 185 ][ 92 ][ 59 ]] +[[ unsigned char*->long double ][ 120 ][ 190 ][ 89 ][ !!! *58* !!! ]] +[[ unsigned char*->string ][ !!! *14* !!! ][ 121 ][ 22 ][ --- ]] +[[ signed char*->char ][ !!! *2* !!! ][ 99 ][ 9 ][ 9 ]] +[[ signed char*->signed char ][ !!! *2* !!! ][ 98 ][ 9 ][ 8 ]] +[[ signed char*->unsigned char ][ !!! *2* !!! ][ 98 ][ 9 ][ 14 ]] +[[ signed char*->int ][ !!! *6* !!! ][ 119 ][ 22 ][ 16 ]] +[[ signed char*->short ][ !!! *6* !!! ][ 115 ][ 22 ][ 15 ]] +[[ signed char*->long int ][ !!! *6* !!! ][ 119 ][ 22 ][ 15 ]] +[[ signed char*->long long ][ !!! *6* !!! ][ 117 ][ 22 ][ 15 ]] +[[ signed char*->unsigned int ][ !!! *6* !!! ][ 117 ][ 23 ][ 15 ]] +[[ signed char*->unsigned short ][ !!! *6* !!! ][ 117 ][ 21 ][ 14 ]] +[[ signed char*->unsigned long int ][ !!! *7* !!! ][ 119 ][ 24 ][ 15 ]] +[[ signed char*->unsigned long long ][ !!! *6* !!! ][ 116 ][ 22 ][ 15 ]] +[[ signed char*->bool ][ !!! *3* !!! ][ 111 ][ 18 ][ 8 ]] +[[ signed char*->float ][ !!! *16* !!! ][ 180 ][ 78 ][ 33 ]] +[[ signed char*->double ][ !!! *16* !!! ][ 185 ][ 89 ][ 59 ]] +[[ signed char*->long double ][ 120 ][ 191 ][ 91 ][ !!! *59* !!! ]] +[[ signed char*->string ][ !!! *14* !!! ][ 122 ][ 23 ][ --- ]] +[[ int->int ][ !!! *<1* !!! ][ 120 ][ 22 ][ --- ]] +[[ float->double ][ !!! *<1* !!! ][ 242 ][ 115 ][ --- ]] +[[ double->double ][ !!! *<1* !!! ][ 243 ][ 115 ][ --- ]] +[[ int->int ][ !!! *<1* !!! ][ 265 ][ 141 ][ --- ]] +[[ int->int ][ !!! *<1* !!! ][ 266 ][ 140 ][ --- ]] +[[ char->unsigned char ][ !!! *<1* !!! ][ 95 ][ 8 ][ --- ]] +[[ char->signed char ][ !!! *<1* !!! ][ 95 ][ 8 ][ --- ]] +[[ unsigned char->char ][ !!! *<1* !!! ][ 94 ][ 8 ][ --- ]] +[[ signed char->char ][ !!! *<1* !!! ][ 94 ][ 8 ][ --- ]] ] [endsect] - - [/ END of section, generated by performance measuring program ] [endsect] diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index e536ac5..94f8c70 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -461,7 +461,7 @@ namespace boost namespace detail // lcast_put_unsigned { template - CharT* lcast_put_unsigned(T n, CharT* finish) + CharT* lcast_put_unsigned(const T n_param, CharT* finish) { #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS BOOST_STATIC_ASSERT(!std::numeric_limits::is_signed); @@ -470,51 +470,58 @@ namespace boost typedef typename Traits::int_type int_type; CharT const czero = lcast_char_constants::zero; int_type const zero = Traits::to_int_type(czero); + BOOST_DEDUCED_TYPENAME boost::mpl::if_c< + (sizeof(int_type) > sizeof(T)) + , int_type + , T + >::type n = n_param; #ifndef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE std::locale loc; - typedef std::numpunct numpunct; - numpunct const& np = BOOST_USE_FACET(numpunct, loc); - std::string const& grouping = np.grouping(); - std::string::size_type const grouping_size = grouping.size(); + if (loc != std::locale::classic()) { + typedef std::numpunct numpunct; + numpunct const& np = BOOST_USE_FACET(numpunct, loc); + std::string const grouping = np.grouping(); + std::string::size_type const grouping_size = grouping.size(); - if ( grouping_size && grouping[0] > 0 ) - { + if ( grouping_size && grouping[0] > 0 ) + { #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS - // Check that ulimited group is unreachable: - BOOST_STATIC_ASSERT(std::numeric_limits::digits10 < CHAR_MAX); + // Check that ulimited group is unreachable: + BOOST_STATIC_ASSERT(std::numeric_limits::digits10 < CHAR_MAX); #endif - CharT thousands_sep = np.thousands_sep(); - std::string::size_type group = 0; // current group number - char last_grp_size = grouping[0]; - char left = last_grp_size; + CharT thousands_sep = np.thousands_sep(); + std::string::size_type group = 0; // current group number + char last_grp_size = grouping[0]; + char left = last_grp_size; - do - { - if(left == 0) + do { - ++group; - if(group < grouping_size) + if(left == 0) { - char const grp_size = grouping[group]; - last_grp_size = grp_size <= 0 ? CHAR_MAX : grp_size; + ++group; + if(group < grouping_size) + { + char const grp_size = grouping[group]; + last_grp_size = grp_size <= 0 ? CHAR_MAX : grp_size; + } + + left = last_grp_size; + --finish; + Traits::assign(*finish, thousands_sep); } - left = last_grp_size; + --left; + --finish; - Traits::assign(*finish, thousands_sep); - } - - --left; - - --finish; - int_type const digit = static_cast(n % 10U); - Traits::assign(*finish, Traits::to_char_type(zero + digit)); - n /= 10; - } while(n); - - } else + int_type const digit = static_cast(n % 10U); + Traits::assign(*finish, Traits::to_char_type(zero + digit)); + n /= 10; + } while(n); + return finish; + } + } #endif { do @@ -551,61 +558,63 @@ namespace boost #ifndef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE std::locale loc; - typedef std::numpunct numpunct; - numpunct const& np = BOOST_USE_FACET(numpunct, loc); - std::string const& grouping = np.grouping(); - std::string::size_type const grouping_size = grouping.size(); + if (loc != std::locale::classic()) { + typedef std::numpunct numpunct; + numpunct const& np = BOOST_USE_FACET(numpunct, loc); + std::string const& grouping = np.grouping(); + std::string::size_type const grouping_size = grouping.size(); - /* According to Programming languages - C++ - * we MUST check for correct grouping - */ - if (grouping_size && grouping[0] > 0) - { - unsigned char current_grouping = 0; - CharT const thousands_sep = np.thousands_sep(); - char remained = grouping[current_grouping] - 1; - bool shall_we_return = true; - - for(;end>=begin; --end) + /* According to Programming languages - C++ + * we MUST check for correct grouping + */ + if (grouping_size && grouping[0] > 0) { - if (remained) { - T const new_sub_value = multiplier * 10 * (*end - czero); + unsigned char current_grouping = 0; + CharT const thousands_sep = np.thousands_sep(); + char remained = grouping[current_grouping] - 1; + bool shall_we_return = true; - if (*end < czero || *end >= czero + 10 - /* detecting overflow */ - || new_sub_value/10 != multiplier * (*end - czero) - || static_cast((std::numeric_limits::max)()-new_sub_value) < value - ) - return false; + for(;end>=begin; --end) + { + if (remained) { + T const new_sub_value = multiplier * 10 * (*end - czero); - value += new_sub_value; - multiplier *= 10; - --remained; - } else { - if ( !Traits::eq(*end, thousands_sep) ) //|| begin == end ) return false; - { - /* - * According to Programming languages - C++ - * Digit grouping is checked. That is, the positions of discarded - * separators is examined for consistency with - * use_facet >(loc ).grouping() - * - * BUT what if there is no separators at all and grouping() - * is not empty? Well, we have no extraced separators, so we - * won`t check them for consistency. This will allow us to - * work with "C" locale from other locales - */ - shall_we_return = false; - break; + if (*end < czero || *end >= czero + 10 + /* detecting overflow */ + || new_sub_value/10 != multiplier * (*end - czero) + || static_cast((std::numeric_limits::max)()-new_sub_value) < value + ) + return false; + + value += new_sub_value; + multiplier *= 10; + --remained; } else { - if ( begin == end ) return false; - if (current_grouping < grouping_size-1 ) ++current_grouping; - remained = grouping[current_grouping]; + if ( !Traits::eq(*end, thousands_sep) ) //|| begin == end ) return false; + { + /* + * According to Programming languages - C++ + * Digit grouping is checked. That is, the positions of discarded + * separators is examined for consistency with + * use_facet >(loc ).grouping() + * + * BUT what if there is no separators at all and grouping() + * is not empty? Well, we have no extraced separators, so we + * won`t check them for consistency. This will allow us to + * work with "C" locale from other locales + */ + shall_we_return = false; + break; + } else { + if ( begin == end ) return false; + if (current_grouping < grouping_size-1 ) ++current_grouping; + remained = grouping[current_grouping]; + } } } - } - if (shall_we_return) return true; + if (shall_we_return) return true; + } } #endif { @@ -809,7 +818,11 @@ namespace boost std::locale loc; typedef std::numpunct numpunct; numpunct const& np = BOOST_USE_FACET(numpunct, loc); - std::string const& grouping = np.grouping(); + std::string const grouping( + (loc == std::locale::classic()) + ? std::string() + : np.grouping() + ); std::string::size_type const grouping_size = grouping.size(); CharT const thousands_sep = grouping_size ? np.thousands_sep() : 0; CharT const decimal_point = np.decimal_point(); diff --git a/lexical_cast_test.cpp b/lexical_cast_test.cpp index 47381cd..6820612 100644 --- a/lexical_cast_test.cpp +++ b/lexical_cast_test.cpp @@ -756,6 +756,16 @@ void test_conversion_from_to_integral() test_conversion_from_integral_to_char(wzero); test_conversion_from_char_to_integral(wzero); #endif +#ifndef BOOST_NO_CHAR16_T + char16_t const u16zero = u'0'; + test_conversion_from_integral_to_char(u16zero); + test_conversion_from_char_to_integral(u16zero); +#endif +#ifndef BOOST_NO_CHAR32_T + char32_t const u32zero = u'0'; + test_conversion_from_integral_to_char(u32zero); + test_conversion_from_char_to_integral(u32zero); +#endif BOOST_CHECK(lexical_cast("-1") == static_cast(-1)); BOOST_CHECK(lexical_cast("-9") == static_cast(-9)); From 3d60698843865475f2ae8b2cd7a025b0bdd624dd Mon Sep 17 00:00:00 2001 From: Gennadiy Rozental Date: Wed, 5 Oct 2011 09:15:12 +0000 Subject: [PATCH 37/39] eliminated unit_test_framework [SVN r74720] --- test/lexical_cast_abstract_test.cpp | 2 +- test/lexical_cast_float_types_test.cpp | 2 +- test/lexical_cast_inf_nan_test.cpp | 2 +- test/lexical_cast_loopback_test.cpp | 2 +- test/lexical_cast_noncopyable_test.cpp | 2 +- test/lexical_cast_vc8_bug_test.cpp | 2 +- test/lexical_cast_wchars_test.cpp | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/test/lexical_cast_abstract_test.cpp b/test/lexical_cast_abstract_test.cpp index 4b92e49..70cdeca 100644 --- a/test/lexical_cast_abstract_test.cpp +++ b/test/lexical_cast_abstract_test.cpp @@ -28,7 +28,7 @@ void test_abstract(); unit_test::test_suite *init_unit_test_suite(int, char *[]) { - unit_test_framework::test_suite *suite = + unit_test::test_suite *suite = BOOST_TEST_SUITE("lexical_cast unit test"); suite->add(BOOST_TEST_CASE(&test_abstract)); diff --git a/test/lexical_cast_float_types_test.cpp b/test/lexical_cast_float_types_test.cpp index 72279bb..808f456 100755 --- a/test/lexical_cast_float_types_test.cpp +++ b/test/lexical_cast_float_types_test.cpp @@ -31,7 +31,7 @@ using namespace boost; unit_test::test_suite *init_unit_test_suite(int, char *[]) { - unit_test_framework::test_suite *suite = + unit_test::test_suite *suite = BOOST_TEST_SUITE("lexical_cast float types unit test"); suite->add(BOOST_TEST_CASE(&test_conversion_from_to_float)); suite->add(BOOST_TEST_CASE(&test_conversion_from_to_double)); diff --git a/test/lexical_cast_inf_nan_test.cpp b/test/lexical_cast_inf_nan_test.cpp index 4617d5e..bb4331a 100755 --- a/test/lexical_cast_inf_nan_test.cpp +++ b/test/lexical_cast_inf_nan_test.cpp @@ -170,7 +170,7 @@ void test_inf_nan_long_double() unit_test::test_suite *init_unit_test_suite(int, char *[]) { - unit_test_framework::test_suite *suite = + unit_test::test_suite *suite = BOOST_TEST_SUITE("lexical_cast inf anf nan parsing unit test"); suite->add(BOOST_TEST_CASE(&test_inf_nan_float)); suite->add(BOOST_TEST_CASE(&test_inf_nan_double)); diff --git a/test/lexical_cast_loopback_test.cpp b/test/lexical_cast_loopback_test.cpp index 5787996..25b18ec 100644 --- a/test/lexical_cast_loopback_test.cpp +++ b/test/lexical_cast_loopback_test.cpp @@ -30,7 +30,7 @@ void test_round_conversion_long_double(); unit_test::test_suite *init_unit_test_suite(int, char *[]) { - unit_test_framework::test_suite *suite = + unit_test::test_suite *suite = BOOST_TEST_SUITE("lexical_cast unit test"); suite->add(BOOST_TEST_CASE(&test_round_conversion_float)); suite->add(BOOST_TEST_CASE(&test_round_conversion_double)); diff --git a/test/lexical_cast_noncopyable_test.cpp b/test/lexical_cast_noncopyable_test.cpp index 6284b14..1f120d9 100644 --- a/test/lexical_cast_noncopyable_test.cpp +++ b/test/lexical_cast_noncopyable_test.cpp @@ -28,7 +28,7 @@ void test_noncopyable(); unit_test::test_suite *init_unit_test_suite(int, char *[]) { - unit_test_framework::test_suite *suite = + unit_test::test_suite *suite = BOOST_TEST_SUITE("lexical_cast unit test"); suite->add(BOOST_TEST_CASE(&test_noncopyable)); diff --git a/test/lexical_cast_vc8_bug_test.cpp b/test/lexical_cast_vc8_bug_test.cpp index 151e4f8..9e5ef0b 100644 --- a/test/lexical_cast_vc8_bug_test.cpp +++ b/test/lexical_cast_vc8_bug_test.cpp @@ -60,7 +60,7 @@ void test_vc8_bug() unit_test::test_suite *init_unit_test_suite(int, char *[]) { - unit_test_framework::test_suite *suite = + unit_test::test_suite *suite = BOOST_TEST_SUITE("lexical_cast vc8 bug unit test"); suite->add(BOOST_TEST_CASE(test_vc8_bug)); return suite; diff --git a/test/lexical_cast_wchars_test.cpp b/test/lexical_cast_wchars_test.cpp index 14ac461..acd78b1 100755 --- a/test/lexical_cast_wchars_test.cpp +++ b/test/lexical_cast_wchars_test.cpp @@ -48,7 +48,7 @@ void test_char_types_conversions() unit_test::test_suite *init_unit_test_suite(int, char *[]) { - unit_test_framework::test_suite *suite = + unit_test::test_suite *suite = BOOST_TEST_SUITE("lexical_cast char<->wchar_t unit test"); suite->add(BOOST_TEST_CASE(&test_char_types_conversions)); From 8c7c7b9237aeab13f0ea50e7c12ae01ab5c6476f Mon Sep 17 00:00:00 2001 From: Gennadiy Rozental Date: Wed, 5 Oct 2011 09:42:21 +0000 Subject: [PATCH 38/39] eliminated unit_test_framework and BOOST_MESSAGE [SVN r74727] --- lexical_cast_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lexical_cast_test.cpp b/lexical_cast_test.cpp index 6820612..faeaa93 100644 --- a/lexical_cast_test.cpp +++ b/lexical_cast_test.cpp @@ -110,7 +110,7 @@ void test_char32_conversions(); unit_test::test_suite *init_unit_test_suite(int, char *[]) { - unit_test_framework::test_suite *suite = + unit_test::test_suite *suite = BOOST_TEST_SUITE("lexical_cast unit test"); suite->add(BOOST_TEST_CASE(test_conversion_to_char)); suite->add(BOOST_TEST_CASE(test_conversion_to_int)); From c07cbcee5cf8ef5ea43706663ee07f89716023ee Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Thu, 13 Oct 2011 18:36:39 +0000 Subject: [PATCH 39/39] Performance optimizations and testsfor conversions to/from boost::container::basic_string [SVN r74940] --- include/boost/lexical_cast.hpp | 63 +++++++++++++++++++++++++++ test/Jamfile.v2 | 1 + test/lexical_cast_containers_test.cpp | 38 ++++++++++++++++ 3 files changed, 102 insertions(+) create mode 100644 test/lexical_cast_containers_test.cpp diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index 94f8c70..62f0f66 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -46,6 +46,7 @@ #include #include #include +#include #include @@ -145,6 +146,12 @@ namespace boost { typedef CharT type; }; + + template + struct stream_char< ::boost::container::basic_string > + { + typedef CharT type; + }; #endif #ifndef BOOST_LCAST_NO_WCHAR_T @@ -259,6 +266,24 @@ namespace boost typedef Traits type; }; + template + struct deduce_char_traits< CharT + , ::boost::container::basic_string + , Source + > + { + typedef Traits type; + }; + + template + struct deduce_char_traits< CharT + , Target + , ::boost::container::basic_string + > + { + typedef Traits type; + }; + template struct deduce_char_traits< CharT , std::basic_string @@ -267,6 +292,15 @@ namespace boost { typedef Traits type; }; + + template + struct deduce_char_traits< CharT + , ::boost::container::basic_string + , ::boost::container::basic_string + > + { + typedef Traits type; + }; #endif } @@ -1257,6 +1291,14 @@ namespace boost return true; } + template + bool operator<<(::boost::container::basic_string const& str) + { + start = const_cast(str.data()); + finish = start + str.length(); + return true; + } + bool operator<<(bool value) { CharT const czero = lcast_char_constants::zero; @@ -1462,6 +1504,9 @@ namespace boost #else 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; } #endif /* * case "-0" || "0" || "+0" : output = false; return true; @@ -1598,6 +1643,12 @@ namespace boost BOOST_STATIC_CONSTANT(bool, value = true ); }; + template + struct is_stdstring< ::boost::container::basic_string > + { + BOOST_STATIC_CONSTANT(bool, value = true ); + }; + template struct is_char_or_wchar { @@ -1698,6 +1749,18 @@ namespace boost BOOST_STATIC_CONSTANT(bool, value = true ); }; + template + 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* > + { + BOOST_STATIC_CONSTANT(bool, value = true ); + }; + #if (defined _MSC_VER) # pragma warning( push ) # pragma warning( disable : 4701 ) // possible use of ... before initialization diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 2dd3500..7e5eacf 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -28,6 +28,7 @@ test-suite conversion [ run lexical_cast_wchars_test.cpp ../../test/build//boost_unit_test_framework/static ] [ run lexical_cast_float_types_test.cpp ../../test/build//boost_unit_test_framework/static ] [ run lexical_cast_inf_nan_test.cpp ../../test/build//boost_unit_test_framework/static ] + [ run lexical_cast_containers_test.cpp ../../test/build//boost_unit_test_framework/static ] ; diff --git a/test/lexical_cast_containers_test.cpp b/test/lexical_cast_containers_test.cpp new file mode 100644 index 0000000..5f98ac8 --- /dev/null +++ b/test/lexical_cast_containers_test.cpp @@ -0,0 +1,38 @@ +// Testing boost::lexical_cast with boost::container::string. +// +// See http://www.boost.org for most recent version, including documentation. +// +// Copyright Antony Polukhin, 2011. +// +// 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 + +void testing_boost_containers_basic_string(); + +using namespace boost; + +boost::unit_test::test_suite *init_unit_test_suite(int, char *[]) +{ + unit_test::test_suite *suite = + BOOST_TEST_SUITE("Testing boost::lexical_cast with boost::container::string"); + suite->add(BOOST_TEST_CASE(testing_boost_containers_basic_string)); + + return suite; +} + +void testing_boost_containers_basic_string() +{ + BOOST_CHECK("100" == lexical_cast("100")); + BOOST_CHECK(L"100" == lexical_cast(L"100")); + + BOOST_CHECK("100" == lexical_cast(100)); + boost::container::string str("1000"); + BOOST_CHECK(1000 == lexical_cast(str)); +} + +