From 5638b5dbec31eeed2121b7f3264b9464c058eb00 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 1 Jan 2012 13:35:27 +0000 Subject: [PATCH] Quickbook: Merge from trunk to quickbook-dev. [SVN r76255] --- doc/lexical_cast.qbk | 12 ++ include/boost/lexical_cast.hpp | 48 ++++++-- test/Jamfile.v2 | 8 +- test/lexical_cast_empty_input_test.cpp | 115 ++++++++++++++++-- test/lexical_cast_typedefed_wchar_test.cpp | 25 ++++ ...ical_cast_typedefed_wchar_test_runtime.cpp | 48 ++++++++ 6 files changed, 236 insertions(+), 20 deletions(-) create mode 100755 test/lexical_cast_typedefed_wchar_test.cpp create mode 100755 test/lexical_cast_typedefed_wchar_test_runtime.cpp diff --git a/doc/lexical_cast.qbk b/doc/lexical_cast.qbk index b540267..bf6b562 100644 --- a/doc/lexical_cast.qbk +++ b/doc/lexical_cast.qbk @@ -159,9 +159,21 @@ Read a good C++ book, study `std::sentry` and [@boost:libs/io/doc/ios_state.html 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. +[pre +] + +* [*Question:] Why `boost::lexical_cast(L'A');` outputs 65 and `boost::lexical_cast(L"65");` does not throw? + * [*Answer:] If you are using an old version of Visual Studio or compile code with /Zc:wchar_t- flag, +`boost::lexical_cast` sees single `wchar_t` character as `unsigned short`. It is not a `boost::lexical_cast` mistake, but a +limitation of compiler options that you use. + [endsect] [section Changes] +* [*boost 1.49.0 :] + + * Restored work with typedefed wchar_t (compilation flag /Zc:wchar_t- for Visual Studio). + * [*boost 1.48.0 :] * Added code to work with Inf and NaN on any platform. diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index e7ab248..b9bc984 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -17,8 +17,8 @@ // enhanced with contributions from Terje Slettebo, // with additional fixes and suggestions from Gennaro Prota, // Beman Dawes, Dave Abrahams, Daryle Walker, Peter Dimov, -// Alexander Nasonov, Antony Polukhin, Justin Viiret, Michael Hofmann -// and other Boosters +// Alexander Nasonov, Antony Polukhin, Justin Viiret, Michael Hofmann, +// Cheng Yang, Matthew Bradbury and other Boosters // when: November 2000, March 2003, June 2005, June 2006, March 2011 #include @@ -586,7 +586,7 @@ namespace boost --end; value = 0; - if ( *end < czero || *end >= czero + 10 || begin > end) + if (begin > end || *end < czero || *end >= czero + 10) return false; value = *end - czero; --end; @@ -684,6 +684,7 @@ namespace boost , const CharT opening_brace, const CharT closing_brace) { using namespace std; + if (begin == end) return false; const CharT minus = lcast_char_constants::minus; const CharT plus = lcast_char_constants::plus; const int inifinity_size = 8; @@ -743,6 +744,26 @@ namespace boost , L'(', L')'); } #endif +#ifndef BOOST_NO_CHAR16_T + template + bool parse_inf_nan(const char16_t* begin, const char16_t* end, T& value) + { + return parse_inf_nan_impl(begin, end, value + , u"NAN", u"nan" + , u"INFINITY", u"infinity" + , u'(', u')'); + } +#endif +#ifndef BOOST_NO_CHAR32_T + template + bool parse_inf_nan(const char32_t* begin, const char32_t* end, T& value) + { + return parse_inf_nan_impl(begin, end, value + , U"NAN", U"nan" + , U"INFINITY", U"infinity" + , U'(', U')'); + } +#endif template bool parse_inf_nan(const CharT* begin, const CharT* end, T& value) @@ -863,7 +884,7 @@ namespace boost 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; + std::string::size_type last_grouping_pos = grouping_size - 1; #else CharT const decimal_point = lcast_char_constants::c_decimal_separator; #endif @@ -1183,7 +1204,7 @@ namespace boost bool const result = !(stream << input).fail(); start = stringbuffer.pbase(); finish = stringbuffer.pptr(); - return result && (start != finish); + return result; } template @@ -1354,9 +1375,11 @@ namespace boost /************************************ HELPER FUNCTIONS FOR OPERATORS >> ( ... ) ********************************/ private: + template bool shr_unsigned(Type& output) { + if (start == finish) return false; CharT const minus = lcast_char_constants::minus; CharT const plus = lcast_char_constants::plus; bool has_minus = false; @@ -1391,6 +1414,7 @@ namespace boost template bool shr_signed(Type& output) { + if (start == finish) return false; CharT const minus = lcast_char_constants::minus; CharT const plus = lcast_char_constants::plus; typedef BOOST_DEDUCED_TYPENAME make_unsigned::type utype; @@ -1480,7 +1504,7 @@ namespace boost } /************************************ OPERATORS >> ( ... ) ********************************/ - public: + 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); } @@ -1493,11 +1517,19 @@ namespace boost #elif defined(BOOST_HAS_MS_INT64) 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>>(char& output) { return shr_xchar(output); } bool operator>>(unsigned char& output) { return shr_xchar(output); } bool operator>>(signed char& output) { return shr_xchar(output); } +#if !defined(BOOST_LCAST_NO_WCHAR_T) && !defined(BOOST_NO_INTRINSIC_WCHAR_T) + bool operator>>(wchar_t& output) { return shr_xchar(output); } +#endif +#ifndef BOOST_NO_CHAR16_T + bool operator>>(char16_t& output) { return shr_xchar(output); } +#endif +#ifndef BOOST_NO_CHAR32_T + bool operator>>(char32_t& output) { return shr_xchar(output); } +#endif #ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION bool operator>>(std::string& str) { str.assign(start, finish); return true; } # ifndef BOOST_LCAST_NO_WCHAR_T diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 6eebe72..8718301 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -14,7 +14,12 @@ # bring in rules for testing import testing ; +import feature ; +feature.feature nowchar : on : + composite optional propagated link-incompatible ; +feature.compose on : /Zc:wchar_t- ; + test-suite conversion : [ run implicit_cast.cpp ] [ compile-fail implicit_cast_fail.cpp ] @@ -30,6 +35,7 @@ test-suite conversion [ 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 ] [ run lexical_cast_empty_input_test.cpp ../../test/build//boost_unit_test_framework/static ] + [ compile lexical_cast_typedefed_wchar_test.cpp : msvc:on ] + [ run lexical_cast_typedefed_wchar_test_runtime.cpp ../../test/build//boost_unit_test_framework/static : : : msvc:on ] ; - diff --git a/test/lexical_cast_empty_input_test.cpp b/test/lexical_cast_empty_input_test.cpp index 42e7cec..5a5881b 100755 --- a/test/lexical_cast_empty_input_test.cpp +++ b/test/lexical_cast_empty_input_test.cpp @@ -22,29 +22,120 @@ using namespace boost; -void test_empty_iterator_range() +#if defined(BOOST_NO_STRINGSTREAM) || defined(BOOST_NO_STD_WSTRING) +#define BOOST_LCAST_NO_WCHAR_T +#endif + +template +void do_test_on_empty_input(T& v) { - boost::iterator_range v; BOOST_CHECK_THROW(lexical_cast(v), bad_lexical_cast); BOOST_CHECK_THROW(lexical_cast(v), bad_lexical_cast); BOOST_CHECK_THROW(lexical_cast(v), bad_lexical_cast); BOOST_CHECK_THROW(lexical_cast(v), bad_lexical_cast); BOOST_CHECK_THROW(lexical_cast(v), bad_lexical_cast); - BOOST_CHECK_THROW(lexical_cast(v), bad_lexical_cast); BOOST_CHECK_THROW(lexical_cast(v), bad_lexical_cast); +#if defined(BOOST_HAS_LONG_LONG) + BOOST_CHECK_THROW(lexical_cast(v), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(v), bad_lexical_cast); +#elif defined(BOOST_HAS_MS_INT64) + BOOST_CHECK_THROW(lexical_cast(v), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast<__int64>(v), bad_lexical_cast); +#endif +} + +void test_empty_iterator_range() +{ + + boost::iterator_range v; + do_test_on_empty_input(v); + BOOST_CHECK_EQUAL(lexical_cast(v), std::string()); BOOST_CHECK_THROW(lexical_cast(v), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(v), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(v), bad_lexical_cast); + + boost::iterator_range cv; + do_test_on_empty_input(cv); + BOOST_CHECK_EQUAL(lexical_cast(cv), std::string()); + BOOST_CHECK_THROW(lexical_cast(cv), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(cv), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(cv), bad_lexical_cast); + + const boost::iterator_range ccv; + do_test_on_empty_input(ccv); + BOOST_CHECK_EQUAL(lexical_cast(ccv), std::string()); + BOOST_CHECK_THROW(lexical_cast(ccv), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(ccv), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(ccv), bad_lexical_cast); } void test_empty_string() { - BOOST_CHECK_THROW(lexical_cast(std::string()), bad_lexical_cast); - BOOST_CHECK_THROW(lexical_cast(std::string()), bad_lexical_cast); - BOOST_CHECK_THROW(lexical_cast(std::string()), bad_lexical_cast); - BOOST_CHECK_THROW(lexical_cast(std::string()), bad_lexical_cast); - BOOST_CHECK_THROW(lexical_cast(std::string()), bad_lexical_cast); - BOOST_CHECK_EQUAL(lexical_cast(std::string()), std::string()); - BOOST_CHECK_THROW(lexical_cast(std::string()), bad_lexical_cast); - BOOST_CHECK_THROW(lexical_cast(std::string()), bad_lexical_cast); + std::string v; + do_test_on_empty_input(v); + BOOST_CHECK_THROW(lexical_cast(v), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(v), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(v), bad_lexical_cast); + +#ifndef BOOST_LCAST_NO_WCHAR_T + std::wstring vw; + do_test_on_empty_input(vw); + BOOST_CHECK_THROW(lexical_cast(vw), bad_lexical_cast); +#endif + +// Currently, no compiler and STL library fully support char16_t and char32_t +//#ifndef BOOST_NO_CHAR16_T +// std::basic_string v16w; +// do_test_on_empty_input(v16w); +// BOOST_CHECK_THROW(lexical_cast(v16w), bad_lexical_cast); +//#endif +//#ifndef BOOST_NO_CHAR32_T +// std::basic_string v32w; +// do_test_on_empty_input(v32w); +// BOOST_CHECK_THROW(lexical_cast(v32w), bad_lexical_cast); +//#endif +} + +struct Escape +{ + Escape(const std::string& s) + : str_(s) + {} + + std::string str_; +}; + +inline std::ostream& operator<< (std::ostream& o, const Escape& rhs) +{ + return o << rhs.str_; +} + +void test_empty_user_class() +{ + Escape v(""); + do_test_on_empty_input(v); + BOOST_CHECK_THROW(lexical_cast(v), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(v), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(v), bad_lexical_cast); +} + +namespace std { +inline std::ostream & operator<<(std::ostream & out, const std::vector & v) +{ + std::ostream_iterator it(out); + std::copy(v.begin(), v.end(), it); + assert(out); + return out; +} +} + +void test_empty_vector() +{ + std::vector v; + do_test_on_empty_input(v); + BOOST_CHECK_THROW(lexical_cast(v), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(v), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(v), bad_lexical_cast); } unit_test::test_suite *init_unit_test_suite(int, char *[]) @@ -53,6 +144,8 @@ unit_test::test_suite *init_unit_test_suite(int, char *[]) BOOST_TEST_SUITE("lexical_cast. Empty input unit test"); suite->add(BOOST_TEST_CASE(&test_empty_iterator_range)); suite->add(BOOST_TEST_CASE(&test_empty_string)); + suite->add(BOOST_TEST_CASE(&test_empty_user_class)); + suite->add(BOOST_TEST_CASE(&test_empty_vector)); return suite; } diff --git a/test/lexical_cast_typedefed_wchar_test.cpp b/test/lexical_cast_typedefed_wchar_test.cpp new file mode 100755 index 0000000..752c3e5 --- /dev/null +++ b/test/lexical_cast_typedefed_wchar_test.cpp @@ -0,0 +1,25 @@ +// 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 + +#include +#include + +int main() +{ +#ifdef BOOST_MSVC + BOOST_STATIC_ASSERT((boost::is_same::value)); +#endif + + return ::boost::lexical_cast(L"1000") == 1000; +} + + diff --git a/test/lexical_cast_typedefed_wchar_test_runtime.cpp b/test/lexical_cast_typedefed_wchar_test_runtime.cpp new file mode 100755 index 0000000..d01700a --- /dev/null +++ b/test/lexical_cast_typedefed_wchar_test_runtime.cpp @@ -0,0 +1,48 @@ +// 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 +using namespace boost; + +void test_typedefed_wchar_t_runtime() +{ +#ifndef BOOST_LCAST_NO_WCHAR_T +#ifdef BOOST_MSVC + BOOST_STATIC_ASSERT((boost::is_same::value)); + + + BOOST_CHECK_EQUAL(boost::lexical_cast(L'A'), 65); + BOOST_CHECK_EQUAL(boost::lexical_cast(L'B'), 66); + + BOOST_CHECK_EQUAL(boost::lexical_cast(L"65"), 65); + BOOST_CHECK_EQUAL(boost::lexical_cast(L"66"), 66); +#endif +#endif + BOOST_CHECK(1); +} + +unit_test::test_suite *init_unit_test_suite(int, char *[]) +{ + unit_test::test_suite *suite = + BOOST_TEST_SUITE("lexical_cast typedefed wchar_t runtime test"); + suite->add(BOOST_TEST_CASE(&test_typedefed_wchar_t_runtime)); + + return suite; +}