From 74fc01da7e20f21b3e6af3651ab03cc1e736e913 Mon Sep 17 00:00:00 2001 From: nobody Date: Tue, 21 Mar 2006 02:26:31 +0000 Subject: [PATCH 01/66] This commit was manufactured by cvs2svn to create branch 'RC_1_34_0'. [SVN r33417] From 06e7d986d297f1affe58bcd0e5e6a8c3c69808d0 Mon Sep 17 00:00:00 2001 From: Gennaro Prota Date: Mon, 17 Jul 2006 03:08:48 +0000 Subject: [PATCH 02/66] fixed library name, copyright notice, removed a tab char and a space-only line; NOTE: is the copyright notice autogenerated? [SVN r34573] --- test/Jamfile | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/test/Jamfile b/test/Jamfile index 8af8d65..b0c960c 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -1,17 +1,10 @@ -# Signals library +# Conversion library # Copyright (C) 2001-2003 Douglas Gregor -# Permission to copy, use, sell and distribute this software is granted -# provided this copyright notice appears in all copies. Permission to modify -# the code and to distribute modified code is granted provided this copyright -# notice appears in all copies, and a notice that the code was modified is -# included with the copyright notice. This software is provided "as is" -# without express or implied warranty, and with no claim as to its suitability -# for any purpose. - -# For more information, see http://www.boost.org/ - +# 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) # Testing Jamfile autogenerated from XML source subproject libs/conversion/test ; @@ -27,8 +20,8 @@ DEPENDS all : test ; : [ run implicit_cast.cpp ] [ compile-fail implicit_cast_fail.cpp ] [ run ../cast_test.cpp ] - [ run ../numeric_cast_test.cpp ] + [ run ../numeric_cast_test.cpp ] [ run ../lexical_cast_test.cpp ../../test/build/boost_unit_test_framework ] ; } - + From abf3aa23de68b44e8437d6f5eac74400afee5d05 Mon Sep 17 00:00:00 2001 From: Gennaro Prota Date: Mon, 17 Jul 2006 04:17:11 +0000 Subject: [PATCH 03/66] removed erroneous macro version [SVN r34578] --- include/boost/implicit_cast.hpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/include/boost/implicit_cast.hpp b/include/boost/implicit_cast.hpp index 2593cb4..7043085 100755 --- a/include/boost/implicit_cast.hpp +++ b/include/boost/implicit_cast.hpp @@ -23,12 +23,6 @@ inline T implicit_cast (typename mpl::identity::type x) { //template //void implicit_cast (...); -// Macro for when you need a constant expression (Gennaro Prota) -#define BOOST_IMPLICIT_CAST(dst_type, expr) \ - ( sizeof( implicit_cast(expr) ) \ - , \ - static_cast(expr) \ - ) } // namespace boost From 78f1acc5ff51e34216cf9105e63b88b0fbfd2338 Mon Sep 17 00:00:00 2001 From: Rene Rivera Date: Mon, 6 Nov 2006 17:10:46 +0000 Subject: [PATCH 04/66] Remove obsolete Boost.Build v1 files. [SVN r35880] --- test/Jamfile | 27 --------------------------- 1 file changed, 27 deletions(-) delete mode 100644 test/Jamfile diff --git a/test/Jamfile b/test/Jamfile deleted file mode 100644 index b0c960c..0000000 --- a/test/Jamfile +++ /dev/null @@ -1,27 +0,0 @@ -# Conversion library - -# Copyright (C) 2001-2003 Douglas Gregor - -# 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) - -# Testing Jamfile autogenerated from XML source -subproject libs/conversion/test ; - -# bring in rules for testing -import testing ; - -# Make tests run by default. -DEPENDS all : test ; - -{ - test-suite conversion - : [ run implicit_cast.cpp ] - [ compile-fail implicit_cast_fail.cpp ] - [ run ../cast_test.cpp ] - [ run ../numeric_cast_test.cpp ] - [ run ../lexical_cast_test.cpp ../../test/build/boost_unit_test_framework ] - ; -} - From bfeb60c400c09da36114c07698fe634c811df377 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Fri, 10 Nov 2006 19:59:52 +0000 Subject: [PATCH 05/66] Merge from HEAD. Allow building of shared versions of some Boost.Test libraries. Adjust tests to use always use static linking to Boost.Test, since linking to the shared version requires test changes. Patch from Juergen Hunold. [SVN r35990] --- test/Jamfile.v2 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 58ae133..0e59404 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -20,7 +20,8 @@ test-suite conversion [ compile-fail implicit_cast_fail.cpp ] [ run ../cast_test.cpp ] [ run ../numeric_cast_test.cpp ] - [ run ../lexical_cast_test.cpp ../../test/build//boost_unit_test_framework ] + [ run ../lexical_cast_test.cpp ../../test/build//boost_unit_test_framework/static ] + [ run lexical_cast_loopback_test.cpp ../../test/build//boost_unit_test_framework/static ] ; - \ No newline at end of file + From 37d07617d13154d9ab8281a027686441fb1ad553 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Fri, 10 Nov 2006 21:03:16 +0000 Subject: [PATCH 06/66] Fix [SVN r35993] --- test/Jamfile.v2 | 1 - 1 file changed, 1 deletion(-) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 0e59404..56a03d8 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -21,7 +21,6 @@ test-suite conversion [ run ../cast_test.cpp ] [ run ../numeric_cast_test.cpp ] [ run ../lexical_cast_test.cpp ../../test/build//boost_unit_test_framework/static ] - [ run lexical_cast_loopback_test.cpp ../../test/build//boost_unit_test_framework/static ] ; From d6eea4ef813d7df541f522c00a90b3f2dbe94392 Mon Sep 17 00:00:00 2001 From: nobody Date: Tue, 24 Jul 2007 19:28:14 +0000 Subject: [PATCH 07/66] This commit was manufactured by cvs2svn to create tag 'Version_1_34_1'. [SVN r38286] From 4224fa5deb2709fd14239fef634a75ba081b4cbc Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Fri, 5 Oct 2007 14:25:06 +0000 Subject: [PATCH 08/66] Starting point for releases [SVN r39706] From ac6e41d676328940dbe656cc47f8b6affd8b95f4 Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Fri, 23 Nov 2007 17:03:14 +0000 Subject: [PATCH 09/66] config, detail, filesystem, system, tools, at 41278. [SVN r41316] --- include/boost/detail/lcast_precision.hpp | 184 +++++++++++++++++++++++ 1 file changed, 184 insertions(+) create mode 100644 include/boost/detail/lcast_precision.hpp diff --git a/include/boost/detail/lcast_precision.hpp b/include/boost/detail/lcast_precision.hpp new file mode 100644 index 0000000..d40ca21 --- /dev/null +++ b/include/boost/detail/lcast_precision.hpp @@ -0,0 +1,184 @@ +// Copyright Alexander Nasonov & Paul A. Bristow 2006. + +// 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) + +#ifndef BOOST_DETAIL_LCAST_PRECISION_HPP_INCLUDED +#define BOOST_DETAIL_LCAST_PRECISION_HPP_INCLUDED + +#include +#include +#include + +#include +#include + +#ifndef BOOST_NO_IS_ABSTRACT +// Fix for SF:1358600 - lexical_cast & pure virtual functions & VC 8 STL +#include +#include +#endif + +#if defined(BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS) || \ + (defined(BOOST_MSVC) && (BOOST_MSVC<1310)) + +#define BOOST_LCAST_NO_COMPILE_TIME_PRECISION +#endif + +#ifdef BOOST_LCAST_NO_COMPILE_TIME_PRECISION +#include +#else +#include +#endif + +namespace boost { namespace detail { + +class lcast_abstract_stub {}; + +#ifndef BOOST_LCAST_NO_COMPILE_TIME_PRECISION +// Calculate an argument to pass to std::ios_base::precision from +// lexical_cast. See alternative implementation for broken standard +// libraries in lcast_get_precision below. Keep them in sync, please. +template +struct lcast_precision +{ +#ifdef BOOST_NO_IS_ABSTRACT + typedef std::numeric_limits limits; // No fix for SF:1358600. +#else + typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_< + boost::is_abstract + , std::numeric_limits + , std::numeric_limits + >::type limits; +#endif + + BOOST_STATIC_CONSTANT(bool, use_default_precision = + !limits::is_specialized || limits::is_exact + ); + + BOOST_STATIC_CONSTANT(bool, is_specialized_bin = + !use_default_precision && + limits::radix == 2 && limits::digits > 0 + ); + + BOOST_STATIC_CONSTANT(bool, is_specialized_dec = + !use_default_precision && + limits::radix == 10 && limits::digits10 > 0 + ); + + BOOST_STATIC_CONSTANT(std::streamsize, streamsize_max = + boost::integer_traits::const_max + ); + + BOOST_STATIC_CONSTANT(unsigned int, precision_dec = limits::digits10 + 1U); + + BOOST_STATIC_ASSERT(!is_specialized_dec || + precision_dec <= streamsize_max + 0UL + ); + + BOOST_STATIC_CONSTANT(unsigned long, precision_bin = + 2UL + limits::digits * 30103UL / 100000UL + ); + + BOOST_STATIC_ASSERT(!is_specialized_bin || + (limits::digits + 0UL < ULONG_MAX / 30103UL && + precision_bin > limits::digits10 + 0UL && + precision_bin <= streamsize_max + 0UL) + ); + + BOOST_STATIC_CONSTANT(std::streamsize, value = + is_specialized_bin ? precision_bin + : is_specialized_dec ? precision_dec : 6 + ); +}; +#endif + +template +inline std::streamsize lcast_get_precision(T* = 0) +{ +#ifndef BOOST_LCAST_NO_COMPILE_TIME_PRECISION + return lcast_precision::value; +#else // Follow lcast_precision algorithm at run-time: + +#ifdef BOOST_NO_IS_ABSTRACT + typedef std::numeric_limits limits; // No fix for SF:1358600. +#else + typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_< + boost::is_abstract + , std::numeric_limits + , std::numeric_limits + >::type limits; +#endif + + bool const use_default_precision = + !limits::is_specialized || limits::is_exact; + + if(!use_default_precision) + { // Includes all built-in floating-point types, float, double ... + // and UDT types for which digits (significand bits) is defined (not zero) + + bool const is_specialized_bin = + limits::radix == 2 && limits::digits > 0; + bool const is_specialized_dec = + limits::radix == 10 && limits::digits10 > 0; + std::streamsize const streamsize_max = + (boost::integer_traits::max)(); + + if(is_specialized_bin) + { // Floating-point types with + // limits::digits defined by the specialization. + + unsigned long const digits = limits::digits; + unsigned long const precision = 2UL + digits * 30103UL / 100000UL; + // unsigned long is selected because it is at least 32-bits + // and thus ULONG_MAX / 30103UL is big enough for all types. + BOOST_ASSERT( + digits < ULONG_MAX / 30103UL && + precision > limits::digits10 + 0UL && + precision <= streamsize_max + 0UL + ); + return precision; + } + else if(is_specialized_dec) + { // Decimal Floating-point type, most likely a User Defined Type + // rather than a real floating-point hardware type. + unsigned int const precision = limits::digits10 + 1U; + BOOST_ASSERT(precision <= streamsize_max + 0UL); + return precision; + } + } + + // Integral type (for which precision has no effect) + // or type T for which limits is NOT specialized, + // so assume stream precision remains the default 6 decimal digits. + // Warning: if your User-defined Floating-point type T is NOT specialized, + // then you may lose accuracy by only using 6 decimal digits. + // To avoid this, you need to specialize T with either + // radix == 2 and digits == the number of significand bits, + // OR + // radix = 10 and digits10 == the number of decimal digits. + + return 6; +#endif +} + +template +inline void lcast_set_precision(std::ios_base& stream, T*) +{ + stream.precision(lcast_get_precision()); +} + +template +inline void lcast_set_precision(std::ios_base& stream, Source*, Target*) +{ + std::streamsize const s = lcast_get_precision((Source*)0); + std::streamsize const t = lcast_get_precision((Target*)0); + stream.precision(s > t ? s : t); +} + +}} + +#endif // BOOST_DETAIL_LCAST_PRECISION_HPP_INCLUDED + From d44a6fcf8bace4216b57ddf61951952a44268c3f Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Sun, 25 Nov 2007 18:07:19 +0000 Subject: [PATCH 10/66] Full merge from trunk at revision 41356 of entire boost-root tree. [SVN r41369] --- include/boost/implicit_cast.hpp | 2 +- include/boost/lexical_cast.hpp | 902 +++++++++++++++++++++++++++++++- 2 files changed, 876 insertions(+), 28 deletions(-) diff --git a/include/boost/implicit_cast.hpp b/include/boost/implicit_cast.hpp index 7043085..5b1cd92 100755 --- a/include/boost/implicit_cast.hpp +++ b/include/boost/implicit_cast.hpp @@ -23,7 +23,7 @@ inline T implicit_cast (typename mpl::identity::type x) { //template //void implicit_cast (...); - } // namespace boost + #endif // IMPLICIT_CAST_DWA200356_HPP diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index 926b95e..754aecf 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -3,24 +3,31 @@ // Boost lexical_cast.hpp header -------------------------------------------// // -// See http://www.boost.org for most recent version including documentation. +// See http://www.boost.org/libs/converston for documentation. // See end of this header for rights and permissions. // // what: lexical_cast custom keyword cast // who: contributed by Kevlin Henney, -// enhanced with contributions from Terje Slettebų, +// enhanced with contributions from Terje Slettebo, // with additional fixes and suggestions from Gennaro Prota, // Beman Dawes, Dave Abrahams, Daryle Walker, Peter Dimov, -// and other Boosters -// when: November 2000, March 2003, June 2005 +// Alexander Nasonov and other Boosters +// when: November 2000, March 2003, June 2005, June 2006 +#include #include +#include +#include #include #include #include #include +#include #include #include +#include +#include +#include #ifdef BOOST_NO_STRINGSTREAM #include @@ -45,9 +52,9 @@ namespace boost { } bad_lexical_cast( - const std::type_info &source_type, - const std::type_info &target_type) : - source(&source_type), target(&target_type) + const std::type_info &source_type_arg, + const std::type_info &target_type_arg) : + source(&source_type_arg), target(&target_type_arg) { } const std::type_info &source_type() const @@ -79,8 +86,8 @@ namespace boost typedef char type; }; - #ifndef DISABLE_WIDE_CHAR_SUPPORT -#if !defined(BOOST_NO_INTRINSIC_WCHAR_T) +#ifndef DISABLE_WIDE_CHAR_SUPPORT +#ifndef BOOST_NO_INTRINSIC_WCHAR_T template<> struct stream_char { @@ -105,7 +112,7 @@ namespace boost { typedef wchar_t type; }; - #endif +#endif template struct widest_char @@ -119,7 +126,393 @@ namespace boost typedef wchar_t type; }; } - + + 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); + // 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() {} + }; + + // No specializations for: + // lcast_src_length + // lcast_src_length + // lcast_src_length + // lcast_src_length + // lcast_src_length + // lcast_src_length + +#ifndef DISABLE_WIDE_CHAR_SUPPORT + 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 DISABLE_WIDE_CHAR_SUPPORT + 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 DISABLE_WIDE_CHAR_SUPPORT + 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 ',': + // "-2,1,4,7,4,8,3,6,4,7" + // ^ - is_signed + // ^ - 1 digit not counted by digits10 + // ^^^^^^^^^^^^^^^^^^ - digits10 * 2 + // + // Constant is_specialized is used instead of constant 1 + // to prevent buffer overflow in a rare case when + // doesn't add missing specialization for + // numeric_limits for some integral type T. + // When is_specialized is false, the whole expression is 0. + template + struct lcast_src_length_integral + { +#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::digits10 * 2 + ); +#else + BOOST_STATIC_CONSTANT(std::size_t, value = 156); + BOOST_STATIC_ASSERT(sizeof(Source) * CHAR_BIT <= 256); +#endif + }; + +#define BOOST_AUX_LEXICAL_CAST_DEF1(CharT, T) template<> \ + struct lcast_src_length : lcast_src_length_integral \ + { static void check_coverage() {} }; + +#ifdef DISABLE_WIDE_CHAR_SUPPORT +#define BOOST_AUX_LEXICAL_CAST_DEF(T) BOOST_AUX_LEXICAL_CAST_DEF1(char, T) +#else +#define BOOST_AUX_LEXICAL_CAST_DEF(T) \ + BOOST_AUX_LEXICAL_CAST_DEF1(char, T) \ + BOOST_AUX_LEXICAL_CAST_DEF1(wchar_t, T) +#endif + + BOOST_AUX_LEXICAL_CAST_DEF(short) + BOOST_AUX_LEXICAL_CAST_DEF(unsigned short) + BOOST_AUX_LEXICAL_CAST_DEF(int) + BOOST_AUX_LEXICAL_CAST_DEF(unsigned int) + BOOST_AUX_LEXICAL_CAST_DEF(long) + BOOST_AUX_LEXICAL_CAST_DEF(unsigned long) +#if defined(BOOST_HAS_LONG_LONG) + BOOST_AUX_LEXICAL_CAST_DEF(boost::ulong_long_type) + BOOST_AUX_LEXICAL_CAST_DEF(boost::long_long_type ) +#elif defined(BOOST_HAS_MS_INT64) + BOOST_AUX_LEXICAL_CAST_DEF(unsigned __int64) + BOOST_AUX_LEXICAL_CAST_DEF( __int64) +#endif + +#undef BOOST_AUX_LEXICAL_CAST_DEF +#undef BOOST_AUX_LEXICAL_CAST_DEF1 + +#ifndef BOOST_LCAST_NO_COMPILE_TIME_PRECISION +// This #if is in sync with lcast_precision + + // Helper for floating point types. + // -1.23456789e-123456 + // ^ sign + // ^ leading digit + // ^ decimal point + // ^^^^^^^^ lcast_precision::value + // ^ "e" + // ^ exponent sign + // ^^^^^^ exponent (assumed 6 or less digits) + // sign + leading digit + decimal point + "e" + exponent sign == 5 + template + struct lcast_src_length_floating + { + BOOST_STATIC_ASSERT( + std::numeric_limits::max_exponent10 <= 999999L && + std::numeric_limits::min_exponent10 >= -999999L + ); + BOOST_STATIC_CONSTANT(std::size_t, value = + 5 + lcast_precision::value + 6 + ); + }; + + 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() {} + }; + +#ifndef DISABLE_WIDE_CHAR_SUPPORT + 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 DISABLE_WIDE_CHAR_SUPPORT +#endif // #ifndef BOOST_LCAST_NO_COMPILE_TIME_PRECISION + } + + namespace detail // '0' and '-' constants + { + template struct lcast_char_constants; + + template<> + struct lcast_char_constants + { + BOOST_STATIC_CONSTANT(char, zero = '0'); + BOOST_STATIC_CONSTANT(char, minus = '-'); + }; + +#ifndef DISABLE_WIDE_CHAR_SUPPORT + template<> + struct lcast_char_constants + { + BOOST_STATIC_CONSTANT(wchar_t, zero = L'0'); + BOOST_STATIC_CONSTANT(wchar_t, minus = L'-'); + }; +#endif + } + + namespace detail // lexical_streambuf_fake + { + struct lexical_streambuf_fake + { + }; + } + + namespace detail // lcast_to_unsigned + { +#if (defined _MSC_VER) +# pragma warning( push ) +// C4146: unary minus operator applied to unsigned type, result still unsigned +# pragma warning( disable : 4146 ) +#endif + + inline unsigned int lcast_to_unsigned(int value) + { + unsigned int uval = value; + return value < 0 ? -uval : uval; + } + + inline unsigned long lcast_to_unsigned(long value) + { + unsigned long uval = value; + return value < 0 ? -uval : uval; + } + +#if defined(BOOST_HAS_LONG_LONG) + inline boost::ulong_long_type lcast_to_unsigned(boost::long_long_type v) + { + boost::ulong_long_type uval = v; + return v < 0 ? -uval : uval; + } +#elif defined(BOOST_HAS_MS_INT64) + inline unsigned __int64 lcast_to_unsigned(__int64 value) + { + unsigned __int64 uval = value; + return value < 0 ? -uval : uval; + } +#endif + +#if (defined _MSC_VER) +# pragma warning( pop ) // C4146: unary minus operator applied to unsigned type, + // result still unsigned +#endif + } + + namespace detail // lcast_put_unsigned + { + // I'd personally put lcast_put_unsigned in .cpp file if not + // boost practice for header-only libraries (Alexander Nasonov). + template + CharT* lcast_put_unsigned(T n, CharT* finish) + { +#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS + BOOST_STATIC_ASSERT(!std::numeric_limits::is_signed); +#endif + CharT thousands_sep = 0; + +#ifdef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE + char const* grouping = ""; + std::size_t const grouping_size = 0; +#else + 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(grouping_size) + thousands_sep = np.thousands_sep(); +#endif + + std::string::size_type group = 0; // current group number + char last_grp_size = grouping[0] <= 0 ? CHAR_MAX : grouping[0]; + // a) Since grouping is const, grouping[grouping.size()] returns 0. + // b) It's safe to assume here and below that CHAR_MAX + // is equivalent to unlimited grouping: +#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS + BOOST_STATIC_ASSERT(std::numeric_limits::digits10 < CHAR_MAX); +#endif + + char left = last_grp_size; + + do + { + if(left == 0) + { + ++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; + *finish = thousands_sep; + } + + --left; + --finish; + int const digit = static_cast(n % 10); + int const cdigit = digit + lcast_char_constants::zero; + *finish = static_cast(cdigit); + n /= 10; + } while(n); + + return finish; + } + } + namespace detail // stream wrapper for handling lexical conversions { template @@ -131,14 +524,10 @@ namespace boost typename stream_char::type>::type char_type; public: - lexical_stream() + lexical_stream(char_type* = 0, char_type* = 0) { stream.unsetf(std::ios::skipws); - - if(std::numeric_limits::is_specialized) - stream.precision(std::numeric_limits::digits10 + 1); - else if(std::numeric_limits::is_specialized) - stream.precision(std::numeric_limits::digits10 + 1); + lcast_set_precision(stream, (Source*)0, (Target*)0); } ~lexical_stream() { @@ -171,13 +560,13 @@ namespace boost #if defined(BOOST_NO_STRINGSTREAM) stream << '\0'; #endif - output = stream.str(); + stream.str().swap(output); return true; } #ifndef DISABLE_WIDE_CHAR_SUPPORT bool operator>>(std::wstring &output) { - output = stream.str(); + stream.str().swap(output); return true; } #endif @@ -192,6 +581,419 @@ namespace boost }; } + namespace detail // optimized stream wrapper + { + // 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 lexical_stream_limited_src : public Base + { + // 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; + + private: + + static void widen_and_assign(char*p, char ch) + { + *p = ch; + } + +#ifndef DISABLE_WIDE_CHAR_SUPPORT + static void widen_and_assign(wchar_t* p, char ch) + { + std::locale loc; + *p = BOOST_USE_FACET(std::ctype, loc).widen(ch); + } + + static void widen_and_assign(wchar_t* p, wchar_t ch) + { + *p = ch; + } + + static void widen_and_assign(char*, wchar_t ch); // undefined +#endif + + template + bool lcast_put(const OutputStreamable& input) + { + this->setp(start, finish); + std::basic_ostream stream(static_cast(this)); + lcast_set_precision(stream, (OutputStreamable*)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&); + + public: + + lexical_stream_limited_src(CharT* start, CharT* finish) + : start(start) + , finish(finish) + {} + + public: // output + + template + bool operator<<(std::basic_string const& str) + { + start = const_cast(str.data()); + finish = start + str.length(); + return true; + } + + bool operator<<(bool); + bool operator<<(char); +#if !defined(DISABLE_WIDE_CHAR_SUPPORT) && !defined(BOOST_NO_INTRINSIC_WCHAR_T) + bool operator<<(wchar_t); +#endif + 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); +#if defined(BOOST_HAS_LONG_LONG) + bool operator<<(boost::ulong_long_type); + bool operator<<(boost::long_long_type ); +#elif defined(BOOST_HAS_MS_INT64) + bool operator<<(unsigned __int64); + bool operator<<( __int64); +#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); + + public: // input + + // Generic istream-based algorithm. + // lcast_streambuf_for_target::value is true. + template + bool operator>>(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, (InputStreamable*)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 + std::char_traits::eof(); +#endif + } + + bool operator>>(CharT&); + +#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +// This #if is in sync with lcast_streambuf_for_target + + bool operator>>(std::string&); + +#ifndef DISABLE_WIDE_CHAR_SUPPORT + 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) + { + *start = value + lcast_char_constants::zero; + 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; + } + +#if !defined(DISABLE_WIDE_CHAR_SUPPORT) && !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 = lcast_char_constants::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 = lcast_char_constants::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 = lcast_char_constants::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 = lcast_char_constants::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 = lcast_char_constants::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 + std::char_traits::length(str); + return true; + } + + template + inline bool lexical_stream_limited_src::operator>>( + CharT& output) + { + bool const ok = (finish - start == 1); + if(ok) + output = *start; + 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 DISABLE_WIDE_CHAR_SUPPORT + 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); + }; + } + + namespace detail // lcast_streambuf_for_target + { + // Returns true if optimized stream wrapper needs istream for reading. + template + struct lcast_streambuf_for_target + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + + template<> + struct lcast_streambuf_for_target + { + BOOST_STATIC_CONSTANT(bool, value = false); + }; + +#if !defined(DISABLE_WIDE_CHAR_SUPPORT) && !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< + std::basic_string > + { + BOOST_STATIC_CONSTANT(bool, value = false); + }; + +#ifndef DISABLE_WIDE_CHAR_SUPPORT + 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 DISABLE_WIDE_CHAR_SUPPORT + 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 @@ -209,19 +1011,64 @@ namespace boost { typedef const T * type; }; + + 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 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); + + // The original form, reproduced below, is more elegant + // but yields a spurious C4701 warning ("possible use of + // "result" before initialization") with VC7.1 (/W4). +// +// Target result; +// +// if(!(interpreter << arg && interpreter >> result)) +// throw_exception(bad_lexical_cast(typeid(Source), typeid(Target))); +// return result; + + if(interpreter << arg) { + Target result; + if (interpreter >> result) + return result; + } + throw_exception(bad_lexical_cast(typeid(Source), typeid(Target))); + return Target(); // normally never reached (throw_exception) + } } template - Target lexical_cast(const Source &arg) + inline Target lexical_cast(const Source &arg) { - typedef typename detail::array_to_pointer_decay::type NewSource; + typedef typename detail::array_to_pointer_decay::type src; - detail::lexical_stream interpreter; - Target result; + typedef typename detail::widest_char< + typename detail::stream_char::type + , typename detail::stream_char::type + >::type char_type; - if(!(interpreter << arg && interpreter >> result)) - throw_exception(bad_lexical_cast(typeid(NewSource), typeid(Target))); - return result; + 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); } #else @@ -242,7 +1089,8 @@ namespace boost #endif } -// Copyright Kevlin Henney, 2000-2005. All rights reserved. +// Copyright Kevlin Henney, 2000-2005. +// Copyright Alexander Nasonov, 2006-2007. // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at From ee3f643c5e9ed40a4bd0d1e24a2dd99204b91e92 Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Sun, 25 Nov 2007 18:38:02 +0000 Subject: [PATCH 11/66] Full merge from trunk at revision 41356 of entire boost-root tree. [SVN r41370] --- lexical_cast.htm | 40 +++- lexical_cast_test.cpp | 288 +++++++++++++++++++++++++ test/Jamfile.v2 | 3 + test/lexical_cast_abstract_test.cpp | 61 ++++++ test/lexical_cast_loopback_test.cpp | 98 +++++++++ test/lexical_cast_noncopyable_test.cpp | 54 +++++ 6 files changed, 542 insertions(+), 2 deletions(-) create mode 100644 test/lexical_cast_abstract_test.cpp create mode 100644 test/lexical_cast_loopback_test.cpp create mode 100644 test/lexical_cast_noncopyable_test.cpp diff --git a/lexical_cast.htm b/lexical_cast.htm index 949b70c..2a08541 100644 --- a/lexical_cast.htm +++ b/lexical_cast.htm @@ -20,6 +20,10 @@ lexical_cast
  • bad_lexical_cast
  • +
  • + Frequently Asked Questions
  • +
  • + References
  • Changes
  • @@ -160,7 +164,7 @@ void log_errno(int yoko) and an instance of the result type on the right.
  • - Both Source and Target are CopyConstructible [20.1.3]. + Target is CopyConstructible [20.1.3].
  • Target is DefaultConstructible, meaning that it is possible @@ -192,7 +196,39 @@ 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. + 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"));
    + +

    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

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

    Changes

    +

    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 @@ -231,4 +267,4 @@ public:
      © Copyright Kevlin Henney, 2000–2005
      - \ No newline at end of file + diff --git a/lexical_cast_test.cpp b/lexical_cast_test.cpp index 4182942..6ba26a3 100644 --- a/lexical_cast_test.cpp +++ b/lexical_cast_test.cpp @@ -3,6 +3,7 @@ // See http://www.boost.org for most recent version, including documentation. // // Copyright Terje Slettebų and Kevlin Henney, 2005. +// Copyright Alexander Nasonov, 2006. // // Distributed under the Boost // Software License, Version 1.0. (See accompanying file @@ -29,6 +30,18 @@ #define DISABLE_WIDE_CHAR_SUPPORT #endif +#if (defined(BOOST_HAS_LONG_LONG) || defined(BOOST_HAS_MS_INT64)) \ + && !(defined(BOOST_MSVC) && BOOST_MSVC < 1300) +#define LCAST_TEST_LONGLONG +#endif + +// Test all 65536 values if true: +bool const lcast_test_small_integral_types_completely = false; + +// lcast_integral_test_counter: use when testing all values of an integral +// types is not possible. Max. portable value is 32767. +int const lcast_integral_test_counter=1000; + using namespace boost; void test_conversion_to_char(); @@ -44,6 +57,16 @@ void test_conversion_from_wstring(); void test_conversion_to_wstring(); void test_bad_lexical_cast(); void test_no_whitespace_stripping(); +void test_conversion_from_short(); +void test_conversion_from_ushort(); +void test_conversion_from_int(); +void test_conversion_from_uint(); +void test_conversion_from_long(); +void test_conversion_from_ulong(); +#ifdef LCAST_TEST_LONGLONG +void test_conversion_from_longlong(); +void test_conversion_from_ulonglong(); +#endif unit_test::test_suite *init_unit_test_suite(int, char *[]) { @@ -64,6 +87,17 @@ unit_test::test_suite *init_unit_test_suite(int, char *[]) #endif suite->add(BOOST_TEST_CASE(test_bad_lexical_cast)); suite->add(BOOST_TEST_CASE(test_no_whitespace_stripping)); + suite->add(BOOST_TEST_CASE(&test_conversion_from_short)); + suite->add(BOOST_TEST_CASE(&test_conversion_from_ushort)); + suite->add(BOOST_TEST_CASE(&test_conversion_from_int)); + suite->add(BOOST_TEST_CASE(&test_conversion_from_uint)); + suite->add(BOOST_TEST_CASE(&test_conversion_from_ulong)); + suite->add(BOOST_TEST_CASE(&test_conversion_from_long)); + #ifdef LCAST_TEST_LONGLONG + suite->add(BOOST_TEST_CASE(&test_conversion_from_longlong)); + suite->add(BOOST_TEST_CASE(&test_conversion_from_ulonglong)); + #endif + return suite; } @@ -167,6 +201,9 @@ void test_conversion_to_bool() void test_conversion_to_string() { + char buf[] = "hello"; + char* str = buf; + BOOST_CHECK_EQUAL(str, lexical_cast(str)); BOOST_CHECK_EQUAL("A", lexical_cast('A')); BOOST_CHECK_EQUAL(" ", lexical_cast(' ')); BOOST_CHECK_EQUAL("123", lexical_cast(123)); @@ -239,6 +276,8 @@ void test_conversion_to_wchar_t() #if !defined(DISABLE_WIDE_CHAR_SUPPORT) && !defined(BOOST_NO_INTRINSIC_WCHAR_T) BOOST_CHECK_EQUAL(L'1', lexical_cast(1)); BOOST_CHECK_EQUAL(L'0', lexical_cast(0)); + BOOST_CHECK_EQUAL(L'1', lexical_cast('1')); + BOOST_CHECK_EQUAL(L'0', lexical_cast('0')); BOOST_CHECK_THROW(lexical_cast(123), bad_lexical_cast); BOOST_CHECK_EQUAL(L'1', lexical_cast(1.0)); BOOST_CHECK_EQUAL(L'0', lexical_cast(0.0)); @@ -280,6 +319,9 @@ void test_conversion_from_wstring() void test_conversion_to_wstring() { #ifndef DISABLE_WIDE_CHAR_SUPPORT + wchar_t buf[] = L"hello"; + wchar_t* str = buf; + BOOST_CHECK(str == lexical_cast(str)); BOOST_CHECK(L"123" == lexical_cast(123)); BOOST_CHECK(L"1.23" == lexical_cast(1.23)); BOOST_CHECK(L"1.111111111" == lexical_cast(1.111111111)); @@ -288,6 +330,7 @@ void test_conversion_to_wstring() #if !defined(BOOST_NO_INTRINSIC_WCHAR_T) BOOST_CHECK(L"A" == lexical_cast(L'A')); BOOST_CHECK(L" " == lexical_cast(L' ')); + BOOST_CHECK(L"A" == lexical_cast('A')); #endif BOOST_CHECK(L"Test" == lexical_cast(L"Test")); BOOST_CHECK(L" " == lexical_cast(L" ")); @@ -318,3 +361,248 @@ void test_no_whitespace_stripping() BOOST_CHECK_THROW(lexical_cast(" 123"), bad_lexical_cast); BOOST_CHECK_THROW(lexical_cast("123 "), bad_lexical_cast); } + +// 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_integral_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_integral_to_integral() +{ + T t = 0; + BOOST_CHECK(lexical_cast(t) == t); + + // Next two variables are used to supress warnings. + int st = 32767; unsigned int ut = st; + t = st; + BOOST_CHECK(lexical_cast(t) == st); + BOOST_CHECK(lexical_cast(t) == ut); + BOOST_CHECK(lexical_cast(t) == st); + BOOST_CHECK(lexical_cast(t) == ut); + BOOST_CHECK(lexical_cast(t) == st); + BOOST_CHECK(lexical_cast(t) == ut); + + t = std::numeric_limits::max(); + BOOST_CHECK(lexical_cast(t) == t); + + t = std::numeric_limits::min(); + BOOST_CHECK(lexical_cast(t) == t); +} + +template +void test_conversion_from_integral_to_string(CharT) +{ + typedef std::numeric_limits limits; + typedef std::basic_string string_type; + + T t; + + t = limits::min(); + BOOST_CHECK(lexical_cast(t) == to_str(t)); + + t = limits::max(); + BOOST_CHECK(lexical_cast(t) == to_str(t)); + + if(limits::digits <= 16 && lcast_test_small_integral_types_completely) + for(t = 1 + limits::min(); t != limits::max(); ++t) + BOOST_CHECK(lexical_cast(t) == to_str(t)); + else + { + T const min_val = limits::min(); + T const max_val = limits::max(); + T const half_max_val = max_val / 2; + T const cnt = lcast_integral_test_counter; // to supress warnings + unsigned int const counter = cnt < half_max_val ? cnt : half_max_val; + + unsigned int i; + + // Test values around min: + t = min_val; + for(i = 0; i < counter; ++i, ++t) + BOOST_CHECK(lexical_cast(t) == to_str(t)); + + // Test values around max: + t = max_val; + for(i = 0; i < counter; ++i, --t) + BOOST_CHECK(lexical_cast(t) == to_str(t)); + + // Test values around zero: + if(limits::is_signed) + for(t = -counter; t < static_cast(counter); ++t) + BOOST_CHECK(lexical_cast(t) == to_str(t)); + + // Test values around 100, 1000, 10000, ... + T ten_power = 100; + for(int e = 2; e <= limits::digits10; ++e, ten_power *= 10) + { + // I believe that (ten_power + 100) never overflows + for(t = ten_power - 100; t != ten_power + 100; ++t) + BOOST_CHECK(lexical_cast(t) == to_str(t)); + } + } +} + +template +void test_conversion_from_integral_for_locale() +{ + test_conversion_from_integral_to_integral(); + test_conversion_from_integral_to_string('0'); +#if !defined(DISABLE_WIDE_CHAR_SUPPORT) && !defined(BOOST_NO_INTRINSIC_WCHAR_T) + test_conversion_from_integral_to_string(L'0'); +#endif +} + +struct restore_oldloc +{ + std::locale oldloc; + ~restore_oldloc() { std::locale::global(oldloc); } +}; + +template +void test_conversion_from_integral() +{ + char const zero = '0'; + signed char const szero = '0'; + unsigned char const uzero = '0'; + test_conversion_from_integral_to_char(zero); + test_conversion_from_integral_to_char(szero); + test_conversion_from_integral_to_char(uzero); +#if !defined(DISABLE_WIDE_CHAR_SUPPORT) && !defined(BOOST_NO_INTRINSIC_WCHAR_T) + wchar_t const wzero = L'0'; + test_conversion_from_integral_to_char(wzero); +#endif + + // test_conversion_from_integral_for_locale + + 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_integral_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_integral_for_locale(); + + if(grouping1.empty() && grouping2.empty()) + BOOST_TEST_MESSAGE("Formatting with thousands_sep has not been tested"); +} + +void test_conversion_from_short() +{ + test_conversion_from_integral(); +} + +void test_conversion_from_ushort() +{ + test_conversion_from_integral(); +} + +void test_conversion_from_int() +{ + test_conversion_from_integral(); +} + +void test_conversion_from_uint() +{ + test_conversion_from_integral(); +} + +void test_conversion_from_ulong() +{ + test_conversion_from_integral(); +} + +void test_conversion_from_long() +{ + test_conversion_from_integral(); +} + +#if defined(BOOST_HAS_LONG_LONG) + +void test_conversion_from_longlong() +{ + test_conversion_from_integral(); +} + +void test_conversion_from_ulonglong() +{ + test_conversion_from_integral(); +} + +#elif defined(LCAST_TEST_LONGLONG) + +void test_conversion_from_longlong() +{ + test_conversion_from_integral<__int64>(); +} + +void test_conversion_from_ulonglong() +{ + test_conversion_from_integral(); +} + +#endif + diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 56a03d8..af68510 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -21,6 +21,9 @@ test-suite conversion [ run ../cast_test.cpp ] [ run ../numeric_cast_test.cpp ] [ run ../lexical_cast_test.cpp ../../test/build//boost_unit_test_framework/static ] + [ run lexical_cast_loopback_test.cpp ../../test/build//boost_unit_test_framework/static ] + [ 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 ] ; diff --git a/test/lexical_cast_abstract_test.cpp b/test/lexical_cast_abstract_test.cpp new file mode 100644 index 0000000..207d3a5 --- /dev/null +++ b/test/lexical_cast_abstract_test.cpp @@ -0,0 +1,61 @@ +// Unit test for boost::lexical_cast. +// +// See http://www.boost.org for most recent version, including documentation. +// +// Copyright Sergey Shandar 2005, 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). +// +// Test abstract class. Bug 1358600: +// http://sf.net/tracker/?func=detail&aid=1358600&group_id=7586&atid=107586 + +#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_abstract(); + +unit_test::test_suite *init_unit_test_suite(int, char *[]) +{ + unit_test_framework::test_suite *suite = + BOOST_TEST_SUITE("lexical_cast unit test"); + suite->add(BOOST_TEST_CASE(&test_abstract)); + + return suite; +} + +class A +{ +public: + virtual void out(std::ostream &) const = 0; +}; + +class B: public A +{ +public: + virtual void out(std::ostream &O) const { O << "B"; } +}; + +std::ostream &operator<<(std::ostream &O, const A &a) +{ + a.out(O); + return O; +}; + +void test_abstract() +{ + const A &a = B(); + BOOST_CHECK(boost::lexical_cast(a) == "B"); +} + diff --git a/test/lexical_cast_loopback_test.cpp b/test/lexical_cast_loopback_test.cpp new file mode 100644 index 0000000..cd058fe --- /dev/null +++ b/test/lexical_cast_loopback_test.cpp @@ -0,0 +1,98 @@ +// Unit test for boost::lexical_cast. +// +// See http://www.boost.org for most recent version, including documentation. +// +// Copyright Alexander Nasonov, 2006. +// +// 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). +// +// Test round-tripping conversion FPT -> string -> FPT, +// where FPT is Floating Point Type. + +#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_round_conversion_float(); +void test_round_conversion_double(); +void test_round_conversion_long_double(); + +unit_test::test_suite *init_unit_test_suite(int, char *[]) +{ + unit_test_framework::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)); + suite->add(BOOST_TEST_CASE(&test_round_conversion_long_double)); + + return suite; +} + +template +void test_round_conversion() +{ + T epsilon = std::numeric_limits::epsilon(); + std::string const epsilon_s = boost::lexical_cast(epsilon); + BOOST_CHECK(epsilon == lexical_cast(epsilon_s)); + + T max_ = (std::numeric_limits::max)(); + std::string const max_s = boost::lexical_cast(max_); + BOOST_CHECK(max_ == lexical_cast(max_s)); + + T min_ = (std::numeric_limits::min)(); + std::string const min_s = boost::lexical_cast(min_); + BOOST_CHECK(min_ == lexical_cast(min_s)); + + T max_div137 = max_ / 137; + std::string max_div137_s = boost::lexical_cast(max_div137); + BOOST_CHECK(max_div137 == lexical_cast(max_div137_s)); + + T epsilon_mult137 = epsilon * 137; + std::string epsilon_mult137_s(lexical_cast(epsilon_mult137)); + BOOST_CHECK(epsilon_mult137 == lexical_cast(epsilon_mult137_s)); + +} + +#if defined(BOOST_MSVC) +// See bug http://tinyurl.com/vhpvo +template +void test_msvc_magic_values() +{ + T magic_msvc = 0.00010000433948393407; + 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() +{ + test_round_conversion(); +} + +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_noncopyable_test.cpp b/test/lexical_cast_noncopyable_test.cpp new file mode 100644 index 0000000..6284b14 --- /dev/null +++ b/test/lexical_cast_noncopyable_test.cpp @@ -0,0 +1,54 @@ +// 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). +// +// Test that Source can be non-copyable. + +#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 + +using namespace boost; + +void test_noncopyable(); + +unit_test::test_suite *init_unit_test_suite(int, char *[]) +{ + unit_test_framework::test_suite *suite = + BOOST_TEST_SUITE("lexical_cast unit test"); + suite->add(BOOST_TEST_CASE(&test_noncopyable)); + + return suite; +} + +class Noncopyable : private boost::noncopyable +{ +public: + Noncopyable() {} +}; + +inline std::ostream &operator<<(std::ostream &out, const Noncopyable&) +{ + return out << "Noncopyable"; +} + +void test_noncopyable() +{ + Noncopyable x; + BOOST_CHECK(boost::lexical_cast(x) == "Noncopyable"); +} + From e9a5ac6d7a95b34fc2113b9dfa6338333dd7f44b Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Sat, 15 Dec 2007 14:39:18 +0000 Subject: [PATCH 12/66] Merge conversion library at rev 41517 [SVN r42070] --- include/boost/lexical_cast.hpp | 267 +++++++++++++++++++++++---------- lexical_cast_test.cpp | 245 +++++++++++++++++++++++------- 2 files changed, 380 insertions(+), 132 deletions(-) diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index 754aecf..44c7a66 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -3,7 +3,7 @@ // Boost lexical_cast.hpp header -------------------------------------------// // -// See http://www.boost.org/libs/converston for documentation. +// See http://www.boost.org/libs/conversion for documentation. // See end of this header for rights and permissions. // // what: lexical_cast custom keyword cast @@ -86,6 +86,14 @@ namespace boost typedef char type; }; +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + template + struct stream_char< std::basic_string > + { + typedef CharT type; + }; +#endif + #ifndef DISABLE_WIDE_CHAR_SUPPORT #ifndef BOOST_NO_INTRINSIC_WCHAR_T template<> @@ -107,11 +115,13 @@ namespace boost typedef wchar_t type; }; +#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION template<> struct stream_char { typedef wchar_t type; }; +#endif #endif template @@ -127,6 +137,44 @@ namespace boost }; } + namespace detail // deduce_char_traits template + { +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + template + struct deduce_char_traits + { + typedef std::char_traits type; + }; + + template + struct deduce_char_traits< CharT + , std::basic_string + , Source + > + { + typedef Traits type; + }; + + template + struct deduce_char_traits< CharT + , Target + , std::basic_string + > + { + typedef Traits type; + }; + + template + struct deduce_char_traits< CharT + , std::basic_string + , std::basic_string + > + { + typedef Traits type; + }; +#endif + } + namespace detail // lcast_src_length { // Return max. length of string representation of Source; @@ -309,8 +357,6 @@ namespace boost #undef BOOST_AUX_LEXICAL_CAST_DEF1 #ifndef BOOST_LCAST_NO_COMPILE_TIME_PRECISION -// This #if is in sync with lcast_precision - // Helper for floating point types. // -1.23456789e-123456 // ^ sign @@ -450,9 +496,7 @@ namespace boost namespace detail // lcast_put_unsigned { - // I'd personally put lcast_put_unsigned in .cpp file if not - // boost practice for header-only libraries (Alexander Nasonov). - template + template CharT* lcast_put_unsigned(T n, CharT* finish) { #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS @@ -482,6 +526,9 @@ namespace boost #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS BOOST_STATIC_ASSERT(std::numeric_limits::digits10 < CHAR_MAX); #endif + typedef typename Traits::int_type int_type; + CharT const czero = lcast_char_constants::zero; + int_type const zero = Traits::to_int_type(czero); char left = last_grp_size; @@ -498,14 +545,13 @@ namespace boost left = last_grp_size; --finish; - *finish = thousands_sep; + Traits::assign(*finish, thousands_sep); } --left; --finish; - int const digit = static_cast(n % 10); - int const cdigit = digit + lcast_char_constants::zero; - *finish = static_cast(cdigit); + int_type const digit = static_cast(n % 10U); + Traits::assign(*finish, Traits::to_char_type(zero + digit)); n /= 10; } while(n); @@ -515,7 +561,7 @@ namespace boost namespace detail // stream wrapper for handling lexical conversions { - template + template class lexical_stream { private: @@ -523,6 +569,8 @@ namespace boost typename stream_char::type, typename stream_char::type>::type char_type; + typedef Traits traits_type; + public: lexical_stream(char_type* = 0, char_type* = 0) { @@ -552,9 +600,12 @@ namespace boost EOF; #else - std::char_traits::eof(); + traits_type::eof(); #endif } + +#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + bool operator>>(std::string &output) { #if defined(BOOST_NO_STRINGSTREAM) @@ -570,13 +621,29 @@ namespace boost 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; + std::basic_stringstream stream; #endif }; } @@ -586,6 +653,7 @@ 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 { @@ -599,19 +667,20 @@ namespace boost static void widen_and_assign(char*p, char ch) { - *p = ch; + Traits::assign(*p, ch); } #ifndef DISABLE_WIDE_CHAR_SUPPORT static void widen_and_assign(wchar_t* p, char ch) { std::locale loc; - *p = BOOST_USE_FACET(std::ctype, loc).widen(ch); + 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) { - *p = ch; + Traits::assign(*p, ch); } static void widen_and_assign(char*, wchar_t ch); // undefined @@ -641,8 +710,8 @@ namespace boost public: // output - template - bool operator<<(std::basic_string const& str) + template + bool operator<<(std::basic_string const& str) { start = const_cast(str.data()); finish = start + str.length(); @@ -705,7 +774,7 @@ namespace boost EOF; #else - std::char_traits::eof(); + Traits::eof(); #endif } @@ -721,7 +790,7 @@ namespace boost #endif #else - template + template bool operator>>(std::basic_string& str) { str.assign(start, finish); @@ -730,17 +799,21 @@ namespace boost #endif }; - template - inline bool lexical_stream_limited_src::operator<<( + template + inline bool lexical_stream_limited_src::operator<<( bool value) { - *start = value + lcast_char_constants::zero; + 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) + template + inline bool lexical_stream_limited_src::operator<<( + char ch) { widen_and_assign(start, ch); finish = start + 1; @@ -748,8 +821,8 @@ namespace boost } #if !defined(DISABLE_WIDE_CHAR_SUPPORT) && !defined(BOOST_NO_INTRINSIC_WCHAR_T) - template - inline bool lexical_stream_limited_src::operator<<( + template + inline bool lexical_stream_limited_src::operator<<( wchar_t ch) { widen_and_assign(start, ch); @@ -758,140 +831,163 @@ namespace boost } #endif - template - inline bool lexical_stream_limited_src::operator<<(short n) + template + inline bool lexical_stream_limited_src::operator<<( + short n) { - start = lcast_put_unsigned(lcast_to_unsigned(n), finish); + start = lcast_put_unsigned(lcast_to_unsigned(n), finish); if(n < 0) - *--start = lcast_char_constants::minus; + { + --start; + CharT const minus = lcast_char_constants::minus; + Traits::assign(*start, minus); + } return true; } - template - inline bool lexical_stream_limited_src::operator<<(int n) + template + inline bool lexical_stream_limited_src::operator<<( + int n) { - start = lcast_put_unsigned(lcast_to_unsigned(n), finish); + start = lcast_put_unsigned(lcast_to_unsigned(n), finish); if(n < 0) - *--start = lcast_char_constants::minus; + { + --start; + CharT const minus = lcast_char_constants::minus; + Traits::assign(*start, minus); + } return true; } - template - inline bool lexical_stream_limited_src::operator<<(long n) + template + inline bool lexical_stream_limited_src::operator<<( + long n) { - start = lcast_put_unsigned(lcast_to_unsigned(n), finish); + start = lcast_put_unsigned(lcast_to_unsigned(n), finish); if(n < 0) - *--start = lcast_char_constants::minus; + { + --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<<( + template + inline bool lexical_stream_limited_src::operator<<( boost::long_long_type n) { - start = lcast_put_unsigned(lcast_to_unsigned(n), finish); + start = lcast_put_unsigned(lcast_to_unsigned(n), finish); if(n < 0) - *--start = lcast_char_constants::minus; + { + --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<<( + template + inline bool lexical_stream_limited_src::operator<<( __int64 n) { - start = lcast_put_unsigned(lcast_to_unsigned(n), finish); + start = lcast_put_unsigned(lcast_to_unsigned(n), finish); if(n < 0) - *--start = lcast_char_constants::minus; + { + --start; + CharT const minus = lcast_char_constants::minus; + Traits::assign(*start, minus); + } return true; } #endif - template - inline bool lexical_stream_limited_src::operator<<( + template + inline bool lexical_stream_limited_src::operator<<( unsigned short n) { - start = lcast_put_unsigned(+n, finish); + start = lcast_put_unsigned(lcast_to_unsigned(n), finish); return true; } - template - inline bool lexical_stream_limited_src::operator<<( + template + inline bool lexical_stream_limited_src::operator<<( unsigned int n) { - start = lcast_put_unsigned(n, finish); + start = lcast_put_unsigned(n, finish); return true; } - template - inline bool lexical_stream_limited_src::operator<<( + template + inline bool lexical_stream_limited_src::operator<<( unsigned long n) { - start = lcast_put_unsigned(n, finish); + start = lcast_put_unsigned(n, finish); return true; } #if defined(BOOST_HAS_LONG_LONG) - template - inline bool lexical_stream_limited_src::operator<<( + template + inline bool lexical_stream_limited_src::operator<<( boost::ulong_long_type n) { - start = lcast_put_unsigned(n, finish); + start = lcast_put_unsigned(n, finish); return true; } #elif defined(BOOST_HAS_MS_INT64) - template - inline bool lexical_stream_limited_src::operator<<( + template + inline bool lexical_stream_limited_src::operator<<( unsigned __int64 n) { - start = lcast_put_unsigned(n, finish); + start = lcast_put_unsigned(n, finish); return true; } #endif - template - inline bool lexical_stream_limited_src::operator<<( + template + inline bool lexical_stream_limited_src::operator<<( float val) { return this->lcast_put(val); } - template - inline bool lexical_stream_limited_src::operator<<( + template + inline bool lexical_stream_limited_src::operator<<( double val) { return this->lcast_put(val); } - template - inline bool lexical_stream_limited_src::operator<<( + template + inline bool lexical_stream_limited_src::operator<<( long double val) { return this->lcast_put(val); } - template - inline bool lexical_stream_limited_src::operator<<( + template + inline bool lexical_stream_limited_src::operator<<( CharT const* str) { start = const_cast(str); - finish = start + std::char_traits::length(str); + finish = start + Traits::length(str); return true; } - template - inline bool lexical_stream_limited_src::operator>>( + template + inline bool lexical_stream_limited_src::operator>>( CharT& output) { bool const ok = (finish - start == 1); if(ok) - output = *start; + Traits::assign(output, *start); return ok; } #ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION - template - inline bool lexical_stream_limited_src::operator>>( + template + inline bool lexical_stream_limited_src::operator>>( std::string& str) { str.assign(start, finish); @@ -899,8 +995,8 @@ namespace boost } #ifndef DISABLE_WIDE_CHAR_SUPPORT - template - inline bool lexical_stream_limited_src::operator>>( + template + inline bool lexical_stream_limited_src::operator>>( std::wstring& str) { str.assign(start, finish); @@ -1021,6 +1117,9 @@ namespace boost 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 @@ -1030,8 +1129,8 @@ namespace boost BOOST_DEDUCED_TYPENAME boost::mpl::if_c< Unlimited - , detail::lexical_stream - , detail::lexical_stream_limited_src + , detail::lexical_stream + , detail::lexical_stream_limited_src >::type interpreter(buf, buf + src_len); // The original form, reproduced below, is more elegant @@ -1078,7 +1177,13 @@ namespace boost template Target lexical_cast(Source arg) { - detail::lexical_stream interpreter; + typedef typename detail::widest_char< + BOOST_DEDUCED_TYPENAME detail::stream_char::type + , BOOST_DEDUCED_TYPENAME detail::stream_char::type + >::type char_type; + + typedef std::char_traits traits; + detail::lexical_stream interpreter; Target result; if(!(interpreter << arg && interpreter >> result)) diff --git a/lexical_cast_test.cpp b/lexical_cast_test.cpp index 6ba26a3..04478e0 100644 --- a/lexical_cast_test.cpp +++ b/lexical_cast_test.cpp @@ -24,6 +24,9 @@ #include #include +#include +#include + #if defined(BOOST_NO_STRINGSTREAM) || \ defined(BOOST_NO_STD_WSTRING) || \ defined(BOOST_NO_STD_LOCALE) @@ -35,6 +38,16 @@ #define LCAST_TEST_LONGLONG #endif +template +struct my_traits : std::char_traits +{ +}; + +template +struct my_allocator : std::allocator +{ +}; + // Test all 65536 values if true: bool const lcast_test_small_integral_types_completely = false; @@ -57,15 +70,21 @@ void test_conversion_from_wstring(); void test_conversion_to_wstring(); void test_bad_lexical_cast(); void test_no_whitespace_stripping(); -void test_conversion_from_short(); -void test_conversion_from_ushort(); -void test_conversion_from_int(); -void test_conversion_from_uint(); -void test_conversion_from_long(); -void test_conversion_from_ulong(); +void test_conversion_from_to_short(); +void test_conversion_from_to_ushort(); +void test_conversion_from_to_int(); +void test_conversion_from_to_uint(); +void test_conversion_from_to_long(); +void test_conversion_from_to_ulong(); #ifdef LCAST_TEST_LONGLONG -void test_conversion_from_longlong(); -void test_conversion_from_ulonglong(); +void test_conversion_from_to_longlong(); +void test_conversion_from_to_ulonglong(); +#endif +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +void test_traits(); +void test_wtraits(); +void test_allocator(); +void test_wallocator(); #endif unit_test::test_suite *init_unit_test_suite(int, char *[]) @@ -87,15 +106,21 @@ unit_test::test_suite *init_unit_test_suite(int, char *[]) #endif suite->add(BOOST_TEST_CASE(test_bad_lexical_cast)); suite->add(BOOST_TEST_CASE(test_no_whitespace_stripping)); - suite->add(BOOST_TEST_CASE(&test_conversion_from_short)); - suite->add(BOOST_TEST_CASE(&test_conversion_from_ushort)); - suite->add(BOOST_TEST_CASE(&test_conversion_from_int)); - suite->add(BOOST_TEST_CASE(&test_conversion_from_uint)); - suite->add(BOOST_TEST_CASE(&test_conversion_from_ulong)); - suite->add(BOOST_TEST_CASE(&test_conversion_from_long)); + suite->add(BOOST_TEST_CASE(&test_conversion_from_to_short)); + suite->add(BOOST_TEST_CASE(&test_conversion_from_to_ushort)); + suite->add(BOOST_TEST_CASE(&test_conversion_from_to_int)); + suite->add(BOOST_TEST_CASE(&test_conversion_from_to_uint)); + suite->add(BOOST_TEST_CASE(&test_conversion_from_to_ulong)); + suite->add(BOOST_TEST_CASE(&test_conversion_from_to_long)); #ifdef LCAST_TEST_LONGLONG - suite->add(BOOST_TEST_CASE(&test_conversion_from_longlong)); - suite->add(BOOST_TEST_CASE(&test_conversion_from_ulonglong)); + suite->add(BOOST_TEST_CASE(&test_conversion_from_to_longlong)); + suite->add(BOOST_TEST_CASE(&test_conversion_from_to_ulonglong)); + #endif + #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + suite->add(BOOST_TEST_CASE(&test_traits)); + suite->add(BOOST_TEST_CASE(&test_wtraits)); + suite->add(BOOST_TEST_CASE(&test_allocator)); + suite->add(BOOST_TEST_CASE(&test_wallocator)); #endif return suite; @@ -129,10 +154,15 @@ void test_conversion_to_int() BOOST_CHECK_EQUAL(0, lexical_cast('0')); BOOST_CHECK_THROW(lexical_cast('A'), bad_lexical_cast); BOOST_CHECK_EQUAL(1, lexical_cast(1)); + BOOST_CHECK_EQUAL(1, lexical_cast(1.0)); + BOOST_CHECK_EQUAL( (std::numeric_limits::max)(), lexical_cast((std::numeric_limits::max)())); - BOOST_CHECK_EQUAL(1, lexical_cast(1.0)); + + BOOST_CHECK_EQUAL( + (std::numeric_limits::min)(), + lexical_cast((std::numeric_limits::min)())); BOOST_CHECK_THROW(lexical_cast(1.23), bad_lexical_cast); @@ -407,7 +437,7 @@ void test_conversion_from_integral_to_char(CharT zero) BOOST_CHECK_THROW(lexical_cast(static_cast(10)), bad_lexical_cast); - T t = std::numeric_limits::max(); + T t = (std::numeric_limits::max)(); BOOST_CHECK_THROW(lexical_cast(t), bad_lexical_cast); } @@ -427,10 +457,10 @@ void test_conversion_from_integral_to_integral() BOOST_CHECK(lexical_cast(t) == st); BOOST_CHECK(lexical_cast(t) == ut); - t = std::numeric_limits::max(); + t = (std::numeric_limits::max)(); BOOST_CHECK(lexical_cast(t) == t); - t = std::numeric_limits::min(); + t = (std::numeric_limits::min)(); BOOST_CHECK(lexical_cast(t) == t); } @@ -442,19 +472,20 @@ void test_conversion_from_integral_to_string(CharT) T t; - t = limits::min(); + t = (limits::min)(); BOOST_CHECK(lexical_cast(t) == to_str(t)); - t = limits::max(); + t = (limits::max)(); BOOST_CHECK(lexical_cast(t) == to_str(t)); if(limits::digits <= 16 && lcast_test_small_integral_types_completely) - for(t = 1 + limits::min(); t != limits::max(); ++t) + // min and max have already been tested. + for(t = 1 + (limits::min)(); t != (limits::max)(); ++t) BOOST_CHECK(lexical_cast(t) == to_str(t)); else { - T const min_val = limits::min(); - T const max_val = limits::max(); + T const min_val = (limits::min)(); + T const max_val = (limits::max)(); T const half_max_val = max_val / 2; T const cnt = lcast_integral_test_counter; // to supress warnings unsigned int const counter = cnt < half_max_val ? cnt : half_max_val; @@ -480,20 +511,75 @@ void test_conversion_from_integral_to_string(CharT) T ten_power = 100; for(int e = 2; e <= limits::digits10; ++e, ten_power *= 10) { - // I believe that (ten_power + 100) never overflows + // ten_power + 100 probably never overflows for(t = ten_power - 100; t != ten_power + 100; ++t) BOOST_CHECK(lexical_cast(t) == to_str(t)); } } } +template +void test_conversion_from_string_to_integral(CharT) +{ + typedef std::numeric_limits limits; + + T t; + + t = (limits::min)(); + BOOST_CHECK(lexical_cast(to_str(t)) == t); + + t = (limits::max)(); + BOOST_CHECK(lexical_cast(to_str(t)) == t); + + if(limits::digits <= 16 && lcast_test_small_integral_types_completely) + // min and max have already been tested. + for(t = 1 + (limits::min)(); t != (limits::max)(); ++t) + BOOST_CHECK(lexical_cast(to_str(t)) == t); + else + { + T const min_val = (limits::min)(); + T const max_val = (limits::max)(); + T const half_max_val = max_val / 2; + T const cnt = lcast_integral_test_counter; // to supress warnings + unsigned int const counter = cnt < half_max_val ? cnt : half_max_val; + + unsigned int i; + + // Test values around min: + t = min_val; + for(i = 0; i < counter; ++i, ++t) + BOOST_CHECK(lexical_cast(to_str(t)) == t); + + // Test values around max: + t = max_val; + for(i = 0; i < counter; ++i, --t) + BOOST_CHECK(lexical_cast(to_str(t)) == t); + + // Test values around zero: + if(limits::is_signed) + for(t = -counter; t < static_cast(counter); ++t) + BOOST_CHECK(lexical_cast(to_str(t)) == t); + + // Test values around 100, 1000, 10000, ... + T ten_power = 100; + for(int e = 2; e <= limits::digits10; ++e, ten_power *= 10) + { + // ten_power + 100 probably never overflows + for(t = ten_power - 100; t != ten_power + 100; ++t) + BOOST_CHECK(lexical_cast(to_str(t)) == t); + } + } +} + template -void test_conversion_from_integral_for_locale() +void test_conversion_from_to_integral_for_locale() { test_conversion_from_integral_to_integral(); test_conversion_from_integral_to_string('0'); + test_conversion_from_string_to_integral('0'); #if !defined(DISABLE_WIDE_CHAR_SUPPORT) && !defined(BOOST_NO_INTRINSIC_WCHAR_T) test_conversion_from_integral_to_string(L'0'); + test_conversion_from_string_to_integral(L'0'); #endif } @@ -504,7 +590,7 @@ struct restore_oldloc }; template -void test_conversion_from_integral() +void test_conversion_from_to_integral() { char const zero = '0'; signed char const szero = '0'; @@ -517,7 +603,7 @@ void test_conversion_from_integral() test_conversion_from_integral_to_char(wzero); #endif - // test_conversion_from_integral_for_locale + // test_conversion_from_to_integral_for_locale typedef std::numpunct numpunct; @@ -527,7 +613,7 @@ void test_conversion_from_integral() std::string grouping1 = BOOST_USE_FACET(numpunct, oldloc).grouping(); std::string grouping2(grouping1); - test_conversion_from_integral_for_locale(); + test_conversion_from_to_integral_for_locale(); try { @@ -544,64 +630,121 @@ void test_conversion_from_integral() } if(grouping1 != grouping2) - test_conversion_from_integral_for_locale(); + test_conversion_from_to_integral_for_locale(); if(grouping1.empty() && grouping2.empty()) BOOST_TEST_MESSAGE("Formatting with thousands_sep has not been tested"); } -void test_conversion_from_short() +void test_conversion_from_to_short() { - test_conversion_from_integral(); + test_conversion_from_to_integral(); } -void test_conversion_from_ushort() +void test_conversion_from_to_ushort() { - test_conversion_from_integral(); + test_conversion_from_to_integral(); } -void test_conversion_from_int() +void test_conversion_from_to_int() { - test_conversion_from_integral(); + test_conversion_from_to_integral(); } -void test_conversion_from_uint() +void test_conversion_from_to_uint() { - test_conversion_from_integral(); + test_conversion_from_to_integral(); } -void test_conversion_from_ulong() +void test_conversion_from_to_ulong() { - test_conversion_from_integral(); + test_conversion_from_to_integral(); } -void test_conversion_from_long() +void test_conversion_from_to_long() { - test_conversion_from_integral(); + test_conversion_from_to_integral(); } #if defined(BOOST_HAS_LONG_LONG) -void test_conversion_from_longlong() +void test_conversion_from_to_longlong() { - test_conversion_from_integral(); + test_conversion_from_to_integral(); } -void test_conversion_from_ulonglong() +void test_conversion_from_to_ulonglong() { - test_conversion_from_integral(); + test_conversion_from_to_integral(); } #elif defined(LCAST_TEST_LONGLONG) -void test_conversion_from_longlong() +void test_conversion_from_to_longlong() { - test_conversion_from_integral<__int64>(); + test_conversion_from_to_integral<__int64>(); } -void test_conversion_from_ulonglong() +void test_conversion_from_to_ulonglong() { - test_conversion_from_integral(); + test_conversion_from_to_integral(); +} + +#endif + +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +void test_traits() +{ + typedef std::basic_string > my_string; + + my_string const s("s"); + BOOST_CHECK(boost::lexical_cast(s) == s[0]); + BOOST_CHECK(boost::lexical_cast(s) == s); + BOOST_CHECK(boost::lexical_cast(-1) == "-1"); +} + +void test_wtraits() +{ + typedef std::basic_string > my_string; + + my_string const s(L"s"); + BOOST_CHECK(boost::lexical_cast(s) == s[0]); + BOOST_CHECK(boost::lexical_cast(s) == s); + //BOOST_CHECK(boost::lexical_cast(-1) == L"-1"); + // Commented out because gcc 3.3 doesn't support this: + // basic_ostream > o; o << -1; +} + +void test_allocator() +{ + typedef std::basic_string< char + , std::char_traits + , my_allocator + > my_string; + + my_string s("s"); + BOOST_CHECK(boost::lexical_cast(s) == s[0]); + BOOST_CHECK(boost::lexical_cast(s) == "s"); + BOOST_CHECK(boost::lexical_cast(s) == s); + BOOST_CHECK(boost::lexical_cast(1) == "1"); + BOOST_CHECK(boost::lexical_cast("s") == s); + BOOST_CHECK(boost::lexical_cast(std::string("s")) == s); +} + +void test_wallocator() +{ + typedef std::basic_string< wchar_t + , std::char_traits + , my_allocator + > my_string; + + my_string s(L"s"); + BOOST_CHECK(boost::lexical_cast(s) == s[0]); + BOOST_CHECK(boost::lexical_cast(s) == L"s"); + BOOST_CHECK(boost::lexical_cast(s) == s); + BOOST_CHECK(boost::lexical_cast(1) == L"1"); + BOOST_CHECK(boost::lexical_cast(L"s") == s); + BOOST_CHECK(boost::lexical_cast(std::wstring(L"s")) == s); } #endif From 49c0b2f333fb1da92127d994d9cb3bd1253ced11 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 10 Feb 2008 16:39:38 +0000 Subject: [PATCH 13/66] Merged revisions 43206,43208-43213 via svnmerge from https://svn.boost.org/svn/boost/trunk ........ r43206 | danieljames | 2008-02-10 09:55:03 +0000 (Sun, 10 Feb 2008) | 1 line Fix some broken links. ........ r43209 | danieljames | 2008-02-10 14:56:22 +0000 (Sun, 10 Feb 2008) | 1 line Link to people pages on the website, as they've been removed from the download. ........ r43210 | danieljames | 2008-02-10 15:02:17 +0000 (Sun, 10 Feb 2008) | 1 line Point links to the pages that used to be in 'more' to the site. ........ r43212 | danieljames | 2008-02-10 16:10:16 +0000 (Sun, 10 Feb 2008) | 1 line Fix links on the home page as well. ........ r43213 | danieljames | 2008-02-10 16:21:22 +0000 (Sun, 10 Feb 2008) | 1 line Generated documentation which is no longer generated. ........ [SVN r43214] --- cast.htm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cast.htm b/cast.htm index 587d08a..cb8add6 100644 --- a/cast.htm +++ b/cast.htm @@ -120,10 +120,10 @@ void f( Fruit * fruit ) {

      polymorphic_cast was suggested by Bjarne Stroustrup in "The C++ Programming Language".
      polymorphic_downcast was contributed by Dave Abrahams.
      + "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams.
      An old numeric_cast
      that was contributed by Kevlin Henney is now superseeded by the Boost Numeric Conversion Library

      + "http://www.boost.org/people/kevlin_henney.htm">Kevlin Henney is now superseeded by the Boost Numeric Conversion Library


      Revised From 2ce20c872e49d0cfc85be1db56d17b47e12fdd86 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 7 Aug 2008 22:12:31 +0000 Subject: [PATCH 14/66] Fix link to numeric conversion library Merged revisions 48003 via svnmerge from https://svn.boost.org/svn/boost/trunk ........ r48003 | danieljames | 2008-08-06 16:28:17 +0100 (Wed, 06 Aug 2008) | 1 line Fix link to numeric conversion library. ........ [SVN r48026] --- cast.htm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cast.htm b/cast.htm index cb8add6..a1580c3 100644 --- a/cast.htm +++ b/cast.htm @@ -123,7 +123,7 @@ void f( Fruit * fruit ) { "http://www.boost.org/people/dave_abrahams.htm">Dave Abrahams.
      An old numeric_cast
      that was contributed by Kevlin Henney is now superseeded by the Boost Numeric Conversion Library

      + "http://www.boost.org/people/kevlin_henney.htm">Kevlin Henney is now superseeded by the Boost Numeric Conversion Library


      Revised From 39329bc5b99a8c36d3c7bbb0c7ad7c207ffea4af Mon Sep 17 00:00:00 2001 From: Daniel James Date: Fri, 10 Oct 2008 09:29:21 +0000 Subject: [PATCH 15/66] Merge quickbook workaround and fix some links. Merged revisions 48987,49230-49231 via svnmerge from https://svn.boost.org/svn/boost/trunk ........ r48987 | danieljames | 2008-09-28 13:21:39 +0100 (Sun, 28 Sep 2008) | 1 line Clean up some link errors. ........ r49230 | danieljames | 2008-10-09 23:13:48 +0100 (Thu, 09 Oct 2008) | 1 line position_iterator is meant to be a forward iterator, so avoid using operator+ with it. ........ r49231 | danieljames | 2008-10-09 23:14:14 +0100 (Thu, 09 Oct 2008) | 4 lines Work around the problems with window newlines in position_iterator. (I'm about to fix them, but this will get quickbook working immediately). Fixes #2155 ........ [SVN r49242] --- lexical_cast.htm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lexical_cast.htm b/lexical_cast.htm index 2a08541..c9d37be 100644 --- a/lexical_cast.htm +++ b/lexical_cast.htm @@ -81,7 +81,7 @@ 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 + 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 @@ -202,9 +202,9 @@ public: 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: + is important, you can also call numeric_cast: -

      numeric_cast<int8_t>(lexical_cast<int>("127"));
      +
      numeric_cast<int8_t>(lexical_cast<int>("127"));

      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: From 0c54d6a0377ec91f724ae6f50eccc59cfdb40308 Mon Sep 17 00:00:00 2001 From: Alexander Nasonov Date: Mon, 13 Oct 2008 23:54:01 +0000 Subject: [PATCH 16/66] Merge lexical_cast from trunk r49262 [SVN r49325] --- include/boost/lexical_cast.hpp | 158 ++++++++++++++++----------------- 1 file changed, 77 insertions(+), 81 deletions(-) diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index 44c7a66..bc678fa 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -17,17 +17,23 @@ #include #include #include -#include #include #include +#include #include #include #include #include #include +#include #include #include #include +#include + +#ifndef BOOST_NO_STD_LOCALE +#include +#endif #ifdef BOOST_NO_STRINGSTREAM #include @@ -38,13 +44,19 @@ #if defined(BOOST_NO_STRINGSTREAM) || \ defined(BOOST_NO_STD_WSTRING) || \ defined(BOOST_NO_STD_LOCALE) -#define DISABLE_WIDE_CHAR_SUPPORT +#define BOOST_LCAST_NO_WCHAR_T #endif namespace boost { // exception used to indicate runtime lexical_cast failure class bad_lexical_cast : public std::bad_cast + +#if defined(__BORLANDC__) && BOOST_WORKAROUND( __BORLANDC__, < 0x560 ) + // under bcc32 5.5.1 bad_cast doesn't derive from exception + , public std::exception +#endif + { public: bad_lexical_cast() : @@ -94,7 +106,7 @@ namespace boost }; #endif -#ifndef DISABLE_WIDE_CHAR_SUPPORT +#ifndef BOOST_LCAST_NO_WCHAR_T #ifndef BOOST_NO_INTRINSIC_WCHAR_T template<> struct stream_char @@ -219,7 +231,7 @@ namespace boost // lcast_src_length // lcast_src_length -#ifndef DISABLE_WIDE_CHAR_SUPPORT +#ifndef BOOST_LCAST_NO_WCHAR_T template<> struct lcast_src_length { @@ -258,7 +270,7 @@ namespace boost static void check_coverage() {} }; -#ifndef DISABLE_WIDE_CHAR_SUPPORT +#ifndef BOOST_LCAST_NO_WCHAR_T template<> struct lcast_src_length { @@ -289,7 +301,7 @@ namespace boost static void check_coverage() {} }; -#ifndef DISABLE_WIDE_CHAR_SUPPORT +#ifndef BOOST_LCAST_NO_WCHAR_T template<> struct lcast_src_length< wchar_t, std::basic_string > { @@ -327,34 +339,35 @@ namespace boost #endif }; -#define BOOST_AUX_LEXICAL_CAST_DEF1(CharT, T) template<> \ - struct lcast_src_length : lcast_src_length_integral \ +#define BOOST_LCAST_DEF1(CharT, T) \ + template<> struct lcast_src_length \ + : lcast_src_length_integral \ { static void check_coverage() {} }; -#ifdef DISABLE_WIDE_CHAR_SUPPORT -#define BOOST_AUX_LEXICAL_CAST_DEF(T) BOOST_AUX_LEXICAL_CAST_DEF1(char, T) +#ifdef BOOST_LCAST_NO_WCHAR_T +#define BOOST_LCAST_DEF(T) BOOST_LCAST_DEF1(char, T) #else -#define BOOST_AUX_LEXICAL_CAST_DEF(T) \ - BOOST_AUX_LEXICAL_CAST_DEF1(char, T) \ - BOOST_AUX_LEXICAL_CAST_DEF1(wchar_t, T) +#define BOOST_LCAST_DEF(T) \ + BOOST_LCAST_DEF1(char, T) \ + BOOST_LCAST_DEF1(wchar_t, T) #endif - BOOST_AUX_LEXICAL_CAST_DEF(short) - BOOST_AUX_LEXICAL_CAST_DEF(unsigned short) - BOOST_AUX_LEXICAL_CAST_DEF(int) - BOOST_AUX_LEXICAL_CAST_DEF(unsigned int) - BOOST_AUX_LEXICAL_CAST_DEF(long) - BOOST_AUX_LEXICAL_CAST_DEF(unsigned long) + BOOST_LCAST_DEF(short) + BOOST_LCAST_DEF(unsigned short) + BOOST_LCAST_DEF(int) + BOOST_LCAST_DEF(unsigned int) + BOOST_LCAST_DEF(long) + BOOST_LCAST_DEF(unsigned long) #if defined(BOOST_HAS_LONG_LONG) - BOOST_AUX_LEXICAL_CAST_DEF(boost::ulong_long_type) - BOOST_AUX_LEXICAL_CAST_DEF(boost::long_long_type ) + BOOST_LCAST_DEF(boost::ulong_long_type) + BOOST_LCAST_DEF(boost::long_long_type ) #elif defined(BOOST_HAS_MS_INT64) - BOOST_AUX_LEXICAL_CAST_DEF(unsigned __int64) - BOOST_AUX_LEXICAL_CAST_DEF( __int64) + BOOST_LCAST_DEF(unsigned __int64) + BOOST_LCAST_DEF( __int64) #endif -#undef BOOST_AUX_LEXICAL_CAST_DEF -#undef BOOST_AUX_LEXICAL_CAST_DEF1 +#undef BOOST_LCAST_DEF +#undef BOOST_LCAST_DEF1 #ifndef BOOST_LCAST_NO_COMPILE_TIME_PRECISION // Helper for floating point types. @@ -400,7 +413,7 @@ namespace boost static void check_coverage() {} }; -#ifndef DISABLE_WIDE_CHAR_SUPPORT +#ifndef BOOST_LCAST_NO_WCHAR_T template<> struct lcast_src_length : lcast_src_length_floating @@ -422,7 +435,7 @@ namespace boost static void check_coverage() {} }; -#endif // #ifndef DISABLE_WIDE_CHAR_SUPPORT +#endif // #ifndef BOOST_LCAST_NO_WCHAR_T #endif // #ifndef BOOST_LCAST_NO_COMPILE_TIME_PRECISION } @@ -437,7 +450,7 @@ namespace boost BOOST_STATIC_CONSTANT(char, minus = '-'); }; -#ifndef DISABLE_WIDE_CHAR_SUPPORT +#ifndef BOOST_LCAST_NO_WCHAR_T template<> struct lcast_char_constants { @@ -460,37 +473,21 @@ namespace boost # 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 - - inline unsigned int lcast_to_unsigned(int value) + template + inline + BOOST_DEDUCED_TYPENAME make_unsigned::type lcast_to_unsigned(T value) { - unsigned int uval = value; - return value < 0 ? -uval : uval; + typedef BOOST_DEDUCED_TYPENAME make_unsigned::type result_type; + result_type uvalue = static_cast(value); + return value < 0 ? -uvalue : uvalue; } - - inline unsigned long lcast_to_unsigned(long value) - { - unsigned long uval = value; - return value < 0 ? -uval : uval; - } - -#if defined(BOOST_HAS_LONG_LONG) - inline boost::ulong_long_type lcast_to_unsigned(boost::long_long_type v) - { - boost::ulong_long_type uval = v; - return v < 0 ? -uval : uval; - } -#elif defined(BOOST_HAS_MS_INT64) - inline unsigned __int64 lcast_to_unsigned(__int64 value) - { - unsigned __int64 uval = value; - return value < 0 ? -uval : uval; - } -#endif - #if (defined _MSC_VER) -# pragma warning( pop ) // C4146: unary minus operator applied to unsigned type, - // result still unsigned +# pragma warning( pop ) +#elif defined( __BORLANDC__ ) +# pragma option pop #endif } @@ -502,22 +499,15 @@ namespace boost #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS BOOST_STATIC_ASSERT(!std::numeric_limits::is_signed); #endif - CharT thousands_sep = 0; -#ifdef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE - char const* grouping = ""; - std::size_t const grouping_size = 0; -#else +#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(); - - if(grouping_size) - thousands_sep = np.thousands_sep(); -#endif - + CharT thousands_sep = grouping_size ? np.thousands_sep() : 0; std::string::size_type group = 0; // current group number char last_grp_size = grouping[0] <= 0 ? CHAR_MAX : grouping[0]; // a) Since grouping is const, grouping[grouping.size()] returns 0. @@ -526,14 +516,17 @@ namespace boost #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS BOOST_STATIC_ASSERT(std::numeric_limits::digits10 < CHAR_MAX); #endif + + 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); - char left = last_grp_size; - do { +#ifndef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE if(left == 0) { ++group; @@ -549,6 +542,8 @@ namespace boost } --left; +#endif + --finish; int_type const digit = static_cast(n % 10U); Traits::assign(*finish, Traits::to_char_type(zero + digit)); @@ -614,7 +609,7 @@ namespace boost stream.str().swap(output); return true; } - #ifndef DISABLE_WIDE_CHAR_SUPPORT + #ifndef BOOST_LCAST_NO_WCHAR_T bool operator>>(std::wstring &output) { stream.str().swap(output); @@ -670,9 +665,10 @@ namespace boost Traits::assign(*p, ch); } -#ifndef DISABLE_WIDE_CHAR_SUPPORT +#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); @@ -703,9 +699,9 @@ namespace boost public: - lexical_stream_limited_src(CharT* start, CharT* finish) - : start(start) - , finish(finish) + lexical_stream_limited_src(CharT* sta, CharT* fin) + : start(sta) + , finish(fin) {} public: // output @@ -720,7 +716,7 @@ namespace boost bool operator<<(bool); bool operator<<(char); -#if !defined(DISABLE_WIDE_CHAR_SUPPORT) && !defined(BOOST_NO_INTRINSIC_WCHAR_T) +#if !defined(BOOST_LCAST_NO_WCHAR_T) && !defined(BOOST_NO_INTRINSIC_WCHAR_T) bool operator<<(wchar_t); #endif bool operator<<(CharT const*); @@ -785,7 +781,7 @@ namespace boost bool operator>>(std::string&); -#ifndef DISABLE_WIDE_CHAR_SUPPORT +#ifndef BOOST_LCAST_NO_WCHAR_T bool operator>>(std::wstring&); #endif @@ -820,7 +816,7 @@ namespace boost return true; } -#if !defined(DISABLE_WIDE_CHAR_SUPPORT) && !defined(BOOST_NO_INTRINSIC_WCHAR_T) +#if !defined(BOOST_LCAST_NO_WCHAR_T) && !defined(BOOST_NO_INTRINSIC_WCHAR_T) template inline bool lexical_stream_limited_src::operator<<( wchar_t ch) @@ -907,7 +903,7 @@ namespace boost inline bool lexical_stream_limited_src::operator<<( unsigned short n) { - start = lcast_put_unsigned(lcast_to_unsigned(n), finish); + start = lcast_put_unsigned(n, finish); return true; } @@ -994,7 +990,7 @@ namespace boost return true; } -#ifndef DISABLE_WIDE_CHAR_SUPPORT +#ifndef BOOST_LCAST_NO_WCHAR_T template inline bool lexical_stream_limited_src::operator>>( std::wstring& str) @@ -1049,7 +1045,7 @@ namespace boost BOOST_STATIC_CONSTANT(bool, value = false); }; -#if !defined(DISABLE_WIDE_CHAR_SUPPORT) && !defined(BOOST_NO_INTRINSIC_WCHAR_T) +#if !defined(BOOST_LCAST_NO_WCHAR_T) && !defined(BOOST_NO_INTRINSIC_WCHAR_T) template<> struct lcast_streambuf_for_target { @@ -1065,7 +1061,7 @@ namespace boost BOOST_STATIC_CONSTANT(bool, value = false); }; -#ifndef DISABLE_WIDE_CHAR_SUPPORT +#ifndef BOOST_LCAST_NO_WCHAR_T template struct lcast_streambuf_for_target< std::basic_string > @@ -1080,7 +1076,7 @@ namespace boost BOOST_STATIC_CONSTANT(bool, value = false); }; -#ifndef DISABLE_WIDE_CHAR_SUPPORT +#ifndef BOOST_LCAST_NO_WCHAR_T template<> struct lcast_streambuf_for_target { @@ -1201,5 +1197,5 @@ namespace boost // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#undef DISABLE_WIDE_CHAR_SUPPORT +#undef BOOST_LCAST_NO_WCHAR_T #endif From 98a67d93f3f1b253e22c743f82bd48df5107e1d1 Mon Sep 17 00:00:00 2001 From: Alexander Nasonov Date: Thu, 4 Dec 2008 23:18:50 +0000 Subject: [PATCH 17/66] Fixes #1220: lexical_cast requires RTTI [SVN r50124] --- include/boost/lexical_cast.hpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index bc678fa..0da0d3d 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -60,15 +60,21 @@ namespace boost { public: bad_lexical_cast() : - source(&typeid(void)), target(&typeid(void)) +#ifndef BOOST_NO_TYPEID + source(&typeid(void)), target(&typeid(void)) +#else + source(0), target(0) // this breaks getters +#endif { } + bad_lexical_cast( const std::type_info &source_type_arg, const std::type_info &target_type_arg) : source(&source_type_arg), target(&target_type_arg) { } + const std::type_info &source_type() const { return *source; @@ -77,6 +83,7 @@ namespace boost { return *target; } + virtual const char *what() const throw() { return "bad lexical cast: " @@ -1144,7 +1151,11 @@ namespace boost if (interpreter >> result) return result; } +#ifndef BOOST_NO_TYPEID throw_exception(bad_lexical_cast(typeid(Source), typeid(Target))); +#else + throw_exception(bad_lexical_cast()); +#endif return Target(); // normally never reached (throw_exception) } } @@ -1183,7 +1194,11 @@ namespace boost Target result; if(!(interpreter << arg && interpreter >> result)) +#ifndef BOOST_NO_TYPEID throw_exception(bad_lexical_cast(typeid(Source), typeid(Target))); +#else + throw_exception(bad_lexical_cast()); +#endif return result; } From fb681bb0eabdd75ee60eff434eb949cb6965890a Mon Sep 17 00:00:00 2001 From: "Troy D. Straszheim" Date: Sat, 24 Jan 2009 18:57:20 +0000 Subject: [PATCH 18/66] merge of cmake build files from trunk per beman [SVN r50756] --- CMakeLists.txt | 22 ++++++++++++++++++++++ test/CMakeLists.txt | 14 ++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 test/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..9006501 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,22 @@ +#---------------------------------------------------------------------------- +# This file was automatically generated from the original CMakeLists.txt file +# Add a variable to hold the headers for the library +set (lib_headers + +) + +# Add a library target to the build system +boost_library_project( + conversion + # SRCDIRS + TESTDIRS test + # HEADERS ${lib_headers} + # DOCDIRS + DESCRIPTION "Polymorphic and lexical casts" + # MODULARIZED + AUTHORS "David Abrahams " + "Kevlin Henney" + # MAINTAINERS +) + + diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..11227a8 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,14 @@ +boost_additional_test_dependencies(conversion BOOST_DEPENDS test detail numeric) + +boost_test_run(implicit_cast) +boost_test_compile_fail(implicit_cast_fail) +boost_test_run(cast_test ../cast_test.cpp) +boost_test_run(numeric_cast_test ../numeric_cast_test.cpp) +boost_test_run( + lexical_cast_test + ../lexical_cast_test.cpp + DEPENDS boost_unit_test_framework +) + + + From a3e690da32118bc0cb720b8b2e9576adeb71baad Mon Sep 17 00:00:00 2001 From: "Troy D. Straszheim" Date: Wed, 22 Jul 2009 21:51:01 +0000 Subject: [PATCH 19/66] Add basic copyright/license to keep cmake out of the inspection report [SVN r55095] --- CMakeLists.txt | 6 ++++++ test/CMakeLists.txt | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9006501..3badd19 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,3 +1,9 @@ +# +# Copyright Troy D. Straszheim +# +# Distributed under the Boost Software License, Version 1.0. +# See http://www.boost.org/LICENSE_1_0.txt +# #---------------------------------------------------------------------------- # This file was automatically generated from the original CMakeLists.txt file # Add a variable to hold the headers for the library diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 11227a8..7b10f31 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,3 +1,9 @@ +# +# Copyright Troy D. Straszheim +# +# Distributed under the Boost Software License, Version 1.0. +# See http://www.boost.org/LICENSE_1_0.txt +# boost_additional_test_dependencies(conversion BOOST_DEPENDS test detail numeric) boost_test_run(implicit_cast) From 9e764f3e4920e37153cfb8299081ef92d20e68a5 Mon Sep 17 00:00:00 2001 From: Alexander Nasonov Date: Sat, 12 Sep 2009 22:11:01 +0000 Subject: [PATCH 20/66] [lexical_cast] Merge from trunk: r56158 (fix warning on MSVC warning level 4) and r53668 (avoid C style casts). [SVN r56159] --- include/boost/lexical_cast.hpp | 47 +++++++++++++++++----------------- 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index 0da0d3d..094caec 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -47,6 +47,13 @@ #define BOOST_LCAST_NO_WCHAR_T #endif +#ifdef BOOST_NO_TYPEID +#define BOOST_LCAST_THROW_BAD_CAST(S, T) throw_exception(bad_lexical_cast()) +#else +#define BOOST_LCAST_THROW_BAD_CAST(Source, Target) \ + throw_exception(bad_lexical_cast(typeid(Source), typeid(Target))) +#endif + namespace boost { // exception used to indicate runtime lexical_cast failure @@ -577,7 +584,7 @@ namespace boost lexical_stream(char_type* = 0, char_type* = 0) { stream.unsetf(std::ios::skipws); - lcast_set_precision(stream, (Source*)0, (Target*)0); + lcast_set_precision(stream, static_cast(0), static_cast(0) ); } ~lexical_stream() { @@ -694,7 +701,7 @@ namespace boost { this->setp(start, finish); std::basic_ostream stream(static_cast(this)); - lcast_set_precision(stream, (OutputStreamable*)0); + lcast_set_precision(stream, static_cast(0)); bool const result = !(stream << input).fail(); finish = this->pptr(); return result; @@ -764,7 +771,7 @@ namespace boost this->setg(start, start, finish); std::basic_istream stream(static_cast(this)); stream.unsetf(std::ios::skipws); - lcast_set_precision(stream, (InputStreamable*)0); + lcast_set_precision(stream, static_cast(0)); #if (defined _MSC_VER) # pragma warning( pop ) #endif @@ -1111,6 +1118,12 @@ 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 +#endif + template< typename Target , typename Source , bool Unlimited // string representation of Source is unlimited @@ -1136,28 +1149,14 @@ namespace boost , detail::lexical_stream_limited_src >::type interpreter(buf, buf + src_len); - // The original form, reproduced below, is more elegant - // but yields a spurious C4701 warning ("possible use of - // "result" before initialization") with VC7.1 (/W4). -// -// Target result; -// -// if(!(interpreter << arg && interpreter >> result)) -// throw_exception(bad_lexical_cast(typeid(Source), typeid(Target))); -// return result; - - if(interpreter << arg) { - Target result; - if (interpreter >> result) - return result; - } -#ifndef BOOST_NO_TYPEID - throw_exception(bad_lexical_cast(typeid(Source), typeid(Target))); -#else - throw_exception(bad_lexical_cast()); -#endif - return Target(); // normally never reached (throw_exception) + 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 From 5055e842cffff200b2c5cf32185aecf898d5f633 Mon Sep 17 00:00:00 2001 From: Alexander Nasonov Date: Sat, 12 Sep 2009 22:24:35 +0000 Subject: [PATCH 21/66] Merge from trunk r56160 (Can't compile without header, boost::lexical_cast problem). [SVN r56161] --- 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 094caec..d7d9052 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -41,9 +41,7 @@ #include #endif -#if defined(BOOST_NO_STRINGSTREAM) || \ - defined(BOOST_NO_STD_WSTRING) || \ - defined(BOOST_NO_STD_LOCALE) +#if defined(BOOST_NO_STRINGSTREAM) || defined(BOOST_NO_STD_WSTRING) #define BOOST_LCAST_NO_WCHAR_T #endif From 23949682c14858fcafd8851cb56674b897b5e506 Mon Sep 17 00:00:00 2001 From: Alexander Nasonov Date: Sun, 13 Sep 2009 15:03:52 +0000 Subject: [PATCH 22/66] [lexical_cast] Merge from trunk r56170 (#2295 Inconsistent behavior when using 64 bit integer types) and r56171 (Add a test for uintmax_t). [SVN r56172] --- lexical_cast_test.cpp | 48 +++++++++++++++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/lexical_cast_test.cpp b/lexical_cast_test.cpp index 04478e0..44b9b5f 100644 --- a/lexical_cast_test.cpp +++ b/lexical_cast_test.cpp @@ -21,6 +21,7 @@ #include +#include #include #include @@ -76,6 +77,8 @@ void test_conversion_from_to_int(); void test_conversion_from_to_uint(); void test_conversion_from_to_long(); void test_conversion_from_to_ulong(); +void test_conversion_from_to_intmax_t(); +void test_conversion_from_to_uintmax_t(); #ifdef LCAST_TEST_LONGLONG void test_conversion_from_to_longlong(); void test_conversion_from_to_ulonglong(); @@ -110,8 +113,10 @@ unit_test::test_suite *init_unit_test_suite(int, char *[]) suite->add(BOOST_TEST_CASE(&test_conversion_from_to_ushort)); suite->add(BOOST_TEST_CASE(&test_conversion_from_to_int)); suite->add(BOOST_TEST_CASE(&test_conversion_from_to_uint)); - suite->add(BOOST_TEST_CASE(&test_conversion_from_to_ulong)); suite->add(BOOST_TEST_CASE(&test_conversion_from_to_long)); + suite->add(BOOST_TEST_CASE(&test_conversion_from_to_ulong)); + suite->add(BOOST_TEST_CASE(&test_conversion_from_to_intmax_t)); + suite->add(BOOST_TEST_CASE(&test_conversion_from_to_uintmax_t)); #ifdef LCAST_TEST_LONGLONG suite->add(BOOST_TEST_CASE(&test_conversion_from_to_longlong)); suite->add(BOOST_TEST_CASE(&test_conversion_from_to_ulonglong)); @@ -522,27 +527,38 @@ template void test_conversion_from_string_to_integral(CharT) { typedef std::numeric_limits limits; + typedef std::basic_string string_type; - T t; + string_type s; + string_type const zero = to_str(0); + string_type const nine = to_str(9); + T const min_val = (limits::min)(); + T const max_val = (limits::max)(); - t = (limits::min)(); - BOOST_CHECK(lexical_cast(to_str(t)) == t); + s = to_str(min_val); + BOOST_CHECK_EQUAL(lexical_cast(s), min_val); + if(limits::is_signed) + { + BOOST_CHECK_THROW(lexical_cast(s + zero), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(s + nine), bad_lexical_cast); + } - t = (limits::max)(); - BOOST_CHECK(lexical_cast(to_str(t)) == t); + s = to_str(max_val); + BOOST_CHECK_EQUAL(lexical_cast(s), max_val); + BOOST_CHECK_THROW(lexical_cast(s + zero), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(s + nine), bad_lexical_cast); if(limits::digits <= 16 && lcast_test_small_integral_types_completely) // min and max have already been tested. - for(t = 1 + (limits::min)(); t != (limits::max)(); ++t) + for(T t = 1 + min_val; t != max_val; ++t) BOOST_CHECK(lexical_cast(to_str(t)) == t); else { - T const min_val = (limits::min)(); - T const max_val = (limits::max)(); T const half_max_val = max_val / 2; T const cnt = lcast_integral_test_counter; // to supress warnings unsigned int const counter = cnt < half_max_val ? cnt : half_max_val; + T t; unsigned int i; // Test values around min: @@ -656,14 +672,24 @@ void test_conversion_from_to_uint() test_conversion_from_to_integral(); } +void test_conversion_from_to_long() +{ + test_conversion_from_to_integral(); +} + void test_conversion_from_to_ulong() { test_conversion_from_to_integral(); } -void test_conversion_from_to_long() +void test_conversion_from_to_intmax_t() { - test_conversion_from_to_integral(); + test_conversion_from_to_integral(); +} + +void test_conversion_from_to_uintmax_t() +{ + test_conversion_from_to_integral(); } #if defined(BOOST_HAS_LONG_LONG) From dc151d2b5a46e0d5a21a48b0caac27c0400e8c38 Mon Sep 17 00:00:00 2001 From: Alexander Nasonov Date: Tue, 15 Sep 2009 22:53:27 +0000 Subject: [PATCH 23/66] DISABLE_WIDE_CHAR_SUPPORT -> BOOST_LCAST_NO_WCHAR_T. [SVN r56227] --- lexical_cast_test.cpp | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/lexical_cast_test.cpp b/lexical_cast_test.cpp index 44b9b5f..81faa5c 100644 --- a/lexical_cast_test.cpp +++ b/lexical_cast_test.cpp @@ -28,12 +28,6 @@ #include #include -#if defined(BOOST_NO_STRINGSTREAM) || \ - defined(BOOST_NO_STD_WSTRING) || \ - defined(BOOST_NO_STD_LOCALE) -#define DISABLE_WIDE_CHAR_SUPPORT -#endif - #if (defined(BOOST_HAS_LONG_LONG) || defined(BOOST_HAS_MS_INT64)) \ && !(defined(BOOST_MSVC) && BOOST_MSVC < 1300) #define LCAST_TEST_LONGLONG @@ -101,7 +95,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)); - #ifndef DISABLE_WIDE_CHAR_SUPPORT + #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)); suite->add(BOOST_TEST_CASE(test_conversion_from_wstring)); @@ -268,14 +262,14 @@ void test_conversion_from_to_wchar_t_alias() void test_conversion_to_pointer() { BOOST_CHECK_THROW(lexical_cast("Test"), bad_lexical_cast); - #ifndef DISABLE_WIDE_CHAR_SUPPORT + #ifndef BOOST_LCAST_NO_WCHAR_T BOOST_CHECK_THROW(lexical_cast("Test"), bad_lexical_cast); #endif } void test_conversion_from_wchar_t() { -#ifndef DISABLE_WIDE_CHAR_SUPPORT +#ifndef BOOST_LCAST_NO_WCHAR_T #if !defined(BOOST_NO_INTRINSIC_WCHAR_T) BOOST_CHECK_EQUAL(1, lexical_cast(L'1')); BOOST_CHECK_THROW(lexical_cast(L'A'), bad_lexical_cast); @@ -308,7 +302,7 @@ void test_conversion_from_wchar_t() void test_conversion_to_wchar_t() { -#if !defined(DISABLE_WIDE_CHAR_SUPPORT) && !defined(BOOST_NO_INTRINSIC_WCHAR_T) +#if !defined(BOOST_LCAST_NO_WCHAR_T) && !defined(BOOST_NO_INTRINSIC_WCHAR_T) BOOST_CHECK_EQUAL(L'1', lexical_cast(1)); BOOST_CHECK_EQUAL(L'0', lexical_cast(0)); BOOST_CHECK_EQUAL(L'1', lexical_cast('1')); @@ -335,7 +329,7 @@ void test_conversion_to_wchar_t() void test_conversion_from_wstring() { - #ifndef DISABLE_WIDE_CHAR_SUPPORT + #ifndef BOOST_LCAST_NO_WCHAR_T BOOST_CHECK_EQUAL(123, lexical_cast(std::wstring(L"123"))); BOOST_CHECK_THROW( lexical_cast(std::wstring(L"")), bad_lexical_cast); @@ -353,7 +347,7 @@ void test_conversion_from_wstring() void test_conversion_to_wstring() { - #ifndef DISABLE_WIDE_CHAR_SUPPORT + #ifndef BOOST_LCAST_NO_WCHAR_T wchar_t buf[] = L"hello"; wchar_t* str = buf; BOOST_CHECK(str == lexical_cast(str)); @@ -593,7 +587,7 @@ void test_conversion_from_to_integral_for_locale() test_conversion_from_integral_to_integral(); test_conversion_from_integral_to_string('0'); test_conversion_from_string_to_integral('0'); -#if !defined(DISABLE_WIDE_CHAR_SUPPORT) && !defined(BOOST_NO_INTRINSIC_WCHAR_T) +#if !defined(BOOST_LCAST_NO_WCHAR_T) && !defined(BOOST_NO_INTRINSIC_WCHAR_T) test_conversion_from_integral_to_string(L'0'); test_conversion_from_string_to_integral(L'0'); #endif @@ -614,7 +608,7 @@ void test_conversion_from_to_integral() test_conversion_from_integral_to_char(zero); test_conversion_from_integral_to_char(szero); test_conversion_from_integral_to_char(uzero); -#if !defined(DISABLE_WIDE_CHAR_SUPPORT) && !defined(BOOST_NO_INTRINSIC_WCHAR_T) +#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); #endif From 65328d9716900a6ea18a8b1418745f222460b299 Mon Sep 17 00:00:00 2001 From: Alexander Nasonov Date: Tue, 15 Sep 2009 23:41:02 +0000 Subject: [PATCH 24/66] Add new test libs/conversion/test/lexical_cast_vc8_bug_test.cpp. [SVN r56230] --- lexical_cast_test.cpp | 20 ++++++++--- test/Jamfile.v2 | 1 + test/lexical_cast_vc8_bug_test.cpp | 53 ++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 4 deletions(-) create mode 100644 test/lexical_cast_vc8_bug_test.cpp diff --git a/lexical_cast_test.cpp b/lexical_cast_test.cpp index 81faa5c..b61db0d 100644 --- a/lexical_cast_test.cpp +++ b/lexical_cast_test.cpp @@ -533,14 +533,26 @@ void test_conversion_from_string_to_integral(CharT) BOOST_CHECK_EQUAL(lexical_cast(s), min_val); if(limits::is_signed) { - BOOST_CHECK_THROW(lexical_cast(s + zero), bad_lexical_cast); - BOOST_CHECK_THROW(lexical_cast(s + nine), bad_lexical_cast); +#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); BOOST_CHECK_EQUAL(lexical_cast(s), max_val); - BOOST_CHECK_THROW(lexical_cast(s + zero), bad_lexical_cast); - BOOST_CHECK_THROW(lexical_cast(s + nine), bad_lexical_cast); +#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); + } if(limits::digits <= 16 && lcast_test_small_integral_types_completely) // min and max have already been tested. diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index af68510..1fea2fb 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -24,6 +24,7 @@ test-suite conversion [ run lexical_cast_loopback_test.cpp ../../test/build//boost_unit_test_framework/static ] [ 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 ] ; diff --git a/test/lexical_cast_vc8_bug_test.cpp b/test/lexical_cast_vc8_bug_test.cpp new file mode 100644 index 0000000..843bea8 --- /dev/null +++ b/test/lexical_cast_vc8_bug_test.cpp @@ -0,0 +1,53 @@ +#include +#include +#include +#include + +#include + +using namespace boost; + +// See also test_conversion_from_string_to_integral(CharT) +// in libs/conversion/lexical_cast_test.cpp +template +void test_too_long_number(CharT zero) +{ + typedef std::numeric_limits limits; + + std::basic_string s; + + std::basic_ostringstream o; + o << (limits::max)() << zero; + s = o.str(); + BOOST_CHECK_THROW(lexical_cast(s), bad_lexical_cast); + s[s.size()-1] += 9; // '0' -> '9' + BOOST_CHECK_THROW(lexical_cast(s), bad_lexical_cast); + + if(limits::is_signed) + { + std::basic_ostringstream o; + o << (limits::min)() << zero; + s = o.str(); + BOOST_CHECK_THROW(lexical_cast(s), bad_lexical_cast); + s[s.size()-1] += 9; // '0' -> '9' + BOOST_CHECK_THROW(lexical_cast(s), bad_lexical_cast); + } +} + +void test_vc8_bug() +{ + test_too_long_number('0'); + test_too_long_number('0'); +#if !defined(BOOST_LCAST_NO_WCHAR_T) + test_too_long_number(L'0'); + test_too_long_number(L'0'); +#endif +} + +unit_test::test_suite *init_unit_test_suite(int, char *[]) +{ + unit_test_framework::test_suite *suite = + BOOST_TEST_SUITE("lexical_cast vc8 bug unit test"); + suite->add(BOOST_TEST_CASE(test_vc8_bug)); + return suite; +} From 04f73e5a89184ca13199c6e83a9ff5ca46591ac7 Mon Sep 17 00:00:00 2001 From: Alexander Nasonov Date: Tue, 15 Sep 2009 23:55:47 +0000 Subject: [PATCH 25/66] Decrease indent of #if and #endif lines and test string<->integral conversons when BOOST_NO_INTRINSIC_WCHAR_T is defined. [SVN r56231] --- lexical_cast_test.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/lexical_cast_test.cpp b/lexical_cast_test.cpp index b61db0d..12e9deb 100644 --- a/lexical_cast_test.cpp +++ b/lexical_cast_test.cpp @@ -95,12 +95,12 @@ 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)); - #ifndef BOOST_LCAST_NO_WCHAR_T +#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)); suite->add(BOOST_TEST_CASE(test_conversion_from_wstring)); suite->add(BOOST_TEST_CASE(test_conversion_to_wstring)); - #endif +#endif suite->add(BOOST_TEST_CASE(test_bad_lexical_cast)); suite->add(BOOST_TEST_CASE(test_no_whitespace_stripping)); suite->add(BOOST_TEST_CASE(&test_conversion_from_to_short)); @@ -111,16 +111,16 @@ unit_test::test_suite *init_unit_test_suite(int, char *[]) suite->add(BOOST_TEST_CASE(&test_conversion_from_to_ulong)); suite->add(BOOST_TEST_CASE(&test_conversion_from_to_intmax_t)); suite->add(BOOST_TEST_CASE(&test_conversion_from_to_uintmax_t)); - #ifdef LCAST_TEST_LONGLONG +#ifdef LCAST_TEST_LONGLONG suite->add(BOOST_TEST_CASE(&test_conversion_from_to_longlong)); suite->add(BOOST_TEST_CASE(&test_conversion_from_to_ulonglong)); - #endif - #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +#endif +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION suite->add(BOOST_TEST_CASE(&test_traits)); suite->add(BOOST_TEST_CASE(&test_wtraits)); suite->add(BOOST_TEST_CASE(&test_allocator)); suite->add(BOOST_TEST_CASE(&test_wallocator)); - #endif +#endif return suite; } @@ -262,9 +262,9 @@ void test_conversion_from_to_wchar_t_alias() void test_conversion_to_pointer() { BOOST_CHECK_THROW(lexical_cast("Test"), bad_lexical_cast); - #ifndef BOOST_LCAST_NO_WCHAR_T +#ifndef BOOST_LCAST_NO_WCHAR_T BOOST_CHECK_THROW(lexical_cast("Test"), bad_lexical_cast); - #endif +#endif } void test_conversion_from_wchar_t() @@ -324,12 +324,12 @@ void test_conversion_to_wchar_t() lexical_cast(std::wstring(L"")), bad_lexical_cast); BOOST_CHECK_THROW( lexical_cast(std::wstring(L"Test")), bad_lexical_cast); - #endif +#endif } void test_conversion_from_wstring() { - #ifndef BOOST_LCAST_NO_WCHAR_T +#ifndef BOOST_LCAST_NO_WCHAR_T BOOST_CHECK_EQUAL(123, lexical_cast(std::wstring(L"123"))); BOOST_CHECK_THROW( lexical_cast(std::wstring(L"")), bad_lexical_cast); @@ -342,12 +342,12 @@ void test_conversion_from_wstring() lexical_cast(std::wstring(L"")), bad_lexical_cast); BOOST_CHECK_THROW( lexical_cast(std::wstring(L"Test")), bad_lexical_cast); - #endif +#endif } void test_conversion_to_wstring() { - #ifndef BOOST_LCAST_NO_WCHAR_T +#ifndef BOOST_LCAST_NO_WCHAR_T wchar_t buf[] = L"hello"; wchar_t* str = buf; BOOST_CHECK(str == lexical_cast(str)); @@ -367,7 +367,7 @@ void test_conversion_to_wstring() BOOST_CHECK(L"Test" == lexical_cast(std::wstring(L"Test"))); BOOST_CHECK(L" " == lexical_cast(std::wstring(L" "))); BOOST_CHECK(L"" == lexical_cast(std::wstring(L""))); - #endif +#endif } void test_bad_lexical_cast() @@ -599,7 +599,7 @@ void test_conversion_from_to_integral_for_locale() test_conversion_from_integral_to_integral(); test_conversion_from_integral_to_string('0'); test_conversion_from_string_to_integral('0'); -#if !defined(BOOST_LCAST_NO_WCHAR_T) && !defined(BOOST_NO_INTRINSIC_WCHAR_T) +#if !defined(BOOST_LCAST_NO_WCHAR_T) test_conversion_from_integral_to_string(L'0'); test_conversion_from_string_to_integral(L'0'); #endif From 5b6e39b2b84a8b8da7a497ed1f062d25ed52cb3f Mon Sep 17 00:00:00 2001 From: "Troy D. Straszheim" Date: Sat, 17 Oct 2009 01:10:45 +0000 Subject: [PATCH 26/66] rm cmake from the release branch before it goes out broken. Policy dictates that you never commit to release, you commit to trunk and merge to release. [SVN r56941] --- CMakeLists.txt | 28 ---------------------------- test/CMakeLists.txt | 20 -------------------- 2 files changed, 48 deletions(-) delete mode 100644 CMakeLists.txt delete mode 100644 test/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index 3badd19..0000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,28 +0,0 @@ -# -# Copyright Troy D. Straszheim -# -# Distributed under the Boost Software License, Version 1.0. -# See http://www.boost.org/LICENSE_1_0.txt -# -#---------------------------------------------------------------------------- -# This file was automatically generated from the original CMakeLists.txt file -# Add a variable to hold the headers for the library -set (lib_headers - -) - -# Add a library target to the build system -boost_library_project( - conversion - # SRCDIRS - TESTDIRS test - # HEADERS ${lib_headers} - # DOCDIRS - DESCRIPTION "Polymorphic and lexical casts" - # MODULARIZED - AUTHORS "David Abrahams " - "Kevlin Henney" - # MAINTAINERS -) - - diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt deleted file mode 100644 index 7b10f31..0000000 --- a/test/CMakeLists.txt +++ /dev/null @@ -1,20 +0,0 @@ -# -# Copyright Troy D. Straszheim -# -# Distributed under the Boost Software License, Version 1.0. -# See http://www.boost.org/LICENSE_1_0.txt -# -boost_additional_test_dependencies(conversion BOOST_DEPENDS test detail numeric) - -boost_test_run(implicit_cast) -boost_test_compile_fail(implicit_cast_fail) -boost_test_run(cast_test ../cast_test.cpp) -boost_test_run(numeric_cast_test ../numeric_cast_test.cpp) -boost_test_run( - lexical_cast_test - ../lexical_cast_test.cpp - DEPENDS boost_unit_test_framework -) - - - From b5583b88fa88bf4d9402e35d6d2d167ff1b393f9 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 14 Feb 2010 16:31:21 +0000 Subject: [PATCH 27/66] Merge some detail changes. - [53670] Avoid C style casts. - [55604] Fix #3346 boost/detail/scoped_enum_emulation.hpp enum_t conflict with Unix rpc/types.h - Don't foward declare containers when using gcc's parallel library and add a macro to disable forward declaration. Fixes #3866. [SVN r59679] --- include/boost/detail/lcast_precision.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/detail/lcast_precision.hpp b/include/boost/detail/lcast_precision.hpp index d40ca21..93abce1 100644 --- a/include/boost/detail/lcast_precision.hpp +++ b/include/boost/detail/lcast_precision.hpp @@ -173,8 +173,8 @@ inline void lcast_set_precision(std::ios_base& stream, T*) template inline void lcast_set_precision(std::ios_base& stream, Source*, Target*) { - std::streamsize const s = lcast_get_precision((Source*)0); - std::streamsize const t = lcast_get_precision((Target*)0); + std::streamsize const s = lcast_get_precision(static_cast(0)); + std::streamsize const t = lcast_get_precision(static_cast(0)); stream.precision(s > t ? s : t); } From 701d5f0bf0cf0236d6e5ded5253b0526ff8ec01c Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Fri, 13 May 2011 17:44:51 +0000 Subject: [PATCH 28/66] Merged from trunk revision 71922. Most part of this modifications of lexical_cast library were made and successfully tested during the year 2009. Later commits affected only documentation bugs. [SVN r71923] --- include/boost/lexical_cast.hpp | 24 +++++----- lexical_cast.htm | 84 ++++++++++++++++++++++++++-------- lexical_cast_test.cpp | 7 +++ 3 files changed, 86 insertions(+), 29 deletions(-) diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index d7d9052..fdc5898 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -55,7 +55,13 @@ namespace boost { // exception used to indicate runtime lexical_cast failure - class bad_lexical_cast : public std::bad_cast + class bad_lexical_cast : + // workaround MSVC bug with std::bad_cast when _HAS_EXCEPTIONS == 0 +#if defined(BOOST_MSVC) && defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS + public std::exception +#else + public std::bad_cast +#endif #if defined(__BORLANDC__) && BOOST_WORKAROUND( __BORLANDC__, < 0x560 ) // under bcc32 5.5.1 bad_cast doesn't derive from exception @@ -521,11 +527,10 @@ namespace boost 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[0] <= 0 ? CHAR_MAX : grouping[0]; - // a) Since grouping is const, grouping[grouping.size()] returns 0. - // b) It's safe to assume here and below that CHAR_MAX - // is equivalent to unlimited grouping: + char last_grp_size = + grouping_size == 0 || grouping[0] <= 0 ? CHAR_MAX : grouping[0]; #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS + // Check that ulimited group is unreachable: BOOST_STATIC_ASSERT(std::numeric_limits::digits10 < CHAR_MAX); #endif @@ -1120,6 +1125,7 @@ namespace boost # 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 @@ -1149,7 +1155,7 @@ namespace boost Target result; if(!(interpreter << arg && interpreter >> result)) - BOOST_LCAST_THROW_BAD_CAST(Source, Target); + BOOST_LCAST_THROW_BAD_CAST(Source, Target); return result; } #if (defined _MSC_VER) @@ -1191,11 +1197,7 @@ namespace boost Target result; if(!(interpreter << arg && interpreter >> result)) -#ifndef BOOST_NO_TYPEID - throw_exception(bad_lexical_cast(typeid(Source), typeid(Target))); -#else - throw_exception(bad_lexical_cast()); -#endif + BOOST_LCAST_THROW_BAD_CAST(Source, Target); return result; } diff --git a/lexical_cast.htm b/lexical_cast.htm index c9d37be..5457a33 100644 --- a/lexical_cast.htm +++ b/lexical_cast.htm @@ -194,32 +194,74 @@ public: Exception used to indicate runtime lexical_cast 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. +
      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. +
      -

      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

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

    Changes

    @@ -265,6 +307,12 @@ public:


    -
    © Copyright Kevlin Henney, 2000–2005
    +
    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) +
    diff --git a/lexical_cast_test.cpp b/lexical_cast_test.cpp index 12e9deb..a994d13 100644 --- a/lexical_cast_test.cpp +++ b/lexical_cast_test.cpp @@ -11,6 +11,13 @@ // // Note: The unit test no longer compile on MSVC 6, but lexical_cast itself works for it. +// +// We need this #define before any #includes: otherwise msvc will emit warnings +// deep within std::string, resulting from our (perfectly legal) use of basic_string +// with a custom traits class: +// +#define _SCL_SECURE_NO_WARNINGS + #include #if defined(__INTEL_COMPILER) From a385c3ec99d99c2376b916c6f67f8e5070f0411d Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Thu, 26 May 2011 16:27:53 +0000 Subject: [PATCH 29/66] Merge from trunk: r72184 (a lot of optimizations, new tests, fix inspection warnings). [SVN r72185] --- include/boost/lexical_cast.hpp | 561 +++++++++++++++++++++++++++-- lexical_cast.htm | 8 +- lexical_cast_test.cpp | 163 ++++++++- test/lexical_cast_vc8_bug_test.cpp | 14 + 4 files changed, 702 insertions(+), 44 deletions(-) diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index fdc5898..6875b16 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -11,8 +11,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 and other Boosters -// when: November 2000, March 2003, June 2005, June 2006 +// Alexander Nasonov, Antony Polukhin and other Boosters +// when: November 2000, March 2003, June 2005, June 2006, March 2011 #include #include @@ -20,12 +20,18 @@ #include #include #include +#include #include #include #include #include #include +#include +#include +#include +#include #include +#include #include #include #include @@ -457,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; @@ -466,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 @@ -474,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 } @@ -571,6 +579,86 @@ 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 @@ -756,8 +844,178 @@ 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; + 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 +# 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; + CharT const plus = lcast_char_constants::plus; + typedef BOOST_DEDUCED_TYPENAME make_unsigned::type utype; + utype out_tmp =0; + 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 ) +// 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 + + /* + * case "-0" || "0" || "+0" : output = false; return true; + * case "1" || "+1": output = true; return true; + * default: return false; + */ + bool operator>>(bool& output) + { + 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; + } + } + + // Generic istream-based algorithm. // lcast_streambuf_for_target::value is true. template @@ -1053,23 +1311,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< @@ -1161,23 +1413,273 @@ namespace boost #if (defined _MSC_VER) # pragma warning( pop ) #endif + + template + struct is_stdstring + { + BOOST_STATIC_CONSTANT(bool, value = false ); + }; + + template + struct is_stdstring< std::basic_string > + { + BOOST_STATIC_CONSTANT(bool, value = true ); + }; + + template + struct is_char_or_wchar + { +#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 + ) + ); +#else + BOOST_STATIC_CONSTANT(bool, value = + ( + ::boost::type_traits::ice_or< + is_same< T, char >::value, + is_same< T, unsigned char >::value, + is_same< T, signed char >::value + >::value + ) + ); +#endif + }; + + template + struct is_arithmetic_and_not_xchars + { + BOOST_STATIC_CONSTANT(bool, value = + ( + ::boost::type_traits::ice_and< + is_arithmetic::value, + is_arithmetic::value, + ::boost::type_traits::ice_not< + detail::is_char_or_wchar::value + >::value, + ::boost::type_traits::ice_not< + detail::is_char_or_wchar::value + >::value + >::value + ) + ); + }; + + template + struct is_xchar_to_xchar + { + BOOST_STATIC_CONSTANT(bool, value = + ( + ::boost::type_traits::ice_and< + is_same::value, + is_char_or_wchar::value + >::value + ) + ); + }; + + template + struct is_char_array_to_stdstring + { + BOOST_STATIC_CONSTANT(bool, value = false ); + }; + + template + struct is_char_array_to_stdstring< std::basic_string, CharT* > + { + BOOST_STATIC_CONSTANT(bool, value = true ); + }; + + template + struct is_char_array_to_stdstring< std::basic_string, const CharT* > + { + BOOST_STATIC_CONSTANT(bool, value = true ); + }; + + template + struct lexical_cast_do_cast + { + static inline Target lexical_cast_impl(const Source &arg) + { + typedef typename detail::array_to_pointer_decay::type src; + + typedef typename detail::widest_char< + typename detail::stream_char::type + , 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); + } + }; + + template + struct lexical_cast_copy + { + static inline Source lexical_cast_impl(const Source &arg) + { + return arg; + } + }; + + class precision_loss_error : public boost::numeric::bad_numeric_cast + { + public: + virtual const char * what() const throw() + { return "bad numeric conversion: precision loss error"; } + }; + + template + struct throw_on_precision_loss + { + typedef boost::numeric::Trunc Rounder; + typedef S source_type ; + + typedef typename mpl::if_< is_arithmetic,S,S const&>::type argument_type ; + + static source_type nearbyint ( argument_type s ) + { + source_type orig_div_round = s / Rounder::nearbyint(s); + + if ( (orig_div_round > 1 ? orig_div_round - 1 : 1 - orig_div_round) > std::numeric_limits::epsilon() ) + BOOST_THROW_EXCEPTION( precision_loss_error() ); + return s ; + } + + typedef typename Rounder::round_style round_style; + } ; + + template + struct lexical_cast_dynamic_num_not_ignoring_minus + { + static inline Target lexical_cast_impl(const Source &arg) + { + try{ + typedef boost::numeric::converter< + Target, + Source, + boost::numeric::conversion_traits, + boost::numeric::def_overflow_handler, + throw_on_precision_loss + > Converter ; + + return Converter::convert(arg); + } catch( ::boost::numeric::bad_numeric_cast const& ) { + BOOST_LCAST_THROW_BAD_CAST(Source, Target); + } + } + }; + + template + struct lexical_cast_dynamic_num_ignoring_minus + { + static inline Target lexical_cast_impl(const Source &arg) + { + try{ + typedef boost::numeric::converter< + Target, + Source, + boost::numeric::conversion_traits, + boost::numeric::def_overflow_handler, + throw_on_precision_loss + > Converter ; + + bool has_minus = ( arg < 0); + if ( has_minus ) { + return static_cast(-Converter::convert(-arg)); + } else { + return Converter::convert(arg); + } + } catch( ::boost::numeric::bad_numeric_cast const& ) { + BOOST_LCAST_THROW_BAD_CAST(Source, Target); + } + } + }; + + /* + * lexical_cast_dynamic_num follows the rules: + * 1) If Source can be converted to Target without precision loss and + * without overflows, then assign Source to Target and return + * + * 2) If Source is less than 0 and Target is an unsigned integer, + * then negate Source, check the requirements of rule 1) and if + * successful, assign static_casted Source to Target and return + * + * 3) Otherwise throw a bad_lexical_cast exception + * + * + * Rule 2) required because boost::lexical_cast has the behavior of + * stringstream, which 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. + */ + template + struct lexical_cast_dynamic_num + { + static inline Target lexical_cast_impl(const Source &arg) + { + typedef BOOST_DEDUCED_TYPENAME ::boost::mpl::if_c< + ::boost::type_traits::ice_and< + ::boost::type_traits::ice_or< + ::boost::is_signed::value, + ::boost::is_float::value + >::value, + ::boost::type_traits::ice_not< + is_same::value + >::value, + ::boost::type_traits::ice_not< + is_same::value + >::value, + ::boost::is_unsigned::value + >::value, + lexical_cast_dynamic_num_ignoring_minus, + lexical_cast_dynamic_num_not_ignoring_minus + >::type caster_type; + + return caster_type::lexical_cast_impl(arg); + } + }; } template inline Target lexical_cast(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 - >::type char_type; + typedef BOOST_DEDUCED_TYPENAME ::boost::type_traits::ice_or< + detail::is_xchar_to_xchar::value, + detail::is_char_array_to_stdstring::value, + ::boost::type_traits::ice_and< + is_same::value, + detail::is_stdstring::value + >::value + > do_copy_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 + detail::is_arithmetic_and_not_xchars do_copy_with_dynamic_check_type; + + typedef BOOST_DEDUCED_TYPENAME ::boost::mpl::if_c< + do_copy_type::value, + detail::lexical_cast_copy, + BOOST_DEDUCED_TYPENAME ::boost::mpl::if_c< + do_copy_with_dynamic_check_type::value, + detail::lexical_cast_dynamic_num, + detail::lexical_cast_do_cast + >::type + >::type caster_type; + + return caster_type::lexical_cast_impl(arg); } #else @@ -1205,7 +1707,8 @@ namespace boost } // Copyright Kevlin Henney, 2000-2005. -// Copyright Alexander Nasonov, 2006-2007. +// 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 diff --git a/lexical_cast.htm b/lexical_cast.htm index 5457a33..3372618 100644 --- a/lexical_cast.htm +++ b/lexical_cast.htm @@ -265,6 +265,12 @@ Eliminate an overhead of std::locale if your program runs in the "C August 2006.
  • Changes

    +

    May 2011:

    +
      +
    • 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 @@ -312,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 a994d13..f366eb2 100644 --- a/lexical_cast_test.cpp +++ b/lexical_cast_test.cpp @@ -2,8 +2,9 @@ // // 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. +// 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 @@ -84,6 +86,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 +127,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)); @@ -229,10 +237,24 @@ 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( 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() @@ -447,6 +469,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() { @@ -540,25 +580,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) @@ -603,6 +664,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'); @@ -625,13 +698,38 @@ 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); + + 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; @@ -665,6 +763,30 @@ 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 ); +} + void test_conversion_from_to_short() { test_conversion_from_to_integral(); @@ -705,6 +827,19 @@ 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() @@ -717,7 +852,7 @@ void test_conversion_from_to_ulonglong() test_conversion_from_to_integral(); } -#elif defined(LCAST_TEST_LONGLONG) +#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 1f7147d24b4081731cbd7d4dc1d0f1e4d88f722f Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Sun, 29 May 2011 19:21:28 +0000 Subject: [PATCH 30/66] mereged lexical_cast from trunk r72267 (more optimizations, updated documentation, added tests) [SVN r72268] --- include/boost/lexical_cast.hpp | 211 +++++++++++++++++++++++++-------- lexical_cast.htm | 31 ++++- lexical_cast_test.cpp | 53 +++++++++ 3 files changed, 243 insertions(+), 52 deletions(-) diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index 6875b16..c1b083b 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<> @@ -526,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; @@ -533,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; } @@ -609,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) @@ -821,9 +861,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 +1094,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 +1137,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 +1330,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 +1414,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 +1570,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..7929dd4 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,8 @@ 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.
    • 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).
    • @@ -312,7 +316,30 @@ Eliminate an overhead of std::locale if your program runs in the "C


    - + +

    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->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 f366eb2..f88017f 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,42 @@ void test_wallocator() #endif +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 6c5f31e7a50fd71710b9927863dc9bbef563669e Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Thu, 2 Jun 2011 16:20:36 +0000 Subject: [PATCH 31/66] lexical-cast mereged from trunk r72347 (allow "C" locale grouping for other locales) [SVN r72348] --- include/boost/lexical_cast.hpp | 28 ++++++++++++++++++++++++---- lexical_cast_test.cpp | 3 +++ test/lexical_cast_abstract_test.cpp | 2 +- 3 files changed, 28 insertions(+), 5 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(); diff --git a/test/lexical_cast_abstract_test.cpp b/test/lexical_cast_abstract_test.cpp index 207d3a5..4b92e49 100644 --- a/test/lexical_cast_abstract_test.cpp +++ b/test/lexical_cast_abstract_test.cpp @@ -51,7 +51,7 @@ std::ostream &operator<<(std::ostream &O, const A &a) { a.out(O); return O; -}; +} void test_abstract() { From 00f1246fafebda2572e205215651af8c7b6613dd Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Wed, 17 Aug 2011 18:43:10 +0000 Subject: [PATCH 32/66] Merge from trunk r73850 * Compile time optimizations * Float types optimizations * Source code refactoring * Parsing and writing inf and nan values according to the standart * Fixed some bugs and warnings * New tests * New documentation [SVN r73851] --- include/boost/lexical_cast.hpp | 1671 +++++++++++++----------- index.html | 2 +- lexical_cast.htm | 357 +---- lexical_cast_test.cpp | 143 +- test/Jamfile.v2 | 3 + test/lexical_cast_float_types_test.cpp | 513 ++++++++ test/lexical_cast_inf_nan_test.cpp | 180 +++ test/lexical_cast_loopback_test.cpp | 6 - test/lexical_cast_wchars_test.cpp | 56 + 9 files changed, 1735 insertions(+), 1196 deletions(-) create mode 100755 test/lexical_cast_float_types_test.cpp create mode 100755 test/lexical_cast_inf_nan_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..6479e5d 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. @@ -18,6 +24,8 @@ #include #include #include +#include +#include #include #include #include @@ -28,17 +36,26 @@ #include #include #include +#include #include #include #include #include -#include +#include +#include #include #include #include +#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 @@ -214,156 +231,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 ',': @@ -383,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 @@ -502,6 +380,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,17 +392,13 @@ 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 } - namespace detail // lexical_streambuf_fake - { - struct lexical_streambuf_fake - { - }; - } - namespace detail // lcast_to_unsigned { #if (defined _MSC_VER) @@ -560,7 +437,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); @@ -639,14 +515,13 @@ 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); 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,158 +594,613 @@ namespace boost } } - namespace detail // stream wrapper for handling lexical conversions + namespace detail { - template - class lexical_stream + /* 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) { - private: - typedef typename widest_char< - typename stream_char::type, - typename stream_char::type>::type char_type; + using namespace std; + const wchar_t minus = lcast_char_constants::minus; + const wchar_t plus = lcast_char_constants::plus; + const int inifinity_size = 8; - typedef Traits traits_type; + bool has_minus = false; + /* Parsing +/- */ + if( *begin == minus) + { + ++ begin; + has_minus = true; + } + else if( *begin == plus ) ++begin; - public: - lexical_stream(char_type* = 0, char_type* = 0) + if( end-begin < 3 ) return false; + if( !memcmp(begin, lc_nan, 3*sizeof(CharT)) || !memcmp(begin, lc_NAN, 3*sizeof(CharT)) ) { - stream.unsetf(std::ios::skipws); - lcast_set_precision(stream, static_cast(0), static_cast(0) ); + 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 = (boost::math::changesign) (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 = (boost::math::changesign) (std::numeric_limits::infinity()); + return true; } - ~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(); + + 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 - } -#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION - - bool operator>>(std::string &output) + 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" + , '(', ')'); + } +#ifndef BOOST_LCAST_NO_WCHAR_T + template + bool put_inf_nan(wchar_t* begin, wchar_t*& end, const T& value) + { + using namespace std; + if ( (boost::math::isnan)(value) ) { - #if defined(BOOST_NO_STRINGSTREAM) - stream << '\0'; - #endif - stream.str().swap(output); + 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; - } - #ifndef BOOST_LCAST_NO_WCHAR_T - bool operator>>(std::wstring &output) + } else if ( (boost::math::isinf)(value) ) { - stream.str().swap(output); - return true; - } - #endif - -#else - bool operator>>(std::basic_string& output) - { - stream.str().swap(output); + 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; } - template - bool operator>>(std::basic_string& out) - { - std::basic_string str(stream.str()); - out.assign(str.begin(), str.end()); - return true; - } + return false; + } #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 + template + bool put_inf_nan(CharT* begin, CharT*& end, const T& value) + { + using namespace std; + if ( (boost::math::isnan)(value) ) + { + 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 ( (boost::math::isinf)(value) ) + { + if ( (boost::math::signbit)(value) ) + { + memcpy(begin,"-inf", sizeof("-inf")); + end = begin + 4; + } else + { + memcpy(begin,"inf", sizeof("inf")); + end = begin + 3; + } + return true; + } + + return false; + } + + } + + + 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 + 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; + + 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); + 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; + } + + bool found_decimal = false; + bool found_number_before_exp = 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; + + found_number_before_exp = true; + } 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; + } + + 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 + /* 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 { + if (!found_number_before_exp) return false; + 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 = static_cast( has_minus ? (boost::math::changesign)(result) : result); + + if ( (boost::math::isinf)(value) || (boost::math::isnan)(value) ) return false; + + return true; + } + } + + namespace detail // stl_buf_unlocker + { + template< class BufferType, class CharT > + class stl_buf_unlocker: public BufferType{ + public: + 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 + 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 + }; + } + + namespace detail + { + struct do_not_construct_stringbuffer_t{}; } namespace detail // optimized stream wrapper { // 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 + , bool RequiresStringbuffer > - 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 + typedef BOOST_DEDUCED_TYPENAME ::boost::mpl::if_c< + RequiresStringbuffer, + local_stringbuffer_t, + do_not_construct_stringbuffer_t + >::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; - - 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) - { - 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&); + deduced_stringbuffer_t stringbuffer; public: - lexical_stream_limited_src(CharT* sta, CharT* fin) : start(sta) , finish(fin) {} - public: // output + private: + // 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 wchar_t to char types." + "Use boost::locale instead" ); + return shl_input_streamable(str); + } +#endif + + template + bool shl_input_streamable(InputStreamable& input) + { + std::basic_ostream stream(&stringbuffer); + bool const result = !(stream << input).fail(); + start = stringbuffer.pbase(); + finish = stringbuffer.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; + } + +#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; + } + + 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; + } +#ifndef __MINGW32__ + 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; + } +#endif + +#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, +#if !defined(__MINGW32__) && !defined(UNDER_CE) + 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; + /* __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 and under WinCE does not conform + * to the ISO C + * Standard. + */ + finish = start + swprintf(out, +#if !defined(__MINGW32__) && !defined(UNDER_CE) + finish-start, +#endif + L"%.*lg", static_cast(boost::detail::lcast_get_precision()), val ); + 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, +#if !defined(UNDER_CE) + finish-start, +#endif + L"%.*Lg", static_cast(boost::detail::lcast_get_precision()), val ); + return finish > start; + } +#endif + +#endif + +/************************************ OPERATORS << ( ... ) ********************************/ + public: template bool operator<<(std::basic_string const& str) { @@ -879,39 +1209,61 @@ 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); } + 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 - 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<<(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); } + 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); + bool operator<<(float val) { return shl_float(val,start); } + bool operator<<(double val) { return shl_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); } + +/************************************ 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; @@ -945,7 +1297,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; @@ -988,63 +1340,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; @@ -1079,401 +1449,78 @@ namespace boost } } + 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 = shr_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 && + ( + *(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; + } + + // Optimised converter + bool float_types_converter_internal(double& output,char /*tag*/) { + 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< +#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 tag = 0; + + return float_types_converter_internal(output, tag); + } + + bool operator>>(long double& output) + { + int tag = 0; + return float_types_converter_internal(output, tag); + } // Generic istream-based algorithm. // lcast_streambuf_for_target::value is true. template - bool operator>>(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 - } - - 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 - { - BOOST_STATIC_CONSTANT(bool, value = - ( - ::boost::type_traits::ice_not< is_integral::value >::value - ) - ); - }; - #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 @@ -1491,47 +1538,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 { @@ -1634,25 +1640,62 @@ 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; + + 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; + // Disabling ADL, by directly specifying operators. + if(!(interpreter.operator <<(arg) && interpreter.operator >>(result))) + BOOST_LCAST_THROW_BAD_CAST(Source, Target); + return result; } }; +#if (defined _MSC_VER) +# pragma warning( pop ) +#endif template struct lexical_cast_copy @@ -1708,6 +1751,7 @@ namespace boost } catch( ::boost::numeric::bad_numeric_cast const& ) { BOOST_LCAST_THROW_BAD_CAST(Source, Target); } + BOOST_UNREACHABLE_RETURN(static_cast(0)); } }; @@ -1734,6 +1778,7 @@ namespace boost } catch( ::boost::numeric::bad_numeric_cast const& ) { BOOST_LCAST_THROW_BAD_CAST(Source, Target); } + BOOST_UNREACHABLE_RETURN(static_cast(0)); } }; @@ -1815,6 +1860,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/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 7929dd4..73b6ba5 100644 --- a/lexical_cast.htm +++ b/lexical_cast.htm @@ -1,351 +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

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

    -

    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->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
    -
    - 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 + diff --git a/lexical_cast_test.cpp b/lexical_cast_test.cpp index f20994e..f07926b 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)) \ @@ -42,6 +43,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 { @@ -65,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(); @@ -86,9 +92,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(); @@ -96,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 *[]) { @@ -108,6 +112,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)); @@ -128,9 +133,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)); @@ -139,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; } @@ -201,19 +204,45 @@ 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(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( @@ -679,7 +708,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 +804,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 +844,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 +953,40 @@ 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(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 } + + + +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); +} + diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 1fea2fb..2dd3500 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -25,6 +25,9 @@ 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 ] + [ 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 new file mode 100755 index 0000000..72279bb --- /dev/null +++ b/test/lexical_cast_float_types_test.cpp @@ -0,0 +1,513 @@ +// 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_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_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_FRACTION( lexical_cast("30000"), static_cast(30000), (std::numeric_limits::epsilon()) ); + } +} + + + + +/* + * 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_FRACTION( (VAL ## L? VAL ## L : std::numeric_limits::epsilon()), \ + (converted_val ? converted_val : std::numeric_limits::epsilon()), \ + 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_FRACTION( (VAL ## L? VAL ## L : std::numeric_limits::epsilon()), \ + (converted_val ? converted_val : std::numeric_limits::epsilon()), \ + std::numeric_limits::epsilon() \ + ); +#endif + +template +void test_converion_to_float_types() +{ + typedef TestType test_t; + test_t converted_val; + + 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_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_FRACTION(1.0, lexical_cast(sc_one), (std::numeric_limits::epsilon())); + BOOST_CHECK_EQUAL(0.0, lexical_cast(sc_zero)); + + BOOST_CHECK_CLOSE_FRACTION(1e34L, lexical_cast( "10000000000000000000000000000000000"), (std::numeric_limits::epsilon()) ); + +// VC failes the next test +// 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()) ); + + 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(.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); + 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); + + CHECK_CLOSE_ABS_DIFF(-.34, test_t); + CHECK_CLOSE_ABS_DIFF(.34, test_t); + CHECK_CLOSE_ABS_DIFF(.34e10, test_t); + + 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_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_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); + + // 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_FRACTION( \ + test_value, \ + converted_val, \ + std::numeric_limits::epsilon() \ + ); + +/* + * 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 ); + + 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_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); +} + +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_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); + 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_inf_nan_test.cpp b/test/lexical_cast_inf_nan_test.cpp new file mode 100755 index 0000000..4617d5e --- /dev/null +++ b/test/lexical_cast_inf_nan_test.cpp @@ -0,0 +1,180 @@ +// 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 +#include +#include + +#if defined(BOOST_NO_STRINGSTREAM) || defined(BOOST_NO_STD_WSTRING) +#define BOOST_LCAST_NO_WCHAR_T +#endif + +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) +{ + /* 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 +void test_inf_nan_templated() +{ + typedef T test_t; + + BOOST_CHECK( is_pos_inf( lexical_cast("inf") ) ); + BOOST_CHECK( is_pos_inf( lexical_cast("INF") ) ); + + BOOST_CHECK( is_neg_inf( lexical_cast("-inf") ) ); + BOOST_CHECK( is_neg_inf( lexical_cast("-INF") ) ); + + BOOST_CHECK( is_pos_inf( lexical_cast("+inf") ) ); + BOOST_CHECK( is_pos_inf( lexical_cast("+INF") ) ); + + BOOST_CHECK( is_pos_inf( lexical_cast("infinity") ) ); + BOOST_CHECK( is_pos_inf( lexical_cast("INFINITY") ) ); + + BOOST_CHECK( is_neg_inf( lexical_cast("-infinity") ) ); + BOOST_CHECK( is_neg_inf( lexical_cast("-INFINITY") ) ); + + BOOST_CHECK( is_pos_inf( lexical_cast("+infinity") ) ); + BOOST_CHECK( is_pos_inf( lexical_cast("+INFINITY") ) ); + + BOOST_CHECK( is_pos_nan( lexical_cast("nan") ) ); + BOOST_CHECK( is_pos_nan( lexical_cast("NAN") ) ); + + BOOST_CHECK( is_neg_nan( lexical_cast("-nan") ) ); + BOOST_CHECK( is_neg_nan( lexical_cast("-NAN") ) ); + + BOOST_CHECK( is_pos_nan( lexical_cast("+nan") ) ); + BOOST_CHECK( is_pos_nan( lexical_cast("+NAN") ) ); + + 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( (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" ); +#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") ) ); + BOOST_CHECK( is_pos_inf( lexical_cast(L"INF") ) ); + + BOOST_CHECK( is_neg_inf( lexical_cast(L"-inf") ) ); + BOOST_CHECK( is_neg_inf( lexical_cast(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" ); +#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() +{ + 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; +} 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..14ac461 --- /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_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); +} + +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 8480a6d0837c2ac05e0efebb83565747bfada039 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Wed, 17 Aug 2011 18:44:00 +0000 Subject: [PATCH 33/66] Merge from trunk r73850 * Documentation commited [SVN r73852] --- doc/Jamfile.v2 | 16 + doc/lexical_cast.qbk | 699 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 715 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..9fb6cdf --- /dev/null +++ b/doc/lexical_cast.qbk @@ -0,0 +1,699 @@ +[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__ [@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]] + +[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: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"));` + +[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? + * [*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 [@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 +`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 e1caac418c1e0086aaaffb8231fe8cd6f8ed5280 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Mon, 12 Sep 2011 18:15:31 +0000 Subject: [PATCH 34/66] Mereged from r74355 Basic support for char16_t and char32_t [SVN r74361] --- 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 3a62368d0ef37a320e98b76bf77ce87ba5ca5cbb Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Sun, 25 Sep 2011 16:44:39 +0000 Subject: [PATCH 35/66] Merge from trunk r74564 * char16_t and char32_t conversions now work on gcc for C locale * Optimizations for C locale * Performance section of documentation updated [SVN r74565] --- 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 1eda87448e2e41fb931ec51a052e7ad7444052d5 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Tue, 8 Nov 2011 18:12:23 +0000 Subject: [PATCH 36/66] Fixes #6083 Merge from trunk [SVN r75411] --- include/boost/lexical_cast.hpp | 2 +- test/Jamfile.v2 | 1 + test/lexical_cast_empty_input_test.cpp | 58 ++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 1 deletion(-) create mode 100755 test/lexical_cast_empty_input_test.cpp diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index 94f8c70..0004461 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -1147,7 +1147,7 @@ namespace boost bool const result = !(stream << input).fail(); start = stringbuffer.pbase(); finish = stringbuffer.pptr(); - return result; + return result && (start != finish); } template diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 2dd3500..55aacc5 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_empty_input_test.cpp ../../test/build//boost_unit_test_framework/static ] ; diff --git a/test/lexical_cast_empty_input_test.cpp b/test/lexical_cast_empty_input_test.cpp new file mode 100755 index 0000000..f655acd --- /dev/null +++ b/test/lexical_cast_empty_input_test.cpp @@ -0,0 +1,58 @@ +// 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 + +using namespace boost; + +void test_empty_iterator_range() +{ + 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); + BOOST_CHECK_THROW(lexical_cast(v), 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); +} + +unit_test::test_suite *init_unit_test_suite(int, char *[]) +{ + unit_test_framework::test_suite *suite = + 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)); + + return suite; +} From 7112ded1b967279a0e984602d68184ea29d2a5b2 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Mon, 19 Dec 2011 15:19:43 +0000 Subject: [PATCH 37/66] Merge from trunk r75937 * fixed a lot of wchar_t errors * Optimizations for boost::containers::basic_string * More tests [SVN r76062] --- doc/lexical_cast.qbk | 12 +++ include/boost/lexical_cast.hpp | 90 +++++++++++++++++-- lexical_cast_test.cpp | 2 +- test/Jamfile.v2 | 9 +- test/lexical_cast_abstract_test.cpp | 2 +- test/lexical_cast_containers_test.cpp | 38 ++++++++ test/lexical_cast_empty_input_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_typedefed_wchar_test.cpp | 25 ++++++ ...ical_cast_typedefed_wchar_test_runtime.cpp | 48 ++++++++++ test/lexical_cast_vc8_bug_test.cpp | 2 +- test/lexical_cast_wchars_test.cpp | 2 +- 15 files changed, 222 insertions(+), 18 deletions(-) create mode 100644 test/lexical_cast_containers_test.cpp 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..0532b56 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 :] + + * Added code to 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 0004461..5fa6a96 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -17,7 +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 and other Boosters +// Alexander Nasonov, Antony Polukhin, Justin Viiret, Michael Hofmann, +// Cheng Yang and other Boosters // when: November 2000, March 2003, June 2005, June 2006, March 2011 #include @@ -46,8 +47,10 @@ #include #include #include -#include - +#include +#ifndef BOOST_NO_CWCHAR +# include +#endif #ifndef BOOST_NO_STD_LOCALE # include @@ -145,6 +148,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 +268,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 +294,15 @@ namespace boost { typedef Traits type; }; + + template + struct deduce_char_traits< CharT + , ::boost::container::basic_string + , ::boost::container::basic_string + > + { + typedef Traits type; + }; #endif } @@ -648,8 +684,8 @@ namespace boost , 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 CharT minus = lcast_char_constants::minus; + const CharT plus = lcast_char_constants::plus; const int inifinity_size = 8; bool has_minus = false; @@ -1257,6 +1293,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; @@ -1310,6 +1354,7 @@ namespace boost /************************************ HELPER FUNCTIONS FOR OPERATORS >> ( ... ) ********************************/ private: + template bool shr_unsigned(Type& output) { @@ -1436,7 +1481,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); } @@ -1449,11 +1494,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 @@ -1462,6 +1515,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 +1654,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 +1760,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/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)); diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 55aacc5..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 ] @@ -28,7 +33,9 @@ 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 ] [ 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_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_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)); +} + + diff --git a/test/lexical_cast_empty_input_test.cpp b/test/lexical_cast_empty_input_test.cpp index f655acd..42e7cec 100755 --- a/test/lexical_cast_empty_input_test.cpp +++ b/test/lexical_cast_empty_input_test.cpp @@ -49,7 +49,7 @@ void test_empty_string() 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. Empty input unit test"); suite->add(BOOST_TEST_CASE(&test_empty_iterator_range)); suite->add(BOOST_TEST_CASE(&test_empty_string)); 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_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; +} 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 82abf7b54faa09276be5fbb0307ca6a65a1c8ec4 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Fri, 30 Dec 2011 15:18:00 +0000 Subject: [PATCH 38/66] Merge from trunk r76232 [SVN r76233] --- doc/lexical_cast.qbk | 2 +- include/boost/lexical_cast.hpp | 31 ++++++- test/lexical_cast_empty_input_test.cpp | 115 ++++++++++++++++++++++--- 3 files changed, 132 insertions(+), 16 deletions(-) diff --git a/doc/lexical_cast.qbk b/doc/lexical_cast.qbk index 0532b56..bf6b562 100644 --- a/doc/lexical_cast.qbk +++ b/doc/lexical_cast.qbk @@ -172,7 +172,7 @@ limitation of compiler options that you use. [section Changes] * [*boost 1.49.0 :] - * Added code to work with typedefed wchar_t (compilation flag /Zc:wchar_t- for Visual Studio). + * Restored work with typedefed wchar_t (compilation flag /Zc:wchar_t- for Visual Studio). * [*boost 1.48.0 :] diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index 5fa6a96..b9bc984 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -18,7 +18,7 @@ // with additional fixes and suggestions from Gennaro Prota, // Beman Dawes, Dave Abrahams, Daryle Walker, Peter Dimov, // Alexander Nasonov, Antony Polukhin, Justin Viiret, Michael Hofmann, -// Cheng Yang and other Boosters +// 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 @@ -1358,6 +1379,7 @@ namespace boost 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; @@ -1392,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; 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; } From a2e4606e6cd3b0909c28894a62db6ae4631fde09 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Sun, 8 Jan 2012 09:05:35 +0000 Subject: [PATCH 39/66] Merge from trunk r76354 (Fixes overflow detection, pointers casts) [SVN r76355] --- include/boost/lexical_cast.hpp | 48 +++++++++++---- lexical_cast_test.cpp | 11 ++++ test/Jamfile.v2 | 1 + test/lexical_cast_pointers_test.cpp | 96 +++++++++++++++++++++++++++++ 4 files changed, 145 insertions(+), 11 deletions(-) create mode 100755 test/lexical_cast_pointers_test.cpp diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index b9bc984..0927e39 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -18,8 +18,8 @@ // with additional fixes and suggestions from Gennaro Prota, // Beman Dawes, Dave Abrahams, Daryle Walker, Peter Dimov, // Alexander Nasonov, Antony Polukhin, Justin Viiret, Michael Hofmann, -// Cheng Yang, Matthew Bradbury and other Boosters -// when: November 2000, March 2003, June 2005, June 2006, March 2011 +// Cheng Yang, Matthew Bradbury, David W. Birdsall and other Boosters +// when: November 2000, March 2003, June 2005, June 2006, March 2011 - 2012 #include #include @@ -591,6 +591,7 @@ namespace boost value = *end - czero; --end; T multiplier = 1; + bool multiplier_overflowed = false; #ifndef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE std::locale loc; @@ -613,12 +614,17 @@ namespace boost for(;end>=begin; --end) { if (remained) { - T const new_sub_value = multiplier * 10 * (*end - czero); + T const multiplier_10 = multiplier * 10; + if (multiplier_10 / 10 != multiplier) multiplier_overflowed = true; + + T const dig_value = *end - czero; + T const new_sub_value = multiplier_10 * dig_value; if (*end < czero || *end >= czero + 10 /* detecting overflow */ - || new_sub_value/10 != multiplier * (*end - czero) + || (dig_value && new_sub_value / dig_value != multiplier_10) || static_cast((std::numeric_limits::max)()-new_sub_value) < value + || (multiplier_overflowed && dig_value) ) return false; @@ -656,12 +662,17 @@ namespace boost { while ( begin <= end ) { - T const new_sub_value = multiplier * 10 * (*end - czero); + T const multiplier_10 = multiplier * 10; + if (multiplier_10 / 10 != multiplier) multiplier_overflowed = true; + + T const dig_value = *end - czero; + T const new_sub_value = multiplier_10 * dig_value; if (*end < czero || *end >= czero + 10 /* detecting overflow */ - || new_sub_value/10 != multiplier * (*end - czero) + || (dig_value && new_sub_value / dig_value != multiplier_10) || static_cast((std::numeric_limits::max)()-new_sub_value) < value + || (multiplier_overflowed && dig_value) ) return false; @@ -1822,6 +1833,24 @@ namespace boost deduce_char_traits::type traits; typedef BOOST_DEDUCED_TYPENAME remove_pointer::type removed_ptr_t; + + // is_char_types_match variable value can be computed via + // sizeof(char_type) == sizeof(removed_ptr_t). But when + // removed_ptr_t is an incomplete type or void*, compilers + // produce warnings or errors. + const bool is_char_types_match = + (::boost::type_traits::ice_or< + ::boost::type_traits::ice_and< + ::boost::type_traits::ice_eq::value, + ::boost::type_traits::ice_or< + ::boost::is_same::value, + ::boost::is_same::value, + ::boost::is_same::value + >::value + >::value, + is_same::value + >::value); + const bool requires_stringbuf = !( ::boost::type_traits::ice_or< @@ -1830,10 +1859,7 @@ namespace boost ::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 + is_char_types_match >::value >::value ); @@ -2111,7 +2137,7 @@ namespace boost // Copyright Kevlin Henney, 2000-2005. // Copyright Alexander Nasonov, 2006-2010. -// Copyright Antony Polukhin, 2011. +// Copyright Antony Polukhin, 2011-2012. // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at diff --git a/lexical_cast_test.cpp b/lexical_cast_test.cpp index faeaa93..4e9ec90 100644 --- a/lexical_cast_test.cpp +++ b/lexical_cast_test.cpp @@ -796,6 +796,17 @@ void test_conversion_from_to_integral() BOOST_CHECK_THROW(lexical_cast("+-9"), bad_lexical_cast); // test_conversion_from_to_integral_for_locale + // Overflow test case from David W. Birdsall + std::string must_owerflow_str = "160000000000000000000"; + std::string must_owerflow_negative_str = "-160000000000000000000"; + for (int i = 0; i < 15; ++i) { + BOOST_CHECK_THROW(lexical_cast(must_owerflow_str), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(must_owerflow_negative_str), bad_lexical_cast); + + must_owerflow_str += '0'; + must_owerflow_negative_str += '0'; + } + typedef std::numpunct numpunct; restore_oldloc guard; diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 8718301..c311420 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -35,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 ] + [ run lexical_cast_pointers_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_pointers_test.cpp b/test/lexical_cast_pointers_test.cpp new file mode 100755 index 0000000..d24a895 --- /dev/null +++ b/test/lexical_cast_pointers_test.cpp @@ -0,0 +1,96 @@ +// Unit test for boost::lexical_cast. +// +// See http://www.boost.org for most recent version, including documentation. +// +// Copyright Antony Polukhin, 2012. +// +// Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). + +#include + +#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; + +#if defined(BOOST_NO_STRINGSTREAM) + typedef std::strstream ss_t; +#else + typedef std::stringstream ss_t; +#endif + +void test_void_pointers_conversions() +{ + void *p_to_null = NULL; + const void *cp_to_data = "Some data"; + char nonconst_data[5]; + void *p_to_data = nonconst_data; + ss_t ss; + + ss << p_to_null; + BOOST_CHECK_EQUAL(boost::lexical_cast(p_to_null), ss.str()); + ss.str(std::string()); + + ss << cp_to_data; + BOOST_CHECK_EQUAL(boost::lexical_cast(cp_to_data), ss.str()); + ss.str(std::string()); + + ss << p_to_data; + BOOST_CHECK_EQUAL(boost::lexical_cast(p_to_data), ss.str()); + ss.str(std::string()); +} + +struct incomplete_type; + +void test_incomplete_type_pointers_conversions() +{ + incomplete_type *p_to_null = NULL; + const incomplete_type *cp_to_data = NULL; + char nonconst_data[5]; + incomplete_type *p_to_data = reinterpret_cast(nonconst_data); + ss_t ss; + + ss << p_to_null; + BOOST_CHECK_EQUAL(boost::lexical_cast(p_to_null), ss.str()); + ss.str(std::string()); + + ss << cp_to_data; + BOOST_CHECK_EQUAL(boost::lexical_cast(cp_to_data), ss.str()); + ss.str(std::string()); + + ss << p_to_data; + BOOST_CHECK_EQUAL(boost::lexical_cast(p_to_data), ss.str()); + ss.str(std::string()); +} + +struct ble; +typedef struct ble *meh; +std::ostream& operator <<(std::ostream &o, meh) { + o << "yay"; + return o; +} + +void test_inomplete_type_with_overloaded_ostream_op() { + meh heh = NULL; + ss_t ss; + ss << heh; + BOOST_CHECK_EQUAL(boost::lexical_cast(heh), ss.str()); +} + +unit_test::test_suite *init_unit_test_suite(int, char *[]) +{ + unit_test::test_suite *suite = + BOOST_TEST_SUITE("lexical_cast pinters test"); + suite->add(BOOST_TEST_CASE(&test_void_pointers_conversions)); + suite->add(BOOST_TEST_CASE(&test_incomplete_type_pointers_conversions)); + suite->add(BOOST_TEST_CASE(&test_inomplete_type_with_overloaded_ostream_op)); + return suite; +} From 51a6aacb57cb8ae1b3c3d99a6f6c3af992d7558a Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Sun, 8 Jan 2012 09:25:04 +0000 Subject: [PATCH 40/66] Merge from trunk r76357 (tiny documentation update) [SVN r76358] --- doc/lexical_cast.qbk | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/lexical_cast.qbk b/doc/lexical_cast.qbk index bf6b562..4715803 100644 --- a/doc/lexical_cast.qbk +++ b/doc/lexical_cast.qbk @@ -172,7 +172,8 @@ limitation of compiler options that you use. [section Changes] * [*boost 1.49.0 :] - * Restored work with typedefed wchar_t (compilation flag /Zc:wchar_t- for Visual Studio). + * Restored work with typedefed wchar_t (compilation flag /Zc:wchar_t- for Visual Studio). + * Better performance and less memory usage for `boost::container::basic_string` conversions. * [*boost 1.48.0 :] From e51cf081b355f248db435dd132a4f80160b5c284 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Sat, 4 Feb 2012 18:04:45 +0000 Subject: [PATCH 41/66] Merge from trunk (fixed #6251, fixed #6453, disabled some optimizations for sunCC #6462) [SVN r76887] --- include/boost/lexical_cast.hpp | 68 +++++++++++++++++++++++++++++----- 1 file changed, 58 insertions(+), 10 deletions(-) diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index 0927e39..5a3d4f0 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -21,6 +21,32 @@ // Cheng Yang, Matthew Bradbury, David W. Birdsall and other Boosters // when: November 2000, March 2003, June 2005, June 2006, March 2011 - 2012 +#include +#if defined(BOOST_NO_STRINGSTREAM) || defined(BOOST_NO_STD_WSTRING) +#define BOOST_LCAST_NO_WCHAR_T +#endif + +#if (defined(__MINGW32__) || defined(__MINGW64__)) && (__GNUC__ == 4) \ + && ((__GNUC_MINOR__ == 4) || (__GNUC_MINOR__ == 5)) && defined(__STRICT_ANSI__) \ + && !defined(BOOST_LCAST_NO_WCHAR_T) + +// workaround for a mingw bug +// http://sourceforge.net/tracker/index.php?func=detail&aid=2373234&group_id=2435&atid=102435 +#include <_mingw.h> +#if (__GNUC_MINOR__ == 4) +extern "C" { +_CRTIMP int __cdecl swprintf(wchar_t * __restrict__ , const wchar_t * __restrict__ , ...); +_CRTIMP int __cdecl vswprintf(wchar_t * __restrict__ , const wchar_t * __restrict__ , ...); +} +#endif +#if (__GNUC_MINOR__ == 5) +extern "C" { +_CRTIMP int __cdecl swprintf(wchar_t * __restrict__ , const wchar_t * __restrict__ , ...); +_CRTIMP int __cdecl vswprintf(wchar_t * __restrict__ , const wchar_t * __restrict__ , va_list); +} +#endif +#endif + #include #include #include @@ -30,7 +56,6 @@ #include #include #include -#include #include #include #include @@ -47,7 +72,9 @@ #include #include #include +#if !defined(__SUNPRO_CC) #include +#endif // !defined(__SUNPRO_CC) #ifndef BOOST_NO_CWCHAR # include #endif @@ -67,10 +94,6 @@ #include #endif -#if defined(BOOST_NO_STRINGSTREAM) || defined(BOOST_NO_STD_WSTRING) -#define BOOST_LCAST_NO_WCHAR_T -#endif - #ifdef BOOST_NO_TYPEID #define BOOST_LCAST_THROW_BAD_CAST(S, T) throw_exception(bad_lexical_cast()) #else @@ -149,11 +172,13 @@ namespace boost typedef CharT type; }; +#if !defined(__SUNPRO_CC) template struct stream_char< ::boost::container::basic_string > { typedef CharT type; }; +#endif // !defined(__SUNPRO_CC) #endif #ifndef BOOST_LCAST_NO_WCHAR_T @@ -268,6 +293,7 @@ namespace boost typedef Traits type; }; +#if !defined(__SUNPRO_CC) template struct deduce_char_traits< CharT , ::boost::container::basic_string @@ -303,6 +329,25 @@ namespace boost { typedef Traits type; }; + + template + struct deduce_char_traits< CharT + , ::boost::container::basic_string + , std::basic_string + > + { + typedef Traits type; + }; + + template + struct deduce_char_traits< CharT + , std::basic_string + , ::boost::container::basic_string + > + { + typedef Traits type; + }; +#endif // !defined(__SUNPRO_CC) #endif } @@ -1325,6 +1370,7 @@ namespace boost return true; } +#if !defined(__SUNPRO_CC) template bool operator<<(::boost::container::basic_string const& str) { @@ -1332,7 +1378,7 @@ namespace boost finish = start + str.length(); return true; } - +#endif // !defined(__SUNPRO_CC) bool operator<<(bool value) { CharT const czero = lcast_char_constants::zero; @@ -1549,9 +1595,10 @@ namespace boost #else template bool operator>>(std::basic_string& str) { str.assign(start, finish); return true; } - +#if !defined(__SUNPRO_CC) template bool operator>>(::boost::container::basic_string& str) { str.assign(start, finish); return true; } +#endif // !defined(__SUNPRO_CC) #endif /* * case "-0" || "0" || "+0" : output = false; return true; @@ -1687,13 +1734,13 @@ namespace boost { BOOST_STATIC_CONSTANT(bool, value = true ); }; - +#if !defined(__SUNPRO_CC) template struct is_stdstring< ::boost::container::basic_string > { BOOST_STATIC_CONSTANT(bool, value = true ); }; - +#endif // !defined(__SUNPRO_CC) template struct is_char_or_wchar { @@ -1793,7 +1840,7 @@ namespace boost { BOOST_STATIC_CONSTANT(bool, value = true ); }; - +#if !defined(__SUNPRO_CC) template struct is_char_array_to_stdstring< ::boost::container::basic_string, CharT* > { @@ -1805,6 +1852,7 @@ namespace boost { BOOST_STATIC_CONSTANT(bool, value = true ); }; +#endif // !defined(__SUNPRO_CC) #if (defined _MSC_VER) # pragma warning( push ) From a065884c59fd9390590ec15bd063b9f5d1eb0e94 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Sat, 10 Mar 2012 07:31:36 +0000 Subject: [PATCH 42/66] Merge from trunk * Much more tests * Now numeric_cast (and lexical_cast) can be compiled with disabled exceptions * Supress warning described in #6645 (implicit conversion shortens 64-bit value into a 32-bit value) * Fixed compilation of lexical_cast with BOOST_NO_STD_LOCALE defined * Documentation updates * Case insensitive "NaN" and "Inf" parsing * Performance tests commit [SVN r77288] --- doc/lexical_cast.qbk | 15 +- include/boost/lexical_cast.hpp | 275 +++++++++--------- perf/Jamfile.v2 | 29 ++ perf/performance_test.cpp | 309 +++++++++++++++++++++ test/Jamfile.v2 | 11 +- test/lexical_cast_containers_test.cpp | 22 ++ test/lexical_cast_empty_input_test.cpp | 14 + test/lexical_cast_inf_nan_test.cpp | 21 ++ test/lexical_cast_no_exceptions_test.cpp | 95 +++++++ test/lexical_cast_no_locale_test.cpp | 166 +++++++++++ test/lexical_cast_typedefed_wchar_test.cpp | 15 + 11 files changed, 839 insertions(+), 133 deletions(-) create mode 100644 perf/Jamfile.v2 create mode 100644 perf/performance_test.cpp create mode 100755 test/lexical_cast_no_exceptions_test.cpp create mode 100755 test/lexical_cast_no_locale_test.cpp diff --git a/doc/lexical_cast.qbk b/doc/lexical_cast.qbk index 4715803..4ad8336 100644 --- a/doc/lexical_cast.qbk +++ b/doc/lexical_cast.qbk @@ -3,7 +3,7 @@ [version 1.0] [copyright 2000-2005 Kevlin Henney] [copyright 2006-2010 Alexander Nasonov] - [copyright 2011 Antony Polukhin] + [copyright 2011-2012 Antony Polukhin] [category String and text processing] [category Miscellaneous] [license @@ -167,9 +167,22 @@ if a negative number is read, no errors will arise and the result will be the tw `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. +[pre +] + +* [*Question:] Why `boost::lexical_cast("-1.#IND");` throws `boost::bad_lexical_cast`? + * [*Answer:] `"-1.#IND"` is a compiler extension, that violates standard. You shall input `"-nan"`, `"nan"`, `"inf"` +, `"-inf"` (case insensitive) strings to get NaN and Inf values. `boost::lexical_cast` outputs `"-nan"`, `"nan"`, +`"inf"`, `"-inf"` strings, when has NaN or Inf input values. + [endsect] [section Changes] +* [*boost 1.50.0 :] + + * `boost::bad_lexical_cast` exception is now globaly visible and can be catched even if code is compiled with -fvisibility=hidden. + * Now it is possible to compile library with disabled exceptions. + * [*boost 1.49.0 :] * Restored work with typedefed wchar_t (compilation flag /Zc:wchar_t- for Visual Studio). diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index 5a3d4f0..b73c741 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -104,7 +104,7 @@ _CRTIMP int __cdecl vswprintf(wchar_t * __restrict__ , const wchar_t * __restric namespace boost { // exception used to indicate runtime lexical_cast failure - class bad_lexical_cast : + class BOOST_SYMBOL_VISIBLE bad_lexical_cast : // workaround MSVC bug with std::bad_cast when _HAS_EXCEPTIONS == 0 #if defined(BOOST_MSVC) && defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS public std::exception @@ -732,6 +732,15 @@ namespace boost namespace detail { + template + bool lc_iequal(const CharT* val, const CharT* lcase, const CharT* ucase, unsigned int len) { + for( unsigned int i=0; i < len; ++i ) { + if ( val[i] != lcase[i] && val[i] != ucase[i] ) return false; + } + + return true; + } + /* 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 @@ -755,7 +764,7 @@ namespace boost 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)) ) + if( lc_iequal(begin, lc_nan, lc_NAN, 3) ) { begin += 3; if (end != begin) /* It is 'nan(...)' or some bad input*/ @@ -772,13 +781,13 @@ namespace boost if (( /* 'INF' or 'inf' */ end-begin==3 && - (!memcmp(begin, lc_infinity, 3*sizeof(CharT)) || !memcmp(begin, lc_INFINITY, 3*sizeof(CharT))) + lc_iequal(begin, lc_infinity, lc_INFINITY, 3) ) || ( /* 'INFINITY' or 'infinity' */ end-begin==inifinity_size && - (!memcmp(begin, lc_infinity, inifinity_size)|| !memcmp(begin, lc_INFINITY, inifinity_size)) + lc_iequal(begin, lc_infinity, lc_INFINITY, inifinity_size) ) ) { @@ -790,6 +799,41 @@ namespace boost return false; } + template + bool put_inf_nan_impl(CharT* begin, CharT*& end, const T& value + , const CharT* lc_nan + , const CharT* lc_infinity) + { + using namespace std; + const CharT minus = lcast_char_constants::minus; + if ( (boost::math::isnan)(value) ) + { + if ( (boost::math::signbit)(value) ) + { + *begin = minus; + ++ begin; + } + + memcpy(begin, lc_nan, 3 * sizeof(CharT)); + end = begin + 3; + return true; + } else if ( (boost::math::isinf)(value) ) + { + if ( (boost::math::signbit)(value) ) + { + *begin = minus; + ++ begin; + } + + memcpy(begin, lc_infinity, 3 * sizeof(CharT)); + end = begin + 3; + 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) @@ -799,6 +843,13 @@ namespace boost , L"INFINITY", L"infinity" , L'(', L')'); } + + template + bool put_inf_nan(wchar_t* begin, wchar_t*& end, const T& value) + { + return put_inf_nan_impl(begin, end, value, L"nan", L"infinity"); + } + #endif #ifndef BOOST_NO_CHAR16_T template @@ -809,6 +860,12 @@ namespace boost , u"INFINITY", u"infinity" , u'(', u')'); } + + template + bool put_inf_nan(char16_t* begin, char16_t*& end, const T& value) + { + return put_inf_nan_impl(begin, end, value, u"nan", u"infinity"); + } #endif #ifndef BOOST_NO_CHAR32_T template @@ -819,6 +876,12 @@ namespace boost , U"INFINITY", U"infinity" , U'(', U')'); } + + template + bool put_inf_nan(char32_t* begin, char32_t*& end, const T& value) + { + return put_inf_nan_impl(begin, end, value, U"nan", U"infinity"); + } #endif template @@ -829,73 +892,12 @@ 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 ( (boost::math::isnan)(value) ) - { - 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 ( (boost::math::isinf)(value) ) - { - 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 ( (boost::math::isnan)(value) ) - { - 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 ( (boost::math::isinf)(value) ) - { - if ( (boost::math::signbit)(value) ) - { - memcpy(begin,"-inf", sizeof("-inf")); - end = begin + 4; - } else - { - memcpy(begin,"inf", sizeof("inf")); - end = begin + 3; - } - return true; - } - - return false; + return put_inf_nan_impl(begin, end, value, "nan", "infinity"); } - } @@ -951,7 +953,7 @@ namespace boost CharT const capital_e = lcast_char_constants::capital_e; CharT const lowercase_e = lcast_char_constants::lowercase_e; - value = 0.0; + value = static_cast(0); if (parse_inf_nan(begin, end, value)) return true; @@ -1165,7 +1167,7 @@ namespace boost namespace detail { - struct do_not_construct_stringbuffer_t{}; + struct do_not_construct_out_stream_t{}; } namespace detail // optimized stream wrapper @@ -1177,25 +1179,27 @@ namespace boost > 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; + typedef std::ostrstream out_stream_t; + typedef stl_buf_unlocker unlocked_but_t; #elif defined(BOOST_NO_STD_LOCALE) - typedef stl_buf_unlocker local_stringbuffer_t; + typedef std::ostringstream out_stream_t; + typedef stl_buf_unlocker unlocked_but_t; #else - typedef stl_buf_unlocker, CharT > local_stringbuffer_t; + typedef std::basic_ostringstream out_stream_t; + typedef stl_buf_unlocker, CharT> unlocked_but_t; #endif typedef BOOST_DEDUCED_TYPENAME ::boost::mpl::if_c< RequiresStringbuffer, - local_stringbuffer_t, - do_not_construct_stringbuffer_t - >::type deduced_stringbuffer_t; + out_stream_t, + do_not_construct_out_stream_t + >::type deduced_out_stream_t; // A string representation of Source is written to [start, finish). CharT* start; CharT* finish; - deduced_stringbuffer_t stringbuffer; + deduced_out_stream_t out_stream; public: lexical_stream_limited_src(CharT* sta, CharT* fin) @@ -1256,10 +1260,16 @@ namespace boost template bool shl_input_streamable(InputStreamable& input) { - std::basic_ostream stream(&stringbuffer); - bool const result = !(stream << input).fail(); - start = stringbuffer.pbase(); - finish = stringbuffer.pptr(); +#if defined(BOOST_NO_STRINGSTREAM) || defined(BOOST_NO_STD_LOCALE) + // If you have compilation error at this point, than your STL library + // unsupports such conversions. Try updating it. + BOOST_STATIC_ASSERT((boost::is_same::value)); +#endif + bool const result = !(out_stream << input).fail(); + const unlocked_but_t* const p + = static_cast(out_stream.rdbuf()) ; + start = p->pbase(); + finish = p->pptr(); return result; } @@ -1524,9 +1534,22 @@ namespace boost if(is_pointer::value) return false; - local_streambuffer_t bb; - bb.setg(start, start, finish); - std::basic_istream stream(&bb); +#if defined(BOOST_NO_STRINGSTREAM) || defined(BOOST_NO_STD_LOCALE) + // If you have compilation error at this point, than your STL library + // unsupports such conversions. Try updating it. + BOOST_STATIC_ASSERT((boost::is_same::value)); +#endif + +#if defined(BOOST_NO_STRINGSTREAM) + std::istrstream stream(start, finish - start); +#elif defined(BOOST_NO_STD_LOCALE) + std::istringstream stream; +#else + std::basic_istringstream stream; +#endif + static_cast(stream.rdbuf()) + ->setg(start, start, finish); + stream.unsetf(std::ios::skipws); lcast_set_precision(stream, static_cast(0)); #if (defined _MSC_VER) @@ -1935,52 +1958,52 @@ namespace boost } }; - class precision_loss_error : public boost::numeric::bad_numeric_cast + template + struct detect_precision_loss { - public: - virtual const char * what() const throw() - { return "bad numeric conversion: precision loss error"; } - }; + typedef boost::numeric::Trunc Rounder; + typedef Source source_type ; - template - struct throw_on_precision_loss - { - typedef boost::numeric::Trunc Rounder; - typedef S source_type ; - - typedef typename mpl::if_< is_arithmetic,S,S const&>::type argument_type ; + typedef BOOST_DEDUCED_TYPENAME mpl::if_< + is_arithmetic, Source, Source const& + >::type argument_type ; static source_type nearbyint ( argument_type s ) { - source_type orig_div_round = s / Rounder::nearbyint(s); + const source_type orig_div_round = s / Rounder::nearbyint(s); + const source_type eps = std::numeric_limits::epsilon(); + + if ((orig_div_round > 1 ? orig_div_round - 1 : 1 - orig_div_round) > eps) + BOOST_LCAST_THROW_BAD_CAST(Source, Target); - if ( (orig_div_round > 1 ? orig_div_round - 1 : 1 - orig_div_round) > std::numeric_limits::epsilon() ) - BOOST_THROW_EXCEPTION( precision_loss_error() ); return s ; } typedef typename Rounder::round_style round_style; } ; + template + struct nothrow_overflow_handler + { + void operator() ( boost::numeric::range_check_result r ) + { + if (r != boost::numeric::cInRange) + BOOST_LCAST_THROW_BAD_CAST(Source, Target); + } + } ; + template struct lexical_cast_dynamic_num_not_ignoring_minus { static inline Target lexical_cast_impl(const Source &arg) { - try{ - typedef boost::numeric::converter< - Target, - Source, - boost::numeric::conversion_traits, - boost::numeric::def_overflow_handler, - throw_on_precision_loss - > Converter ; - - return Converter::convert(arg); - } catch( ::boost::numeric::bad_numeric_cast const& ) { - BOOST_LCAST_THROW_BAD_CAST(Source, Target); - } - BOOST_UNREACHABLE_RETURN(static_cast(0)); + return boost::numeric::converter< + Target, + Source, + boost::numeric::conversion_traits, + nothrow_overflow_handler, + detect_precision_loss + >::convert(arg); } }; @@ -1989,25 +2012,17 @@ namespace boost { static inline Target lexical_cast_impl(const Source &arg) { - try{ - typedef boost::numeric::converter< - Target, - Source, - boost::numeric::conversion_traits, - boost::numeric::def_overflow_handler, - throw_on_precision_loss - > Converter ; + typedef boost::numeric::converter< + Target, + Source, + boost::numeric::conversion_traits, + nothrow_overflow_handler, + detect_precision_loss + > converter_t; - bool has_minus = ( arg < 0); - if ( has_minus ) { - return static_cast(-Converter::convert(-arg)); - } else { - return Converter::convert(arg); - } - } catch( ::boost::numeric::bad_numeric_cast const& ) { - BOOST_LCAST_THROW_BAD_CAST(Source, Target); - } - BOOST_UNREACHABLE_RETURN(static_cast(0)); + return ( + arg < 0 ? -converter_t::convert(-arg) : converter_t::convert(arg) + ); } }; diff --git a/perf/Jamfile.v2 b/perf/Jamfile.v2 new file mode 100644 index 0000000..78176be --- /dev/null +++ b/perf/Jamfile.v2 @@ -0,0 +1,29 @@ +#============================================================================== +# Copyright (c) 2012 Antony Polukhin +# +# 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) +#============================================================================== + +# performance tests +import testing ; +import path ; + +path-constant TEST_DIR : . ; + +project performance/test + : source-location ./ + : requirements +# /boost/chrono//boost_chrono +# /boost/system//boost_system + static + freebsd:"-lrt" + linux:"-lrt" + gcc:-fvisibility=hidden + intel-linux:-fvisibility=hidden + sun:-xldscope=hidden + : default-build release + ; + +run performance_test.cpp : $(TEST_DIR) ; + diff --git a/perf/performance_test.cpp b/perf/performance_test.cpp new file mode 100644 index 0000000..ff1eb1d --- /dev/null +++ b/perf/performance_test.cpp @@ -0,0 +1,309 @@ +// (C) Copyright Antony Polukhin 2012. +// 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) + +// See http://www.boost.org/libs/config for most recent version. + +// +// Testing lexical_cast<> performance +// + +#define BOOST_ERROR_CODE_HEADER_ONLY +#define BOOST_CHRONO_HEADER_ONLY + +#include +#include +#include +#include + +// File to output data +std::fstream fout; + +template +static inline void test_lexical(const InT& in_val) { + OutT out_val = boost::lexical_cast(in_val); + (void)out_val; +} + +template +static inline void test_ss_constr(const InT& in_val) { + OutT out_val; + std::stringstream ss; + ss << in_val; + if (ss.fail()) throw std::logic_error("descr"); + ss >> out_val; + if (ss.fail()) throw std::logic_error("descr"); +} + +template +static inline void test_ss_noconstr(StringStreamT& ss, const InT& in_val) { + OutT out_val; + ss << in_val; // ss is an instance of std::stringstream + if (ss.fail()) throw std::logic_error("descr"); + ss >> out_val; + if (ss.fail()) throw std::logic_error("descr"); + /* reseting std::stringstream to use it again */ + ss.str(std::string()); + ss.clear(); +} + +struct structure_sprintf { + template + static inline void test(BufferT* buffer, const InT& in_val, const char* const conv) { + sprintf(buffer, conv, in_val); + OutT out_val(buffer); + } + + template + static inline void test(BufferT* buffer, const std::string& in_val, const char* const conv) { + sprintf(buffer, conv, in_val.c_str()); + OutT out_val(buffer); + } +}; + +struct structure_sscanf { + template + static inline void test(BufferT* /*buffer*/, const InT& in_val, const char* const conv) { + OutT out_val; + sscanf(reinterpret_cast(in_val), conv, &out_val); + } + + template + static inline void test(BufferT* /*buffer*/, const std::string& in_val, const char* const conv) { + OutT out_val; + sscanf(in_val.c_str(), conv, &out_val); + } +}; + +struct structure_fake { + template + static inline void test(BufferT* /*buffer*/, const InT& /*in_val*/, const char* const /*conv*/) {} +}; + +static const int fake_test_value = 9999; + +template +static inline void min_fancy_output(T v1, T v2, T v3, T v4) { + const char beg_mark[] = "!!! *"; + const char end_mark[] = "* !!!"; + const char no_mark[] = ""; + + unsigned int res = 4; + if (v1 < v2 && v1 < v3 && v1 < v4) res = 1; + if (v2 < v1 && v2 < v3 && v2 < v4) res = 2; + if (v3 < v1 && v3 < v2 && v3 < v4) res = 3; + + fout << "[ " + << (res == 1 ? beg_mark : no_mark) + ; + + if (v1) fout << v1; + else fout << "<1"; + + fout << (res == 1 ? end_mark : no_mark) + << " ][ " + << (res == 2 ? beg_mark : no_mark) + ; + + if (v2) fout << v2; + else fout << "<1"; + + fout << (res == 2 ? end_mark : no_mark) + << " ][ " + << (res == 3 ? beg_mark : no_mark) + ; + + if (v3) fout << v3; + else fout << "<1"; + + fout << (res == 3 ? end_mark : no_mark) + << " ][ " + << (res == 4 ? beg_mark : no_mark) + ; + + if (!v4) fout << "<1"; + else if (v4 == fake_test_value) fout << "---"; + else fout << v4; + + fout + << (res == 4 ? end_mark : no_mark) + << " ]"; +} + +template +static inline void perf_test_impl(const FromT& in_val, const char* const conv) { + + typedef boost::chrono::steady_clock test_clock; + test_clock::time_point start; + typedef boost::chrono::milliseconds duration_t; + duration_t lexical_cast_time, ss_constr_time, ss_noconstr_time, printf_time; + + start = test_clock::now(); + for (unsigned int i = 0; i < IetartionsCountV; ++i) { + test_lexical(in_val); + test_lexical(in_val); + test_lexical(in_val); + test_lexical(in_val); + } + lexical_cast_time = boost::chrono::duration_cast(test_clock::now() - start); + + + start = test_clock::now(); + for (unsigned int i = 0; i < IetartionsCountV; ++i) { + test_ss_constr(in_val); + test_ss_constr(in_val); + test_ss_constr(in_val); + test_ss_constr(in_val); + } + ss_constr_time = boost::chrono::duration_cast(test_clock::now() - start); + + std::stringstream ss; + start = test_clock::now(); + for (unsigned int i = 0; i < IetartionsCountV; ++i) { + test_ss_noconstr(ss, in_val); + test_ss_noconstr(ss, in_val); + test_ss_noconstr(ss, in_val); + test_ss_noconstr(ss, in_val); + } + ss_noconstr_time = boost::chrono::duration_cast(test_clock::now() - start); + + + char buffer[128]; + start = test_clock::now(); + for (unsigned int i = 0; i < IetartionsCountV; ++i) { + SprintfT::template test(buffer, in_val, conv); + SprintfT::template test(buffer, in_val, conv); + SprintfT::template test(buffer, in_val, conv); + SprintfT::template test(buffer, in_val, conv); + } + printf_time = boost::chrono::duration_cast(test_clock::now() - start); + + min_fancy_output( + lexical_cast_time.count(), + ss_constr_time.count(), + ss_noconstr_time.count(), + boost::is_same::value ? fake_test_value : printf_time.count() + ); +} + +template +static inline void perf_test(const std::string& test_name, const FromT& in_val, const char* const conv) { + const unsigned int ITERATIONSCOUNT = 100000; + fout << " [[ " << test_name << " ]"; + + perf_test_impl(in_val, conv); + + fout << "]\n"; +} + + +template +void string_like_test_set(const std::string& from) { + typedef structure_sscanf ssc_t; + ConverterT conv; + + perf_test(from + "->char", conv("c"), "%c"); + perf_test(from + "->signed char", conv("c"), "%hhd"); + perf_test(from + "->unsigned char", conv("c"), "%hhu"); + + perf_test(from + "->int", conv("100"), "%d"); + perf_test(from + "->short", conv("100"), "%hd"); + perf_test(from + "->long int", conv("100"), "%ld"); + perf_test(from + "->long long", conv("100"), "%lld"); + + perf_test(from + "->unsigned int", conv("100"), "%u"); + perf_test(from + "->unsigned short", conv("100"), "%hu"); + perf_test(from + "->unsigned long int", conv("100"), "%lu"); + perf_test(from + "->unsigned long long", conv("100"), "%llu"); + + // perf_test(from + "->bool", conv("1"), "%"); + + perf_test(from + "->float", conv("1.123"), "%f"); + perf_test(from + "->double", conv("1.123"), "%lf"); + perf_test(from + "->long double", conv("1.123"), "%Lf"); + + + perf_test(from + "->string", conv("string"), "%Lf"); + perf_test(from + "->container::string" + , conv("string"), "%Lf"); + +} + +struct to_string_conv { + std::string operator()(const char* const c) const { + return c; + } +}; + +struct to_char_conv { + const char* operator()(const char* const c) const { + return c; + } +}; + +struct to_uchar_conv { + const unsigned char* operator()(const char* const c) const { + return reinterpret_cast(c); + } +}; + + +struct to_schar_conv { + const signed char* operator()(const char* const c) const { + return reinterpret_cast(c); + } +}; + +int main(int argc, char** argv) { + BOOST_ASSERT(argc >= 2); + std::string output_path(argv[1]); + output_path += "/results.txt"; + fout.open(output_path.c_str(), std::fstream::in | std::fstream::out | std::fstream::app); + BOOST_ASSERT(fout); + + fout << "[section " << BOOST_COMPILER << "]\n" + << "[table:id Performance Table ( "<< BOOST_COMPILER << ")\n" + << "[[From->To] [lexical_cast] [std::stringstream with construction] " + << "[std::stringstream without construction][scanf/printf]]\n"; + + + // From std::string to ... + string_like_test_set("string"); + + // From ... to std::string + perf_test("string->char", 'c', "%c"); + perf_test("string->signed char", static_cast('c'), "%hhd"); + perf_test("string->unsigned char", static_cast('c'), "%hhu"); + + perf_test("int->string", 100, "%d"); + perf_test("short->string", static_cast(100), "%hd"); + perf_test("long int->string", 100l, "%ld"); + perf_test("long long->string", 100ll, "%lld"); + + perf_test("unsigned int->string", static_cast(100u), "%u"); + perf_test("unsigned short->string", 100u, "%hu"); + perf_test("unsigned long int->string", 100ul, "%lu"); + perf_test("unsigned long long->string", static_cast(100), "%llu"); + + // perf_test("bool->string", std::string("1"), "%"); + + perf_test("float->string", 1.123f, "%f"); + perf_test("double->string", 1.123, "%lf"); + perf_test("long double->string", 1.123L, "%Lf"); + + + string_like_test_set("char*"); + string_like_test_set("unsigned char*"); + string_like_test_set("signed char*"); + + perf_test("int->int", 100, ""); + perf_test("float->double", 100.0f, ""); + perf_test("char->signed char", 'c', ""); + + fout << "]\n" + << "[endsect]\n\n"; + return 0; +} + + diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index c311420..019c9e7 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -38,5 +38,12 @@ test-suite conversion [ run lexical_cast_pointers_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 ] - ; - + [ run lexical_cast_no_locale_test.cpp ../../test/build//boost_unit_test_framework/static : : : BOOST_NO_STD_LOCALE BOOST_LEXICAL_CAST_ASSUME_C_LOCALE ] + [ run lexical_cast_no_exceptions_test.cpp ../../test/build//boost_unit_test_framework/static : : : BOOST_NO_EXCEPTIONS + gcc-4.3:-fno-exceptions + gcc-4.4:-fno-exceptions + gcc-4.5:-fno-exceptions + gcc-4.6:-fno-exceptions + ] + ; + diff --git a/test/lexical_cast_containers_test.cpp b/test/lexical_cast_containers_test.cpp index 5f98ac8..0c6315b 100644 --- a/test/lexical_cast_containers_test.cpp +++ b/test/lexical_cast_containers_test.cpp @@ -13,6 +13,7 @@ #include void testing_boost_containers_basic_string(); +void testing_boost_containers_string_std_string(); using namespace boost; @@ -21,6 +22,7 @@ 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)); + suite->add(BOOST_TEST_CASE(testing_boost_containers_string_std_string)); return suite; } @@ -35,4 +37,24 @@ void testing_boost_containers_basic_string() BOOST_CHECK(1000 == lexical_cast(str)); } +#if defined(BOOST_NO_STRINGSTREAM) || defined(BOOST_NO_STD_WSTRING) +#define BOOST_LCAST_NO_WCHAR_T +#endif +void testing_boost_containers_string_std_string() +{ + std::string std_str("std_str"); + boost::container::string boost_str("boost_str"); + BOOST_CHECK(boost::lexical_cast(boost_str) == "boost_str"); + BOOST_CHECK(boost::lexical_cast(std_str) == "std_str"); + +#ifndef BOOST_LCAST_NO_WCHAR_T + std::wstring std_wstr(L"std_wstr"); + boost::container::wstring boost_wstr(L"boost_wstr"); + + BOOST_CHECK(boost::lexical_cast(boost_wstr) == L"boost_wstr"); + BOOST_CHECK(boost::lexical_cast(std_wstr) == L"std_wstr"); + +#endif + +} diff --git a/test/lexical_cast_empty_input_test.cpp b/test/lexical_cast_empty_input_test.cpp index 5a5881b..df05981 100755 --- a/test/lexical_cast_empty_input_test.cpp +++ b/test/lexical_cast_empty_input_test.cpp @@ -138,6 +138,19 @@ void test_empty_vector() BOOST_CHECK_THROW(lexical_cast(v), bad_lexical_cast); } + +struct my_string { + friend std::ostream &operator<<(std::ostream& sout, my_string const&/* st*/) { + return sout << ""; + } +}; + +void test_empty_zero_terminated_string() +{ + my_string st; + BOOST_CHECK_EQUAL(boost::lexical_cast(st), std::string());; +} + unit_test::test_suite *init_unit_test_suite(int, char *[]) { unit_test::test_suite *suite = @@ -146,6 +159,7 @@ unit_test::test_suite *init_unit_test_suite(int, char *[]) 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)); + suite->add(BOOST_TEST_CASE(&test_empty_zero_terminated_string)); return suite; } diff --git a/test/lexical_cast_inf_nan_test.cpp b/test/lexical_cast_inf_nan_test.cpp index bb4331a..af1caa0 100755 --- a/test/lexical_cast_inf_nan_test.cpp +++ b/test/lexical_cast_inf_nan_test.cpp @@ -85,6 +85,12 @@ void test_inf_nan_templated() BOOST_CHECK( is_pos_inf( lexical_cast("+infinity") ) ); BOOST_CHECK( is_pos_inf( lexical_cast("+INFINITY") ) ); + BOOST_CHECK( is_pos_inf( lexical_cast("iNfiNity") ) ); + BOOST_CHECK( is_pos_inf( lexical_cast("INfinity") ) ); + + BOOST_CHECK( is_neg_inf( lexical_cast("-inFINITY") ) ); + BOOST_CHECK( is_neg_inf( lexical_cast("-INFINITY") ) ); + BOOST_CHECK( is_pos_nan( lexical_cast("nan") ) ); BOOST_CHECK( is_pos_nan( lexical_cast("NAN") ) ); @@ -94,6 +100,15 @@ void test_inf_nan_templated() BOOST_CHECK( is_pos_nan( lexical_cast("+nan") ) ); BOOST_CHECK( is_pos_nan( lexical_cast("+NAN") ) ); + BOOST_CHECK( is_pos_nan( lexical_cast("nAn") ) ); + BOOST_CHECK( is_pos_nan( lexical_cast("NaN") ) ); + + BOOST_CHECK( is_neg_nan( lexical_cast("-nAn") ) ); + BOOST_CHECK( is_neg_nan( lexical_cast("-NaN") ) ); + + BOOST_CHECK( is_pos_nan( lexical_cast("+Nan") ) ); + BOOST_CHECK( is_pos_nan( lexical_cast("+nAN") ) ); + 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 ); @@ -127,6 +142,12 @@ void test_inf_nan_templated() 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") ) ); diff --git a/test/lexical_cast_no_exceptions_test.cpp b/test/lexical_cast_no_exceptions_test.cpp new file mode 100755 index 0000000..8431c3a --- /dev/null +++ b/test/lexical_cast_no_exceptions_test.cpp @@ -0,0 +1,95 @@ +// Unit test for boost::lexical_cast. +// +// See http://www.boost.org for most recent version, including documentation. +// +// Copyright Antony Polukhin, 2012. +// +// Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). + +#include + +#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 + +#ifndef BOOST_NO_EXCEPTIONS +#error "This test must be compiled with -DBOOST_NO_EXCEPTIONS" +#endif + +bool g_was_exception = false; + +namespace boost { + +void throw_exception(std::exception const & ) { + g_was_exception = true; +} + +} + +using namespace boost; + + +struct Escape +{ + 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_; +} + +inline std::istream& operator>> (std::istream& i, Escape& rhs) +{ + return i >> rhs.str_; +} + +void test_exceptions_off() +{ + Escape v(""); + + g_was_exception = false; + lexical_cast(v); + BOOST_CHECK(g_was_exception); + + g_was_exception = false; + lexical_cast(v); + BOOST_CHECK(g_was_exception); + + v = lexical_cast(100); + BOOST_CHECK_EQUAL(lexical_cast(v), 100); + BOOST_CHECK_EQUAL(lexical_cast(v), 100u); + + v = lexical_cast(0.0); + BOOST_CHECK_EQUAL(lexical_cast(v), 0.0); + + BOOST_CHECK_EQUAL(lexical_cast(100), 100); + BOOST_CHECK_EQUAL(lexical_cast(0.0), 0.0); + + g_was_exception = false; + lexical_cast(700000); + BOOST_CHECK(g_was_exception); +} + +unit_test::test_suite *init_unit_test_suite(int, char *[]) +{ + unit_test::test_suite *suite = + BOOST_TEST_SUITE("lexical_cast. Testing with BOOST_NO_EXCEPTIONS"); + suite->add(BOOST_TEST_CASE(&test_exceptions_off)); + + return suite; +} + diff --git a/test/lexical_cast_no_locale_test.cpp b/test/lexical_cast_no_locale_test.cpp new file mode 100755 index 0000000..f3defb3 --- /dev/null +++ b/test/lexical_cast_no_locale_test.cpp @@ -0,0 +1,166 @@ +// Unit test for boost::lexical_cast. +// +// See http://www.boost.org for most recent version, including documentation. +// +// Copyright Antony Polukhin, 2012. +// +// Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). + +#include + +#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 + +using namespace boost; + +// Testing compilation and some basic usage with BOOST_NO_STD_LOCALE +// Tests are mainly copyied from lexical_cast_empty_input_test.cpp (something +// new added to test_empty_3) + +#ifndef BOOST_NO_STD_LOCALE +#error "This test must be compiled with -DBOOST_NO_STD_LOCALE" +#endif + + +template +void do_test_on_empty_input(T& 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); +#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_1() +{ + 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_2() +{ + 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); +} + +struct Escape +{ + 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_; +} + +inline std::istream& operator>> (std::istream& i, Escape& rhs) +{ + return i >> rhs.str_; +} + +void test_empty_3() +{ + 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); + + v = lexical_cast(100); + BOOST_CHECK_EQUAL(lexical_cast(v), 100); + BOOST_CHECK_EQUAL(lexical_cast(v), 100u); + + v = lexical_cast(0.0); + BOOST_CHECK_EQUAL(lexical_cast(v), 0.0); +} + +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_4() +{ + 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); +} + + +struct my_string { + friend std::ostream &operator<<(std::ostream& sout, my_string const&/* st*/) { + return sout << ""; + } +}; + +void test_empty_5() +{ + my_string st; + BOOST_CHECK_EQUAL(boost::lexical_cast(st), std::string());; +} + +unit_test::test_suite *init_unit_test_suite(int, char *[]) +{ + unit_test::test_suite *suite = + BOOST_TEST_SUITE("lexical_cast. Testing with BOOST_NO_STD_LOCALE"); + suite->add(BOOST_TEST_CASE(&test_empty_1)); + suite->add(BOOST_TEST_CASE(&test_empty_2)); + suite->add(BOOST_TEST_CASE(&test_empty_3)); + suite->add(BOOST_TEST_CASE(&test_empty_4)); + suite->add(BOOST_TEST_CASE(&test_empty_5)); + + return suite; +} + diff --git a/test/lexical_cast_typedefed_wchar_test.cpp b/test/lexical_cast_typedefed_wchar_test.cpp index 752c3e5..2dc0098 100755 --- a/test/lexical_cast_typedefed_wchar_test.cpp +++ b/test/lexical_cast_typedefed_wchar_test.cpp @@ -13,12 +13,27 @@ #include #include +#include +#include + +void parseDate() +{ + std::locale locale; + boost::date_time::format_date_parser parser(L"", locale); + boost::date_time::special_values_parser svp; + + boost::gregorian::date date = parser.parse_date(L"", L"", svp); + (void)date; +} + + int main() { #ifdef BOOST_MSVC BOOST_STATIC_ASSERT((boost::is_same::value)); #endif + parseDate(); return ::boost::lexical_cast(L"1000") == 1000; } From 93ee01ab691d75bde4f16740158186bab5b38640 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Thu, 29 Mar 2012 16:48:31 +0000 Subject: [PATCH 43/66] Merge from trunk r77627 (merged lexical_cast optimizations for iterator_range<>, fixed performance regression, docs updated) [SVN r77628] --- doc/lexical_cast.qbk | 802 ++++++++++++---------- include/boost/lexical_cast.hpp | 108 ++- perf/performance_test.cpp | 15 + test/Jamfile.v2 | 1 + test/lexical_cast_iterator_range_test.cpp | 189 +++++ 5 files changed, 753 insertions(+), 362 deletions(-) create mode 100644 test/lexical_cast_iterator_range_test.cpp diff --git a/doc/lexical_cast.qbk b/doc/lexical_cast.qbk index 4ad8336..ffab311 100644 --- a/doc/lexical_cast.qbk +++ b/doc/lexical_cast.qbk @@ -115,6 +115,55 @@ Exception used to indicate runtime lexical_cast failure. [endsect] +[section Tuning classes for fast lexical conversions] +Because of `boost::lexical_cast` optimizations for `boost::iterator_range`, it is possibile to make very fast lexical conversions for non zero terminated strings, substrings and user-defined classes. + +Consider the following example: +`` + class example_class { + char non_zero_terminated_data[10]; + std::size_t data_length; + + public: + example_class(); + void fill_data(); + + const char* data() const { + return non_zero_terminated_data; + } + + std::size_t size() const { + return data_length; + } + }; + + inline std::ostream& operator << (std::ostream& ostr, const example_class& rhs) { + return ostr << boost::make_iterator_range(rhs.data(), rhs.data() + rhs.size()); + } +`` + +This is a good generic solution for most use cases. +But we can make it even faster for some performance critical applications. During conversion, we loose speed at: + +* `std::ostream` construction (it makes some heap allocations) +* `operator <<` (it copyies one by one all the symbols to an instance of `std::ostream`) +* `std::ostream` destruction (it makes some heap deallocations) + +We can avoid all of this, by specifieng an overload for `boost::lexical_cast`: +`` +namespace boost { + template + OutT lexical_cast(const example_class& rhs) { + return boost::lexical_cast( + boost::make_iterator_range(rhs.data(), rhs.data() + rhs.size()) + ); + } +} +`` +Now `boost::lexical_cast(example_class_instance)` conversions won't copy data and construct heavy STL stream objects. See [link boost_lexical_cast.performance Performance] section for info on `boost::iterator_range` conversion performance. +[endsect] + + [section Frequently Asked Questions] * [*Question:] Why does `lexical_cast("127")` throw `bad_lexical_cast`? @@ -175,6 +224,9 @@ limitation of compiler options that you use. , `"-inf"` (case insensitive) strings to get NaN and Inf values. `boost::lexical_cast` outputs `"-nan"`, `"nan"`, `"inf"`, `"-inf"` strings, when has NaN or Inf input values. +* [*Question:] What is the fastest way to convert a non zero terminated string or a substring using `boost::lexical_cast`? + * [*Answer:] Use `boost::iterator_range` for conversion. For example, if you whant to convert to `int` two characters from a string `str`, you shall write `lexacal_cast(make_iterator_range(str.c_str(), str.c_str() + 2));`. + [endsect] [section Changes] @@ -182,7 +234,8 @@ limitation of compiler options that you use. * `boost::bad_lexical_cast` exception is now globaly visible and can be catched even if code is compiled with -fvisibility=hidden. * Now it is possible to compile library with disabled exceptions. - + * Better performance, less memory usage and bugfixes for `boost::iterator_range` conversions. + * [*boost 1.49.0 :] * Restored work with typedefed wchar_t (compilation flag /Zc:wchar_t- for Visual Studio). @@ -267,364 +320,415 @@ Do not use this results to compare compilers, because tests were taken on differ [/ BEGIN of section, generated by performance measuring program ] -[section clang-linux-2.8][table:id Performance Table (clang-linux-2.8) +[section Clang version 2.9 (tags/RELEASE_29/final)] +[table:id Performance Table ( Clang version 2.9 (tags/RELEASE_29/final)) [[From->To] [lexical_cast] [std::stringstream with construction] [std::stringstream without construction][scanf/printf]] -[[ 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 ][ --- ]] + [[ string->char ][ !!! *<1* !!! ][ 319 ][ 17 ][ 16 ]] + [[ string->signed char ][ !!! *<1* !!! ][ 192 ][ 16 ][ 9 ]] + [[ string->unsigned char ][ !!! *<1* !!! ][ 142 ][ 9 ][ 9 ]] + [[ string->int ][ !!! *7* !!! ][ 109 ][ 21 ][ 16 ]] + [[ string->short ][ !!! *6* !!! ][ 113 ][ 21 ][ 15 ]] + [[ string->long int ][ !!! *7* !!! ][ 110 ][ 22 ][ 15 ]] + [[ string->long long ][ !!! *7* !!! ][ 112 ][ 23 ][ 17 ]] + [[ string->unsigned int ][ !!! *6* !!! ][ 107 ][ 19 ][ 14 ]] + [[ string->unsigned short ][ !!! *6* !!! ][ 106 ][ 18 ][ 16 ]] + [[ string->unsigned long int ][ !!! *7* !!! ][ 108 ][ 20 ][ 15 ]] + [[ string->unsigned long long ][ !!! *7* !!! ][ 109 ][ 22 ][ 15 ]] + [[ string->float ][ !!! *14* !!! ][ 204 ][ 81 ][ 43 ]] + [[ string->double ][ !!! *24* !!! ][ 244 ][ 74 ][ 45 ]] + [[ string->long double ][ 121 ][ 170 ][ 62 ][ !!! *38* !!! ]] + [[ string->string ][ !!! *1* !!! ][ 124 ][ 25 ][ --- ]] + [[ string->container::string ][ !!! *3* !!! ][ 121 ][ 28 ][ --- ]] + [[ string->char ][ 6 ][ 115 ][ 26 ][ !!! *6* !!! ]] + [[ string->signed char ][ !!! *6* !!! ][ 115 ][ 23 ][ 21 ]] + [[ string->unsigned char ][ !!! *6* !!! ][ 113 ][ 25 ][ 22 ]] + [[ int->string ][ !!! *12* !!! ][ 128 ][ 29 ][ 19 ]] + [[ short->string ][ !!! *12* !!! ][ 128 ][ 29 ][ 21 ]] + [[ long int->string ][ !!! *12* !!! ][ 132 ][ 29 ][ 21 ]] + [[ long long->string ][ !!! *12* !!! ][ 127 ][ 29 ][ 22 ]] + [[ unsigned int->string ][ !!! *12* !!! ][ 137 ][ 33 ][ 19 ]] + [[ unsigned short->string ][ !!! *12* !!! ][ 137 ][ 31 ][ 20 ]] + [[ unsigned long int->string ][ !!! *12* !!! ][ 136 ][ 30 ][ 21 ]] + [[ unsigned long long->string ][ !!! *12* !!! ][ 128 ][ 27 ][ 23 ]] + [[ float->string ][ 51 ][ 187 ][ 82 ][ !!! *44* !!! ]] + [[ double->string ][ 56 ][ 190 ][ 83 ][ !!! *42* !!! ]] + [[ long double->string ][ 69 ][ 208 ][ 90 ][ !!! *54* !!! ]] + [[ char*->char ][ !!! *<1* !!! ][ 138 ][ 18 ][ 8 ]] + [[ char*->signed char ][ !!! *8* !!! ][ 126 ][ 10 ][ 9 ]] + [[ char*->unsigned char ][ !!! *<1* !!! ][ 98 ][ 9 ][ 9 ]] + [[ char*->int ][ !!! *8* !!! ][ 113 ][ 22 ][ 15 ]] + [[ char*->short ][ !!! *7* !!! ][ 113 ][ 22 ][ 17 ]] + [[ char*->long int ][ !!! *8* !!! ][ 111 ][ 23 ][ 15 ]] + [[ char*->long long ][ !!! *9* !!! ][ 112 ][ 24 ][ 18 ]] + [[ char*->unsigned int ][ !!! *8* !!! ][ 113 ][ 20 ][ 15 ]] + [[ char*->unsigned short ][ !!! *8* !!! ][ 113 ][ 20 ][ 15 ]] + [[ char*->unsigned long int ][ !!! *8* !!! ][ 112 ][ 21 ][ 16 ]] + [[ char*->unsigned long long ][ !!! *9* !!! ][ 110 ][ 23 ][ 14 ]] + [[ char*->float ][ !!! *14* !!! ][ 149 ][ 54 ][ 32 ]] + [[ char*->double ][ !!! *15* !!! ][ 166 ][ 59 ][ 33 ]] + [[ char*->long double ][ 122 ][ 171 ][ 63 ][ !!! *38* !!! ]] + [[ char*->string ][ !!! *7* !!! ][ 126 ][ 26 ][ --- ]] + [[ char*->container::string ][ !!! *2* !!! ][ 124 ][ 27 ][ --- ]] + [[ unsigned char*->char ][ !!! *<1* !!! ][ 99 ][ 10 ][ 8 ]] + [[ unsigned char*->signed char ][ !!! *<1* !!! ][ 102 ][ 10 ][ 9 ]] + [[ unsigned char*->unsigned char ][ !!! *<1* !!! ][ 98 ][ 10 ][ 9 ]] + [[ unsigned char*->int ][ !!! *7* !!! ][ 115 ][ 24 ][ 15 ]] + [[ unsigned char*->short ][ !!! *7* !!! ][ 115 ][ 25 ][ 17 ]] + [[ unsigned char*->long int ][ !!! *8* !!! ][ 115 ][ 22 ][ 16 ]] + [[ unsigned char*->long long ][ !!! *8* !!! ][ 116 ][ 23 ][ 16 ]] + [[ unsigned char*->unsigned int ][ !!! *8* !!! ][ 113 ][ 20 ][ 14 ]] + [[ unsigned char*->unsigned short ][ !!! *7* !!! ][ 114 ][ 21 ][ 15 ]] + [[ unsigned char*->unsigned long int ][ !!! *8* !!! ][ 114 ][ 21 ][ 14 ]] + [[ unsigned char*->unsigned long long ][ !!! *9* !!! ][ 112 ][ 23 ][ 16 ]] + [[ unsigned char*->float ][ !!! *14* !!! ][ 149 ][ 52 ][ 32 ]] + [[ unsigned char*->double ][ !!! *15* !!! ][ 165 ][ 59 ][ 33 ]] + [[ unsigned char*->long double ][ 122 ][ 172 ][ 63 ][ !!! *37* !!! ]] + [[ unsigned char*->string ][ !!! *8* !!! ][ 125 ][ 26 ][ --- ]] + [[ unsigned char*->container::string ][ !!! *4* !!! ][ 119 ][ 26 ][ --- ]] + [[ signed char*->char ][ !!! *<1* !!! ][ 98 ][ 10 ][ 8 ]] + [[ signed char*->signed char ][ !!! *<1* !!! ][ 95 ][ 10 ][ 9 ]] + [[ signed char*->unsigned char ][ !!! *<1* !!! ][ 98 ][ 9 ][ 9 ]] + [[ signed char*->int ][ !!! *8* !!! ][ 111 ][ 21 ][ 15 ]] + [[ signed char*->short ][ !!! *7* !!! ][ 114 ][ 22 ][ 16 ]] + [[ signed char*->long int ][ !!! *8* !!! ][ 113 ][ 22 ][ 17 ]] + [[ signed char*->long long ][ !!! *8* !!! ][ 116 ][ 24 ][ 17 ]] + [[ signed char*->unsigned int ][ !!! *8* !!! ][ 109 ][ 20 ][ 15 ]] + [[ signed char*->unsigned short ][ !!! *8* !!! ][ 111 ][ 20 ][ 14 ]] + [[ signed char*->unsigned long int ][ !!! *8* !!! ][ 109 ][ 22 ][ 15 ]] + [[ signed char*->unsigned long long ][ !!! *8* !!! ][ 111 ][ 23 ][ 15 ]] + [[ signed char*->float ][ !!! *14* !!! ][ 150 ][ 53 ][ 32 ]] + [[ signed char*->double ][ !!! *15* !!! ][ 168 ][ 59 ][ 30 ]] + [[ signed char*->long double ][ 123 ][ 174 ][ 62 ][ !!! *37* !!! ]] + [[ signed char*->string ][ !!! *8* !!! ][ 127 ][ 28 ][ --- ]] + [[ signed char*->container::string ][ !!! *4* !!! ][ 124 ][ 27 ][ --- ]] + [[ iterator_range->char ][ !!! *<1* !!! ][ 103 ][ 13 ][ 8 ]] + [[ iterator_range->signed char ][ !!! *<1* !!! ][ 107 ][ 13 ][ 9 ]] + [[ iterator_range->unsigned char ][ !!! *<1* !!! ][ 121 ][ 26 ][ 13 ]] + [[ iterator_range->int ][ !!! *6* !!! ][ 165 ][ 33 ][ 23 ]] + [[ iterator_range->short ][ !!! *8* !!! ][ 175 ][ 34 ][ 29 ]] + [[ iterator_range->long int ][ !!! *14* !!! ][ 160 ][ 33 ][ 23 ]] + [[ iterator_range->long long ][ !!! *10* !!! ][ 199 ][ 35 ][ 28 ]] + [[ iterator_range->unsigned int ][ !!! *6* !!! ][ 131 ][ 24 ][ 16 ]] + [[ iterator_range->unsigned short ][ !!! *7* !!! ][ 110 ][ 22 ][ 16 ]] + [[ iterator_range->unsigned long int ][ !!! *7* !!! ][ 111 ][ 22 ][ 14 ]] + [[ iterator_range->unsigned long long ][ !!! *8* !!! ][ 115 ][ 24 ][ 15 ]] + [[ iterator_range->float ][ !!! *13* !!! ][ 134 ][ 40 ][ 33 ]] + [[ iterator_range->double ][ !!! *15* !!! ][ 140 ][ 59 ][ 41 ]] + [[ iterator_range->long double ][ 131 ][ 146 ][ 53 ][ !!! *38* !!! ]] + [[ iterator_range->string ][ !!! *9* !!! ][ 121 ][ 31 ][ --- ]] + [[ iterator_range->container::string ][ !!! *4* !!! ][ 115 ][ 25 ][ --- ]] + [[ int->int ][ !!! *<1* !!! ][ 113 ][ 25 ][ --- ]] + [[ float->double ][ !!! *<1* !!! ][ 234 ][ 117 ][ --- ]] + [[ char->signed char ][ !!! *<1* !!! ][ 97 ][ 9 ][ --- ]] ] [endsect] -[section gcc-4.4][table:id Performance Table (gcc-4.4) + +[section GNU C++ version 4.6.1] +[table:id Performance Table ( GNU C++ version 4.6.1) [[From->To] [lexical_cast] [std::stringstream with construction] [std::stringstream without construction][scanf/printf]] -[[ 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 ][ --- ]] + [[ string->char ][ !!! *<1* !!! ][ 140 ][ 17 ][ 13 ]] + [[ string->signed char ][ !!! *<1* !!! ][ 129 ][ 8 ][ 10 ]] + [[ string->unsigned char ][ !!! *<1* !!! ][ 91 ][ 8 ][ 10 ]] + [[ string->int ][ !!! *6* !!! ][ 110 ][ 20 ][ 14 ]] + [[ string->short ][ !!! *5* !!! ][ 106 ][ 20 ][ 14 ]] + [[ string->long int ][ !!! *7* !!! ][ 107 ][ 22 ][ 14 ]] + [[ string->long long ][ !!! *7* !!! ][ 112 ][ 21 ][ 14 ]] + [[ string->unsigned int ][ !!! *6* !!! ][ 110 ][ 20 ][ 14 ]] + [[ string->unsigned short ][ !!! *5* !!! ][ 107 ][ 18 ][ 14 ]] + [[ string->unsigned long int ][ !!! *7* !!! ][ 108 ][ 23 ][ 14 ]] + [[ string->unsigned long long ][ !!! *7* !!! ][ 108 ][ 21 ][ 14 ]] + [[ string->float ][ !!! *12* !!! ][ 154 ][ 57 ][ 32 ]] + [[ string->double ][ !!! *11* !!! ][ 151 ][ 61 ][ 33 ]] + [[ string->long double ][ 109 ][ 187 ][ 79 ][ !!! *55* !!! ]] + [[ string->string ][ !!! *2* !!! ][ 122 ][ 27 ][ --- ]] + [[ string->container::string ][ !!! *3* !!! ][ 123 ][ 22 ][ --- ]] + [[ string->char ][ !!! *7* !!! ][ 109 ][ 27 ][ 17 ]] + [[ string->signed char ][ !!! *7* !!! ][ 110 ][ 25 ][ 22 ]] + [[ string->unsigned char ][ !!! *7* !!! ][ 112 ][ 27 ][ 24 ]] + [[ int->string ][ !!! *12* !!! ][ 187 ][ 48 ][ 37 ]] + [[ short->string ][ !!! *18* !!! ][ 133 ][ 33 ][ 20 ]] + [[ long int->string ][ !!! *12* !!! ][ 129 ][ 32 ][ 21 ]] + [[ long long->string ][ !!! *12* !!! ][ 127 ][ 35 ][ 23 ]] + [[ unsigned int->string ][ !!! *15* !!! ][ 133 ][ 31 ][ 21 ]] + [[ unsigned short->string ][ !!! *12* !!! ][ 133 ][ 31 ][ 21 ]] + [[ unsigned long int->string ][ !!! *12* !!! ][ 132 ][ 31 ][ 21 ]] + [[ unsigned long long->string ][ !!! *12* !!! ][ 127 ][ 29 ][ 24 ]] + [[ float->string ][ 53 ][ 215 ][ 103 ][ !!! *40* !!! ]] + [[ double->string ][ 58 ][ 215 ][ 103 ][ !!! *41* !!! ]] + [[ long double->string ][ 67 ][ 227 ][ 112 ][ !!! *45* !!! ]] + [[ char*->char ][ !!! *<1* !!! ][ 132 ][ 12 ][ 8 ]] + [[ char*->signed char ][ !!! *<1* !!! ][ 98 ][ 11 ][ 9 ]] + [[ char*->unsigned char ][ !!! *<1* !!! ][ 96 ][ 10 ][ 9 ]] + [[ char*->int ][ !!! *6* !!! ][ 109 ][ 22 ][ 14 ]] + [[ char*->short ][ !!! *5* !!! ][ 109 ][ 26 ][ 14 ]] + [[ char*->long int ][ !!! *7* !!! ][ 111 ][ 23 ][ 14 ]] + [[ char*->long long ][ !!! *8* !!! ][ 112 ][ 25 ][ 16 ]] + [[ char*->unsigned int ][ !!! *6* !!! ][ 113 ][ 19 ][ 14 ]] + [[ char*->unsigned short ][ !!! *6* !!! ][ 111 ][ 20 ][ 14 ]] + [[ char*->unsigned long int ][ !!! *7* !!! ][ 109 ][ 21 ][ 14 ]] + [[ char*->unsigned long long ][ !!! *7* !!! ][ 111 ][ 22 ][ 14 ]] + [[ char*->float ][ !!! *12* !!! ][ 156 ][ 62 ][ 32 ]] + [[ char*->double ][ !!! *13* !!! ][ 156 ][ 65 ][ 33 ]] + [[ char*->long double ][ 108 ][ 156 ][ 59 ][ !!! *36* !!! ]] + [[ char*->string ][ !!! *7* !!! ][ 123 ][ 29 ][ --- ]] + [[ char*->container::string ][ !!! *2* !!! ][ 116 ][ 24 ][ --- ]] + [[ unsigned char*->char ][ !!! *<1* !!! ][ 96 ][ 12 ][ 8 ]] + [[ unsigned char*->signed char ][ !!! *<1* !!! ][ 97 ][ 9 ][ 9 ]] + [[ unsigned char*->unsigned char ][ !!! *<1* !!! ][ 93 ][ 10 ][ 9 ]] + [[ unsigned char*->int ][ !!! *6* !!! ][ 110 ][ 22 ][ 14 ]] + [[ unsigned char*->short ][ !!! *6* !!! ][ 111 ][ 22 ][ 15 ]] + [[ unsigned char*->long int ][ !!! *8* !!! ][ 110 ][ 23 ][ 14 ]] + [[ unsigned char*->long long ][ !!! *7* !!! ][ 111 ][ 25 ][ 14 ]] + [[ unsigned char*->unsigned int ][ !!! *6* !!! ][ 111 ][ 21 ][ 16 ]] + [[ unsigned char*->unsigned short ][ !!! *6* !!! ][ 110 ][ 21 ][ 15 ]] + [[ unsigned char*->unsigned long int ][ !!! *8* !!! ][ 114 ][ 21 ][ 14 ]] + [[ unsigned char*->unsigned long long ][ !!! *8* !!! ][ 108 ][ 23 ][ 15 ]] + [[ unsigned char*->float ][ !!! *12* !!! ][ 154 ][ 62 ][ 33 ]] + [[ unsigned char*->double ][ !!! *14* !!! ][ 157 ][ 65 ][ 32 ]] + [[ unsigned char*->long double ][ 107 ][ 154 ][ 56 ][ !!! *36* !!! ]] + [[ unsigned char*->string ][ !!! *9* !!! ][ 122 ][ 28 ][ --- ]] + [[ unsigned char*->container::string ][ !!! *4* !!! ][ 118 ][ 26 ][ --- ]] + [[ signed char*->char ][ !!! *<1* !!! ][ 94 ][ 10 ][ 8 ]] + [[ signed char*->signed char ][ !!! *<1* !!! ][ 94 ][ 12 ][ 9 ]] + [[ signed char*->unsigned char ][ !!! *<1* !!! ][ 95 ][ 12 ][ 9 ]] + [[ signed char*->int ][ !!! *7* !!! ][ 109 ][ 22 ][ 14 ]] + [[ signed char*->short ][ !!! *5* !!! ][ 108 ][ 22 ][ 14 ]] + [[ signed char*->long int ][ !!! *7* !!! ][ 110 ][ 23 ][ 14 ]] + [[ signed char*->long long ][ !!! *7* !!! ][ 110 ][ 25 ][ 15 ]] + [[ signed char*->unsigned int ][ !!! *6* !!! ][ 109 ][ 20 ][ 15 ]] + [[ signed char*->unsigned short ][ !!! *6* !!! ][ 107 ][ 21 ][ 14 ]] + [[ signed char*->unsigned long int ][ !!! *8* !!! ][ 111 ][ 21 ][ 14 ]] + [[ signed char*->unsigned long long ][ !!! *7* !!! ][ 109 ][ 23 ][ 14 ]] + [[ signed char*->float ][ !!! *12* !!! ][ 156 ][ 61 ][ 31 ]] + [[ signed char*->double ][ !!! *13* !!! ][ 156 ][ 68 ][ 33 ]] + [[ signed char*->long double ][ 109 ][ 159 ][ 56 ][ !!! *36* !!! ]] + [[ signed char*->string ][ !!! *9* !!! ][ 123 ][ 28 ][ --- ]] + [[ signed char*->container::string ][ !!! *4* !!! ][ 125 ][ 25 ][ --- ]] + [[ iterator_range->char ][ !!! *<1* !!! ][ 100 ][ 13 ][ 8 ]] + [[ iterator_range->signed char ][ !!! *<1* !!! ][ 98 ][ 14 ][ 9 ]] + [[ iterator_range->unsigned char ][ !!! *<1* !!! ][ 99 ][ 12 ][ 10 ]] + [[ iterator_range->int ][ !!! *6* !!! ][ 108 ][ 21 ][ 16 ]] + [[ iterator_range->short ][ !!! *5* !!! ][ 110 ][ 22 ][ 17 ]] + [[ iterator_range->long int ][ !!! *7* !!! ][ 107 ][ 22 ][ 15 ]] + [[ iterator_range->long long ][ !!! *7* !!! ][ 110 ][ 27 ][ 15 ]] + [[ iterator_range->unsigned int ][ !!! *6* !!! ][ 107 ][ 24 ][ 15 ]] + [[ iterator_range->unsigned short ][ !!! *5* !!! ][ 106 ][ 21 ][ 15 ]] + [[ iterator_range->unsigned long int ][ !!! *7* !!! ][ 110 ][ 21 ][ 16 ]] + [[ iterator_range->unsigned long long ][ !!! *7* !!! ][ 109 ][ 23 ][ 16 ]] + [[ iterator_range->float ][ !!! *11* !!! ][ 137 ][ 46 ][ 33 ]] + [[ iterator_range->double ][ !!! *11* !!! ][ 131 ][ 50 ][ 33 ]] + [[ iterator_range->long double ][ 107 ][ 136 ][ 44 ][ !!! *39* !!! ]] + [[ iterator_range->string ][ !!! *8* !!! ][ 117 ][ 32 ][ --- ]] + [[ iterator_range->container::string ][ !!! *3* !!! ][ 111 ][ 23 ][ --- ]] + [[ int->int ][ !!! *<1* !!! ][ 110 ][ 33 ][ --- ]] + [[ float->double ][ !!! *<1* !!! ][ 241 ][ 152 ][ --- ]] + [[ char->signed char ][ !!! *<1* !!! ][ 90 ][ 8 ][ --- ]] ] [endsect] -[section gcc-4.5][table:id Performance Table (gcc-4.5) + +[section GNU C++ version 4.5.4] +[table:id Performance Table ( GNU C++ version 4.5.4) [[From->To] [lexical_cast] [std::stringstream with construction] [std::stringstream without construction][scanf/printf]] -[[ 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 ][ --- ]] + [[ string->char ][ !!! *<1* !!! ][ 147 ][ 12 ][ 8 ]] + [[ string->signed char ][ !!! *<1* !!! ][ 138 ][ 13 ][ 10 ]] + [[ string->unsigned char ][ !!! *<1* !!! ][ 86 ][ 12 ][ 9 ]] + [[ string->int ][ !!! *7* !!! ][ 103 ][ 20 ][ 15 ]] + [[ string->short ][ !!! *5* !!! ][ 103 ][ 20 ][ 15 ]] + [[ string->long int ][ !!! *7* !!! ][ 103 ][ 22 ][ 15 ]] + [[ string->long long ][ !!! *7* !!! ][ 104 ][ 22 ][ 16 ]] + [[ string->unsigned int ][ !!! *6* !!! ][ 108 ][ 19 ][ 15 ]] + [[ string->unsigned short ][ !!! *5* !!! ][ 104 ][ 19 ][ 15 ]] + [[ string->unsigned long int ][ !!! *7* !!! ][ 103 ][ 20 ][ 16 ]] + [[ string->unsigned long long ][ !!! *7* !!! ][ 101 ][ 22 ][ 14 ]] + [[ string->float ][ !!! *13* !!! ][ 148 ][ 58 ][ 35 ]] + [[ string->double ][ !!! *13* !!! ][ 147 ][ 60 ][ 34 ]] + [[ string->long double ][ 103 ][ 149 ][ 56 ][ !!! *38* !!! ]] + [[ string->string ][ !!! *2* !!! ][ 127 ][ 27 ][ --- ]] + [[ string->container::string ][ !!! *3* !!! ][ 101 ][ 24 ][ --- ]] + [[ string->char ][ !!! *7* !!! ][ 108 ][ 35 ][ 17 ]] + [[ string->signed char ][ !!! *7* !!! ][ 112 ][ 26 ][ 23 ]] + [[ string->unsigned char ][ !!! *7* !!! ][ 113 ][ 25 ][ 25 ]] + [[ int->string ][ !!! *11* !!! ][ 183 ][ 47 ][ 40 ]] + [[ short->string ][ !!! *14* !!! ][ 153 ][ 35 ][ 23 ]] + [[ long int->string ][ !!! *12* !!! ][ 135 ][ 32 ][ 22 ]] + [[ long long->string ][ !!! *11* !!! ][ 131 ][ 30 ][ 24 ]] + [[ unsigned int->string ][ !!! *12* !!! ][ 137 ][ 31 ][ 22 ]] + [[ unsigned short->string ][ !!! *11* !!! ][ 137 ][ 33 ][ 22 ]] + [[ unsigned long int->string ][ !!! *11* !!! ][ 136 ][ 36 ][ 23 ]] + [[ unsigned long long->string ][ !!! *11* !!! ][ 127 ][ 29 ][ 23 ]] + [[ float->string ][ 56 ][ 218 ][ 107 ][ !!! *44* !!! ]] + [[ double->string ][ 63 ][ 223 ][ 106 ][ !!! *44* !!! ]] + [[ long double->string ][ 69 ][ 229 ][ 118 ][ !!! *49* !!! ]] + [[ char*->char ][ !!! *<1* !!! ][ 91 ][ 12 ][ 9 ]] + [[ char*->signed char ][ !!! *<1* !!! ][ 100 ][ 11 ][ 11 ]] + [[ char*->unsigned char ][ !!! *<1* !!! ][ 97 ][ 12 ][ 10 ]] + [[ char*->int ][ !!! *7* !!! ][ 112 ][ 23 ][ 16 ]] + [[ char*->short ][ !!! *6* !!! ][ 116 ][ 23 ][ 16 ]] + [[ char*->long int ][ !!! *8* !!! ][ 113 ][ 23 ][ 16 ]] + [[ char*->long long ][ !!! *8* !!! ][ 122 ][ 28 ][ 16 ]] + [[ char*->unsigned int ][ !!! *6* !!! ][ 117 ][ 21 ][ 15 ]] + [[ char*->unsigned short ][ !!! *6* !!! ][ 113 ][ 21 ][ 16 ]] + [[ char*->unsigned long int ][ !!! *7* !!! ][ 118 ][ 22 ][ 16 ]] + [[ char*->unsigned long long ][ !!! *8* !!! ][ 113 ][ 22 ][ 17 ]] + [[ char*->float ][ !!! *11* !!! ][ 164 ][ 67 ][ 34 ]] + [[ char*->double ][ !!! *13* !!! ][ 163 ][ 66 ][ 35 ]] + [[ char*->long double ][ 110 ][ 164 ][ 63 ][ !!! *39* !!! ]] + [[ char*->string ][ !!! *8* !!! ][ 130 ][ 30 ][ --- ]] + [[ char*->container::string ][ !!! *2* !!! ][ 113 ][ 24 ][ --- ]] + [[ unsigned char*->char ][ !!! *<1* !!! ][ 98 ][ 11 ][ 10 ]] + [[ unsigned char*->signed char ][ !!! *<1* !!! ][ 97 ][ 12 ][ 10 ]] + [[ unsigned char*->unsigned char ][ !!! *<1* !!! ][ 97 ][ 11 ][ 10 ]] + [[ unsigned char*->int ][ !!! *7* !!! ][ 112 ][ 23 ][ 16 ]] + [[ unsigned char*->short ][ !!! *6* !!! ][ 115 ][ 22 ][ 20 ]] + [[ unsigned char*->long int ][ !!! *8* !!! ][ 112 ][ 23 ][ 15 ]] + [[ unsigned char*->long long ][ !!! *8* !!! ][ 115 ][ 29 ][ 17 ]] + [[ unsigned char*->unsigned int ][ !!! *6* !!! ][ 114 ][ 21 ][ 14 ]] + [[ unsigned char*->unsigned short ][ !!! *7* !!! ][ 112 ][ 22 ][ 15 ]] + [[ unsigned char*->unsigned long int ][ !!! *7* !!! ][ 115 ][ 23 ][ 14 ]] + [[ unsigned char*->unsigned long long ][ !!! *8* !!! ][ 112 ][ 24 ][ 15 ]] + [[ unsigned char*->float ][ !!! *12* !!! ][ 161 ][ 66 ][ 34 ]] + [[ unsigned char*->double ][ !!! *13* !!! ][ 162 ][ 66 ][ 36 ]] + [[ unsigned char*->long double ][ 112 ][ 161 ][ 63 ][ !!! *39* !!! ]] + [[ unsigned char*->string ][ !!! *9* !!! ][ 127 ][ 29 ][ --- ]] + [[ unsigned char*->container::string ][ !!! *4* !!! ][ 111 ][ 25 ][ --- ]] + [[ signed char*->char ][ !!! *<1* !!! ][ 104 ][ 11 ][ 8 ]] + [[ signed char*->signed char ][ !!! *<1* !!! ][ 98 ][ 11 ][ 11 ]] + [[ signed char*->unsigned char ][ !!! *<1* !!! ][ 98 ][ 11 ][ 11 ]] + [[ signed char*->int ][ !!! *7* !!! ][ 112 ][ 23 ][ 16 ]] + [[ signed char*->short ][ !!! *7* !!! ][ 113 ][ 23 ][ 15 ]] + [[ signed char*->long int ][ !!! *8* !!! ][ 112 ][ 22 ][ 14 ]] + [[ signed char*->long long ][ !!! *8* !!! ][ 115 ][ 25 ][ 16 ]] + [[ signed char*->unsigned int ][ !!! *8* !!! ][ 114 ][ 21 ][ 18 ]] + [[ signed char*->unsigned short ][ !!! *6* !!! ][ 112 ][ 22 ][ 15 ]] + [[ signed char*->unsigned long int ][ !!! *8* !!! ][ 116 ][ 22 ][ 15 ]] + [[ signed char*->unsigned long long ][ !!! *8* !!! ][ 113 ][ 23 ][ 16 ]] + [[ signed char*->float ][ !!! *13* !!! ][ 161 ][ 65 ][ 34 ]] + [[ signed char*->double ][ !!! *12* !!! ][ 172 ][ 67 ][ 34 ]] + [[ signed char*->long double ][ 110 ][ 164 ][ 63 ][ !!! *38* !!! ]] + [[ signed char*->string ][ !!! *9* !!! ][ 131 ][ 30 ][ --- ]] + [[ signed char*->container::string ][ !!! *4* !!! ][ 112 ][ 24 ][ --- ]] + [[ iterator_range->char ][ !!! *<1* !!! ][ 103 ][ 12 ][ 8 ]] + [[ iterator_range->signed char ][ !!! *<1* !!! ][ 101 ][ 13 ][ 9 ]] + [[ iterator_range->unsigned char ][ !!! *<1* !!! ][ 103 ][ 13 ][ 10 ]] + [[ iterator_range->int ][ !!! *7* !!! ][ 113 ][ 26 ][ 14 ]] + [[ iterator_range->short ][ !!! *5* !!! ][ 115 ][ 21 ][ 16 ]] + [[ iterator_range->long int ][ !!! *7* !!! ][ 115 ][ 22 ][ 15 ]] + [[ iterator_range->long long ][ !!! *7* !!! ][ 116 ][ 25 ][ 16 ]] + [[ iterator_range->unsigned int ][ !!! *6* !!! ][ 115 ][ 24 ][ 23 ]] + [[ iterator_range->unsigned short ][ !!! *5* !!! ][ 113 ][ 22 ][ 16 ]] + [[ iterator_range->unsigned long int ][ !!! *7* !!! ][ 117 ][ 20 ][ 16 ]] + [[ iterator_range->unsigned long long ][ !!! *7* !!! ][ 114 ][ 21 ][ 16 ]] + [[ iterator_range->float ][ !!! *11* !!! ][ 145 ][ 51 ][ 34 ]] + [[ iterator_range->double ][ !!! *11* !!! ][ 139 ][ 53 ][ 35 ]] + [[ iterator_range->long double ][ 109 ][ 147 ][ 44 ][ !!! *38* !!! ]] + [[ iterator_range->string ][ !!! *9* !!! ][ 123 ][ 36 ][ --- ]] + [[ iterator_range->container::string ][ !!! *3* !!! ][ 113 ][ 20 ][ --- ]] + [[ int->int ][ !!! *<1* !!! ][ 117 ][ 23 ][ --- ]] + [[ float->double ][ !!! *<1* !!! ][ 262 ][ 150 ][ --- ]] + [[ char->signed char ][ !!! *<1* !!! ][ 97 ][ 9 ][ --- ]] ] [endsect] -[section gcc-4.6][table:id Performance Table (gcc-4.6) + +[section GNU C++ version 4.4.6] +[table:id Performance Table ( GNU C++ version 4.4.6) [[From->To] [lexical_cast] [std::stringstream with construction] [std::stringstream without construction][scanf/printf]] -[[ 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 ][ --- ]] + [[ string->char ][ !!! *<1* !!! ][ 162 ][ 17 ][ 8 ]] + [[ string->signed char ][ !!! *<1* !!! ][ 103 ][ 9 ][ 9 ]] + [[ string->unsigned char ][ !!! *<1* !!! ][ 91 ][ 9 ][ 9 ]] + [[ string->int ][ !!! *6* !!! ][ 104 ][ 21 ][ 14 ]] + [[ string->short ][ !!! *5* !!! ][ 107 ][ 22 ][ 14 ]] + [[ string->long int ][ !!! *7* !!! ][ 106 ][ 23 ][ 15 ]] + [[ string->long long ][ !!! *7* !!! ][ 104 ][ 21 ][ 16 ]] + [[ string->unsigned int ][ !!! *6* !!! ][ 100 ][ 20 ][ 16 ]] + [[ string->unsigned short ][ !!! *5* !!! ][ 102 ][ 20 ][ 16 ]] + [[ string->unsigned long int ][ !!! *7* !!! ][ 106 ][ 25 ][ 16 ]] + [[ string->unsigned long long ][ !!! *7* !!! ][ 109 ][ 25 ][ 14 ]] + [[ string->float ][ !!! *13* !!! ][ 142 ][ 48 ][ 32 ]] + [[ string->double ][ !!! *13* !!! ][ 162 ][ 62 ][ 33 ]] + [[ string->long double ][ 119 ][ 164 ][ 62 ][ !!! *37* !!! ]] + [[ string->string ][ !!! *2* !!! ][ 122 ][ 27 ][ --- ]] + [[ string->container::string ][ !!! *2* !!! ][ 107 ][ 23 ][ --- ]] + [[ string->char ][ !!! *6* !!! ][ 110 ][ 24 ][ 15 ]] + [[ string->signed char ][ !!! *6* !!! ][ 107 ][ 24 ][ 21 ]] + [[ string->unsigned char ][ !!! *6* !!! ][ 106 ][ 27 ][ 21 ]] + [[ int->string ][ !!! *12* !!! ][ 122 ][ 31 ][ 21 ]] + [[ short->string ][ !!! *12* !!! ][ 136 ][ 29 ][ 20 ]] + [[ long int->string ][ !!! *12* !!! ][ 127 ][ 32 ][ 19 ]] + [[ long long->string ][ !!! *12* !!! ][ 121 ][ 32 ][ 21 ]] + [[ unsigned int->string ][ !!! *12* !!! ][ 133 ][ 32 ][ 19 ]] + [[ unsigned short->string ][ !!! *12* !!! ][ 126 ][ 33 ][ 20 ]] + [[ unsigned long int->string ][ !!! *11* !!! ][ 126 ][ 34 ][ 19 ]] + [[ unsigned long long->string ][ !!! *12* !!! ][ 125 ][ 28 ][ 21 ]] + [[ float->string ][ 47 ][ 183 ][ 86 ][ !!! *43* !!! ]] + [[ double->string ][ 57 ][ 184 ][ 90 ][ !!! *42* !!! ]] + [[ long double->string ][ 64 ][ 199 ][ 87 ][ !!! *46* !!! ]] + [[ char*->char ][ !!! *<1* !!! ][ 95 ][ 10 ][ 8 ]] + [[ char*->signed char ][ !!! *<1* !!! ][ 90 ][ 12 ][ 9 ]] + [[ char*->unsigned char ][ !!! *<1* !!! ][ 93 ][ 12 ][ 9 ]] + [[ char*->int ][ !!! *6* !!! ][ 108 ][ 24 ][ 14 ]] + [[ char*->short ][ !!! *6* !!! ][ 106 ][ 23 ][ 14 ]] + [[ char*->long int ][ !!! *7* !!! ][ 107 ][ 24 ][ 17 ]] + [[ char*->long long ][ !!! *7* !!! ][ 109 ][ 25 ][ 17 ]] + [[ char*->unsigned int ][ !!! *6* !!! ][ 104 ][ 23 ][ 17 ]] + [[ char*->unsigned short ][ !!! *6* !!! ][ 102 ][ 22 ][ 17 ]] + [[ char*->unsigned long int ][ !!! *7* !!! ][ 107 ][ 23 ][ 17 ]] + [[ char*->unsigned long long ][ !!! *7* !!! ][ 115 ][ 26 ][ 14 ]] + [[ char*->float ][ !!! *12* !!! ][ 150 ][ 56 ][ 30 ]] + [[ char*->double ][ !!! *12* !!! ][ 165 ][ 66 ][ 32 ]] + [[ char*->long double ][ 116 ][ 173 ][ 66 ][ !!! *37* !!! ]] + [[ char*->string ][ !!! *7* !!! ][ 120 ][ 28 ][ --- ]] + [[ char*->container::string ][ !!! *2* !!! ][ 108 ][ 26 ][ --- ]] + [[ unsigned char*->char ][ !!! *<1* !!! ][ 90 ][ 12 ][ 8 ]] + [[ unsigned char*->signed char ][ !!! *<1* !!! ][ 91 ][ 11 ][ 9 ]] + [[ unsigned char*->unsigned char ][ !!! *<1* !!! ][ 91 ][ 12 ][ 9 ]] + [[ unsigned char*->int ][ !!! *6* !!! ][ 106 ][ 24 ][ 14 ]] + [[ unsigned char*->short ][ !!! *6* !!! ][ 108 ][ 24 ][ 14 ]] + [[ unsigned char*->long int ][ !!! *7* !!! ][ 116 ][ 23 ][ 14 ]] + [[ unsigned char*->long long ][ !!! *7* !!! ][ 108 ][ 28 ][ 14 ]] + [[ unsigned char*->unsigned int ][ !!! *6* !!! ][ 107 ][ 22 ][ 14 ]] + [[ unsigned char*->unsigned short ][ !!! *6* !!! ][ 105 ][ 21 ][ 16 ]] + [[ unsigned char*->unsigned long int ][ !!! *7* !!! ][ 106 ][ 25 ][ 16 ]] + [[ unsigned char*->unsigned long long ][ !!! *7* !!! ][ 105 ][ 24 ][ 17 ]] + [[ unsigned char*->float ][ !!! *14* !!! ][ 150 ][ 57 ][ 33 ]] + [[ unsigned char*->double ][ !!! *14* !!! ][ 171 ][ 72 ][ 34 ]] + [[ unsigned char*->long double ][ 118 ][ 171 ][ 73 ][ !!! *38* !!! ]] + [[ unsigned char*->string ][ !!! *8* !!! ][ 120 ][ 29 ][ --- ]] + [[ unsigned char*->container::string ][ !!! *3* !!! ][ 114 ][ 26 ][ --- ]] + [[ signed char*->char ][ !!! *<1* !!! ][ 92 ][ 12 ][ 8 ]] + [[ signed char*->signed char ][ !!! *<1* !!! ][ 92 ][ 12 ][ 9 ]] + [[ signed char*->unsigned char ][ !!! *<1* !!! ][ 91 ][ 14 ][ 9 ]] + [[ signed char*->int ][ !!! *6* !!! ][ 109 ][ 22 ][ 15 ]] + [[ signed char*->short ][ !!! *6* !!! ][ 106 ][ 24 ][ 17 ]] + [[ signed char*->long int ][ !!! *7* !!! ][ 107 ][ 24 ][ 16 ]] + [[ signed char*->long long ][ !!! *7* !!! ][ 106 ][ 24 ][ 14 ]] + [[ signed char*->unsigned int ][ !!! *6* !!! ][ 106 ][ 22 ][ 14 ]] + [[ signed char*->unsigned short ][ !!! *6* !!! ][ 104 ][ 20 ][ 14 ]] + [[ signed char*->unsigned long int ][ !!! *7* !!! ][ 105 ][ 22 ][ 16 ]] + [[ signed char*->unsigned long long ][ !!! *7* !!! ][ 108 ][ 24 ][ 15 ]] + [[ signed char*->float ][ !!! *14* !!! ][ 147 ][ 54 ][ 32 ]] + [[ signed char*->double ][ !!! *14* !!! ][ 170 ][ 68 ][ 37 ]] + [[ signed char*->long double ][ 133 ][ 167 ][ 66 ][ !!! *37* !!! ]] + [[ signed char*->string ][ !!! *8* !!! ][ 119 ][ 30 ][ --- ]] + [[ signed char*->container::string ][ !!! *3* !!! ][ 108 ][ 24 ][ --- ]] + [[ iterator_range->char ][ !!! *<1* !!! ][ 98 ][ 13 ][ 8 ]] + [[ iterator_range->signed char ][ !!! *<1* !!! ][ 98 ][ 15 ][ 9 ]] + [[ iterator_range->unsigned char ][ !!! *<1* !!! ][ 97 ][ 15 ][ 9 ]] + [[ iterator_range->int ][ !!! *6* !!! ][ 107 ][ 27 ][ 14 ]] + [[ iterator_range->short ][ !!! *5* !!! ][ 109 ][ 23 ][ 14 ]] + [[ iterator_range->long int ][ !!! *7* !!! ][ 109 ][ 22 ][ 14 ]] + [[ iterator_range->long long ][ !!! *7* !!! ][ 107 ][ 24 ][ 14 ]] + [[ iterator_range->unsigned int ][ !!! *6* !!! ][ 120 ][ 23 ][ 14 ]] + [[ iterator_range->unsigned short ][ !!! *5* !!! ][ 104 ][ 21 ][ 17 ]] + [[ iterator_range->unsigned long int ][ !!! *8* !!! ][ 108 ][ 25 ][ 16 ]] + [[ iterator_range->unsigned long long ][ !!! *7* !!! ][ 106 ][ 25 ][ 15 ]] + [[ iterator_range->float ][ !!! *13* !!! ][ 132 ][ 41 ][ 32 ]] + [[ iterator_range->double ][ !!! *12* !!! ][ 136 ][ 45 ][ 32 ]] + [[ iterator_range->long double ][ 113 ][ 138 ][ 50 ][ !!! *36* !!! ]] + [[ iterator_range->string ][ !!! *7* !!! ][ 114 ][ 33 ][ --- ]] + [[ iterator_range->container::string ][ !!! *2* !!! ][ 105 ][ 24 ][ --- ]] + [[ int->int ][ !!! *<1* !!! ][ 112 ][ 31 ][ --- ]] + [[ float->double ][ !!! *<1* !!! ][ 233 ][ 199 ][ --- ]] + [[ char->signed char ][ !!! *<1* !!! ][ 129 ][ 10 ][ --- ]] ] [endsect] diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index b73c741..fb1808f 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -72,6 +72,7 @@ _CRTIMP int __cdecl vswprintf(wchar_t * __restrict__ , const wchar_t * __restric #include #include #include +#include #if !defined(__SUNPRO_CC) #include #endif // !defined(__SUNPRO_CC) @@ -166,6 +167,18 @@ namespace boost }; #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + template + struct stream_char > + { + typedef BOOST_DEDUCED_TYPENAME stream_char::type type; + }; + + template + struct stream_char > + { + typedef BOOST_DEDUCED_TYPENAME stream_char::type type; + }; + template struct stream_char< std::basic_string > { @@ -1225,7 +1238,7 @@ namespace boost 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." + "boost::lexical_cast does not support conversions from wchar_t to char types." "Use boost::locale instead" ); #ifndef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE std::locale loc; @@ -1397,6 +1410,52 @@ namespace boost return true; } + bool operator<<(const iterator_range& rng) + { + start = rng.begin(); + finish = rng.end(); + return true; + } + + bool operator<<(const iterator_range& rng) + { + start = const_cast(rng.begin()); + finish = const_cast(rng.end()); + return true; + } + + bool operator<<(const iterator_range& rng) + { + return (*this) << iterator_range( + const_cast(reinterpret_cast(rng.begin())), + const_cast(reinterpret_cast(rng.end())) + ); + } + + bool operator<<(const iterator_range& rng) + { + return (*this) << iterator_range( + const_cast(reinterpret_cast(rng.begin())), + const_cast(reinterpret_cast(rng.end())) + ); + } + + bool operator<<(const iterator_range& rng) + { + return (*this) << iterator_range( + reinterpret_cast(rng.begin()), + reinterpret_cast(rng.end()) + ); + } + + bool operator<<(const iterator_range& rng) + { + return (*this) << iterator_range( + reinterpret_cast(rng.begin()), + reinterpret_cast(rng.end()) + ); + } + 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)); } @@ -1572,7 +1631,7 @@ namespace boost inline bool shr_xchar(T& output) { BOOST_STATIC_ASSERT_MSG(( sizeof(CharT) == sizeof(T) ), - "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" ); bool const ok = (finish - start == 1); if(ok) { @@ -1801,6 +1860,24 @@ namespace boost ); }; + template + struct is_char_iterator_range + { + BOOST_STATIC_CONSTANT(bool, value = false ); + }; + + template + struct is_char_iterator_range > + { + BOOST_STATIC_CONSTANT(bool, value = (is_char_or_wchar::value) ); + }; + + template + struct is_char_iterator_range > + { + BOOST_STATIC_CONSTANT(bool, value = (is_char_or_wchar::value) ); + }; + template struct is_arithmetic_and_not_xchars { @@ -1889,10 +1966,10 @@ namespace boost static inline Target lexical_cast_impl(const Source& arg) { typedef BOOST_DEDUCED_TYPENAME detail::array_to_pointer_decay::type src; - + typedef BOOST_DEDUCED_TYPENAME detail::stream_char::type target_char_t; + typedef BOOST_DEDUCED_TYPENAME detail::stream_char::type src_char_type; typedef BOOST_DEDUCED_TYPENAME detail::widest_char< - BOOST_DEDUCED_TYPENAME detail::stream_char::type - , BOOST_DEDUCED_TYPENAME detail::stream_char::type + target_char_t, src_char_type >::type char_type; typedef detail::lcast_src_length lcast_src_length; @@ -1903,7 +1980,8 @@ namespace boost typedef BOOST_DEDUCED_TYPENAME deduce_char_traits::type traits; - typedef BOOST_DEDUCED_TYPENAME remove_pointer::type removed_ptr_t; + typedef BOOST_DEDUCED_TYPENAME remove_pointer::type removed_ptr_t_1; + typedef BOOST_DEDUCED_TYPENAME remove_cv::type removed_ptr_t; // is_char_types_match variable value can be computed via // sizeof(char_type) == sizeof(removed_ptr_t). But when @@ -1914,12 +1992,12 @@ namespace boost ::boost::type_traits::ice_and< ::boost::type_traits::ice_eq::value, ::boost::type_traits::ice_or< - ::boost::is_same::value, - ::boost::is_same::value, - ::boost::is_same::value + ::boost::is_same::value, + ::boost::is_same::value, + ::boost::is_same::value >::value >::value, - is_same::value + is_same::value >::value); const bool requires_stringbuf = @@ -1928,14 +2006,18 @@ namespace boost is_stdstring::value, is_arithmetic::value, ::boost::type_traits::ice_and< - is_pointer::value, - is_char_or_wchar::value, + is_char_iterator_range::value, + is_char_types_match + >::value, + ::boost::type_traits::ice_and< + is_pointer::value, + is_char_or_wchar::value, is_char_types_match >::value >::value ); - detail::lexical_stream_limited_src + detail::lexical_stream_limited_src interpreter(buf, buf + src_len); Target result; diff --git a/perf/performance_test.cpp b/perf/performance_test.cpp index ff1eb1d..8640bc4 100644 --- a/perf/performance_test.cpp +++ b/perf/performance_test.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include // File to output data @@ -74,6 +75,12 @@ struct structure_sscanf { OutT out_val; sscanf(in_val.c_str(), conv, &out_val); } + + template + static inline void test(BufferT* /*buffer*/, const boost::iterator_range& in_val, const char* const conv) { + OutT out_val; + sscanf(in_val.begin(), conv, &out_val); + } }; struct structure_fake { @@ -255,6 +262,12 @@ struct to_schar_conv { } }; +struct to_iterator_range { + boost::iterator_range operator()(const char* const c) const { + return boost::make_iterator_range(c, c + std::strlen(c)); + } +}; + int main(int argc, char** argv) { BOOST_ASSERT(argc >= 2); std::string output_path(argv[1]); @@ -296,11 +309,13 @@ int main(int argc, char** argv) { string_like_test_set("char*"); string_like_test_set("unsigned char*"); string_like_test_set("signed char*"); + string_like_test_set("iterator_range"); perf_test("int->int", 100, ""); perf_test("float->double", 100.0f, ""); perf_test("char->signed char", 'c', ""); + fout << "]\n" << "[endsect]\n\n"; return 0; diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 019c9e7..131fa3e 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -45,5 +45,6 @@ test-suite conversion gcc-4.5:-fno-exceptions gcc-4.6:-fno-exceptions ] + [ run lexical_cast_iterator_range_test.cpp ../../test/build//boost_unit_test_framework/static ] ; diff --git a/test/lexical_cast_iterator_range_test.cpp b/test/lexical_cast_iterator_range_test.cpp new file mode 100644 index 0000000..7afb1ae --- /dev/null +++ b/test/lexical_cast_iterator_range_test.cpp @@ -0,0 +1,189 @@ +// Unit test for boost::lexical_cast. +// +// See http://www.boost.org for most recent version, including documentation. +// +// Copyright Antony Polukhin, 2012. +// +// Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). + +#include + +#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 + +using namespace boost; + +#if defined(BOOST_NO_STRINGSTREAM) || defined(BOOST_NO_STD_WSTRING) +#define BOOST_LCAST_NO_WCHAR_T +#endif + +struct class_with_user_defined_sream_operators { + int i; + + operator int() const { + return i; + } +}; + +template +inline std::basic_istream& operator >> (std::basic_istream& istr, class_with_user_defined_sream_operators& rhs) +{ + return istr >> rhs.i; +} + + +template +void do_test_iterator_range(const RngT& rng) +{ + BOOST_CHECK_EQUAL(lexical_cast(rng), 1); + BOOST_CHECK_EQUAL(lexical_cast(rng), 1u); + BOOST_CHECK_EQUAL(lexical_cast(rng), 1); + BOOST_CHECK_EQUAL(lexical_cast(rng), 1u); + BOOST_CHECK_EQUAL(lexical_cast(rng), 1); + BOOST_CHECK_EQUAL(lexical_cast(rng), 1u); + BOOST_CHECK_EQUAL(lexical_cast(rng), 1.0f); + BOOST_CHECK_EQUAL(lexical_cast(rng), 1.0); + BOOST_CHECK_EQUAL(lexical_cast(rng), 1.0L); + BOOST_CHECK_EQUAL(lexical_cast(rng), 1); + +#if defined(BOOST_HAS_LONG_LONG) + BOOST_CHECK_EQUAL(lexical_cast(rng), 1u); + BOOST_CHECK_EQUAL(lexical_cast(rng), 1); +#elif defined(BOOST_HAS_MS_INT64) + BOOST_CHECK_EQUAL(lexical_cast(rng), 1u); + BOOST_CHECK_EQUAL(lexical_cast<__int64>(rng), 1); +#endif + +#ifndef BOOST_LCAST_NO_WCHAR_T + BOOST_CHECK(lexical_cast(rng) == L"1"); +#endif +} + +void test_char_iterator_ranges() +{ + typedef char test_char_type; + + // Zero terminated + test_char_type data1[] = "1"; + iterator_range rng1(data1, data1 + 1); + do_test_iterator_range(rng1); + BOOST_CHECK_EQUAL(lexical_cast(rng1), "1"); + + const test_char_type cdata1[] = "1"; + iterator_range crng1(cdata1, cdata1 + 1); + do_test_iterator_range(crng1); + BOOST_CHECK_EQUAL(lexical_cast(crng1), "1"); + + // Non zero terminated + test_char_type data2[] = "11"; + iterator_range rng2(data2, data2 + 1); + do_test_iterator_range(rng2); + BOOST_CHECK_EQUAL(lexical_cast(rng2), "1"); + + const test_char_type cdata2[] = "11"; + iterator_range crng2(cdata2, cdata2 + 1); + do_test_iterator_range(crng2); + BOOST_CHECK_EQUAL(lexical_cast(crng2), "1"); +} + +void test_unsigned_char_iterator_ranges() +{ + typedef unsigned char test_char_type; + + // Zero terminated + test_char_type data1[] = "1"; + iterator_range rng1(data1, data1 + 1); + do_test_iterator_range(rng1); + BOOST_CHECK_EQUAL(lexical_cast(rng1), "1"); + + const test_char_type cdata1[] = "1"; + iterator_range crng1(cdata1, cdata1 + 1); + do_test_iterator_range(crng1); + BOOST_CHECK_EQUAL(lexical_cast(crng1), "1"); + + // Non zero terminated + test_char_type data2[] = "11"; + iterator_range rng2(data2, data2 + 1); + do_test_iterator_range(rng2); + BOOST_CHECK_EQUAL(lexical_cast(rng2), "1"); + + const test_char_type cdata2[] = "11"; + iterator_range crng2(cdata2, cdata2 + 1); + do_test_iterator_range(crng2); + BOOST_CHECK_EQUAL(lexical_cast(crng2), "1"); +} + +void test_signed_char_iterator_ranges() +{ + typedef signed char test_char_type; + + // Zero terminated + test_char_type data1[] = "1"; + iterator_range rng1(data1, data1 + 1); + do_test_iterator_range(rng1); + BOOST_CHECK_EQUAL(lexical_cast(rng1), "1"); + + const test_char_type cdata1[] = "1"; + iterator_range crng1(cdata1, cdata1 + 1); + do_test_iterator_range(crng1); + BOOST_CHECK_EQUAL(lexical_cast(crng1), "1"); + + // Non zero terminated + test_char_type data2[] = "11"; + iterator_range rng2(data2, data2 + 1); + do_test_iterator_range(rng2); + BOOST_CHECK_EQUAL(lexical_cast(rng2), "1"); + + const test_char_type cdata2[] = "11"; + iterator_range crng2(cdata2, cdata2 + 1); + do_test_iterator_range(crng2); + BOOST_CHECK_EQUAL(lexical_cast(crng2), "1"); +} + +void test_wide_char_iterator_ranges() +{ +#ifndef BOOST_LCAST_NO_WCHAR_T + typedef wchar_t test_char_type; + + // Zero terminated + test_char_type data1[] = L"1"; + iterator_range rng1(data1, data1 + 1); + do_test_iterator_range(rng1); + + const test_char_type cdata1[] = L"1"; + iterator_range crng1(cdata1, cdata1 + 1); + do_test_iterator_range(crng1); + + // Non zero terminated + test_char_type data2[] = L"11"; + iterator_range rng2(data2, data2 + 1); + do_test_iterator_range(rng2); + + const test_char_type cdata2[] = L"11"; + iterator_range crng2(cdata2, cdata2 + 1); + do_test_iterator_range(crng2); +#endif + + BOOST_CHECK(true); +} + +unit_test::test_suite *init_unit_test_suite(int, char *[]) +{ + unit_test::test_suite *suite = BOOST_TEST_SUITE("lexical_cast. Testing conversions using iterator_range<>"); + suite->add(BOOST_TEST_CASE(&test_char_iterator_ranges)); + suite->add(BOOST_TEST_CASE(&test_unsigned_char_iterator_ranges)); + suite->add(BOOST_TEST_CASE(&test_signed_char_iterator_ranges)); + suite->add(BOOST_TEST_CASE(&test_wide_char_iterator_ranges)); + + return suite; +} From 1e58331bafdc716eb68f10eb78c4f3ec62a4a415 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Sat, 7 Apr 2012 07:52:23 +0000 Subject: [PATCH 44/66] Merge lexical_cast from trunk: * fixed #6717 (now lexical_cast won`t try to support non confirming swprintf) * fixed #6670 (now using BOOST_NO_UNICODE_LITERALS macro to detect unicode literals support) * rewritten Jamfile [SVN r77804] --- include/boost/lexical_cast.hpp | 203 +++++++++++------------ lexical_cast_test.cpp | 16 +- test/Jamfile.v2 | 60 +++---- test/lexical_cast_no_exceptions_test.cpp | 2 +- 4 files changed, 140 insertions(+), 141 deletions(-) diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index fb1808f..61501d6 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -26,27 +26,6 @@ #define BOOST_LCAST_NO_WCHAR_T #endif -#if (defined(__MINGW32__) || defined(__MINGW64__)) && (__GNUC__ == 4) \ - && ((__GNUC_MINOR__ == 4) || (__GNUC_MINOR__ == 5)) && defined(__STRICT_ANSI__) \ - && !defined(BOOST_LCAST_NO_WCHAR_T) - -// workaround for a mingw bug -// http://sourceforge.net/tracker/index.php?func=detail&aid=2373234&group_id=2435&atid=102435 -#include <_mingw.h> -#if (__GNUC_MINOR__ == 4) -extern "C" { -_CRTIMP int __cdecl swprintf(wchar_t * __restrict__ , const wchar_t * __restrict__ , ...); -_CRTIMP int __cdecl vswprintf(wchar_t * __restrict__ , const wchar_t * __restrict__ , ...); -} -#endif -#if (__GNUC_MINOR__ == 5) -extern "C" { -_CRTIMP int __cdecl swprintf(wchar_t * __restrict__ , const wchar_t * __restrict__ , ...); -_CRTIMP int __cdecl vswprintf(wchar_t * __restrict__ , const wchar_t * __restrict__ , va_list); -} -#endif -#endif - #include #include #include @@ -501,7 +480,7 @@ namespace boost }; #endif -#ifndef BOOST_NO_CHAR16_T +#if !defined(BOOST_NO_CHAR16_T) && !defined(BOOST_NO_UNICODE_LITERALS) template<> struct lcast_char_constants { @@ -514,7 +493,7 @@ namespace boost }; #endif -#ifndef BOOST_NO_CHAR32_T +#if !defined(BOOST_NO_CHAR32_T) && !defined(BOOST_NO_UNICODE_LITERALS) template<> struct lcast_char_constants { @@ -864,7 +843,7 @@ namespace boost } #endif -#ifndef BOOST_NO_CHAR16_T +#if !defined(BOOST_NO_CHAR16_T) && !defined(BOOST_NO_UNICODE_LITERALS) template bool parse_inf_nan(const char16_t* begin, const char16_t* end, T& value) { @@ -880,7 +859,7 @@ namespace boost return put_inf_nan_impl(begin, end, value, u"nan", u"infinity"); } #endif -#ifndef BOOST_NO_CHAR32_T +#if !defined(BOOST_NO_CHAR32_T) && !defined(BOOST_NO_UNICODE_LITERALS) template bool parse_inf_nan(const char32_t* begin, const char32_t* end, T& value) { @@ -1275,7 +1254,7 @@ namespace boost { #if defined(BOOST_NO_STRINGSTREAM) || defined(BOOST_NO_STD_LOCALE) // If you have compilation error at this point, than your STL library - // unsupports such conversions. Try updating it. + // does not support such conversions. Try updating it. BOOST_STATIC_ASSERT((boost::is_same::value)); #endif bool const result = !(out_stream << input).fail(); @@ -1299,34 +1278,42 @@ namespace boost return true; } + template + bool shl_real_type(const T& val, SomeCharT* begin, SomeCharT*& end) + { + if (put_inf_nan(begin, end, val)) return true; + lcast_set_precision(out_stream, &val); + return shl_input_streamable(val); + } + #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) + static bool shl_real_type(float val, char* begin, char*& end) { 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; + if (put_inf_nan(begin, end, val)) return true; + end = begin; + end += sprintf(begin,"%.*g", static_cast(boost::detail::lcast_get_precision()), val); + return end > begin; } - template - bool shl_double(double val,T* out) + static bool shl_real_type(double val, char* begin, char*& end) { 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 (put_inf_nan(begin, end, val)) return true; + end = begin; + end += sprintf(begin,"%.*lg", static_cast(boost::detail::lcast_get_precision()), val); + return end > begin; } + #ifndef __MINGW32__ - template - bool shl_long_double(long double val,T* out) + static bool shl_real_type(long double val, char* begin, char*& end) { 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 (put_inf_nan(begin, end, val)) return true; + end = begin; + end += sprintf(begin,"%.*Lg", static_cast(boost::detail::lcast_get_precision()), val ); + return end > begin; } #endif @@ -1335,54 +1322,32 @@ namespace boost #endif -#ifndef BOOST_LCAST_NO_WCHAR_T - bool shl_float(float val,wchar_t* out) +#if !defined(BOOST_LCAST_NO_WCHAR_T) && !defined(BOOST_NO_SWPRINTF) && !defined(__MINGW32__) + static bool shl_real_type(float val, wchar_t* begin, wchar_t*& end) { using namespace std; - if (put_inf_nan(start,finish,val)) return true; - finish = start + swprintf(out, -#if !defined(__MINGW32__) && !defined(UNDER_CE) - finish-start, -#endif + if (put_inf_nan(begin, end, val)) return true; + end = begin + swprintf(begin, end-begin, L"%.*g", static_cast(boost::detail::lcast_get_precision()), val ); - - return finish > start; + return end > begin; } - - bool shl_double(double val,wchar_t* out) + static bool shl_real_type(double val, wchar_t* begin, wchar_t*& end) { using namespace std; - if (put_inf_nan(start,finish,val)) return true; - /* __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 and under WinCE does not conform - * to the ISO C - * Standard. - */ - finish = start + swprintf(out, -#if !defined(__MINGW32__) && !defined(UNDER_CE) - finish-start, -#endif + if (put_inf_nan(begin, end, val)) return true; + end = begin + swprintf(begin, end-begin, L"%.*lg", static_cast(boost::detail::lcast_get_precision()), val ); - return finish > start; + return end > begin; } -#ifndef __MINGW32__ - bool shl_long_double(long double val,wchar_t* out) + static bool shl_real_type(long double val, wchar_t* begin, wchar_t*& end) { using namespace std; - if (put_inf_nan(start,finish,val)) return true; - finish = start + swprintf(out, -#if !defined(UNDER_CE) - finish-start, -#endif + if (put_inf_nan(begin, end, val)) return true; + end = begin + swprintf(begin, end-begin, L"%.*Lg", static_cast(boost::detail::lcast_get_precision()), val ); - return finish > start; + return end > begin; } #endif -#endif - /************************************ OPERATORS << ( ... ) ********************************/ public: template @@ -1486,13 +1451,13 @@ namespace boost bool operator<<(unsigned __int64 n) { start = lcast_put_unsigned(n, finish); return true; } bool operator<<( __int64 n) { return shl_signed(n); } #endif - bool operator<<(float val) { return shl_float(val,start); } - bool operator<<(double val) { return shl_double(val,start); } + bool operator<<(float val) { return shl_real_type(val, start, finish); } + bool operator<<(double val) { return shl_real_type(val, start, finish); } bool operator<<(long double val) { #ifndef __MINGW32__ - return shl_long_double(val,start); + return shl_real_type(val, start, finish); #else - return shl_double(val,start); + return shl_real_type(static_cast(val), start, finish); #endif } @@ -1663,10 +1628,10 @@ namespace boost #if !defined(BOOST_LCAST_NO_WCHAR_T) && !defined(BOOST_NO_INTRINSIC_WCHAR_T) bool operator>>(wchar_t& output) { return shr_xchar(output); } #endif -#ifndef BOOST_NO_CHAR16_T +#if !defined(BOOST_NO_CHAR16_T) && !defined(BOOST_NO_UNICODE_LITERALS) bool operator>>(char16_t& output) { return shr_xchar(output); } #endif -#ifndef BOOST_NO_CHAR32_T +#if !defined(BOOST_NO_CHAR32_T) && !defined(BOOST_NO_UNICODE_LITERALS) bool operator>>(char32_t& output) { return shr_xchar(output); } #endif #ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION @@ -1884,8 +1849,8 @@ namespace boost BOOST_STATIC_CONSTANT(bool, value = ( ::boost::type_traits::ice_and< - is_arithmetic::value, - is_arithmetic::value, + ::boost::is_arithmetic::value, + ::boost::is_arithmetic::value, ::boost::type_traits::ice_not< detail::is_char_or_wchar::value >::value, @@ -1923,6 +1888,28 @@ namespace boost ); }; + + // this metafunction evaluates to true, if we have optimized comnversion + // from Float type to Char array. + // Must be in sync with lexical_stream_limited_src::shl_real_type(...) + template + struct is_this_float_conversion_optimized + { + typedef ::boost::type_traits::ice_and< + ::boost::is_float::value, +#if !defined(BOOST_LCAST_NO_WCHAR_T) && !defined(BOOST_NO_SWPRINTF) && !defined(__MINGW32__) + ::boost::type_traits::ice_or< + ::boost::type_traits::ice_eq::value, + ::boost::is_same::value + >::value +#else + ::boost::type_traits::ice_eq::value +#endif + > result_type; + + BOOST_STATIC_CONSTANT(bool, value = (result_type::value) ); + }; + template struct is_char_array_to_stdstring { @@ -1972,6 +1959,17 @@ namespace boost target_char_t, src_char_type >::type char_type; +#if !defined(BOOST_NO_CHAR16_T) && defined(BOOST_NO_UNICODE_LITERALS) + BOOST_STATIC_ASSERT_MSG(( !::boost::is_same::value + && !::boost::is_same::value), + "Your compiler does not have full support for char16_t" ); +#endif +#if !defined(BOOST_NO_CHAR32_T) && defined(BOOST_NO_UNICODE_LITERALS) + BOOST_STATIC_ASSERT_MSG(( !::boost::is_same::value + && !::boost::is_same::value), + "Your compiler does not have full support for char32_t" ); +#endif + typedef detail::lcast_src_length lcast_src_length; std::size_t const src_len = lcast_src_length::value; char_type buf[src_len + 1]; @@ -1997,21 +1995,22 @@ namespace boost ::boost::is_same::value >::value >::value, - is_same::value + ::boost::is_same::value >::value); const bool requires_stringbuf = !( ::boost::type_traits::ice_or< - is_stdstring::value, - is_arithmetic::value, + ::boost::detail::is_stdstring::value, + ::boost::is_integral::value, + ::boost::detail::is_this_float_conversion_optimized::value, ::boost::type_traits::ice_and< - is_char_iterator_range::value, + ::boost::detail::is_char_iterator_range::value, is_char_types_match >::value, ::boost::type_traits::ice_and< - is_pointer::value, - is_char_or_wchar::value, + ::boost::is_pointer::value, + ::boost::detail::is_char_or_wchar::value, is_char_types_match >::value >::value @@ -2047,7 +2046,7 @@ namespace boost typedef Source source_type ; typedef BOOST_DEDUCED_TYPENAME mpl::if_< - is_arithmetic, Source, Source const& + ::boost::is_arithmetic, Source, Source const& >::type argument_type ; static source_type nearbyint ( argument_type s ) @@ -2138,10 +2137,10 @@ namespace boost ::boost::is_float::value >::value, ::boost::type_traits::ice_not< - is_same::value + ::boost::is_same::value >::value, ::boost::type_traits::ice_not< - is_same::value + ::boost::is_same::value >::value, ::boost::is_unsigned::value >::value, @@ -2157,27 +2156,27 @@ namespace boost template inline Target lexical_cast(const Source &arg) { - typedef BOOST_DEDUCED_TYPENAME detail::array_to_pointer_decay::type src; + typedef BOOST_DEDUCED_TYPENAME ::boost::detail::array_to_pointer_decay::type src; typedef BOOST_DEDUCED_TYPENAME ::boost::type_traits::ice_or< - detail::is_xchar_to_xchar::value, - detail::is_char_array_to_stdstring::value, + ::boost::detail::is_xchar_to_xchar::value, + ::boost::detail::is_char_array_to_stdstring::value, ::boost::type_traits::ice_and< - is_same::value, - detail::is_stdstring::value + ::boost::is_same::value, + ::boost::detail::is_stdstring::value >::value > do_copy_type; typedef BOOST_DEDUCED_TYPENAME - detail::is_arithmetic_and_not_xchars do_copy_with_dynamic_check_type; + ::boost::detail::is_arithmetic_and_not_xchars do_copy_with_dynamic_check_type; typedef BOOST_DEDUCED_TYPENAME ::boost::mpl::if_c< do_copy_type::value, detail::lexical_cast_copy, BOOST_DEDUCED_TYPENAME ::boost::mpl::if_c< do_copy_with_dynamic_check_type::value, - detail::lexical_cast_dynamic_num, - detail::lexical_cast_do_cast + ::boost::detail::lexical_cast_dynamic_num, + ::boost::detail::lexical_cast_do_cast >::type >::type caster_type; diff --git a/lexical_cast_test.cpp b/lexical_cast_test.cpp index 4e9ec90..4e70bdd 100644 --- a/lexical_cast_test.cpp +++ b/lexical_cast_test.cpp @@ -100,10 +100,10 @@ void test_wallocator(); #endif void test_char_types_conversions(); void operators_overload_test(); -#ifndef BOOST_NO_CHAR16_T +#if !defined(BOOST_NO_CHAR16_T) && !defined(BOOST_NO_UNICODE_LITERALS) void test_char16_conversions(); #endif -#ifndef BOOST_NO_CHAR32_T +#if !defined(BOOST_NO_CHAR32_T) && !defined(BOOST_NO_UNICODE_LITERALS) void test_char32_conversions(); #endif @@ -149,10 +149,10 @@ unit_test::test_suite *init_unit_test_suite(int, char *[]) suite->add(BOOST_TEST_CASE(&test_char_types_conversions)); suite->add(BOOST_TEST_CASE(&operators_overload_test)); -#ifndef BOOST_NO_CHAR16_T +#if !defined(BOOST_NO_CHAR16_T) && !defined(BOOST_NO_UNICODE_LITERALS) suite->add(BOOST_TEST_CASE(&test_char16_conversions)); #endif -#ifndef BOOST_NO_CHAR32_T +#if !defined(BOOST_NO_CHAR32_T) && !defined(BOOST_NO_UNICODE_LITERALS) suite->add(BOOST_TEST_CASE(&test_char32_conversions)); #endif @@ -756,12 +756,12 @@ 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 +#if !defined(BOOST_NO_CHAR16_T) && !defined(BOOST_NO_UNICODE_LITERALS) 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 +#if !defined(BOOST_NO_CHAR32_T) && !defined(BOOST_NO_UNICODE_LITERALS) char32_t const u32zero = u'0'; test_conversion_from_integral_to_char(u32zero); test_conversion_from_char_to_integral(u32zero); @@ -1025,7 +1025,7 @@ void operators_overload_test() } -#ifndef BOOST_NO_CHAR16_T +#if !defined(BOOST_NO_CHAR16_T) && !defined(BOOST_NO_UNICODE_LITERALS) void test_char16_conversions() { BOOST_CHECK(u"100" == lexical_cast(u"100")); @@ -1033,7 +1033,7 @@ void test_char16_conversions() } #endif -#ifndef BOOST_NO_CHAR32_T +#if !defined(BOOST_NO_CHAR16_T) && !defined(BOOST_NO_UNICODE_LITERALS) void test_char32_conversions() { BOOST_CHECK(U"100" == lexical_cast(U"100")); diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 131fa3e..2673009 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -1,50 +1,50 @@ -# Signals library - # Copyright (C) 2001-2003 Douglas Gregor +# Copyright (C) 2011-2012 Antony Polukhin +# +# 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) +# -# Permission to copy, use, sell and distribute this software is granted -# provided this copyright notice appears in all copies. Permission to modify -# the code and to distribute modified code is granted provided this copyright -# notice appears in all copies, and a notice that the code was modified is -# included with the copyright notice. This software is provided "as is" -# without express or implied warranty, and with no claim as to its suitability -# for any purpose. - -# For more information, see http://www.boost.org/ - -# bring in rules for testing import testing ; import feature ; +project + : requirements + /boost/test//boost_unit_test_framework + static + ; + +# Thanks to Steven Watanabe for helping with feature feature.feature nowchar : on : composite optional propagated link-incompatible ; -feature.compose on : /Zc:wchar_t- ; +feature.compose on : /Zc:wchar_t- ; test-suite conversion : [ run implicit_cast.cpp ] [ compile-fail implicit_cast_fail.cpp ] [ run ../cast_test.cpp ] [ run ../numeric_cast_test.cpp ] - [ run ../lexical_cast_test.cpp ../../test/build//boost_unit_test_framework/static ] - [ run lexical_cast_loopback_test.cpp ../../test/build//boost_unit_test_framework/static ] - [ 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 ] - [ 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 ] - [ run lexical_cast_pointers_test.cpp ../../test/build//boost_unit_test_framework/static ] + [ run ../lexical_cast_test.cpp ] + [ run lexical_cast_loopback_test.cpp ] + [ run lexical_cast_abstract_test.cpp ] + [ run lexical_cast_noncopyable_test.cpp ] + [ run lexical_cast_vc8_bug_test.cpp ] + [ run lexical_cast_wchars_test.cpp ] + [ run lexical_cast_float_types_test.cpp ] + [ run lexical_cast_inf_nan_test.cpp ] + [ run lexical_cast_containers_test.cpp ] + [ run lexical_cast_empty_input_test.cpp ] + [ run lexical_cast_pointers_test.cpp ] [ 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 ] - [ run lexical_cast_no_locale_test.cpp ../../test/build//boost_unit_test_framework/static : : : BOOST_NO_STD_LOCALE BOOST_LEXICAL_CAST_ASSUME_C_LOCALE ] - [ run lexical_cast_no_exceptions_test.cpp ../../test/build//boost_unit_test_framework/static : : : BOOST_NO_EXCEPTIONS + [ run lexical_cast_typedefed_wchar_test_runtime.cpp : : : msvc:on msvc,stlport:no ] + [ run lexical_cast_no_locale_test.cpp : : : BOOST_NO_STD_LOCALE BOOST_LEXICAL_CAST_ASSUME_C_LOCALE ] + [ run lexical_cast_no_exceptions_test.cpp : : : BOOST_NO_EXCEPTIONS gcc-4.3:-fno-exceptions gcc-4.4:-fno-exceptions gcc-4.5:-fno-exceptions gcc-4.6:-fno-exceptions + gcc-4.7:-fno-exceptions ] - [ run lexical_cast_iterator_range_test.cpp ../../test/build//boost_unit_test_framework/static ] - ; + [ run lexical_cast_iterator_range_test.cpp ] + ; diff --git a/test/lexical_cast_no_exceptions_test.cpp b/test/lexical_cast_no_exceptions_test.cpp index 8431c3a..dbec8ea 100755 --- a/test/lexical_cast_no_exceptions_test.cpp +++ b/test/lexical_cast_no_exceptions_test.cpp @@ -29,7 +29,7 @@ bool g_was_exception = false; namespace boost { void throw_exception(std::exception const & ) { - g_was_exception = true; + g_was_exception = true; } } From eb4ad73cafed624fcb68e12b4bf11c1d195fbe62 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Wed, 18 Apr 2012 04:09:49 +0000 Subject: [PATCH 45/66] Merge lexical_cast library from trunk: * multiple optimizations and bugfixes for boost::iterator_range (refs #6786, refs #6430, refs #6663) * documentation update * new Unicode characters support updated * much more tests, removed incorrect tests [SVN r78059] --- doc/lexical_cast.qbk | 25 +- include/boost/lexical_cast.hpp | 523 +++++++++++----------- lexical_cast_test.cpp | 1 - test/Jamfile.v2 | 1 + test/lexical_cast_containers_test.cpp | 23 + test/lexical_cast_iterator_range_test.cpp | 188 ++++---- test/lexical_cast_wchars_test.cpp | 62 ++- 7 files changed, 459 insertions(+), 364 deletions(-) diff --git a/doc/lexical_cast.qbk b/doc/lexical_cast.qbk index ffab311..c786fbc 100644 --- a/doc/lexical_cast.qbk +++ b/doc/lexical_cast.qbk @@ -97,7 +97,21 @@ The requirements on the argument and result types are: * Target is CopyConstructible [20.1.3]. * Target is DefaultConstructible, meaning that it is possible to default-initialize an object of that type [8.5, 20.1.4]. -The character type of the underlying stream is assumed to be char unless either the Source or the Target requires wide-character streaming, in which case the underlying stream uses `wchar_t`. Source types that require wide-character streaming are `wchar_t`, `wchar_t *`, and `std::wstring`. Target types that require wide-character streaming are `wchar_t` and `std::wstring`. +The character type of the underlying stream is assumed to be `char` unless either the `Source` or the `Target` requires wide-character streaming, in which case the underlying stream uses `wchar_t`, `char16_t` or `char32_t`. Wide-character streaming is currently detected for: + +* Single character: `wchar_t`, `char16_t`, `char32_t` +* Arrays of characters: `wchar_t *`, `char16_t *`, `char32_t *`, `const wchar_t *`, `const char16_t *`, `const char32_t *` +* Strings: `std::basic_string`, `boost::containers::basic_string` +* `boost::iterator_range`, where `WideCharPtr` is a pointer to wide-character or pointer to const wide-character + +[important Many compilers and runtime libraries fail to make conversions using new Unicode characters. Make shure that the following code compiles and outputs nonzero values, before using new types: +`` + std::cout + << booat::lexical_cast(1.0).size() + << " " + << booat::lexical_cast(1.0).size(); +`` +] Where a higher degree of control is required over conversions, `std::stringstream` and `std::wstringstream` offer a more appropriate path. Where non-stream-based conversions are required, `lexical_cast` is the wrong tool for the job and is not special-cased for such scenarios. [endsect] @@ -115,6 +129,7 @@ Exception used to indicate runtime lexical_cast failure. [endsect] +[/ Commenting out bad advise (this will break the ability to get correct function pointers via &lexical_cast) [section Tuning classes for fast lexical conversions] Because of `boost::lexical_cast` optimizations for `boost::iterator_range`, it is possibile to make very fast lexical conversions for non zero terminated strings, substrings and user-defined classes. @@ -145,9 +160,9 @@ Consider the following example: This is a good generic solution for most use cases. But we can make it even faster for some performance critical applications. During conversion, we loose speed at: -* `std::ostream` construction (it makes some heap allocations) -* `operator <<` (it copyies one by one all the symbols to an instance of `std::ostream`) -* `std::ostream` destruction (it makes some heap deallocations) + * `std::ostream` construction (it makes some heap allocations) + * `operator <<` (it copyies one by one all the symbols to an instance of `std::ostream`) + * `std::ostream` destruction (it makes some heap deallocations) We can avoid all of this, by specifieng an overload for `boost::lexical_cast`: `` @@ -162,7 +177,7 @@ namespace boost { `` Now `boost::lexical_cast(example_class_instance)` conversions won't copy data and construct heavy STL stream objects. See [link boost_lexical_cast.performance Performance] section for info on `boost::iterator_range` conversion performance. [endsect] - +] [section Frequently Asked Questions] diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index 61501d6..2e5c140 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -28,36 +28,20 @@ #include #include -#include #include #include #include #include #include -#include #include #include #include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include +#include #include #include #include -#include -#if !defined(__SUNPRO_CC) -#include -#endif // !defined(__SUNPRO_CC) -#ifndef BOOST_NO_CWCHAR -# include -#endif + #ifndef BOOST_NO_STD_LOCALE # include @@ -137,118 +121,9 @@ namespace boost const std::type_info *target; }; - namespace detail // selectors for choosing stream character type + namespace detail // widest_char { - template - struct stream_char - { - typedef char type; - }; - -#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION - template - struct stream_char > - { - typedef BOOST_DEDUCED_TYPENAME stream_char::type type; - }; - - template - struct stream_char > - { - typedef BOOST_DEDUCED_TYPENAME stream_char::type type; - }; - - template - struct stream_char< std::basic_string > - { - typedef CharT type; - }; - -#if !defined(__SUNPRO_CC) - template - struct stream_char< ::boost::container::basic_string > - { - typedef CharT type; - }; -#endif // !defined(__SUNPRO_CC) -#endif - -#ifndef BOOST_LCAST_NO_WCHAR_T -#ifndef BOOST_NO_INTRINSIC_WCHAR_T - template<> - struct stream_char - { - typedef wchar_t type; - }; -#endif - - template<> - struct stream_char - { - typedef wchar_t type; - }; - - template<> - struct stream_char - { - typedef wchar_t type; - }; - -#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION - template<> - struct stream_char - { - typedef wchar_t type; - }; -#endif -#endif - - -#ifndef BOOST_NO_CHAR16_T - - template<> - struct stream_char - { - typedef char16_t type; - }; - - template<> - struct stream_char - { - typedef char16_t type; - }; - - template<> - struct stream_char - { - typedef char16_t type; - }; - -#endif - -#ifndef BOOST_NO_CHAR32_T - - template<> - struct stream_char - { - typedef char32_t type; - }; - - template<> - struct stream_char - { - typedef char32_t type; - }; - - template<> - struct stream_char - { - typedef char32_t type; - }; - -#endif - - template + template struct widest_char { typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_c< @@ -257,10 +132,162 @@ namespace boost , SourceChar >::type type; }; } +} // namespace boost + +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if !defined(__SUNPRO_CC) +#include +#endif // !defined(__SUNPRO_CC) +#ifndef BOOST_NO_CWCHAR +# include +#endif + +namespace boost { + namespace detail // widest_char<...> (continuation) + { + struct not_a_character_type{}; + + template + struct widest_char + { + typedef CharT type; + }; + + template + struct widest_char< CharT, not_a_character_type > + { + typedef CharT type; + }; + + template <> + struct widest_char< not_a_character_type, not_a_character_type > + { + typedef char type; + }; + } + + namespace detail // is_char_or_wchar<...> and stream_char<...> templates + { + // returns true, if T is one of the character types + template + struct is_char_or_wchar + { + typedef ::boost::type_traits::ice_or< + ::boost::is_same< T, char >::value, + #ifndef BOOST_LCAST_NO_WCHAR_T + ::boost::is_same< T, wchar_t >::value, + #endif + #ifndef BOOST_NO_CHAR16_T + ::boost::is_same< T, char16_t >::value, + #endif + #ifndef BOOST_NO_CHAR32_T + ::boost::is_same< T, char32_t >::value, + #endif + ::boost::is_same< T, unsigned char >::value, + ::boost::is_same< T, signed char >::value + > result_type; + + BOOST_STATIC_CONSTANT(bool, value = (result_type::value) ); + }; + + // selectors for choosing stream character type + // returns one of char, wchar_t, char16_t, char32_t or not_a_character_type types + template + struct stream_char + { + typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_c< + is_char_or_wchar::value, + Type, + boost::detail::not_a_character_type + >::type type; + }; + + template <> + struct stream_char + { + typedef char type; + }; + + template <> + struct stream_char + { + typedef char type; + }; + + template + struct stream_char + { + typedef BOOST_DEDUCED_TYPENAME stream_char::type type; + }; + + template + struct stream_char + { + typedef BOOST_DEDUCED_TYPENAME stream_char::type type; + }; + + template + struct stream_char > + { + typedef BOOST_DEDUCED_TYPENAME stream_char::type type; + }; + + template + struct stream_char > + { + typedef BOOST_DEDUCED_TYPENAME stream_char::type type; + }; + + template + struct stream_char< std::basic_string > + { + typedef CharT type; + }; + +#if !defined(__SUNPRO_CC) + template + struct stream_char< ::boost::container::basic_string > + { + typedef CharT type; + }; +#endif // !defined(__SUNPRO_CC) + +#if !defined(BOOST_LCAST_NO_WCHAR_T) && defined(BOOST_NO_INTRINSIC_WCHAR_T) + template<> + struct stream_char + { + typedef boost::detail::not_a_character_type type; + }; + + template<> + struct stream_char + { + typedef wchar_t type; + }; + + template<> + struct stream_char + { + typedef wchar_t type; + }; +#endif + } namespace detail // deduce_char_traits template { -#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + template struct deduce_char_traits { @@ -325,7 +352,7 @@ namespace boost template struct deduce_char_traits< CharT , ::boost::container::basic_string - , std::basic_string + , ::std::basic_string > { typedef Traits type; @@ -333,14 +360,13 @@ namespace boost template struct deduce_char_traits< CharT - , std::basic_string + , ::std::basic_string , ::boost::container::basic_string > { typedef Traits type; }; #endif // !defined(__SUNPRO_CC) -#endif } namespace detail // lcast_src_length @@ -383,7 +409,7 @@ namespace boost BOOST_STATIC_ASSERT(sizeof(Source) * CHAR_BIT <= 256); #endif }; -// TODO: FIX for char16_t, char32_t, we can ignore CharT + #define BOOST_LCAST_DEF(T) \ template<> struct lcast_src_length \ : lcast_src_length_integral \ @@ -1217,7 +1243,7 @@ namespace boost bool shl_char(T ch) { BOOST_STATIC_ASSERT_MSG(( sizeof(T) <= sizeof(CharT)) , - "boost::lexical_cast does not support conversions from wchar_t to char types." + "boost::lexical_cast does not support conversions from wide character to char types." "Use boost::locale instead" ); #ifndef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE std::locale loc; @@ -1243,7 +1269,7 @@ namespace boost bool shl_char_array(T const* str) { BOOST_STATIC_ASSERT_MSG(( sizeof(T) <= sizeof(CharT)), - "boost::lexical_cast does not support conversions from wchar_t to char types." + "boost::lexical_cast does not support conversions from wide characters to char types." "Use boost::locale instead" ); return shl_input_streamable(str); } @@ -1430,6 +1456,16 @@ namespace boost #ifndef BOOST_NO_INTRINSIC_WCHAR_T bool operator<<(wchar_t ch) { return shl_char(ch); } #endif +#endif +#if !defined(BOOST_NO_CHAR16_T) && !defined(BOOST_NO_UNICODE_LITERALS) + bool operator<<(char16_t ch) { return shl_char(ch); } + bool operator<<(char16_t * str) { return shl_char_array(str); } + bool operator<<(char16_t const * str) { return shl_char_array(str); } +#endif +#if !defined(BOOST_NO_CHAR32_T) && !defined(BOOST_NO_UNICODE_LITERALS) + bool operator<<(char32_t ch) { return shl_char(ch); } + bool operator<<(char32_t * str) { return shl_char_array(str); } + bool operator<<(char32_t const * str) { return shl_char_array(str); } #endif bool operator<<(unsigned char const* ch) { return ((*this) << reinterpret_cast(ch)); } bool operator<<(unsigned char * ch) { return ((*this) << reinterpret_cast(ch)); } @@ -1634,19 +1670,13 @@ namespace boost #if !defined(BOOST_NO_CHAR32_T) && !defined(BOOST_NO_UNICODE_LITERALS) bool operator>>(char32_t& output) { return shr_xchar(output); } #endif -#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION - bool operator>>(std::string& str) { str.assign(start, finish); return true; } -# ifndef BOOST_LCAST_NO_WCHAR_T - bool operator>>(std::wstring& str) { str.assign(start, finish); return true; } -# endif -#else template bool operator>>(std::basic_string& str) { str.assign(start, finish); return true; } #if !defined(__SUNPRO_CC) template bool operator>>(::boost::container::basic_string& str) { str.assign(start, finish); return true; } #endif // !defined(__SUNPRO_CC) -#endif + /* * case "-0" || "0" || "+0" : output = false; return true; * case "1" || "+1": output = true; return true; @@ -1752,10 +1782,6 @@ namespace boost }; } -#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION - - // call-by-const reference version - namespace detail { template @@ -1788,60 +1814,6 @@ namespace boost BOOST_STATIC_CONSTANT(bool, value = true ); }; #endif // !defined(__SUNPRO_CC) - template - struct is_char_or_wchar - { - private: -#ifndef BOOST_LCAST_NO_WCHAR_T - typedef wchar_t wchar_t_if_supported; -#else - typedef char wchar_t_if_supported; -#endif - -#ifndef BOOST_NO_CHAR16_T - typedef char16_t char16_t_if_supported; -#else - typedef char char16_t_if_supported; -#endif - -#ifndef BOOST_NO_CHAR32_T - typedef char32_t char32_t_if_supported; -#else - typedef char char32_t_if_supported; -#endif - public: - - BOOST_STATIC_CONSTANT(bool, value = - ( - ::boost::type_traits::ice_or< - is_same< T, char >::value, - is_same< T, wchar_t_if_supported >::value, - is_same< T, char16_t_if_supported >::value, - is_same< T, char32_t_if_supported >::value, - is_same< T, unsigned char >::value, - is_same< T, signed char >::value - >::value - ) - ); - }; - - template - struct is_char_iterator_range - { - BOOST_STATIC_CONSTANT(bool, value = false ); - }; - - template - struct is_char_iterator_range > - { - BOOST_STATIC_CONSTANT(bool, value = (is_char_or_wchar::value) ); - }; - - template - struct is_char_iterator_range > - { - BOOST_STATIC_CONSTANT(bool, value = (is_char_or_wchar::value) ); - }; template struct is_arithmetic_and_not_xchars @@ -1970,51 +1942,34 @@ namespace boost "Your compiler does not have full support for char32_t" ); #endif - typedef detail::lcast_src_length lcast_src_length; + typedef detail::lcast_src_length lcast_src_length; std::size_t const src_len = lcast_src_length::value; char_type buf[src_len + 1]; lcast_src_length::check_coverage(); - typedef BOOST_DEDUCED_TYPENAME - deduce_char_traits::type traits; + typedef BOOST_DEDUCED_TYPENAME ::boost::detail::deduce_char_traits< + char_type, Target, Source + >::type traits; - typedef BOOST_DEDUCED_TYPENAME remove_pointer::type removed_ptr_t_1; - typedef BOOST_DEDUCED_TYPENAME remove_cv::type removed_ptr_t; + typedef ::boost::type_traits::ice_and< + ::boost::detail::is_char_or_wchar::value, // source is lexical type + ::boost::detail::is_char_or_wchar::value, // target is a lexical type + ::boost::is_same::value, // source is not a wide character based type + ::boost::type_traits::ice_ne::value // target type is based on wide character + > is_string_widening_required_t; - // is_char_types_match variable value can be computed via - // sizeof(char_type) == sizeof(removed_ptr_t). But when - // removed_ptr_t is an incomplete type or void*, compilers - // produce warnings or errors. - const bool is_char_types_match = - (::boost::type_traits::ice_or< - ::boost::type_traits::ice_and< - ::boost::type_traits::ice_eq::value, - ::boost::type_traits::ice_or< - ::boost::is_same::value, - ::boost::is_same::value, - ::boost::is_same::value - >::value - >::value, - ::boost::is_same::value - >::value); + typedef ::boost::type_traits::ice_or< + ::boost::is_integral::value, + ::boost::detail::is_this_float_conversion_optimized::value, + ::boost::detail::is_char_or_wchar::value + > is_source_input_optimized_t; - const bool requires_stringbuf = - !( - ::boost::type_traits::ice_or< - ::boost::detail::is_stdstring::value, - ::boost::is_integral::value, - ::boost::detail::is_this_float_conversion_optimized::value, - ::boost::type_traits::ice_and< - ::boost::detail::is_char_iterator_range::value, - is_char_types_match - >::value, - ::boost::type_traits::ice_and< - ::boost::is_pointer::value, - ::boost::detail::is_char_or_wchar::value, - is_char_types_match - >::value - >::value - ); + // If we have an optimized conversion for + // Source, we do not need to construct stringbuf. + const bool requires_stringbuf = ::boost::type_traits::ice_or< + is_string_widening_required_t::value, + ::boost::type_traits::ice_not< is_source_input_optimized_t::value >::value + >::value; detail::lexical_stream_limited_src interpreter(buf, buf + src_len); @@ -2030,7 +1985,7 @@ namespace boost # pragma warning( pop ) #endif - template + template struct lexical_cast_copy { static inline Source lexical_cast_impl(const Source &arg) @@ -2039,7 +1994,7 @@ namespace boost } }; - template + template struct detect_precision_loss { typedef boost::numeric::Trunc Rounder; @@ -2063,7 +2018,7 @@ namespace boost typedef typename Rounder::round_style round_style; } ; - template + template struct nothrow_overflow_handler { void operator() ( boost::numeric::range_check_result r ) @@ -2073,7 +2028,7 @@ namespace boost } } ; - template + template struct lexical_cast_dynamic_num_not_ignoring_minus { static inline Target lexical_cast_impl(const Source &arg) @@ -2088,7 +2043,7 @@ namespace boost } }; - template + template struct lexical_cast_dynamic_num_ignoring_minus { static inline Target lexical_cast_impl(const Source &arg) @@ -2125,7 +2080,7 @@ namespace boost * optional, so if a negative number is read, no errors will arise * and the result will be the two's complement. */ - template + template struct lexical_cast_dynamic_num { static inline Target lexical_cast_impl(const Source &arg) @@ -2153,40 +2108,80 @@ namespace boost }; } - template + template inline Target lexical_cast(const Source &arg) { typedef BOOST_DEDUCED_TYPENAME ::boost::detail::array_to_pointer_decay::type src; typedef BOOST_DEDUCED_TYPENAME ::boost::type_traits::ice_or< - ::boost::detail::is_xchar_to_xchar::value, - ::boost::detail::is_char_array_to_stdstring::value, + ::boost::detail::is_xchar_to_xchar::value, + ::boost::detail::is_char_array_to_stdstring::value, ::boost::type_traits::ice_and< - ::boost::is_same::value, - ::boost::detail::is_stdstring::value + ::boost::is_same::value, + ::boost::detail::is_stdstring::value >::value - > do_copy_type; + > shall_we_copy_t; typedef BOOST_DEDUCED_TYPENAME - ::boost::detail::is_arithmetic_and_not_xchars do_copy_with_dynamic_check_type; + ::boost::detail::is_arithmetic_and_not_xchars shall_we_copy_with_dynamic_check_t; typedef BOOST_DEDUCED_TYPENAME ::boost::mpl::if_c< - do_copy_type::value, - detail::lexical_cast_copy, + shall_we_copy_t::value, + ::boost::detail::lexical_cast_copy, BOOST_DEDUCED_TYPENAME ::boost::mpl::if_c< - do_copy_with_dynamic_check_type::value, - ::boost::detail::lexical_cast_dynamic_num, - ::boost::detail::lexical_cast_do_cast + shall_we_copy_with_dynamic_check_t::value, + ::boost::detail::lexical_cast_dynamic_num, + ::boost::detail::lexical_cast_do_cast >::type >::type caster_type; return caster_type::lexical_cast_impl(arg); } - #else +} // namespace boost - namespace detail // stream wrapper for handling lexical conversions +#else // #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + +namespace boost { + namespace detail { + + // selectors for choosing stream character type + template + struct stream_char + { + typedef char type; + }; + +#ifndef BOOST_LCAST_NO_WCHAR_T +#ifndef BOOST_NO_INTRINSIC_WCHAR_T + template<> + struct stream_char + { + typedef wchar_t type; + }; +#endif + + template<> + struct stream_char + { + typedef wchar_t type; + }; + + template<> + struct stream_char + { + typedef wchar_t type; + }; + + template<> + struct stream_char + { + typedef wchar_t type; + }; +#endif + + // stream wrapper for handling lexical conversions template class lexical_stream { @@ -2276,8 +2271,9 @@ namespace boost return result; } - #endif -} +} // namespace boost + +#endif // Copyright Kevlin Henney, 2000-2005. // Copyright Alexander Nasonov, 2006-2010. @@ -2287,5 +2283,8 @@ namespace boost // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +#undef BOOST_LCAST_THROW_BAD_CAST #undef BOOST_LCAST_NO_WCHAR_T -#endif + +#endif // BOOST_LEXICAL_CAST_INCLUDED + diff --git a/lexical_cast_test.cpp b/lexical_cast_test.cpp index 4e70bdd..844ee71 100644 --- a/lexical_cast_test.cpp +++ b/lexical_cast_test.cpp @@ -427,7 +427,6 @@ void test_conversion_to_wstring() BOOST_CHECK(str == lexical_cast(str)); BOOST_CHECK(L"123" == lexical_cast(123)); BOOST_CHECK(L"1.23" == lexical_cast(1.23)); - BOOST_CHECK(L"1.111111111" == lexical_cast(1.111111111)); BOOST_CHECK(L"1" == lexical_cast(true)); BOOST_CHECK(L"0" == lexical_cast(false)); #if !defined(BOOST_NO_INTRINSIC_WCHAR_T) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 2673009..6edd59b 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -12,6 +12,7 @@ project : requirements /boost/test//boost_unit_test_framework static + gcc-4.8:BOOST_STL_SUPPORTS_NEW_UNICODE_LOCALES ; # Thanks to Steven Watanabe for helping with feature diff --git a/test/lexical_cast_containers_test.cpp b/test/lexical_cast_containers_test.cpp index 0c6315b..e6c544a 100644 --- a/test/lexical_cast_containers_test.cpp +++ b/test/lexical_cast_containers_test.cpp @@ -14,6 +14,8 @@ void testing_boost_containers_basic_string(); void testing_boost_containers_string_std_string(); +void testing_boost_containers_string_widening(); + using namespace boost; @@ -23,6 +25,7 @@ boost::unit_test::test_suite *init_unit_test_suite(int, char *[]) BOOST_TEST_SUITE("Testing boost::lexical_cast with boost::container::string"); suite->add(BOOST_TEST_CASE(testing_boost_containers_basic_string)); suite->add(BOOST_TEST_CASE(testing_boost_containers_string_std_string)); + suite->add(BOOST_TEST_CASE(testing_boost_containers_string_widening)); return suite; } @@ -58,3 +61,23 @@ void testing_boost_containers_string_std_string() #endif } + +void testing_boost_containers_string_widening() +{ + const char char_array[] = "Test string"; + +#ifndef BOOST_LCAST_NO_WCHAR_T + const wchar_t wchar_array[] = L"Test string"; + BOOST_CHECK(boost::lexical_cast(char_array) == wchar_array); +#endif + +#if !defined(BOOST_NO_CHAR16_T) && !defined(BOOST_NO_UNICODE_LITERALS) && defined(BOOST_STL_SUPPORTS_NEW_UNICODE_LOCALES) + const char16_t char16_array[] = u"Test string"; + BOOST_CHECK(boost::lexical_cast >(char_array) == char16_array); +#endif + +#if !defined(BOOST_NO_CHAR32_T) && !defined(BOOST_NO_UNICODE_LITERALS) && defined(BOOST_STL_SUPPORTS_NEW_UNICODE_LOCALES) + const char32_t char32_array[] = U"Test string"; + BOOST_CHECK(boost::lexical_cast >(char_array) == char32_array); +#endif +} diff --git a/test/lexical_cast_iterator_range_test.cpp b/test/lexical_cast_iterator_range_test.cpp index 7afb1ae..d54de7a 100644 --- a/test/lexical_cast_iterator_range_test.cpp +++ b/test/lexical_cast_iterator_range_test.cpp @@ -43,7 +43,7 @@ inline std::basic_istream& operator >> (std::basic_istream& istr, template -void do_test_iterator_range(const RngT& rng) +void do_test_iterator_range_impl(const RngT& rng) { BOOST_CHECK_EQUAL(lexical_cast(rng), 1); BOOST_CHECK_EQUAL(lexical_cast(rng), 1u); @@ -51,11 +51,13 @@ void do_test_iterator_range(const RngT& rng) BOOST_CHECK_EQUAL(lexical_cast(rng), 1u); BOOST_CHECK_EQUAL(lexical_cast(rng), 1); BOOST_CHECK_EQUAL(lexical_cast(rng), 1u); + +#ifdef BOOST_STL_SUPPORTS_NEW_UNICODE_LOCALES BOOST_CHECK_EQUAL(lexical_cast(rng), 1.0f); BOOST_CHECK_EQUAL(lexical_cast(rng), 1.0); BOOST_CHECK_EQUAL(lexical_cast(rng), 1.0L); BOOST_CHECK_EQUAL(lexical_cast(rng), 1); - +#endif #if defined(BOOST_HAS_LONG_LONG) BOOST_CHECK_EQUAL(lexical_cast(rng), 1u); BOOST_CHECK_EQUAL(lexical_cast(rng), 1); @@ -63,115 +65,139 @@ void do_test_iterator_range(const RngT& rng) BOOST_CHECK_EQUAL(lexical_cast(rng), 1u); BOOST_CHECK_EQUAL(lexical_cast<__int64>(rng), 1); #endif +} + +template +void test_it_range_using_any_chars(CharT* one, CharT* eleven) +{ + typedef CharT test_char_type; + + // Zero terminated + iterator_range rng1(one, one + 1); + do_test_iterator_range_impl(rng1); + + iterator_range crng1(one, one + 1); + do_test_iterator_range_impl(crng1); + + // Non zero terminated + iterator_range rng2(eleven, eleven + 1); + do_test_iterator_range_impl(rng2); + + iterator_range crng2(eleven, eleven + 1); + do_test_iterator_range_impl(crng2); +} + +template +void test_it_range_using_char(CharT* one, CharT* eleven) +{ + typedef CharT test_char_type; + + iterator_range rng1(one, one + 1); + BOOST_CHECK_EQUAL(lexical_cast(rng1), "1"); + + iterator_range crng1(one, one + 1); + BOOST_CHECK_EQUAL(lexical_cast(crng1), "1"); + + iterator_range rng2(eleven, eleven + 1); + BOOST_CHECK_EQUAL(lexical_cast(rng2), "1"); + + iterator_range crng2(eleven, eleven + 1); + BOOST_CHECK_EQUAL(lexical_cast(crng2), "1"); + + BOOST_CHECK_EQUAL(lexical_cast(rng1), 1.0f); + BOOST_CHECK_EQUAL(lexical_cast(rng1), 1.0); + BOOST_CHECK_EQUAL(lexical_cast(rng1), 1.0L); + BOOST_CHECK_EQUAL(lexical_cast(rng1), 1); + + BOOST_CHECK_EQUAL(lexical_cast(crng2), 1.0f); + BOOST_CHECK_EQUAL(lexical_cast(crng2), 1.0); + BOOST_CHECK_EQUAL(lexical_cast(crng2), 1.0L); + BOOST_CHECK_EQUAL(lexical_cast(crng2), 1); #ifndef BOOST_LCAST_NO_WCHAR_T - BOOST_CHECK(lexical_cast(rng) == L"1"); + BOOST_CHECK(lexical_cast(rng1) == L"1"); + BOOST_CHECK(lexical_cast(crng1) == L"1"); + BOOST_CHECK(lexical_cast(rng2) == L"1"); + BOOST_CHECK(lexical_cast(crng2) == L"1"); +#endif + +#if !defined(BOOST_NO_CHAR16_T) && !defined(BOOST_NO_UNICODE_LITERALS) && defined(BOOST_STL_SUPPORTS_NEW_UNICODE_LOCALES) + typedef std::basic_string my_char16_string; + BOOST_CHECK(lexical_cast(rng1) == u"1"); + BOOST_CHECK(lexical_cast(crng1) == u"1"); + BOOST_CHECK(lexical_cast(rng2) == u"1"); + BOOST_CHECK(lexical_cast(crng2) == u"1"); +#endif + +#if !defined(BOOST_NO_CHAR32_T) && !defined(BOOST_NO_UNICODE_LITERALS) && defined(BOOST_STL_SUPPORTS_NEW_UNICODE_LOCALES) + typedef std::basic_string my_char32_string; + BOOST_CHECK(lexical_cast(rng1) == U"1"); + BOOST_CHECK(lexical_cast(crng1) == U"1"); + BOOST_CHECK(lexical_cast(rng2) == U"1"); + BOOST_CHECK(lexical_cast(crng2) == U"1"); #endif } void test_char_iterator_ranges() { typedef char test_char_type; - - // Zero terminated test_char_type data1[] = "1"; - iterator_range rng1(data1, data1 + 1); - do_test_iterator_range(rng1); - BOOST_CHECK_EQUAL(lexical_cast(rng1), "1"); - - const test_char_type cdata1[] = "1"; - iterator_range crng1(cdata1, cdata1 + 1); - do_test_iterator_range(crng1); - BOOST_CHECK_EQUAL(lexical_cast(crng1), "1"); - - // Non zero terminated test_char_type data2[] = "11"; - iterator_range rng2(data2, data2 + 1); - do_test_iterator_range(rng2); - BOOST_CHECK_EQUAL(lexical_cast(rng2), "1"); - - const test_char_type cdata2[] = "11"; - iterator_range crng2(cdata2, cdata2 + 1); - do_test_iterator_range(crng2); - BOOST_CHECK_EQUAL(lexical_cast(crng2), "1"); + test_it_range_using_any_chars(data1, data2); + test_it_range_using_char(data1, data2); } + + void test_unsigned_char_iterator_ranges() { typedef unsigned char test_char_type; - - // Zero terminated test_char_type data1[] = "1"; - iterator_range rng1(data1, data1 + 1); - do_test_iterator_range(rng1); - BOOST_CHECK_EQUAL(lexical_cast(rng1), "1"); - - const test_char_type cdata1[] = "1"; - iterator_range crng1(cdata1, cdata1 + 1); - do_test_iterator_range(crng1); - BOOST_CHECK_EQUAL(lexical_cast(crng1), "1"); - - // Non zero terminated test_char_type data2[] = "11"; - iterator_range rng2(data2, data2 + 1); - do_test_iterator_range(rng2); - BOOST_CHECK_EQUAL(lexical_cast(rng2), "1"); - - const test_char_type cdata2[] = "11"; - iterator_range crng2(cdata2, cdata2 + 1); - do_test_iterator_range(crng2); - BOOST_CHECK_EQUAL(lexical_cast(crng2), "1"); + test_it_range_using_any_chars(data1, data2); + test_it_range_using_char(data1, data2); } void test_signed_char_iterator_ranges() { typedef signed char test_char_type; - - // Zero terminated test_char_type data1[] = "1"; - iterator_range rng1(data1, data1 + 1); - do_test_iterator_range(rng1); - BOOST_CHECK_EQUAL(lexical_cast(rng1), "1"); - - const test_char_type cdata1[] = "1"; - iterator_range crng1(cdata1, cdata1 + 1); - do_test_iterator_range(crng1); - BOOST_CHECK_EQUAL(lexical_cast(crng1), "1"); - - // Non zero terminated test_char_type data2[] = "11"; - iterator_range rng2(data2, data2 + 1); - do_test_iterator_range(rng2); - BOOST_CHECK_EQUAL(lexical_cast(rng2), "1"); - - const test_char_type cdata2[] = "11"; - iterator_range crng2(cdata2, cdata2 + 1); - do_test_iterator_range(crng2); - BOOST_CHECK_EQUAL(lexical_cast(crng2), "1"); + test_it_range_using_any_chars(data1, data2); + test_it_range_using_char(data1, data2); } -void test_wide_char_iterator_ranges() +void test_wchar_iterator_ranges() { #ifndef BOOST_LCAST_NO_WCHAR_T typedef wchar_t test_char_type; - - // Zero terminated test_char_type data1[] = L"1"; - iterator_range rng1(data1, data1 + 1); - do_test_iterator_range(rng1); - - const test_char_type cdata1[] = L"1"; - iterator_range crng1(cdata1, cdata1 + 1); - do_test_iterator_range(crng1); - - // Non zero terminated test_char_type data2[] = L"11"; - iterator_range rng2(data2, data2 + 1); - do_test_iterator_range(rng2); + test_it_range_using_any_chars(data1, data2); +#endif - const test_char_type cdata2[] = L"11"; - iterator_range crng2(cdata2, cdata2 + 1); - do_test_iterator_range(crng2); + BOOST_CHECK(true); +} + +void test_char16_iterator_ranges() +{ +#if !defined(BOOST_NO_CHAR16_T) && !defined(BOOST_NO_UNICODE_LITERALS) + typedef char16_t test_char_type; + test_char_type data1[] = u"1"; + test_char_type data2[] = u"11"; + test_it_range_using_any_chars(data1, data2); +#endif + + BOOST_CHECK(true); +} + +void test_char32_iterator_ranges() +{ +#if !defined(BOOST_NO_CHAR32_T) && !defined(BOOST_NO_UNICODE_LITERALS) + typedef char32_t test_char_type; + test_char_type data1[] = U"1"; + test_char_type data2[] = U"11"; + test_it_range_using_any_chars(data1, data2); #endif BOOST_CHECK(true); @@ -183,7 +209,9 @@ unit_test::test_suite *init_unit_test_suite(int, char *[]) suite->add(BOOST_TEST_CASE(&test_char_iterator_ranges)); suite->add(BOOST_TEST_CASE(&test_unsigned_char_iterator_ranges)); suite->add(BOOST_TEST_CASE(&test_signed_char_iterator_ranges)); - suite->add(BOOST_TEST_CASE(&test_wide_char_iterator_ranges)); + suite->add(BOOST_TEST_CASE(&test_wchar_iterator_ranges)); + suite->add(BOOST_TEST_CASE(&test_char16_iterator_ranges)); + suite->add(BOOST_TEST_CASE(&test_char32_iterator_ranges)); return suite; } diff --git a/test/lexical_cast_wchars_test.cpp b/test/lexical_cast_wchars_test.cpp index acd78b1..f78de1d 100755 --- a/test/lexical_cast_wchars_test.cpp +++ b/test/lexical_cast_wchars_test.cpp @@ -2,7 +2,7 @@ // // See http://www.boost.org for most recent version, including documentation. // -// Copyright Antony Polukhin, 2011. +// Copyright Antony Polukhin, 2011-2012. // // Distributed under the Boost // Software License, Version 1.0. (See accompanying file @@ -17,40 +17,70 @@ #endif #include - -#include #include -#include using namespace boost; -void test_char_types_conversions() +#if defined(BOOST_NO_STRINGSTREAM) || defined(BOOST_NO_STD_WSTRING) +#define BOOST_LCAST_NO_WCHAR_T +#endif + +template +void test_impl(const CharT* wc_arr) { -#ifndef BOOST_LCAST_NO_WCHAR_T + typedef CharT wide_char; + typedef std::basic_string wide_string; const char c_arr[] = "Test array of chars"; const unsigned char uc_arr[] = "Test array of chars"; const signed char sc_arr[] = "Test array of chars"; - const wchar_t wc_arr[] =L"Test array of chars"; // Following tests depend on realization of std::locale // and pass for popular compilers and STL realizations - BOOST_CHECK(boost::lexical_cast(c_arr[0]) == wc_arr[0]); - BOOST_CHECK(boost::lexical_cast(c_arr) == std::wstring(wc_arr)); + BOOST_CHECK(boost::lexical_cast(c_arr[0]) == wc_arr[0]); + BOOST_CHECK(boost::lexical_cast(c_arr) == wide_string(wc_arr)); - BOOST_CHECK(boost::lexical_cast(sc_arr) == std::wstring(wc_arr) ); - BOOST_CHECK(boost::lexical_cast(uc_arr) == std::wstring(wc_arr) ); + BOOST_CHECK(boost::lexical_cast(sc_arr) == wide_string(wc_arr) ); + BOOST_CHECK(boost::lexical_cast(uc_arr) == wide_string(wc_arr) ); - BOOST_CHECK_EQUAL(boost::lexical_cast(uc_arr[0]), wc_arr[0]); - BOOST_CHECK_EQUAL(boost::lexical_cast(sc_arr[0]), wc_arr[0]); + BOOST_CHECK_EQUAL(boost::lexical_cast(uc_arr[0]), wc_arr[0]); + BOOST_CHECK_EQUAL(boost::lexical_cast(sc_arr[0]), wc_arr[0]); +} + + +void test_char_types_conversions_wchar_t() +{ +#ifndef BOOST_LCAST_NO_WCHAR_T + test_impl(L"Test array of chars"); #endif - BOOST_CHECK(1); + + BOOST_CHECK(true); +} + +void test_char_types_conversions_char16_t() +{ +#if !defined(BOOST_NO_CHAR16_T) && !defined(BOOST_NO_UNICODE_LITERALS) && defined(BOOST_STL_SUPPORTS_NEW_UNICODE_LOCALES) + test_impl(u"Test array of chars"); +#endif + + BOOST_CHECK(true); +} + +void test_char_types_conversions_char32_t() +{ +#if !defined(BOOST_NO_CHAR32_T) && !defined(BOOST_NO_UNICODE_LITERALS) && defined(BOOST_STL_SUPPORTS_NEW_UNICODE_LOCALES) + test_impl(U"Test array of chars"); +#endif + + BOOST_CHECK(true); } unit_test::test_suite *init_unit_test_suite(int, char *[]) { unit_test::test_suite *suite = - BOOST_TEST_SUITE("lexical_cast char<->wchar_t unit test"); - suite->add(BOOST_TEST_CASE(&test_char_types_conversions)); + BOOST_TEST_SUITE("lexical_cast char => wide characters unit test (widening test)"); + suite->add(BOOST_TEST_CASE(&test_char_types_conversions_wchar_t)); + suite->add(BOOST_TEST_CASE(&test_char_types_conversions_char16_t)); + suite->add(BOOST_TEST_CASE(&test_char_types_conversions_char32_t)); return suite; } From b1b53059847d8c5eb891e65387c4b0c044fdc58f Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Thu, 26 Apr 2012 17:59:17 +0000 Subject: [PATCH 46/66] Merge from trunk: * fixed #6812 (now converting "." to float type throws bad_lexical_cast) [SVN r78211] --- include/boost/lexical_cast.hpp | 3 ++- test/lexical_cast_float_types_test.cpp | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index 2e5c140..fb76d29 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -1062,9 +1062,10 @@ namespace boost { ) return false; #endif - if(*begin == decimal_point){ + if(*begin == decimal_point) { ++ begin; found_decimal = true; + if (!found_number_before_exp && begin==end) return false; continue; }else { if (!found_number_before_exp) return false; diff --git a/test/lexical_cast_float_types_test.cpp b/test/lexical_cast_float_types_test.cpp index 808f456..60db0e1 100755 --- a/test/lexical_cast_float_types_test.cpp +++ b/test/lexical_cast_float_types_test.cpp @@ -261,6 +261,7 @@ void test_converion_to_float_types() 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("."), bad_lexical_cast); BOOST_CHECK_THROW(lexical_cast("-B"), bad_lexical_cast); BOOST_CHECK_THROW(lexical_cast("0xB"), bad_lexical_cast); @@ -276,6 +277,7 @@ void test_converion_to_float_types() 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); + BOOST_CHECK_THROW(lexical_cast('.'), bad_lexical_cast); } template From ca9c8d30bd31cd937ef57a77eb9c131b026a8c1c Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Sun, 13 May 2012 08:15:51 +0000 Subject: [PATCH 47/66] =?UTF-8?q?Merge=20from=20trunk:=20*=20Fixes=20ISO?= =?UTF-8?q?=20C++=20does=20not=20support=20the=20=E2=80=98%lg=E2=80=99=20g?= =?UTF-8?q?nu=5Fprintf=20format=20(refs=20#6852)=20*=20explicit-failures-m?= =?UTF-8?q?arkup=20merge=20from=20trunk=20*=20supress=20warnings=20in=20im?= =?UTF-8?q?plicit=5Fcast.cpp=20test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [SVN r78450] --- include/boost/lexical_cast.hpp | 12 ++++++++---- test/implicit_cast.cpp | 6 ++++++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index fb76d29..c2580ec 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -1322,7 +1322,8 @@ namespace boost { { using namespace std; if (put_inf_nan(begin, end, val)) return true; end = begin; - end += sprintf(begin,"%.*g", static_cast(boost::detail::lcast_get_precision()), val); + const double val_as_double = val; + end += sprintf(begin,"%.*g", static_cast(boost::detail::lcast_get_precision()), val_as_double); return end > begin; } @@ -1330,7 +1331,7 @@ namespace boost { { using namespace std; if (put_inf_nan(begin, end, val)) return true; end = begin; - end += sprintf(begin,"%.*lg", static_cast(boost::detail::lcast_get_precision()), val); + end += sprintf(begin,"%.*g", static_cast(boost::detail::lcast_get_precision()), val); return end > begin; } @@ -1353,8 +1354,11 @@ namespace boost { static bool shl_real_type(float val, wchar_t* begin, wchar_t*& end) { using namespace std; if (put_inf_nan(begin, end, val)) return true; + const double val_as_double = val; end = begin + swprintf(begin, end-begin, - L"%.*g", static_cast(boost::detail::lcast_get_precision()), val ); + L"%.*g", + static_cast(boost::detail::lcast_get_precision()), + val_as_double ); return end > begin; } @@ -1362,7 +1366,7 @@ namespace boost { { using namespace std; if (put_inf_nan(begin, end, val)) return true; end = begin + swprintf(begin, end-begin, - L"%.*lg", static_cast(boost::detail::lcast_get_precision()), val ); + L"%.*g", static_cast(boost::detail::lcast_get_precision()), val ); return end > begin; } diff --git a/test/implicit_cast.cpp b/test/implicit_cast.cpp index e18e17a..8c3bc52 100644 --- a/test/implicit_cast.cpp +++ b/test/implicit_cast.cpp @@ -28,5 +28,11 @@ int main() type f = check_return(boost::implicit_cast("hello")); type z = check_return(boost::implicit_cast(foo("hello"))); + + // warning supression: + (void)x; + (void)f; + (void)z; + return boost::report_errors(); } From 79d6468aebf86e9ae9edb83c98912227f24fc340 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Thu, 24 May 2012 04:22:04 +0000 Subject: [PATCH 48/66] Merge lexical_cast from trunk : * force SunCC compiler to use fallback version of lexical_cast (with fallbak version SunCC can pass at least some tests) * removed trailing whitespaces [SVN r78565] --- doc/Jamfile.v2 | 6 +- doc/lexical_cast.qbk | 62 +++++++++---------- include/boost/lexical_cast.hpp | 60 ++++++++---------- perf/Jamfile.v2 | 10 +-- test/Jamfile.v2 | 10 +-- test/lexical_cast_containers_test.cpp | 2 +- test/lexical_cast_float_types_test.cpp | 2 +- test/lexical_cast_iterator_range_test.cpp | 12 ++-- test/lexical_cast_no_exceptions_test.cpp | 14 ++--- test/lexical_cast_no_locale_test.cpp | 10 +-- ...ical_cast_typedefed_wchar_test_runtime.cpp | 2 +- 11 files changed, 90 insertions(+), 100 deletions(-) diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index b629c6a..0b47ee3 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -6,9 +6,9 @@ using quickbook ; import boostbook : boostbook ; xml lexical_cast : lexical_cast.qbk ; -boostbook standalone - : - lexical_cast +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 index c786fbc..b856594 100644 --- a/doc/lexical_cast.qbk +++ b/doc/lexical_cast.qbk @@ -34,7 +34,7 @@ The standard C++ library offers `stringstream` for the kind of in-core formattin 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. +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] @@ -105,8 +105,8 @@ The character type of the underlying stream is assumed to be `char` unless eithe * `boost::iterator_range`, where `WideCharPtr` is a pointer to wide-character or pointer to const wide-character [important Many compilers and runtime libraries fail to make conversions using new Unicode characters. Make shure that the following code compiles and outputs nonzero values, before using new types: -`` - std::cout +`` + std::cout << booat::lexical_cast(1.0).size() << " " << booat::lexical_cast(1.0).size(); @@ -151,13 +151,13 @@ Consider the following example: return data_length; } }; - + inline std::ostream& operator << (std::ostream& ostr, const example_class& rhs) { return ostr << boost::make_iterator_range(rhs.data(), rhs.data() + rhs.size()); } `` -This is a good generic solution for most use cases. +This is a good generic solution for most use cases. But we can make it even faster for some performance critical applications. During conversion, we loose speed at: * `std::ostream` construction (it makes some heap allocations) @@ -182,35 +182,35 @@ Now `boost::lexical_cast(example_class_instance)` conversions won't c [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__: + * [*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__: + * [*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 + * [*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. +* [*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 + * [*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 [@boost:libs/io/doc/ios_state.html `ios_state_saver`]. @@ -218,17 +218,17 @@ Read a good C++ book, study `std::sentry` and [@boost:libs/io/doc/ios_state.html ] * [*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 + * [*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. [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 + * [*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. [pre @@ -236,7 +236,7 @@ limitation of compiler options that you use. * [*Question:] Why `boost::lexical_cast("-1.#IND");` throws `boost::bad_lexical_cast`? * [*Answer:] `"-1.#IND"` is a compiler extension, that violates standard. You shall input `"-nan"`, `"nan"`, `"inf"` -, `"-inf"` (case insensitive) strings to get NaN and Inf values. `boost::lexical_cast` outputs `"-nan"`, `"nan"`, +, `"-inf"` (case insensitive) strings to get NaN and Inf values. `boost::lexical_cast` outputs `"-nan"`, `"nan"`, `"inf"`, `"-inf"` strings, when has NaN or Inf input values. * [*Question:] What is the fastest way to convert a non zero terminated string or a substring using `boost::lexical_cast`? @@ -246,21 +246,21 @@ limitation of compiler options that you use. [section Changes] * [*boost 1.50.0 :] - + * `boost::bad_lexical_cast` exception is now globaly visible and can be catched even if code is compiled with -fvisibility=hidden. * Now it is possible to compile library with disabled exceptions. * Better performance, less memory usage and bugfixes for `boost::iterator_range` conversions. * [*boost 1.49.0 :] - - * Restored work with typedefed wchar_t (compilation flag /Zc:wchar_t- for Visual Studio). + + * Restored work with typedefed wchar_t (compilation flag /Zc:wchar_t- for Visual Studio). * Better performance and less memory usage for `boost::container::basic_string` conversions. - + * [*boost 1.48.0 :] - - * Added code to work with Inf and NaN on any platform. + + * 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. @@ -283,7 +283,7 @@ limitation of compiler options that you use. * 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. + * 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] @@ -328,7 +328,7 @@ All the tests measure execution speed in milliseconds for 10000 iterations of th ``] ] ] -Fastest results are highlitened with "!!! *x* !!!". +Fastest results are highlitened with "!!! *x* !!!". Do not use this results to compare compilers, because tests were taken on different hardware. [endsect] diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index c2580ec..3e2e53f 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -69,12 +69,12 @@ namespace boost { // exception used to indicate runtime lexical_cast failure class BOOST_SYMBOL_VISIBLE bad_lexical_cast : - // workaround MSVC bug with std::bad_cast when _HAS_EXCEPTIONS == 0 -#if defined(BOOST_MSVC) && defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS - public std::exception -#else - public std::bad_cast -#endif + // workaround MSVC bug with std::bad_cast when _HAS_EXCEPTIONS == 0 +#if defined(BOOST_MSVC) && defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS + public std::exception +#else + public std::bad_cast +#endif #if defined(__BORLANDC__) && BOOST_WORKAROUND( __BORLANDC__, < 0x560 ) // under bcc32 5.5.1 bad_cast doesn't derive from exception @@ -134,7 +134,7 @@ namespace boost } } // namespace boost -#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) && !defined(__SUNPRO_CC) #include #include @@ -147,9 +147,7 @@ namespace boost #include #include #include -#if !defined(__SUNPRO_CC) #include -#endif // !defined(__SUNPRO_CC) #ifndef BOOST_NO_CWCHAR # include #endif @@ -170,13 +168,13 @@ namespace boost { { typedef CharT type; }; - + template <> struct widest_char< not_a_character_type, not_a_character_type > { typedef char type; }; - } + } namespace detail // is_char_or_wchar<...> and stream_char<...> templates { @@ -243,7 +241,7 @@ namespace boost { { typedef BOOST_DEDUCED_TYPENAME stream_char::type type; }; - + template struct stream_char > { @@ -256,13 +254,11 @@ namespace boost { typedef CharT type; }; -#if !defined(__SUNPRO_CC) template struct stream_char< ::boost::container::basic_string > { typedef CharT type; }; -#endif // !defined(__SUNPRO_CC) #if !defined(BOOST_LCAST_NO_WCHAR_T) && defined(BOOST_NO_INTRINSIC_WCHAR_T) template<> @@ -312,7 +308,6 @@ namespace boost { typedef Traits type; }; -#if !defined(__SUNPRO_CC) template struct deduce_char_traits< CharT , ::boost::container::basic_string @@ -366,7 +361,6 @@ namespace boost { { typedef Traits type; }; -#endif // !defined(__SUNPRO_CC) } namespace detail // lcast_src_length @@ -436,7 +430,7 @@ namespace boost { // -1.23456789e-123456 // ^ sign // ^ leading digit - // ^ decimal point + // ^ decimal point // ^^^^^^^^ lcast_precision::value // ^ "e" // ^ exponent sign @@ -1389,7 +1383,6 @@ namespace boost { return true; } -#if !defined(__SUNPRO_CC) template bool operator<<(::boost::container::basic_string const& str) { @@ -1397,7 +1390,7 @@ namespace boost { finish = start + str.length(); return true; } -#endif // !defined(__SUNPRO_CC) + bool operator<<(bool value) { CharT const czero = lcast_char_constants::zero; @@ -1410,14 +1403,14 @@ namespace boost { { start = rng.begin(); finish = rng.end(); - return true; + return true; } - + bool operator<<(const iterator_range& rng) { start = const_cast(rng.begin()); finish = const_cast(rng.end()); - return true; + return true; } bool operator<<(const iterator_range& rng) @@ -1677,10 +1670,9 @@ namespace boost { #endif template bool operator>>(std::basic_string& str) { str.assign(start, finish); return true; } -#if !defined(__SUNPRO_CC) + template bool operator>>(::boost::container::basic_string& str) { str.assign(start, finish); return true; } -#endif // !defined(__SUNPRO_CC) /* * case "-0" || "0" || "+0" : output = false; return true; @@ -1812,13 +1804,12 @@ namespace boost { { BOOST_STATIC_CONSTANT(bool, value = true ); }; -#if !defined(__SUNPRO_CC) + template struct is_stdstring< ::boost::container::basic_string > { BOOST_STATIC_CONSTANT(bool, value = true ); }; -#endif // !defined(__SUNPRO_CC) template struct is_arithmetic_and_not_xchars @@ -1866,11 +1857,11 @@ namespace boost { }; - // this metafunction evaluates to true, if we have optimized comnversion - // from Float type to Char array. + // this metafunction evaluates to true, if we have optimized comnversion + // from Float type to Char array. // Must be in sync with lexical_stream_limited_src::shl_real_type(...) template - struct is_this_float_conversion_optimized + struct is_this_float_conversion_optimized { typedef ::boost::type_traits::ice_and< ::boost::is_float::value, @@ -1904,7 +1895,7 @@ namespace boost { { BOOST_STATIC_CONSTANT(bool, value = true ); }; -#if !defined(__SUNPRO_CC) + template struct is_char_array_to_stdstring< ::boost::container::basic_string, CharT* > { @@ -1916,7 +1907,6 @@ namespace boost { { BOOST_STATIC_CONSTANT(bool, value = true ); }; -#endif // !defined(__SUNPRO_CC) #if (defined _MSC_VER) # pragma warning( push ) @@ -2262,10 +2252,10 @@ namespace boost { template Target lexical_cast(Source arg) { - typedef typename detail::widest_char< - BOOST_DEDUCED_TYPENAME detail::stream_char::type - , BOOST_DEDUCED_TYPENAME detail::stream_char::type - >::type char_type; + typedef typename detail::widest_char< + BOOST_DEDUCED_TYPENAME detail::stream_char::type + , BOOST_DEDUCED_TYPENAME detail::stream_char::type + >::type char_type; typedef std::char_traits traits; detail::lexical_stream interpreter; diff --git a/perf/Jamfile.v2 b/perf/Jamfile.v2 index 78176be..6f03fe1 100644 --- a/perf/Jamfile.v2 +++ b/perf/Jamfile.v2 @@ -13,17 +13,17 @@ path-constant TEST_DIR : . ; project performance/test : source-location ./ - : requirements -# /boost/chrono//boost_chrono + : requirements +# /boost/chrono//boost_chrono # /boost/system//boost_system static - freebsd:"-lrt" + freebsd:"-lrt" linux:"-lrt" gcc:-fvisibility=hidden intel-linux:-fvisibility=hidden sun:-xldscope=hidden : default-build release ; - + run performance_test.cpp : $(TEST_DIR) ; - + diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 6edd59b..f8ee0d3 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -11,20 +11,20 @@ import feature ; project : requirements /boost/test//boost_unit_test_framework - static + static gcc-4.8:BOOST_STL_SUPPORTS_NEW_UNICODE_LOCALES ; -# Thanks to Steven Watanabe for helping with feature +# Thanks to Steven Watanabe for helping with 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 ] [ run ../cast_test.cpp ] - [ run ../numeric_cast_test.cpp ] + [ run ../numeric_cast_test.cpp ] [ run ../lexical_cast_test.cpp ] [ run lexical_cast_loopback_test.cpp ] [ run lexical_cast_abstract_test.cpp ] @@ -39,7 +39,7 @@ test-suite conversion [ compile lexical_cast_typedefed_wchar_test.cpp : msvc:on ] [ run lexical_cast_typedefed_wchar_test_runtime.cpp : : : msvc:on msvc,stlport:no ] [ run lexical_cast_no_locale_test.cpp : : : BOOST_NO_STD_LOCALE BOOST_LEXICAL_CAST_ASSUME_C_LOCALE ] - [ run lexical_cast_no_exceptions_test.cpp : : : BOOST_NO_EXCEPTIONS + [ run lexical_cast_no_exceptions_test.cpp : : : BOOST_NO_EXCEPTIONS gcc-4.3:-fno-exceptions gcc-4.4:-fno-exceptions gcc-4.5:-fno-exceptions diff --git a/test/lexical_cast_containers_test.cpp b/test/lexical_cast_containers_test.cpp index e6c544a..bb13f31 100644 --- a/test/lexical_cast_containers_test.cpp +++ b/test/lexical_cast_containers_test.cpp @@ -31,7 +31,7 @@ boost::unit_test::test_suite *init_unit_test_suite(int, char *[]) } void testing_boost_containers_basic_string() -{ +{ BOOST_CHECK("100" == lexical_cast("100")); BOOST_CHECK(L"100" == lexical_cast(L"100")); diff --git a/test/lexical_cast_float_types_test.cpp b/test/lexical_cast_float_types_test.cpp index 60db0e1..827b6ec 100755 --- a/test/lexical_cast_float_types_test.cpp +++ b/test/lexical_cast_float_types_test.cpp @@ -237,7 +237,7 @@ 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); diff --git a/test/lexical_cast_iterator_range_test.cpp b/test/lexical_cast_iterator_range_test.cpp index d54de7a..50b86ff 100644 --- a/test/lexical_cast_iterator_range_test.cpp +++ b/test/lexical_cast_iterator_range_test.cpp @@ -138,7 +138,7 @@ void test_it_range_using_char(CharT* one, CharT* eleven) #endif } -void test_char_iterator_ranges() +void test_char_iterator_ranges() { typedef char test_char_type; test_char_type data1[] = "1"; @@ -149,7 +149,7 @@ void test_char_iterator_ranges() -void test_unsigned_char_iterator_ranges() +void test_unsigned_char_iterator_ranges() { typedef unsigned char test_char_type; test_char_type data1[] = "1"; @@ -158,7 +158,7 @@ void test_unsigned_char_iterator_ranges() test_it_range_using_char(data1, data2); } -void test_signed_char_iterator_ranges() +void test_signed_char_iterator_ranges() { typedef signed char test_char_type; test_char_type data1[] = "1"; @@ -167,7 +167,7 @@ void test_signed_char_iterator_ranges() test_it_range_using_char(data1, data2); } -void test_wchar_iterator_ranges() +void test_wchar_iterator_ranges() { #ifndef BOOST_LCAST_NO_WCHAR_T typedef wchar_t test_char_type; @@ -179,7 +179,7 @@ void test_wchar_iterator_ranges() BOOST_CHECK(true); } -void test_char16_iterator_ranges() +void test_char16_iterator_ranges() { #if !defined(BOOST_NO_CHAR16_T) && !defined(BOOST_NO_UNICODE_LITERALS) typedef char16_t test_char_type; @@ -191,7 +191,7 @@ void test_char16_iterator_ranges() BOOST_CHECK(true); } -void test_char32_iterator_ranges() +void test_char32_iterator_ranges() { #if !defined(BOOST_NO_CHAR32_T) && !defined(BOOST_NO_UNICODE_LITERALS) typedef char32_t test_char_type; diff --git a/test/lexical_cast_no_exceptions_test.cpp b/test/lexical_cast_no_exceptions_test.cpp index dbec8ea..c470eda 100755 --- a/test/lexical_cast_no_exceptions_test.cpp +++ b/test/lexical_cast_no_exceptions_test.cpp @@ -22,7 +22,7 @@ #ifndef BOOST_NO_EXCEPTIONS #error "This test must be compiled with -DBOOST_NO_EXCEPTIONS" -#endif +#endif bool g_was_exception = false; @@ -60,25 +60,25 @@ inline std::istream& operator>> (std::istream& i, Escape& rhs) void test_exceptions_off() { Escape v(""); - - g_was_exception = false; + + g_was_exception = false; lexical_cast(v); BOOST_CHECK(g_was_exception); - + g_was_exception = false; lexical_cast(v); BOOST_CHECK(g_was_exception); - + v = lexical_cast(100); BOOST_CHECK_EQUAL(lexical_cast(v), 100); BOOST_CHECK_EQUAL(lexical_cast(v), 100u); - + v = lexical_cast(0.0); BOOST_CHECK_EQUAL(lexical_cast(v), 0.0); BOOST_CHECK_EQUAL(lexical_cast(100), 100); BOOST_CHECK_EQUAL(lexical_cast(0.0), 0.0); - + g_was_exception = false; lexical_cast(700000); BOOST_CHECK(g_was_exception); diff --git a/test/lexical_cast_no_locale_test.cpp b/test/lexical_cast_no_locale_test.cpp index f3defb3..2a5120b 100755 --- a/test/lexical_cast_no_locale_test.cpp +++ b/test/lexical_cast_no_locale_test.cpp @@ -23,12 +23,12 @@ using namespace boost; // Testing compilation and some basic usage with BOOST_NO_STD_LOCALE -// Tests are mainly copyied from lexical_cast_empty_input_test.cpp (something +// Tests are mainly copyied from lexical_cast_empty_input_test.cpp (something // new added to test_empty_3) #ifndef BOOST_NO_STD_LOCALE #error "This test must be compiled with -DBOOST_NO_STD_LOCALE" -#endif +#endif template @@ -106,15 +106,15 @@ void test_empty_3() { 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); - + v = lexical_cast(100); BOOST_CHECK_EQUAL(lexical_cast(v), 100); BOOST_CHECK_EQUAL(lexical_cast(v), 100u); - + v = lexical_cast(0.0); BOOST_CHECK_EQUAL(lexical_cast(v), 0.0); } diff --git a/test/lexical_cast_typedefed_wchar_test_runtime.cpp b/test/lexical_cast_typedefed_wchar_test_runtime.cpp index d01700a..adb024e 100755 --- a/test/lexical_cast_typedefed_wchar_test_runtime.cpp +++ b/test/lexical_cast_typedefed_wchar_test_runtime.cpp @@ -30,7 +30,7 @@ void test_typedefed_wchar_t_runtime() 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 From 675d0bb4516025323a5ff5dd67aa12368abf22e5 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Sun, 8 Jul 2012 18:06:32 +0000 Subject: [PATCH 49/66] Merge from trunk (now lexical_cast has optimized conversions to and from array<>, fixes #7065) [SVN r79364] --- doc/lexical_cast.qbk | 920 ++++++++++++---------- include/boost/lexical_cast.hpp | 231 +++++- lexical_cast_test.cpp | 477 +---------- perf/performance_test.cpp | 47 +- test/Jamfile.v2 | 2 + test/implicit_cast.cpp | 2 +- test/implicit_cast_fail.cpp | 2 + test/lexical_cast_arrays_test.cpp | 367 +++++++++ test/lexical_cast_integral_types_test.cpp | 539 +++++++++++++ 9 files changed, 1670 insertions(+), 917 deletions(-) create mode 100644 test/lexical_cast_arrays_test.cpp create mode 100644 test/lexical_cast_integral_types_test.cpp diff --git a/doc/lexical_cast.qbk b/doc/lexical_cast.qbk index b856594..59309d2 100644 --- a/doc/lexical_cast.qbk +++ b/doc/lexical_cast.qbk @@ -70,6 +70,15 @@ The following example uses numeric data in a string expression: log_message("Error " + boost::lexical_cast(yoko) + ": " + strerror(yoko)); } `` +Following example converts some number and puts it to file: +`` + int i; + FILE* file; + ... + typedef boost::array buf_t; // You can use std::array if your compiler supports it + buf_t buffer = boost::lexical_cast(i); // No dynamic memory allocation + puts(buffer.begin(), file); +`` [endsect] [section Synopsis] @@ -103,6 +112,7 @@ The character type of the underlying stream is assumed to be `char` unless eithe * Arrays of characters: `wchar_t *`, `char16_t *`, `char32_t *`, `const wchar_t *`, `const char16_t *`, `const char32_t *` * Strings: `std::basic_string`, `boost::containers::basic_string` * `boost::iterator_range`, where `WideCharPtr` is a pointer to wide-character or pointer to const wide-character +* `boost::array` and `std::array`, `boost::array` and `std::array` [important Many compilers and runtime libraries fail to make conversions using new Unicode characters. Make shure that the following code compiles and outputs nonzero values, before using new types: `` @@ -239,12 +249,20 @@ limitation of compiler options that you use. , `"-inf"` (case insensitive) strings to get NaN and Inf values. `boost::lexical_cast` outputs `"-nan"`, `"nan"`, `"inf"`, `"-inf"` strings, when has NaN or Inf input values. +[pre +] + * [*Question:] What is the fastest way to convert a non zero terminated string or a substring using `boost::lexical_cast`? * [*Answer:] Use `boost::iterator_range` for conversion. For example, if you whant to convert to `int` two characters from a string `str`, you shall write `lexacal_cast(make_iterator_range(str.c_str(), str.c_str() + 2));`. [endsect] [section Changes] + +* [*boost 1.51.0 :] + + * Better performance, less memory usage for `boost::array` and `std::array` conversions. + * [*boost 1.50.0 :] * `boost::bad_lexical_cast` exception is now globaly visible and can be catched even if code is compiled with -fvisibility=hidden. @@ -335,417 +353,507 @@ Do not use this results to compare compilers, because tests were taken on differ [/ BEGIN of section, generated by performance measuring program ] -[section Clang version 2.9 (tags/RELEASE_29/final)] -[table:id Performance Table ( Clang version 2.9 (tags/RELEASE_29/final)) + +[section Clang version 3.0 (tags/RELEASE_30/final)] +[table:id Performance Table ( Clang version 3.0 (tags/RELEASE_30/final)) [[From->To] [lexical_cast] [std::stringstream with construction] [std::stringstream without construction][scanf/printf]] - [[ string->char ][ !!! *<1* !!! ][ 319 ][ 17 ][ 16 ]] - [[ string->signed char ][ !!! *<1* !!! ][ 192 ][ 16 ][ 9 ]] - [[ string->unsigned char ][ !!! *<1* !!! ][ 142 ][ 9 ][ 9 ]] - [[ string->int ][ !!! *7* !!! ][ 109 ][ 21 ][ 16 ]] - [[ string->short ][ !!! *6* !!! ][ 113 ][ 21 ][ 15 ]] - [[ string->long int ][ !!! *7* !!! ][ 110 ][ 22 ][ 15 ]] - [[ string->long long ][ !!! *7* !!! ][ 112 ][ 23 ][ 17 ]] - [[ string->unsigned int ][ !!! *6* !!! ][ 107 ][ 19 ][ 14 ]] - [[ string->unsigned short ][ !!! *6* !!! ][ 106 ][ 18 ][ 16 ]] - [[ string->unsigned long int ][ !!! *7* !!! ][ 108 ][ 20 ][ 15 ]] - [[ string->unsigned long long ][ !!! *7* !!! ][ 109 ][ 22 ][ 15 ]] - [[ string->float ][ !!! *14* !!! ][ 204 ][ 81 ][ 43 ]] - [[ string->double ][ !!! *24* !!! ][ 244 ][ 74 ][ 45 ]] - [[ string->long double ][ 121 ][ 170 ][ 62 ][ !!! *38* !!! ]] - [[ string->string ][ !!! *1* !!! ][ 124 ][ 25 ][ --- ]] - [[ string->container::string ][ !!! *3* !!! ][ 121 ][ 28 ][ --- ]] - [[ string->char ][ 6 ][ 115 ][ 26 ][ !!! *6* !!! ]] - [[ string->signed char ][ !!! *6* !!! ][ 115 ][ 23 ][ 21 ]] - [[ string->unsigned char ][ !!! *6* !!! ][ 113 ][ 25 ][ 22 ]] - [[ int->string ][ !!! *12* !!! ][ 128 ][ 29 ][ 19 ]] - [[ short->string ][ !!! *12* !!! ][ 128 ][ 29 ][ 21 ]] - [[ long int->string ][ !!! *12* !!! ][ 132 ][ 29 ][ 21 ]] - [[ long long->string ][ !!! *12* !!! ][ 127 ][ 29 ][ 22 ]] - [[ unsigned int->string ][ !!! *12* !!! ][ 137 ][ 33 ][ 19 ]] - [[ unsigned short->string ][ !!! *12* !!! ][ 137 ][ 31 ][ 20 ]] - [[ unsigned long int->string ][ !!! *12* !!! ][ 136 ][ 30 ][ 21 ]] - [[ unsigned long long->string ][ !!! *12* !!! ][ 128 ][ 27 ][ 23 ]] - [[ float->string ][ 51 ][ 187 ][ 82 ][ !!! *44* !!! ]] - [[ double->string ][ 56 ][ 190 ][ 83 ][ !!! *42* !!! ]] - [[ long double->string ][ 69 ][ 208 ][ 90 ][ !!! *54* !!! ]] - [[ char*->char ][ !!! *<1* !!! ][ 138 ][ 18 ][ 8 ]] - [[ char*->signed char ][ !!! *8* !!! ][ 126 ][ 10 ][ 9 ]] - [[ char*->unsigned char ][ !!! *<1* !!! ][ 98 ][ 9 ][ 9 ]] - [[ char*->int ][ !!! *8* !!! ][ 113 ][ 22 ][ 15 ]] - [[ char*->short ][ !!! *7* !!! ][ 113 ][ 22 ][ 17 ]] - [[ char*->long int ][ !!! *8* !!! ][ 111 ][ 23 ][ 15 ]] - [[ char*->long long ][ !!! *9* !!! ][ 112 ][ 24 ][ 18 ]] - [[ char*->unsigned int ][ !!! *8* !!! ][ 113 ][ 20 ][ 15 ]] - [[ char*->unsigned short ][ !!! *8* !!! ][ 113 ][ 20 ][ 15 ]] - [[ char*->unsigned long int ][ !!! *8* !!! ][ 112 ][ 21 ][ 16 ]] - [[ char*->unsigned long long ][ !!! *9* !!! ][ 110 ][ 23 ][ 14 ]] - [[ char*->float ][ !!! *14* !!! ][ 149 ][ 54 ][ 32 ]] - [[ char*->double ][ !!! *15* !!! ][ 166 ][ 59 ][ 33 ]] - [[ char*->long double ][ 122 ][ 171 ][ 63 ][ !!! *38* !!! ]] - [[ char*->string ][ !!! *7* !!! ][ 126 ][ 26 ][ --- ]] - [[ char*->container::string ][ !!! *2* !!! ][ 124 ][ 27 ][ --- ]] - [[ unsigned char*->char ][ !!! *<1* !!! ][ 99 ][ 10 ][ 8 ]] - [[ unsigned char*->signed char ][ !!! *<1* !!! ][ 102 ][ 10 ][ 9 ]] - [[ unsigned char*->unsigned char ][ !!! *<1* !!! ][ 98 ][ 10 ][ 9 ]] - [[ unsigned char*->int ][ !!! *7* !!! ][ 115 ][ 24 ][ 15 ]] - [[ unsigned char*->short ][ !!! *7* !!! ][ 115 ][ 25 ][ 17 ]] - [[ unsigned char*->long int ][ !!! *8* !!! ][ 115 ][ 22 ][ 16 ]] - [[ unsigned char*->long long ][ !!! *8* !!! ][ 116 ][ 23 ][ 16 ]] - [[ unsigned char*->unsigned int ][ !!! *8* !!! ][ 113 ][ 20 ][ 14 ]] - [[ unsigned char*->unsigned short ][ !!! *7* !!! ][ 114 ][ 21 ][ 15 ]] - [[ unsigned char*->unsigned long int ][ !!! *8* !!! ][ 114 ][ 21 ][ 14 ]] - [[ unsigned char*->unsigned long long ][ !!! *9* !!! ][ 112 ][ 23 ][ 16 ]] - [[ unsigned char*->float ][ !!! *14* !!! ][ 149 ][ 52 ][ 32 ]] - [[ unsigned char*->double ][ !!! *15* !!! ][ 165 ][ 59 ][ 33 ]] - [[ unsigned char*->long double ][ 122 ][ 172 ][ 63 ][ !!! *37* !!! ]] - [[ unsigned char*->string ][ !!! *8* !!! ][ 125 ][ 26 ][ --- ]] - [[ unsigned char*->container::string ][ !!! *4* !!! ][ 119 ][ 26 ][ --- ]] - [[ signed char*->char ][ !!! *<1* !!! ][ 98 ][ 10 ][ 8 ]] - [[ signed char*->signed char ][ !!! *<1* !!! ][ 95 ][ 10 ][ 9 ]] - [[ signed char*->unsigned char ][ !!! *<1* !!! ][ 98 ][ 9 ][ 9 ]] - [[ signed char*->int ][ !!! *8* !!! ][ 111 ][ 21 ][ 15 ]] - [[ signed char*->short ][ !!! *7* !!! ][ 114 ][ 22 ][ 16 ]] - [[ signed char*->long int ][ !!! *8* !!! ][ 113 ][ 22 ][ 17 ]] - [[ signed char*->long long ][ !!! *8* !!! ][ 116 ][ 24 ][ 17 ]] - [[ signed char*->unsigned int ][ !!! *8* !!! ][ 109 ][ 20 ][ 15 ]] - [[ signed char*->unsigned short ][ !!! *8* !!! ][ 111 ][ 20 ][ 14 ]] - [[ signed char*->unsigned long int ][ !!! *8* !!! ][ 109 ][ 22 ][ 15 ]] - [[ signed char*->unsigned long long ][ !!! *8* !!! ][ 111 ][ 23 ][ 15 ]] - [[ signed char*->float ][ !!! *14* !!! ][ 150 ][ 53 ][ 32 ]] - [[ signed char*->double ][ !!! *15* !!! ][ 168 ][ 59 ][ 30 ]] - [[ signed char*->long double ][ 123 ][ 174 ][ 62 ][ !!! *37* !!! ]] + [[ string->char ][ !!! *<1* !!! ][ 169 ][ 9 ][ 10 ]] + [[ string->signed char ][ !!! *<1* !!! ][ 108 ][ 8 ][ 10 ]] + [[ string->unsigned char ][ !!! *<1* !!! ][ 103 ][ 9 ][ 10 ]] + [[ string->int ][ !!! *6* !!! ][ 117 ][ 24 ][ 24 ]] + [[ string->short ][ !!! *7* !!! ][ 115 ][ 20 ][ 24 ]] + [[ string->long int ][ !!! *7* !!! ][ 115 ][ 19 ][ 22 ]] + [[ string->long long ][ !!! *8* !!! ][ 116 ][ 21 ][ 23 ]] + [[ string->unsigned int ][ !!! *6* !!! ][ 121 ][ 18 ][ 23 ]] + [[ string->unsigned short ][ !!! *6* !!! ][ 116 ][ 19 ][ 22 ]] + [[ string->unsigned long int ][ !!! *7* !!! ][ 117 ][ 23 ][ 21 ]] + [[ string->unsigned long long ][ !!! *8* !!! ][ 118 ][ 19 ][ 34 ]] + [[ string->float ][ !!! *13* !!! ][ 201 ][ 55 ][ 41 ]] + [[ string->double ][ !!! *14* !!! ][ 151 ][ 54 ][ 41 ]] + [[ string->long double ][ 195 ][ 231 ][ 67 ][ !!! *42* !!! ]] + [[ string->array ][ !!! *<1* !!! ][ 121 ][ 18 ][ 12 ]] + [[ string->string ][ !!! *1* !!! ][ 124 ][ 27 ][ --- ]] + [[ string->container::string ][ !!! *3* !!! ][ 114 ][ 25 ][ --- ]] + [[ string->char ][ 7 ][ 111 ][ 25 ][ !!! *7* !!! ]] + [[ string->signed char ][ !!! *6* !!! ][ 112 ][ 30 ][ 26 ]] + [[ string->unsigned char ][ !!! *6* !!! ][ 113 ][ 25 ][ 24 ]] + [[ int->string ][ !!! *12* !!! ][ 126 ][ 36 ][ 21 ]] + [[ short->string ][ !!! *11* !!! ][ 135 ][ 30 ][ 21 ]] + [[ long int->string ][ !!! *11* !!! ][ 128 ][ 28 ][ 21 ]] + [[ long long->string ][ !!! *12* !!! ][ 126 ][ 32 ][ 24 ]] + [[ unsigned int->string ][ !!! *11* !!! ][ 131 ][ 36 ][ 22 ]] + [[ unsigned short->string ][ !!! *11* !!! ][ 130 ][ 28 ][ 22 ]] + [[ unsigned long int->string ][ !!! *11* !!! ][ 130 ][ 36 ][ 22 ]] + [[ unsigned long long->string ][ !!! *11* !!! ][ 127 ][ 43 ][ 25 ]] + [[ float->string ][ 53 ][ 190 ][ 83 ][ !!! *41* !!! ]] + [[ double->string ][ 59 ][ 197 ][ 82 ][ !!! *44* !!! ]] + [[ long double->string ][ 118 ][ 229 ][ 101 ][ !!! *44* !!! ]] + [[ char*->char ][ !!! *1* !!! ][ 105 ][ 9 ][ 9 ]] + [[ char*->signed char ][ !!! *1* !!! ][ 107 ][ 10 ][ 10 ]] + [[ char*->unsigned char ][ !!! *1* !!! ][ 106 ][ 9 ][ 11 ]] + [[ char*->int ][ !!! *7* !!! ][ 149 ][ 25 ][ 24 ]] + [[ char*->short ][ !!! *7* !!! ][ 118 ][ 20 ][ 22 ]] + [[ char*->long int ][ !!! *9* !!! ][ 117 ][ 20 ][ 28 ]] + [[ char*->long long ][ !!! *9* !!! ][ 128 ][ 23 ][ 29 ]] + [[ char*->unsigned int ][ !!! *7* !!! ][ 120 ][ 19 ][ 23 ]] + [[ char*->unsigned short ][ !!! *7* !!! ][ 125 ][ 20 ][ 22 ]] + [[ char*->unsigned long int ][ !!! *8* !!! ][ 125 ][ 21 ][ 24 ]] + [[ char*->unsigned long long ][ !!! *8* !!! ][ 130 ][ 19 ][ 22 ]] + [[ char*->float ][ !!! *14* !!! ][ 162 ][ 56 ][ 41 ]] + [[ char*->double ][ !!! *16* !!! ][ 151 ][ 54 ][ 39 ]] + [[ char*->long double ][ 111 ][ 176 ][ 58 ][ !!! *42* !!! ]] + [[ char*->array ][ !!! *1* !!! ][ 116 ][ 20 ][ 17 ]] + [[ char*->string ][ !!! *8* !!! ][ 125 ][ 27 ][ --- ]] + [[ char*->container::string ][ !!! *2* !!! ][ 115 ][ 26 ][ --- ]] + [[ unsigned char*->char ][ !!! *1* !!! ][ 101 ][ 9 ][ 9 ]] + [[ unsigned char*->signed char ][ !!! *1* !!! ][ 104 ][ 9 ][ 11 ]] + [[ unsigned char*->unsigned char ][ !!! *1* !!! ][ 103 ][ 9 ][ 13 ]] + [[ unsigned char*->int ][ !!! *8* !!! ][ 116 ][ 20 ][ 24 ]] + [[ unsigned char*->short ][ !!! *7* !!! ][ 121 ][ 20 ][ 26 ]] + [[ unsigned char*->long int ][ !!! *8* !!! ][ 118 ][ 20 ][ 22 ]] + [[ unsigned char*->long long ][ !!! *8* !!! ][ 122 ][ 20 ][ 23 ]] + [[ unsigned char*->unsigned int ][ !!! *6* !!! ][ 119 ][ 22 ][ 23 ]] + [[ unsigned char*->unsigned short ][ !!! *7* !!! ][ 122 ][ 20 ][ 22 ]] + [[ unsigned char*->unsigned long int ][ !!! *8* !!! ][ 125 ][ 21 ][ 22 ]] + [[ unsigned char*->unsigned long long ][ !!! *8* !!! ][ 122 ][ 19 ][ 25 ]] + [[ unsigned char*->float ][ !!! *14* !!! ][ 162 ][ 62 ][ 37 ]] + [[ unsigned char*->double ][ !!! *15* !!! ][ 151 ][ 58 ][ 39 ]] + [[ unsigned char*->long double ][ 116 ][ 156 ][ 58 ][ !!! *42* !!! ]] + [[ unsigned char*->array ][ !!! *1* !!! ][ 122 ][ 19 ][ 15 ]] + [[ unsigned char*->string ][ !!! *8* !!! ][ 124 ][ 27 ][ --- ]] + [[ unsigned char*->container::string ][ !!! *4* !!! ][ 119 ][ 25 ][ --- ]] + [[ signed char*->char ][ !!! *1* !!! ][ 107 ][ 9 ][ 9 ]] + [[ signed char*->signed char ][ !!! *1* !!! ][ 108 ][ 10 ][ 11 ]] + [[ signed char*->unsigned char ][ !!! *1* !!! ][ 106 ][ 9 ][ 11 ]] + [[ signed char*->int ][ !!! *7* !!! ][ 122 ][ 21 ][ 22 ]] + [[ signed char*->short ][ !!! *7* !!! ][ 126 ][ 20 ][ 22 ]] + [[ signed char*->long int ][ !!! *8* !!! ][ 119 ][ 20 ][ 23 ]] + [[ signed char*->long long ][ !!! *8* !!! ][ 119 ][ 21 ][ 26 ]] + [[ signed char*->unsigned int ][ !!! *6* !!! ][ 124 ][ 18 ][ 22 ]] + [[ signed char*->unsigned short ][ !!! *7* !!! ][ 124 ][ 21 ][ 23 ]] + [[ signed char*->unsigned long int ][ !!! *8* !!! ][ 121 ][ 24 ][ 23 ]] + [[ signed char*->unsigned long long ][ !!! *8* !!! ][ 122 ][ 20 ][ 22 ]] + [[ signed char*->float ][ !!! *14* !!! ][ 167 ][ 56 ][ 37 ]] + [[ signed char*->double ][ !!! *14* !!! ][ 162 ][ 53 ][ 40 ]] + [[ signed char*->long double ][ 110 ][ 152 ][ 56 ][ !!! *42* !!! ]] + [[ signed char*->array ][ !!! *1* !!! ][ 117 ][ 19 ][ 12 ]] + [[ signed char*->string ][ !!! *8* !!! ][ 132 ][ 27 ][ --- ]] + [[ signed char*->container::string ][ !!! *4* !!! ][ 116 ][ 26 ][ --- ]] + [[ iterator_range->char ][ !!! *<1* !!! ][ 112 ][ 14 ][ 9 ]] + [[ iterator_range->signed char ][ !!! *<1* !!! ][ 107 ][ 13 ][ 10 ]] + [[ iterator_range->unsigned char ][ !!! *<1* !!! ][ 145 ][ 15 ][ 10 ]] + [[ iterator_range->int ][ !!! *6* !!! ][ 119 ][ 22 ][ 23 ]] + [[ iterator_range->short ][ !!! *6* !!! ][ 115 ][ 22 ][ 23 ]] + [[ iterator_range->long int ][ !!! *7* !!! ][ 115 ][ 25 ][ 22 ]] + [[ iterator_range->long long ][ !!! *7* !!! ][ 117 ][ 21 ][ 23 ]] + [[ iterator_range->unsigned int ][ !!! *6* !!! ][ 118 ][ 22 ][ 22 ]] + [[ iterator_range->unsigned short ][ !!! *6* !!! ][ 117 ][ 24 ][ 22 ]] + [[ iterator_range->unsigned long int ][ !!! *7* !!! ][ 124 ][ 25 ][ 22 ]] + [[ iterator_range->unsigned long long ][ !!! *7* !!! ][ 119 ][ 22 ][ 22 ]] + [[ iterator_range->float ][ !!! *13* !!! ][ 159 ][ 42 ][ 41 ]] + [[ iterator_range->double ][ !!! *14* !!! ][ 152 ][ 40 ][ 40 ]] + [[ iterator_range->long double ][ 113 ][ 155 ][ 58 ][ !!! *54* !!! ]] + [[ iterator_range->array ][ !!! *<1* !!! ][ 127 ][ 23 ][ 13 ]] + [[ iterator_range->string ][ !!! *7* !!! ][ 132 ][ 30 ][ --- ]] + [[ iterator_range->container::string ][ !!! *3* !!! ][ 122 ][ 24 ][ --- ]] + [[ array->char ][ !!! *<1* !!! ][ 110 ][ 9 ][ 10 ]] + [[ array->signed char ][ !!! *<1* !!! ][ 119 ][ 9 ][ 13 ]] + [[ array->unsigned char ][ !!! *<1* !!! ][ 106 ][ 13 ][ 11 ]] + [[ array->int ][ !!! *6* !!! ][ 131 ][ 21 ][ 22 ]] + [[ array->short ][ !!! *7* !!! ][ 119 ][ 22 ][ 28 ]] + [[ array->long int ][ !!! *8* !!! ][ 133 ][ 21 ][ 26 ]] + [[ array->long long ][ !!! *8* !!! ][ 115 ][ 22 ][ 23 ]] + [[ array->unsigned int ][ !!! *6* !!! ][ 118 ][ 18 ][ 22 ]] + [[ array->unsigned short ][ !!! *7* !!! ][ 119 ][ 19 ][ 22 ]] + [[ array->unsigned long int ][ !!! *7* !!! ][ 118 ][ 23 ][ 21 ]] + [[ array->unsigned long long ][ !!! *7* !!! ][ 117 ][ 20 ][ 22 ]] + [[ array->float ][ !!! *15* !!! ][ 156 ][ 53 ][ 36 ]] + [[ array->double ][ !!! *15* !!! ][ 148 ][ 55 ][ 39 ]] + [[ array->long double ][ 110 ][ 150 ][ 56 ][ !!! *41* !!! ]] + [[ array->array ][ !!! *<1* !!! ][ 117 ][ 19 ][ 12 ]] + [[ array->string ][ !!! *7* !!! ][ 124 ][ 26 ][ --- ]] + [[ array->container::string ][ !!! *4* !!! ][ 115 ][ 26 ][ --- ]] + [[ int->int ][ !!! *<1* !!! ][ 117 ][ 24 ][ --- ]] + [[ float->double ][ !!! *<1* !!! ][ 245 ][ 125 ][ --- ]] + [[ char->signed char ][ !!! *<1* !!! ][ 100 ][ 9 ][ --- ]] +] +[endsect] + +[section GNU C++ version 4.6.3] +[table:id Performance Table ( GNU C++ version 4.6.3) +[[From->To] [lexical_cast] [std::stringstream with construction] [std::stringstream without construction][scanf/printf]] + [[ string->char ][ !!! *<1* !!! ][ 142 ][ 10 ][ 18 ]] + [[ string->signed char ][ !!! *<1* !!! ][ 111 ][ 8 ][ 10 ]] + [[ string->unsigned char ][ !!! *<1* !!! ][ 101 ][ 8 ][ 10 ]] + [[ string->int ][ !!! *7* !!! ][ 110 ][ 20 ][ 24 ]] + [[ string->short ][ !!! *6* !!! ][ 109 ][ 20 ][ 25 ]] + [[ string->long int ][ !!! *7* !!! ][ 113 ][ 19 ][ 24 ]] + [[ string->long long ][ !!! *7* !!! ][ 116 ][ 24 ][ 23 ]] + [[ string->unsigned int ][ !!! *6* !!! ][ 110 ][ 19 ][ 23 ]] + [[ string->unsigned short ][ !!! *5* !!! ][ 116 ][ 18 ][ 23 ]] + [[ string->unsigned long int ][ !!! *7* !!! ][ 111 ][ 22 ][ 23 ]] + [[ string->unsigned long long ][ !!! *7* !!! ][ 108 ][ 20 ][ 22 ]] + [[ string->float ][ !!! *11* !!! ][ 161 ][ 54 ][ 38 ]] + [[ string->double ][ !!! *11* !!! ][ 146 ][ 56 ][ 41 ]] + [[ string->long double ][ 113 ][ 151 ][ 59 ][ !!! *43* !!! ]] + [[ string->array ][ !!! *<1* !!! ][ 107 ][ 18 ][ 14 ]] + [[ string->string ][ !!! *2* !!! ][ 127 ][ 24 ][ --- ]] + [[ string->container::string ][ !!! *3* !!! ][ 142 ][ 26 ][ --- ]] + [[ string->char ][ !!! *7* !!! ][ 110 ][ 23 ][ 17 ]] + [[ string->signed char ][ !!! *7* !!! ][ 114 ][ 23 ][ 24 ]] + [[ string->unsigned char ][ !!! *7* !!! ][ 110 ][ 25 ][ 24 ]] + [[ int->string ][ !!! *12* !!! ][ 127 ][ 31 ][ 22 ]] + [[ short->string ][ !!! *13* !!! ][ 129 ][ 31 ][ 22 ]] + [[ long int->string ][ !!! *12* !!! ][ 125 ][ 30 ][ 22 ]] + [[ long long->string ][ !!! *13* !!! ][ 127 ][ 34 ][ 24 ]] + [[ unsigned int->string ][ !!! *13* !!! ][ 127 ][ 27 ][ 21 ]] + [[ unsigned short->string ][ !!! *12* !!! ][ 127 ][ 28 ][ 22 ]] + [[ unsigned long int->string ][ !!! *12* !!! ][ 131 ][ 27 ][ 22 ]] + [[ unsigned long long->string ][ !!! *12* !!! ][ 125 ][ 28 ][ 24 ]] + [[ float->string ][ 51 ][ 200 ][ 81 ][ !!! *40* !!! ]] + [[ double->string ][ 56 ][ 194 ][ 82 ][ !!! *48* !!! ]] + [[ long double->string ][ 65 ][ 220 ][ 82 ][ !!! *41* !!! ]] + [[ char*->char ][ !!! *<1* !!! ][ 104 ][ 10 ][ 9 ]] + [[ char*->signed char ][ !!! *<1* !!! ][ 101 ][ 10 ][ 11 ]] + [[ char*->unsigned char ][ !!! *<1* !!! ][ 99 ][ 10 ][ 12 ]] + [[ char*->int ][ !!! *6* !!! ][ 112 ][ 23 ][ 24 ]] + [[ char*->short ][ !!! *6* !!! ][ 115 ][ 21 ][ 23 ]] + [[ char*->long int ][ !!! *8* !!! ][ 111 ][ 21 ][ 24 ]] + [[ char*->long long ][ !!! *9* !!! ][ 112 ][ 21 ][ 30 ]] + [[ char*->unsigned int ][ !!! *7* !!! ][ 112 ][ 22 ][ 24 ]] + [[ char*->unsigned short ][ !!! *6* !!! ][ 119 ][ 19 ][ 23 ]] + [[ char*->unsigned long int ][ !!! *7* !!! ][ 115 ][ 22 ][ 23 ]] + [[ char*->unsigned long long ][ !!! *7* !!! ][ 115 ][ 20 ][ 23 ]] + [[ char*->float ][ !!! *12* !!! ][ 153 ][ 54 ][ 39 ]] + [[ char*->double ][ !!! *12* !!! ][ 153 ][ 61 ][ 41 ]] + [[ char*->long double ][ 108 ][ 160 ][ 61 ][ !!! *49* !!! ]] + [[ char*->array ][ !!! *<1* !!! ][ 107 ][ 20 ][ 14 ]] + [[ char*->string ][ !!! *7* !!! ][ 123 ][ 26 ][ --- ]] + [[ char*->container::string ][ !!! *2* !!! ][ 121 ][ 24 ][ --- ]] + [[ unsigned char*->char ][ !!! *<1* !!! ][ 97 ][ 10 ][ 9 ]] + [[ unsigned char*->signed char ][ !!! *<1* !!! ][ 98 ][ 10 ][ 12 ]] + [[ unsigned char*->unsigned char ][ !!! *<1* !!! ][ 99 ][ 11 ][ 12 ]] + [[ unsigned char*->int ][ !!! *6* !!! ][ 112 ][ 22 ][ 24 ]] + [[ unsigned char*->short ][ !!! *10* !!! ][ 111 ][ 24 ][ 24 ]] + [[ unsigned char*->long int ][ !!! *8* !!! ][ 110 ][ 23 ][ 24 ]] + [[ unsigned char*->long long ][ !!! *9* !!! ][ 115 ][ 21 ][ 25 ]] + [[ unsigned char*->unsigned int ][ !!! *6* !!! ][ 111 ][ 24 ][ 23 ]] + [[ unsigned char*->unsigned short ][ !!! *6* !!! ][ 118 ][ 19 ][ 23 ]] + [[ unsigned char*->unsigned long int ][ !!! *8* !!! ][ 112 ][ 21 ][ 23 ]] + [[ unsigned char*->unsigned long long ][ !!! *13* !!! ][ 109 ][ 20 ][ 23 ]] + [[ unsigned char*->float ][ !!! *12* !!! ][ 154 ][ 56 ][ 39 ]] + [[ unsigned char*->double ][ !!! *17* !!! ][ 150 ][ 58 ][ 41 ]] + [[ unsigned char*->long double ][ 108 ][ 149 ][ 68 ][ !!! *43* !!! ]] + [[ unsigned char*->array ][ !!! *1* !!! ][ 107 ][ 19 ][ 15 ]] + [[ unsigned char*->string ][ !!! *8* !!! ][ 124 ][ 26 ][ --- ]] + [[ unsigned char*->container::string ][ !!! *4* !!! ][ 121 ][ 24 ][ --- ]] + [[ signed char*->char ][ !!! *<1* !!! ][ 99 ][ 10 ][ 9 ]] + [[ signed char*->signed char ][ !!! *<1* !!! ][ 99 ][ 10 ][ 10 ]] + [[ signed char*->unsigned char ][ !!! *<1* !!! ][ 99 ][ 10 ][ 12 ]] + [[ signed char*->int ][ !!! *6* !!! ][ 113 ][ 28 ][ 24 ]] + [[ signed char*->short ][ !!! *6* !!! ][ 110 ][ 21 ][ 25 ]] + [[ signed char*->long int ][ !!! *8* !!! ][ 110 ][ 21 ][ 24 ]] + [[ signed char*->long long ][ !!! *9* !!! ][ 116 ][ 21 ][ 24 ]] + [[ signed char*->unsigned int ][ !!! *7* !!! ][ 114 ][ 21 ][ 23 ]] + [[ signed char*->unsigned short ][ !!! *6* !!! ][ 116 ][ 20 ][ 23 ]] + [[ signed char*->unsigned long int ][ !!! *8* !!! ][ 113 ][ 27 ][ 23 ]] + [[ signed char*->unsigned long long ][ !!! *8* !!! ][ 110 ][ 20 ][ 23 ]] + [[ signed char*->float ][ !!! *12* !!! ][ 155 ][ 53 ][ 44 ]] + [[ signed char*->double ][ !!! *13* !!! ][ 150 ][ 60 ][ 42 ]] + [[ signed char*->long double ][ 108 ][ 151 ][ 62 ][ !!! *44* !!! ]] + [[ signed char*->array ][ !!! *1* !!! ][ 107 ][ 19 ][ 15 ]] + [[ signed char*->string ][ !!! *8* !!! ][ 124 ][ 26 ][ --- ]] + [[ signed char*->container::string ][ !!! *4* !!! ][ 121 ][ 24 ][ --- ]] + [[ iterator_range->char ][ !!! *<1* !!! ][ 103 ][ 14 ][ 10 ]] + [[ iterator_range->signed char ][ !!! *<1* !!! ][ 102 ][ 15 ][ 12 ]] + [[ iterator_range->unsigned char ][ !!! *<1* !!! ][ 102 ][ 14 ][ 12 ]] + [[ iterator_range->int ][ !!! *6* !!! ][ 115 ][ 23 ][ 24 ]] + [[ iterator_range->short ][ !!! *5* !!! ][ 110 ][ 22 ][ 24 ]] + [[ iterator_range->long int ][ !!! *7* !!! ][ 109 ][ 22 ][ 29 ]] + [[ iterator_range->long long ][ !!! *7* !!! ][ 111 ][ 24 ][ 28 ]] + [[ iterator_range->unsigned int ][ !!! *6* !!! ][ 114 ][ 22 ][ 23 ]] + [[ iterator_range->unsigned short ][ !!! *5* !!! ][ 115 ][ 20 ][ 22 ]] + [[ iterator_range->unsigned long int ][ !!! *7* !!! ][ 123 ][ 26 ][ 23 ]] + [[ iterator_range->unsigned long long ][ !!! *7* !!! ][ 110 ][ 23 ][ 24 ]] + [[ iterator_range->float ][ !!! *11* !!! ][ 153 ][ 38 ][ 38 ]] + [[ iterator_range->double ][ !!! *11* !!! ][ 140 ][ 43 ][ 40 ]] + [[ iterator_range->long double ][ 108 ][ 147 ][ !!! *41* !!! ][ 46 ]] + [[ iterator_range->array ][ !!! *<1* !!! ][ 109 ][ 22 ][ 15 ]] + [[ iterator_range->string ][ !!! *8* !!! ][ 122 ][ 29 ][ --- ]] + [[ iterator_range->container::string ][ !!! *3* !!! ][ 117 ][ 23 ][ --- ]] + [[ array->char ][ !!! *<1* !!! ][ 98 ][ 10 ][ 9 ]] + [[ array->signed char ][ !!! *<1* !!! ][ 99 ][ 9 ][ 12 ]] + [[ array->unsigned char ][ !!! *<1* !!! ][ 102 ][ 9 ][ 12 ]] + [[ array->int ][ !!! *6* !!! ][ 119 ][ 23 ][ 23 ]] + [[ array->short ][ !!! *6* !!! ][ 111 ][ 21 ][ 26 ]] + [[ array->long int ][ !!! *7* !!! ][ 115 ][ 20 ][ 28 ]] + [[ array->long long ][ !!! *9* !!! ][ 110 ][ 21 ][ 26 ]] + [[ array->unsigned int ][ !!! *6* !!! ][ 115 ][ 22 ][ 23 ]] + [[ array->unsigned short ][ !!! *6* !!! ][ 115 ][ 19 ][ 23 ]] + [[ array->unsigned long int ][ !!! *7* !!! ][ 118 ][ 23 ][ 23 ]] + [[ array->unsigned long long ][ !!! *7* !!! ][ 109 ][ 20 ][ 24 ]] + [[ array->float ][ !!! *12* !!! ][ 160 ][ 53 ][ 38 ]] + [[ array->double ][ !!! *11* !!! ][ 147 ][ 57 ][ 41 ]] + [[ array->long double ][ 109 ][ 154 ][ 59 ][ !!! *42* !!! ]] + [[ array->array ][ !!! *1* !!! ][ 105 ][ 19 ][ 14 ]] + [[ array->string ][ !!! *8* !!! ][ 129 ][ 26 ][ --- ]] + [[ array->container::string ][ !!! *4* !!! ][ 116 ][ 25 ][ --- ]] + [[ int->int ][ !!! *<1* !!! ][ 118 ][ 24 ][ --- ]] + [[ float->double ][ !!! *<1* !!! ][ 242 ][ 132 ][ --- ]] + [[ char->signed char ][ !!! *<1* !!! ][ 94 ][ 8 ][ --- ]] +] +[endsect] + +[section GNU C++ version 4.5.3] +[table:id Performance Table ( GNU C++ version 4.5.3) +[[From->To] [lexical_cast] [std::stringstream with construction] [std::stringstream without construction][scanf/printf]] + [[ string->char ][ !!! *<1* !!! ][ 153 ][ 15 ][ 9 ]] + [[ string->signed char ][ !!! *<1* !!! ][ 134 ][ 8 ][ 10 ]] + [[ string->unsigned char ][ !!! *<1* !!! ][ 97 ][ 8 ][ 14 ]] + [[ string->int ][ !!! *7* !!! ][ 115 ][ 22 ][ 22 ]] + [[ string->short ][ !!! *5* !!! ][ 112 ][ 19 ][ 21 ]] + [[ string->long int ][ !!! *7* !!! ][ 110 ][ 19 ][ 24 ]] + [[ string->long long ][ !!! *7* !!! ][ 115 ][ 21 ][ 23 ]] + [[ string->unsigned int ][ !!! *6* !!! ][ 113 ][ 20 ][ 23 ]] + [[ string->unsigned short ][ !!! *5* !!! ][ 116 ][ 18 ][ 23 ]] + [[ string->unsigned long int ][ !!! *7* !!! ][ 111 ][ 20 ][ 23 ]] + [[ string->unsigned long long ][ !!! *7* !!! ][ 115 ][ 18 ][ 23 ]] + [[ string->float ][ !!! *14* !!! ][ 153 ][ 55 ][ 38 ]] + [[ string->double ][ !!! *11* !!! ][ 151 ][ 60 ][ 38 ]] + [[ string->long double ][ 107 ][ 151 ][ 59 ][ !!! *44* !!! ]] + [[ string->array ][ !!! *<1* !!! ][ 107 ][ 18 ][ 12 ]] + [[ string->string ][ !!! *2* !!! ][ 129 ][ 49 ][ --- ]] + [[ string->container::string ][ !!! *9* !!! ][ 199 ][ 22 ][ --- ]] + [[ string->char ][ !!! *7* !!! ][ 114 ][ 27 ][ 16 ]] + [[ string->signed char ][ !!! *7* !!! ][ 116 ][ 32 ][ 23 ]] + [[ string->unsigned char ][ !!! *7* !!! ][ 114 ][ 27 ][ 22 ]] + [[ int->string ][ !!! *11* !!! ][ 125 ][ 31 ][ 21 ]] + [[ short->string ][ !!! *11* !!! ][ 126 ][ 33 ][ 21 ]] + [[ long int->string ][ !!! *11* !!! ][ 126 ][ 32 ][ 22 ]] + [[ long long->string ][ !!! *11* !!! ][ 118 ][ 30 ][ 23 ]] + [[ unsigned int->string ][ !!! *11* !!! ][ 125 ][ 31 ][ 20 ]] + [[ unsigned short->string ][ !!! *12* !!! ][ 128 ][ 30 ][ 21 ]] + [[ unsigned long int->string ][ !!! *11* !!! ][ 131 ][ 30 ][ 21 ]] + [[ unsigned long long->string ][ !!! *11* !!! ][ 127 ][ 32 ][ 23 ]] + [[ float->string ][ 49 ][ 197 ][ 92 ][ !!! *39* !!! ]] + [[ double->string ][ 56 ][ 195 ][ 80 ][ !!! *43* !!! ]] + [[ long double->string ][ 60 ][ 222 ][ 88 ][ !!! *42* !!! ]] + [[ char*->char ][ !!! *<1* !!! ][ 100 ][ 10 ][ 9 ]] + [[ char*->signed char ][ !!! *<1* !!! ][ 99 ][ 10 ][ 10 ]] + [[ char*->unsigned char ][ !!! *<1* !!! ][ 106 ][ 10 ][ 10 ]] + [[ char*->int ][ !!! *7* !!! ][ 113 ][ 23 ][ 22 ]] + [[ char*->short ][ !!! *6* !!! ][ 113 ][ 21 ][ 23 ]] + [[ char*->long int ][ !!! *8* !!! ][ 116 ][ 21 ][ 23 ]] + [[ char*->long long ][ !!! *8* !!! ][ 115 ][ 21 ][ 21 ]] + [[ char*->unsigned int ][ !!! *6* !!! ][ 114 ][ 25 ][ 22 ]] + [[ char*->unsigned short ][ !!! *6* !!! ][ 119 ][ 20 ][ 23 ]] + [[ char*->unsigned long int ][ !!! *8* !!! ][ 114 ][ 23 ][ 23 ]] + [[ char*->unsigned long long ][ !!! *7* !!! ][ 111 ][ 20 ][ 24 ]] + [[ char*->float ][ !!! *16* !!! ][ 154 ][ 54 ][ 38 ]] + [[ char*->double ][ !!! *12* !!! ][ 149 ][ 59 ][ 40 ]] + [[ char*->long double ][ 107 ][ 166 ][ 62 ][ !!! *44* !!! ]] + [[ char*->array ][ !!! *1* !!! ][ 108 ][ 20 ][ 12 ]] + [[ char*->string ][ !!! *8* !!! ][ 125 ][ 28 ][ --- ]] + [[ char*->container::string ][ !!! *2* !!! ][ 123 ][ 24 ][ --- ]] + [[ unsigned char*->char ][ !!! *<1* !!! ][ 104 ][ 11 ][ 9 ]] + [[ unsigned char*->signed char ][ !!! *<1* !!! ][ 106 ][ 10 ][ 10 ]] + [[ unsigned char*->unsigned char ][ !!! *<1* !!! ][ 101 ][ 10 ][ 10 ]] + [[ unsigned char*->int ][ !!! *7* !!! ][ 117 ][ 22 ][ 24 ]] + [[ unsigned char*->short ][ !!! *6* !!! ][ 111 ][ 26 ][ 22 ]] + [[ unsigned char*->long int ][ !!! *8* !!! ][ 111 ][ 23 ][ 23 ]] + [[ unsigned char*->long long ][ !!! *8* !!! ][ 114 ][ 21 ][ 23 ]] + [[ unsigned char*->unsigned int ][ !!! *7* !!! ][ 115 ][ 20 ][ 25 ]] + [[ unsigned char*->unsigned short ][ !!! *6* !!! ][ 113 ][ 20 ][ 22 ]] + [[ unsigned char*->unsigned long int ][ !!! *8* !!! ][ 115 ][ 25 ][ 24 ]] + [[ unsigned char*->unsigned long long ][ !!! *7* !!! ][ 113 ][ 25 ][ 25 ]] + [[ unsigned char*->float ][ !!! *16* !!! ][ 158 ][ 55 ][ 38 ]] + [[ unsigned char*->double ][ !!! *12* !!! ][ 155 ][ 62 ][ 40 ]] + [[ unsigned char*->long double ][ 108 ][ 153 ][ 60 ][ !!! *41* !!! ]] + [[ unsigned char*->array ][ !!! *1* !!! ][ 111 ][ 19 ][ 12 ]] + [[ unsigned char*->string ][ !!! *8* !!! ][ 125 ][ 30 ][ --- ]] + [[ unsigned char*->container::string ][ !!! *4* !!! ][ 121 ][ 23 ][ --- ]] + [[ signed char*->char ][ !!! *<1* !!! ][ 98 ][ 14 ][ 9 ]] + [[ signed char*->signed char ][ !!! *<1* !!! ][ 98 ][ 11 ][ 10 ]] + [[ signed char*->unsigned char ][ !!! *<1* !!! ][ 99 ][ 10 ][ 10 ]] + [[ signed char*->int ][ !!! *7* !!! ][ 111 ][ 22 ][ 24 ]] + [[ signed char*->short ][ !!! *6* !!! ][ 123 ][ 22 ][ 23 ]] + [[ signed char*->long int ][ !!! *8* !!! ][ 112 ][ 21 ][ 23 ]] + [[ signed char*->long long ][ !!! *8* !!! ][ 114 ][ 24 ][ 24 ]] + [[ signed char*->unsigned int ][ !!! *6* !!! ][ 114 ][ 19 ][ 22 ]] + [[ signed char*->unsigned short ][ !!! *6* !!! ][ 112 ][ 21 ][ 24 ]] + [[ signed char*->unsigned long int ][ !!! *8* !!! ][ 114 ][ 23 ][ 22 ]] + [[ signed char*->unsigned long long ][ !!! *8* !!! ][ 116 ][ 22 ][ 24 ]] + [[ signed char*->float ][ !!! *16* !!! ][ 156 ][ 55 ][ 38 ]] + [[ signed char*->double ][ !!! *12* !!! ][ 151 ][ 59 ][ 39 ]] + [[ signed char*->long double ][ 111 ][ 159 ][ 60 ][ !!! *44* !!! ]] + [[ signed char*->array ][ !!! *1* !!! ][ 107 ][ 24 ][ 12 ]] + [[ signed char*->string ][ !!! *8* !!! ][ 122 ][ 28 ][ --- ]] + [[ signed char*->container::string ][ !!! *4* !!! ][ 122 ][ 23 ][ --- ]] + [[ iterator_range->char ][ !!! *<1* !!! ][ 103 ][ 13 ][ 10 ]] + [[ iterator_range->signed char ][ !!! *<1* !!! ][ 103 ][ 13 ][ 10 ]] + [[ iterator_range->unsigned char ][ !!! *<1* !!! ][ 104 ][ 14 ][ 10 ]] + [[ iterator_range->int ][ !!! *6* !!! ][ 115 ][ 23 ][ 24 ]] + [[ iterator_range->short ][ !!! *7* !!! ][ 111 ][ 21 ][ 24 ]] + [[ iterator_range->long int ][ !!! *7* !!! ][ 108 ][ 21 ][ 23 ]] + [[ iterator_range->long long ][ !!! *7* !!! ][ 114 ][ 24 ][ 23 ]] + [[ iterator_range->unsigned int ][ !!! *6* !!! ][ 111 ][ 22 ][ 23 ]] + [[ iterator_range->unsigned short ][ !!! *5* !!! ][ 114 ][ 20 ][ 23 ]] + [[ iterator_range->unsigned long int ][ !!! *7* !!! ][ 119 ][ 25 ][ 24 ]] + [[ iterator_range->unsigned long long ][ !!! *7* !!! ][ 110 ][ 20 ][ 24 ]] + [[ iterator_range->float ][ !!! *15* !!! ][ 148 ][ 38 ][ 40 ]] + [[ iterator_range->double ][ !!! *10* !!! ][ 146 ][ 41 ][ 40 ]] + [[ iterator_range->long double ][ 103 ][ 138 ][ !!! *39* !!! ][ 42 ]] + [[ iterator_range->array ][ !!! *<1* !!! ][ 109 ][ 22 ][ 13 ]] + [[ iterator_range->string ][ !!! *7* !!! ][ 121 ][ 32 ][ --- ]] + [[ iterator_range->container::string ][ !!! *3* !!! ][ 120 ][ 24 ][ --- ]] + [[ array->char ][ !!! *<1* !!! ][ 102 ][ 9 ][ 9 ]] + [[ array->signed char ][ !!! *<1* !!! ][ 97 ][ 9 ][ 10 ]] + [[ array->unsigned char ][ !!! *<1* !!! ][ 99 ][ 9 ][ 10 ]] + [[ array->int ][ !!! *7* !!! ][ 114 ][ 22 ][ 23 ]] + [[ array->short ][ !!! *6* !!! ][ 116 ][ 21 ][ 23 ]] + [[ array->long int ][ !!! *7* !!! ][ 109 ][ 20 ][ 23 ]] + [[ array->long long ][ !!! *7* !!! ][ 114 ][ 21 ][ 23 ]] + [[ array->unsigned int ][ !!! *7* !!! ][ 119 ][ 20 ][ 25 ]] + [[ array->unsigned short ][ !!! *6* !!! ][ 120 ][ 20 ][ 23 ]] + [[ array->unsigned long int ][ !!! *7* !!! ][ 113 ][ 20 ][ 21 ]] + [[ array->unsigned long long ][ !!! *7* !!! ][ 112 ][ 20 ][ 24 ]] + [[ array->float ][ !!! *16* !!! ][ 155 ][ 57 ][ 38 ]] + [[ array->double ][ !!! *11* !!! ][ 152 ][ 59 ][ 42 ]] + [[ array->long double ][ 107 ][ 152 ][ 60 ][ !!! *41* !!! ]] + [[ array->array ][ !!! *1* !!! ][ 111 ][ 20 ][ 12 ]] + [[ array->string ][ !!! *8* !!! ][ 123 ][ 36 ][ --- ]] + [[ array->container::string ][ !!! *4* !!! ][ 128 ][ 23 ][ --- ]] + [[ int->int ][ !!! *<1* !!! ][ 118 ][ 26 ][ --- ]] + [[ float->double ][ !!! *<1* !!! ][ 233 ][ 120 ][ --- ]] + [[ char->signed char ][ !!! *<1* !!! ][ 97 ][ 8 ][ --- ]] +] +[endsect] + +[section GNU C++ version 4.4.7] +[table:id Performance Table ( GNU C++ version 4.4.7) +[[From->To] [lexical_cast] [std::stringstream with construction] [std::stringstream without construction][scanf/printf]] + [[ string->char ][ !!! *<1* !!! ][ 111 ][ 8 ][ 9 ]] + [[ string->signed char ][ !!! *<1* !!! ][ 100 ][ 8 ][ 10 ]] + [[ string->unsigned char ][ !!! *<1* !!! ][ 102 ][ 8 ][ 11 ]] + [[ string->int ][ !!! *6* !!! ][ 114 ][ 21 ][ 23 ]] + [[ string->short ][ !!! *5* !!! ][ 120 ][ 21 ][ 29 ]] + [[ string->long int ][ !!! *7* !!! ][ 114 ][ 22 ][ 26 ]] + [[ string->long long ][ !!! *7* !!! ][ 118 ][ 21 ][ 23 ]] + [[ string->unsigned int ][ !!! *7* !!! ][ 115 ][ 21 ][ 23 ]] + [[ string->unsigned short ][ !!! *5* !!! ][ 119 ][ 18 ][ 22 ]] + [[ string->unsigned long int ][ !!! *7* !!! ][ 115 ][ 20 ][ 23 ]] + [[ string->unsigned long long ][ !!! *9* !!! ][ 116 ][ 26 ][ 24 ]] + [[ string->float ][ !!! *12* !!! ][ 165 ][ 53 ][ 40 ]] + [[ string->double ][ !!! *12* !!! ][ 154 ][ 54 ][ 40 ]] + [[ string->long double ][ 112 ][ 148 ][ 61 ][ !!! *45* !!! ]] + [[ string->array ][ !!! *<1* !!! ][ 120 ][ 19 ][ 14 ]] + [[ string->string ][ !!! *2* !!! ][ 141 ][ 55 ][ --- ]] + [[ string->container::string ][ !!! *2* !!! ][ 164 ][ 36 ][ --- ]] + [[ string->char ][ !!! *7* !!! ][ 161 ][ 24 ][ 18 ]] + [[ string->signed char ][ !!! *6* !!! ][ 109 ][ 25 ][ 24 ]] + [[ string->unsigned char ][ !!! *6* !!! ][ 109 ][ 25 ][ 25 ]] + [[ int->string ][ !!! *11* !!! ][ 128 ][ 32 ][ 23 ]] + [[ short->string ][ !!! *12* !!! ][ 136 ][ 54 ][ 34 ]] + [[ long int->string ][ !!! *15* !!! ][ 187 ][ 41 ][ 23 ]] + [[ long long->string ][ !!! *11* !!! ][ 128 ][ 30 ][ 29 ]] + [[ unsigned int->string ][ !!! *13* !!! ][ 124 ][ 29 ][ 23 ]] + [[ unsigned short->string ][ !!! *11* !!! ][ 128 ][ 30 ][ 22 ]] + [[ unsigned long int->string ][ !!! *11* !!! ][ 131 ][ 30 ][ 22 ]] + [[ unsigned long long->string ][ !!! *11* !!! ][ 133 ][ 33 ][ 29 ]] + [[ float->string ][ 52 ][ 187 ][ 90 ][ !!! *39* !!! ]] + [[ double->string ][ 58 ][ 190 ][ 86 ][ !!! *45* !!! ]] + [[ long double->string ][ 70 ][ 218 ][ 88 ][ !!! *47* !!! ]] + [[ char*->char ][ !!! *<1* !!! ][ 99 ][ 11 ][ 9 ]] + [[ char*->signed char ][ !!! *<1* !!! ][ 99 ][ 11 ][ 10 ]] + [[ char*->unsigned char ][ !!! *<1* !!! ][ 100 ][ 12 ][ 10 ]] + [[ char*->int ][ !!! *6* !!! ][ 117 ][ 23 ][ 21 ]] + [[ char*->short ][ !!! *6* !!! ][ 115 ][ 28 ][ 23 ]] + [[ char*->long int ][ !!! *7* !!! ][ 119 ][ 22 ][ 24 ]] + [[ char*->long long ][ !!! *7* !!! ][ 114 ][ 23 ][ 22 ]] + [[ char*->unsigned int ][ !!! *6* !!! ][ 113 ][ 21 ][ 21 ]] + [[ char*->unsigned short ][ !!! *6* !!! ][ 120 ][ 21 ][ 21 ]] + [[ char*->unsigned long int ][ !!! *7* !!! ][ 117 ][ 25 ][ 23 ]] + [[ char*->unsigned long long ][ !!! *7* !!! ][ 119 ][ 23 ][ 21 ]] + [[ char*->float ][ !!! *13* !!! ][ 160 ][ 61 ][ 36 ]] + [[ char*->double ][ !!! *13* !!! ][ 152 ][ 54 ][ 40 ]] + [[ char*->long double ][ 116 ][ 173 ][ 58 ][ !!! *43* !!! ]] + [[ char*->array ][ !!! *1* !!! ][ 121 ][ 20 ][ 12 ]] + [[ char*->string ][ !!! *7* !!! ][ 126 ][ 29 ][ --- ]] + [[ char*->container::string ][ !!! *2* !!! ][ 119 ][ 27 ][ --- ]] + [[ unsigned char*->char ][ !!! *<1* !!! ][ 96 ][ 12 ][ 9 ]] + [[ unsigned char*->signed char ][ !!! *<1* !!! ][ 95 ][ 11 ][ 12 ]] + [[ unsigned char*->unsigned char ][ !!! *<1* !!! ][ 95 ][ 12 ][ 12 ]] + [[ unsigned char*->int ][ !!! *6* !!! ][ 113 ][ 27 ][ 24 ]] + [[ unsigned char*->short ][ !!! *6* !!! ][ 120 ][ 23 ][ 21 ]] + [[ unsigned char*->long int ][ !!! *7* !!! ][ 114 ][ 22 ][ 23 ]] + [[ unsigned char*->long long ][ !!! *7* !!! ][ 114 ][ 23 ][ 23 ]] + [[ unsigned char*->unsigned int ][ !!! *6* !!! ][ 115 ][ 23 ][ 23 ]] + [[ unsigned char*->unsigned short ][ !!! *6* !!! ][ 120 ][ 21 ][ 23 ]] + [[ unsigned char*->unsigned long int ][ !!! *7* !!! ][ 117 ][ 23 ][ 21 ]] + [[ unsigned char*->unsigned long long ][ !!! *7* !!! ][ 121 ][ 23 ][ 21 ]] + [[ unsigned char*->float ][ !!! *12* !!! ][ 161 ][ 58 ][ 39 ]] + [[ unsigned char*->double ][ !!! *13* !!! ][ 153 ][ 54 ][ 38 ]] + [[ unsigned char*->long double ][ 110 ][ 150 ][ 62 ][ !!! *43* !!! ]] + [[ unsigned char*->array ][ !!! *1* !!! ][ 113 ][ 20 ][ 12 ]] + [[ unsigned char*->string ][ !!! *8* !!! ][ 124 ][ 30 ][ --- ]] + [[ unsigned char*->container::string ][ !!! *3* !!! ][ 118 ][ 27 ][ --- ]] + [[ signed char*->char ][ !!! *<1* !!! ][ 99 ][ 11 ][ 9 ]] + [[ signed char*->signed char ][ !!! *<1* !!! ][ 102 ][ 12 ][ 10 ]] + [[ signed char*->unsigned char ][ !!! *<1* !!! ][ 99 ][ 12 ][ 10 ]] + [[ signed char*->int ][ !!! *6* !!! ][ 114 ][ 30 ][ 23 ]] + [[ signed char*->short ][ !!! *6* !!! ][ 118 ][ 23 ][ 23 ]] + [[ signed char*->long int ][ !!! *7* !!! ][ 119 ][ 22 ][ 21 ]] + [[ signed char*->long long ][ !!! *7* !!! ][ 114 ][ 23 ][ 26 ]] + [[ signed char*->unsigned int ][ !!! *6* !!! ][ 114 ][ 26 ][ 23 ]] + [[ signed char*->unsigned short ][ !!! *6* !!! ][ 121 ][ 22 ][ 23 ]] + [[ signed char*->unsigned long int ][ !!! *7* !!! ][ 126 ][ 23 ][ 21 ]] + [[ signed char*->unsigned long long ][ !!! *7* !!! ][ 114 ][ 22 ][ 21 ]] + [[ signed char*->float ][ !!! *12* !!! ][ 163 ][ 57 ][ 39 ]] + [[ signed char*->double ][ !!! *13* !!! ][ 156 ][ 53 ][ 40 ]] + [[ signed char*->long double ][ 112 ][ 156 ][ 56 ][ !!! *42* !!! ]] + [[ signed char*->array ][ !!! *1* !!! ][ 117 ][ 20 ][ 12 ]] [[ signed char*->string ][ !!! *8* !!! ][ 127 ][ 28 ][ --- ]] - [[ signed char*->container::string ][ !!! *4* !!! ][ 124 ][ 27 ][ --- ]] - [[ iterator_range->char ][ !!! *<1* !!! ][ 103 ][ 13 ][ 8 ]] - [[ iterator_range->signed char ][ !!! *<1* !!! ][ 107 ][ 13 ][ 9 ]] - [[ iterator_range->unsigned char ][ !!! *<1* !!! ][ 121 ][ 26 ][ 13 ]] - [[ iterator_range->int ][ !!! *6* !!! ][ 165 ][ 33 ][ 23 ]] - [[ iterator_range->short ][ !!! *8* !!! ][ 175 ][ 34 ][ 29 ]] - [[ iterator_range->long int ][ !!! *14* !!! ][ 160 ][ 33 ][ 23 ]] - [[ iterator_range->long long ][ !!! *10* !!! ][ 199 ][ 35 ][ 28 ]] - [[ iterator_range->unsigned int ][ !!! *6* !!! ][ 131 ][ 24 ][ 16 ]] - [[ iterator_range->unsigned short ][ !!! *7* !!! ][ 110 ][ 22 ][ 16 ]] - [[ iterator_range->unsigned long int ][ !!! *7* !!! ][ 111 ][ 22 ][ 14 ]] - [[ iterator_range->unsigned long long ][ !!! *8* !!! ][ 115 ][ 24 ][ 15 ]] - [[ iterator_range->float ][ !!! *13* !!! ][ 134 ][ 40 ][ 33 ]] - [[ iterator_range->double ][ !!! *15* !!! ][ 140 ][ 59 ][ 41 ]] - [[ iterator_range->long double ][ 131 ][ 146 ][ 53 ][ !!! *38* !!! ]] - [[ iterator_range->string ][ !!! *9* !!! ][ 121 ][ 31 ][ --- ]] - [[ iterator_range->container::string ][ !!! *4* !!! ][ 115 ][ 25 ][ --- ]] - [[ int->int ][ !!! *<1* !!! ][ 113 ][ 25 ][ --- ]] - [[ float->double ][ !!! *<1* !!! ][ 234 ][ 117 ][ --- ]] - [[ char->signed char ][ !!! *<1* !!! ][ 97 ][ 9 ][ --- ]] + [[ signed char*->container::string ][ !!! *4* !!! ][ 112 ][ 27 ][ --- ]] + [[ iterator_range->char ][ !!! *<1* !!! ][ 103 ][ 14 ][ 9 ]] + [[ iterator_range->signed char ][ !!! *<1* !!! ][ 104 ][ 16 ][ 10 ]] + [[ iterator_range->unsigned char ][ !!! *<1* !!! ][ 103 ][ 16 ][ 10 ]] + [[ iterator_range->int ][ !!! *6* !!! ][ 121 ][ 22 ][ 21 ]] + [[ iterator_range->short ][ !!! *7* !!! ][ 112 ][ 23 ][ 23 ]] + [[ iterator_range->long int ][ !!! *7* !!! ][ 115 ][ 24 ][ 23 ]] + [[ iterator_range->long long ][ !!! *7* !!! ][ 113 ][ 24 ][ 23 ]] + [[ iterator_range->unsigned int ][ !!! *6* !!! ][ 117 ][ 26 ][ 23 ]] + [[ iterator_range->unsigned short ][ !!! *5* !!! ][ 120 ][ 20 ][ 23 ]] + [[ iterator_range->unsigned long int ][ !!! *7* !!! ][ 124 ][ 28 ][ 21 ]] + [[ iterator_range->unsigned long long ][ !!! *7* !!! ][ 113 ][ 22 ][ 21 ]] + [[ iterator_range->float ][ !!! *11* !!! ][ 190 ][ 58 ][ 63 ]] + [[ iterator_range->double ][ !!! *20* !!! ][ 194 ][ 44 ][ 39 ]] + [[ iterator_range->long double ][ 116 ][ 145 ][ 46 ][ !!! *44* !!! ]] + [[ iterator_range->array ][ !!! *<1* !!! ][ 116 ][ 23 ][ 15 ]] + [[ iterator_range->string ][ !!! *7* !!! ][ 127 ][ 33 ][ --- ]] + [[ iterator_range->container::string ][ !!! *3* !!! ][ 112 ][ 24 ][ --- ]] + [[ array->char ][ !!! *<1* !!! ][ 98 ][ 11 ][ 10 ]] + [[ array->signed char ][ !!! *<1* !!! ][ 99 ][ 12 ][ 15 ]] + [[ array->unsigned char ][ !!! *<1* !!! ][ 100 ][ 11 ][ 10 ]] + [[ array->int ][ !!! *6* !!! ][ 114 ][ 27 ][ 22 ]] + [[ array->short ][ !!! *5* !!! ][ 113 ][ 23 ][ 23 ]] + [[ array->long int ][ !!! *7* !!! ][ 118 ][ 22 ][ 23 ]] + [[ array->long long ][ !!! *7* !!! ][ 114 ][ 26 ][ 23 ]] + [[ array->unsigned int ][ !!! *6* !!! ][ 113 ][ 27 ][ 23 ]] + [[ array->unsigned short ][ !!! *5* !!! ][ 124 ][ 21 ][ 23 ]] + [[ array->unsigned long int ][ !!! *7* !!! ][ 116 ][ 23 ][ 21 ]] + [[ array->unsigned long long ][ !!! *7* !!! ][ 115 ][ 22 ][ 21 ]] + [[ array->float ][ !!! *11* !!! ][ 162 ][ 58 ][ 36 ]] + [[ array->double ][ !!! *13* !!! ][ 155 ][ 54 ][ 44 ]] + [[ array->long double ][ 111 ][ 149 ][ 55 ][ !!! *42* !!! ]] + [[ array->array ][ !!! *1* !!! ][ 114 ][ 18 ][ 14 ]] + [[ array->string ][ !!! *7* !!! ][ 129 ][ 29 ][ --- ]] + [[ array->container::string ][ !!! *3* !!! ][ 113 ][ 26 ][ --- ]] + [[ int->int ][ !!! *<1* !!! ][ 114 ][ 25 ][ --- ]] + [[ float->double ][ !!! *<1* !!! ][ 236 ][ 121 ][ --- ]] + [[ char->signed char ][ !!! *<1* !!! ][ 97 ][ 8 ][ --- ]] ] [endsect] -[section GNU C++ version 4.6.1] -[table:id Performance Table ( GNU C++ version 4.6.1) -[[From->To] [lexical_cast] [std::stringstream with construction] [std::stringstream without construction][scanf/printf]] - [[ string->char ][ !!! *<1* !!! ][ 140 ][ 17 ][ 13 ]] - [[ string->signed char ][ !!! *<1* !!! ][ 129 ][ 8 ][ 10 ]] - [[ string->unsigned char ][ !!! *<1* !!! ][ 91 ][ 8 ][ 10 ]] - [[ string->int ][ !!! *6* !!! ][ 110 ][ 20 ][ 14 ]] - [[ string->short ][ !!! *5* !!! ][ 106 ][ 20 ][ 14 ]] - [[ string->long int ][ !!! *7* !!! ][ 107 ][ 22 ][ 14 ]] - [[ string->long long ][ !!! *7* !!! ][ 112 ][ 21 ][ 14 ]] - [[ string->unsigned int ][ !!! *6* !!! ][ 110 ][ 20 ][ 14 ]] - [[ string->unsigned short ][ !!! *5* !!! ][ 107 ][ 18 ][ 14 ]] - [[ string->unsigned long int ][ !!! *7* !!! ][ 108 ][ 23 ][ 14 ]] - [[ string->unsigned long long ][ !!! *7* !!! ][ 108 ][ 21 ][ 14 ]] - [[ string->float ][ !!! *12* !!! ][ 154 ][ 57 ][ 32 ]] - [[ string->double ][ !!! *11* !!! ][ 151 ][ 61 ][ 33 ]] - [[ string->long double ][ 109 ][ 187 ][ 79 ][ !!! *55* !!! ]] - [[ string->string ][ !!! *2* !!! ][ 122 ][ 27 ][ --- ]] - [[ string->container::string ][ !!! *3* !!! ][ 123 ][ 22 ][ --- ]] - [[ string->char ][ !!! *7* !!! ][ 109 ][ 27 ][ 17 ]] - [[ string->signed char ][ !!! *7* !!! ][ 110 ][ 25 ][ 22 ]] - [[ string->unsigned char ][ !!! *7* !!! ][ 112 ][ 27 ][ 24 ]] - [[ int->string ][ !!! *12* !!! ][ 187 ][ 48 ][ 37 ]] - [[ short->string ][ !!! *18* !!! ][ 133 ][ 33 ][ 20 ]] - [[ long int->string ][ !!! *12* !!! ][ 129 ][ 32 ][ 21 ]] - [[ long long->string ][ !!! *12* !!! ][ 127 ][ 35 ][ 23 ]] - [[ unsigned int->string ][ !!! *15* !!! ][ 133 ][ 31 ][ 21 ]] - [[ unsigned short->string ][ !!! *12* !!! ][ 133 ][ 31 ][ 21 ]] - [[ unsigned long int->string ][ !!! *12* !!! ][ 132 ][ 31 ][ 21 ]] - [[ unsigned long long->string ][ !!! *12* !!! ][ 127 ][ 29 ][ 24 ]] - [[ float->string ][ 53 ][ 215 ][ 103 ][ !!! *40* !!! ]] - [[ double->string ][ 58 ][ 215 ][ 103 ][ !!! *41* !!! ]] - [[ long double->string ][ 67 ][ 227 ][ 112 ][ !!! *45* !!! ]] - [[ char*->char ][ !!! *<1* !!! ][ 132 ][ 12 ][ 8 ]] - [[ char*->signed char ][ !!! *<1* !!! ][ 98 ][ 11 ][ 9 ]] - [[ char*->unsigned char ][ !!! *<1* !!! ][ 96 ][ 10 ][ 9 ]] - [[ char*->int ][ !!! *6* !!! ][ 109 ][ 22 ][ 14 ]] - [[ char*->short ][ !!! *5* !!! ][ 109 ][ 26 ][ 14 ]] - [[ char*->long int ][ !!! *7* !!! ][ 111 ][ 23 ][ 14 ]] - [[ char*->long long ][ !!! *8* !!! ][ 112 ][ 25 ][ 16 ]] - [[ char*->unsigned int ][ !!! *6* !!! ][ 113 ][ 19 ][ 14 ]] - [[ char*->unsigned short ][ !!! *6* !!! ][ 111 ][ 20 ][ 14 ]] - [[ char*->unsigned long int ][ !!! *7* !!! ][ 109 ][ 21 ][ 14 ]] - [[ char*->unsigned long long ][ !!! *7* !!! ][ 111 ][ 22 ][ 14 ]] - [[ char*->float ][ !!! *12* !!! ][ 156 ][ 62 ][ 32 ]] - [[ char*->double ][ !!! *13* !!! ][ 156 ][ 65 ][ 33 ]] - [[ char*->long double ][ 108 ][ 156 ][ 59 ][ !!! *36* !!! ]] - [[ char*->string ][ !!! *7* !!! ][ 123 ][ 29 ][ --- ]] - [[ char*->container::string ][ !!! *2* !!! ][ 116 ][ 24 ][ --- ]] - [[ unsigned char*->char ][ !!! *<1* !!! ][ 96 ][ 12 ][ 8 ]] - [[ unsigned char*->signed char ][ !!! *<1* !!! ][ 97 ][ 9 ][ 9 ]] - [[ unsigned char*->unsigned char ][ !!! *<1* !!! ][ 93 ][ 10 ][ 9 ]] - [[ unsigned char*->int ][ !!! *6* !!! ][ 110 ][ 22 ][ 14 ]] - [[ unsigned char*->short ][ !!! *6* !!! ][ 111 ][ 22 ][ 15 ]] - [[ unsigned char*->long int ][ !!! *8* !!! ][ 110 ][ 23 ][ 14 ]] - [[ unsigned char*->long long ][ !!! *7* !!! ][ 111 ][ 25 ][ 14 ]] - [[ unsigned char*->unsigned int ][ !!! *6* !!! ][ 111 ][ 21 ][ 16 ]] - [[ unsigned char*->unsigned short ][ !!! *6* !!! ][ 110 ][ 21 ][ 15 ]] - [[ unsigned char*->unsigned long int ][ !!! *8* !!! ][ 114 ][ 21 ][ 14 ]] - [[ unsigned char*->unsigned long long ][ !!! *8* !!! ][ 108 ][ 23 ][ 15 ]] - [[ unsigned char*->float ][ !!! *12* !!! ][ 154 ][ 62 ][ 33 ]] - [[ unsigned char*->double ][ !!! *14* !!! ][ 157 ][ 65 ][ 32 ]] - [[ unsigned char*->long double ][ 107 ][ 154 ][ 56 ][ !!! *36* !!! ]] - [[ unsigned char*->string ][ !!! *9* !!! ][ 122 ][ 28 ][ --- ]] - [[ unsigned char*->container::string ][ !!! *4* !!! ][ 118 ][ 26 ][ --- ]] - [[ signed char*->char ][ !!! *<1* !!! ][ 94 ][ 10 ][ 8 ]] - [[ signed char*->signed char ][ !!! *<1* !!! ][ 94 ][ 12 ][ 9 ]] - [[ signed char*->unsigned char ][ !!! *<1* !!! ][ 95 ][ 12 ][ 9 ]] - [[ signed char*->int ][ !!! *7* !!! ][ 109 ][ 22 ][ 14 ]] - [[ signed char*->short ][ !!! *5* !!! ][ 108 ][ 22 ][ 14 ]] - [[ signed char*->long int ][ !!! *7* !!! ][ 110 ][ 23 ][ 14 ]] - [[ signed char*->long long ][ !!! *7* !!! ][ 110 ][ 25 ][ 15 ]] - [[ signed char*->unsigned int ][ !!! *6* !!! ][ 109 ][ 20 ][ 15 ]] - [[ signed char*->unsigned short ][ !!! *6* !!! ][ 107 ][ 21 ][ 14 ]] - [[ signed char*->unsigned long int ][ !!! *8* !!! ][ 111 ][ 21 ][ 14 ]] - [[ signed char*->unsigned long long ][ !!! *7* !!! ][ 109 ][ 23 ][ 14 ]] - [[ signed char*->float ][ !!! *12* !!! ][ 156 ][ 61 ][ 31 ]] - [[ signed char*->double ][ !!! *13* !!! ][ 156 ][ 68 ][ 33 ]] - [[ signed char*->long double ][ 109 ][ 159 ][ 56 ][ !!! *36* !!! ]] - [[ signed char*->string ][ !!! *9* !!! ][ 123 ][ 28 ][ --- ]] - [[ signed char*->container::string ][ !!! *4* !!! ][ 125 ][ 25 ][ --- ]] - [[ iterator_range->char ][ !!! *<1* !!! ][ 100 ][ 13 ][ 8 ]] - [[ iterator_range->signed char ][ !!! *<1* !!! ][ 98 ][ 14 ][ 9 ]] - [[ iterator_range->unsigned char ][ !!! *<1* !!! ][ 99 ][ 12 ][ 10 ]] - [[ iterator_range->int ][ !!! *6* !!! ][ 108 ][ 21 ][ 16 ]] - [[ iterator_range->short ][ !!! *5* !!! ][ 110 ][ 22 ][ 17 ]] - [[ iterator_range->long int ][ !!! *7* !!! ][ 107 ][ 22 ][ 15 ]] - [[ iterator_range->long long ][ !!! *7* !!! ][ 110 ][ 27 ][ 15 ]] - [[ iterator_range->unsigned int ][ !!! *6* !!! ][ 107 ][ 24 ][ 15 ]] - [[ iterator_range->unsigned short ][ !!! *5* !!! ][ 106 ][ 21 ][ 15 ]] - [[ iterator_range->unsigned long int ][ !!! *7* !!! ][ 110 ][ 21 ][ 16 ]] - [[ iterator_range->unsigned long long ][ !!! *7* !!! ][ 109 ][ 23 ][ 16 ]] - [[ iterator_range->float ][ !!! *11* !!! ][ 137 ][ 46 ][ 33 ]] - [[ iterator_range->double ][ !!! *11* !!! ][ 131 ][ 50 ][ 33 ]] - [[ iterator_range->long double ][ 107 ][ 136 ][ 44 ][ !!! *39* !!! ]] - [[ iterator_range->string ][ !!! *8* !!! ][ 117 ][ 32 ][ --- ]] - [[ iterator_range->container::string ][ !!! *3* !!! ][ 111 ][ 23 ][ --- ]] - [[ int->int ][ !!! *<1* !!! ][ 110 ][ 33 ][ --- ]] - [[ float->double ][ !!! *<1* !!! ][ 241 ][ 152 ][ --- ]] - [[ char->signed char ][ !!! *<1* !!! ][ 90 ][ 8 ][ --- ]] -] -[endsect] - -[section GNU C++ version 4.5.4] -[table:id Performance Table ( GNU C++ version 4.5.4) -[[From->To] [lexical_cast] [std::stringstream with construction] [std::stringstream without construction][scanf/printf]] - [[ string->char ][ !!! *<1* !!! ][ 147 ][ 12 ][ 8 ]] - [[ string->signed char ][ !!! *<1* !!! ][ 138 ][ 13 ][ 10 ]] - [[ string->unsigned char ][ !!! *<1* !!! ][ 86 ][ 12 ][ 9 ]] - [[ string->int ][ !!! *7* !!! ][ 103 ][ 20 ][ 15 ]] - [[ string->short ][ !!! *5* !!! ][ 103 ][ 20 ][ 15 ]] - [[ string->long int ][ !!! *7* !!! ][ 103 ][ 22 ][ 15 ]] - [[ string->long long ][ !!! *7* !!! ][ 104 ][ 22 ][ 16 ]] - [[ string->unsigned int ][ !!! *6* !!! ][ 108 ][ 19 ][ 15 ]] - [[ string->unsigned short ][ !!! *5* !!! ][ 104 ][ 19 ][ 15 ]] - [[ string->unsigned long int ][ !!! *7* !!! ][ 103 ][ 20 ][ 16 ]] - [[ string->unsigned long long ][ !!! *7* !!! ][ 101 ][ 22 ][ 14 ]] - [[ string->float ][ !!! *13* !!! ][ 148 ][ 58 ][ 35 ]] - [[ string->double ][ !!! *13* !!! ][ 147 ][ 60 ][ 34 ]] - [[ string->long double ][ 103 ][ 149 ][ 56 ][ !!! *38* !!! ]] - [[ string->string ][ !!! *2* !!! ][ 127 ][ 27 ][ --- ]] - [[ string->container::string ][ !!! *3* !!! ][ 101 ][ 24 ][ --- ]] - [[ string->char ][ !!! *7* !!! ][ 108 ][ 35 ][ 17 ]] - [[ string->signed char ][ !!! *7* !!! ][ 112 ][ 26 ][ 23 ]] - [[ string->unsigned char ][ !!! *7* !!! ][ 113 ][ 25 ][ 25 ]] - [[ int->string ][ !!! *11* !!! ][ 183 ][ 47 ][ 40 ]] - [[ short->string ][ !!! *14* !!! ][ 153 ][ 35 ][ 23 ]] - [[ long int->string ][ !!! *12* !!! ][ 135 ][ 32 ][ 22 ]] - [[ long long->string ][ !!! *11* !!! ][ 131 ][ 30 ][ 24 ]] - [[ unsigned int->string ][ !!! *12* !!! ][ 137 ][ 31 ][ 22 ]] - [[ unsigned short->string ][ !!! *11* !!! ][ 137 ][ 33 ][ 22 ]] - [[ unsigned long int->string ][ !!! *11* !!! ][ 136 ][ 36 ][ 23 ]] - [[ unsigned long long->string ][ !!! *11* !!! ][ 127 ][ 29 ][ 23 ]] - [[ float->string ][ 56 ][ 218 ][ 107 ][ !!! *44* !!! ]] - [[ double->string ][ 63 ][ 223 ][ 106 ][ !!! *44* !!! ]] - [[ long double->string ][ 69 ][ 229 ][ 118 ][ !!! *49* !!! ]] - [[ char*->char ][ !!! *<1* !!! ][ 91 ][ 12 ][ 9 ]] - [[ char*->signed char ][ !!! *<1* !!! ][ 100 ][ 11 ][ 11 ]] - [[ char*->unsigned char ][ !!! *<1* !!! ][ 97 ][ 12 ][ 10 ]] - [[ char*->int ][ !!! *7* !!! ][ 112 ][ 23 ][ 16 ]] - [[ char*->short ][ !!! *6* !!! ][ 116 ][ 23 ][ 16 ]] - [[ char*->long int ][ !!! *8* !!! ][ 113 ][ 23 ][ 16 ]] - [[ char*->long long ][ !!! *8* !!! ][ 122 ][ 28 ][ 16 ]] - [[ char*->unsigned int ][ !!! *6* !!! ][ 117 ][ 21 ][ 15 ]] - [[ char*->unsigned short ][ !!! *6* !!! ][ 113 ][ 21 ][ 16 ]] - [[ char*->unsigned long int ][ !!! *7* !!! ][ 118 ][ 22 ][ 16 ]] - [[ char*->unsigned long long ][ !!! *8* !!! ][ 113 ][ 22 ][ 17 ]] - [[ char*->float ][ !!! *11* !!! ][ 164 ][ 67 ][ 34 ]] - [[ char*->double ][ !!! *13* !!! ][ 163 ][ 66 ][ 35 ]] - [[ char*->long double ][ 110 ][ 164 ][ 63 ][ !!! *39* !!! ]] - [[ char*->string ][ !!! *8* !!! ][ 130 ][ 30 ][ --- ]] - [[ char*->container::string ][ !!! *2* !!! ][ 113 ][ 24 ][ --- ]] - [[ unsigned char*->char ][ !!! *<1* !!! ][ 98 ][ 11 ][ 10 ]] - [[ unsigned char*->signed char ][ !!! *<1* !!! ][ 97 ][ 12 ][ 10 ]] - [[ unsigned char*->unsigned char ][ !!! *<1* !!! ][ 97 ][ 11 ][ 10 ]] - [[ unsigned char*->int ][ !!! *7* !!! ][ 112 ][ 23 ][ 16 ]] - [[ unsigned char*->short ][ !!! *6* !!! ][ 115 ][ 22 ][ 20 ]] - [[ unsigned char*->long int ][ !!! *8* !!! ][ 112 ][ 23 ][ 15 ]] - [[ unsigned char*->long long ][ !!! *8* !!! ][ 115 ][ 29 ][ 17 ]] - [[ unsigned char*->unsigned int ][ !!! *6* !!! ][ 114 ][ 21 ][ 14 ]] - [[ unsigned char*->unsigned short ][ !!! *7* !!! ][ 112 ][ 22 ][ 15 ]] - [[ unsigned char*->unsigned long int ][ !!! *7* !!! ][ 115 ][ 23 ][ 14 ]] - [[ unsigned char*->unsigned long long ][ !!! *8* !!! ][ 112 ][ 24 ][ 15 ]] - [[ unsigned char*->float ][ !!! *12* !!! ][ 161 ][ 66 ][ 34 ]] - [[ unsigned char*->double ][ !!! *13* !!! ][ 162 ][ 66 ][ 36 ]] - [[ unsigned char*->long double ][ 112 ][ 161 ][ 63 ][ !!! *39* !!! ]] - [[ unsigned char*->string ][ !!! *9* !!! ][ 127 ][ 29 ][ --- ]] - [[ unsigned char*->container::string ][ !!! *4* !!! ][ 111 ][ 25 ][ --- ]] - [[ signed char*->char ][ !!! *<1* !!! ][ 104 ][ 11 ][ 8 ]] - [[ signed char*->signed char ][ !!! *<1* !!! ][ 98 ][ 11 ][ 11 ]] - [[ signed char*->unsigned char ][ !!! *<1* !!! ][ 98 ][ 11 ][ 11 ]] - [[ signed char*->int ][ !!! *7* !!! ][ 112 ][ 23 ][ 16 ]] - [[ signed char*->short ][ !!! *7* !!! ][ 113 ][ 23 ][ 15 ]] - [[ signed char*->long int ][ !!! *8* !!! ][ 112 ][ 22 ][ 14 ]] - [[ signed char*->long long ][ !!! *8* !!! ][ 115 ][ 25 ][ 16 ]] - [[ signed char*->unsigned int ][ !!! *8* !!! ][ 114 ][ 21 ][ 18 ]] - [[ signed char*->unsigned short ][ !!! *6* !!! ][ 112 ][ 22 ][ 15 ]] - [[ signed char*->unsigned long int ][ !!! *8* !!! ][ 116 ][ 22 ][ 15 ]] - [[ signed char*->unsigned long long ][ !!! *8* !!! ][ 113 ][ 23 ][ 16 ]] - [[ signed char*->float ][ !!! *13* !!! ][ 161 ][ 65 ][ 34 ]] - [[ signed char*->double ][ !!! *12* !!! ][ 172 ][ 67 ][ 34 ]] - [[ signed char*->long double ][ 110 ][ 164 ][ 63 ][ !!! *38* !!! ]] - [[ signed char*->string ][ !!! *9* !!! ][ 131 ][ 30 ][ --- ]] - [[ signed char*->container::string ][ !!! *4* !!! ][ 112 ][ 24 ][ --- ]] - [[ iterator_range->char ][ !!! *<1* !!! ][ 103 ][ 12 ][ 8 ]] - [[ iterator_range->signed char ][ !!! *<1* !!! ][ 101 ][ 13 ][ 9 ]] - [[ iterator_range->unsigned char ][ !!! *<1* !!! ][ 103 ][ 13 ][ 10 ]] - [[ iterator_range->int ][ !!! *7* !!! ][ 113 ][ 26 ][ 14 ]] - [[ iterator_range->short ][ !!! *5* !!! ][ 115 ][ 21 ][ 16 ]] - [[ iterator_range->long int ][ !!! *7* !!! ][ 115 ][ 22 ][ 15 ]] - [[ iterator_range->long long ][ !!! *7* !!! ][ 116 ][ 25 ][ 16 ]] - [[ iterator_range->unsigned int ][ !!! *6* !!! ][ 115 ][ 24 ][ 23 ]] - [[ iterator_range->unsigned short ][ !!! *5* !!! ][ 113 ][ 22 ][ 16 ]] - [[ iterator_range->unsigned long int ][ !!! *7* !!! ][ 117 ][ 20 ][ 16 ]] - [[ iterator_range->unsigned long long ][ !!! *7* !!! ][ 114 ][ 21 ][ 16 ]] - [[ iterator_range->float ][ !!! *11* !!! ][ 145 ][ 51 ][ 34 ]] - [[ iterator_range->double ][ !!! *11* !!! ][ 139 ][ 53 ][ 35 ]] - [[ iterator_range->long double ][ 109 ][ 147 ][ 44 ][ !!! *38* !!! ]] - [[ iterator_range->string ][ !!! *9* !!! ][ 123 ][ 36 ][ --- ]] - [[ iterator_range->container::string ][ !!! *3* !!! ][ 113 ][ 20 ][ --- ]] - [[ int->int ][ !!! *<1* !!! ][ 117 ][ 23 ][ --- ]] - [[ float->double ][ !!! *<1* !!! ][ 262 ][ 150 ][ --- ]] - [[ char->signed char ][ !!! *<1* !!! ][ 97 ][ 9 ][ --- ]] -] -[endsect] - -[section GNU C++ version 4.4.6] -[table:id Performance Table ( GNU C++ version 4.4.6) -[[From->To] [lexical_cast] [std::stringstream with construction] [std::stringstream without construction][scanf/printf]] - [[ string->char ][ !!! *<1* !!! ][ 162 ][ 17 ][ 8 ]] - [[ string->signed char ][ !!! *<1* !!! ][ 103 ][ 9 ][ 9 ]] - [[ string->unsigned char ][ !!! *<1* !!! ][ 91 ][ 9 ][ 9 ]] - [[ string->int ][ !!! *6* !!! ][ 104 ][ 21 ][ 14 ]] - [[ string->short ][ !!! *5* !!! ][ 107 ][ 22 ][ 14 ]] - [[ string->long int ][ !!! *7* !!! ][ 106 ][ 23 ][ 15 ]] - [[ string->long long ][ !!! *7* !!! ][ 104 ][ 21 ][ 16 ]] - [[ string->unsigned int ][ !!! *6* !!! ][ 100 ][ 20 ][ 16 ]] - [[ string->unsigned short ][ !!! *5* !!! ][ 102 ][ 20 ][ 16 ]] - [[ string->unsigned long int ][ !!! *7* !!! ][ 106 ][ 25 ][ 16 ]] - [[ string->unsigned long long ][ !!! *7* !!! ][ 109 ][ 25 ][ 14 ]] - [[ string->float ][ !!! *13* !!! ][ 142 ][ 48 ][ 32 ]] - [[ string->double ][ !!! *13* !!! ][ 162 ][ 62 ][ 33 ]] - [[ string->long double ][ 119 ][ 164 ][ 62 ][ !!! *37* !!! ]] - [[ string->string ][ !!! *2* !!! ][ 122 ][ 27 ][ --- ]] - [[ string->container::string ][ !!! *2* !!! ][ 107 ][ 23 ][ --- ]] - [[ string->char ][ !!! *6* !!! ][ 110 ][ 24 ][ 15 ]] - [[ string->signed char ][ !!! *6* !!! ][ 107 ][ 24 ][ 21 ]] - [[ string->unsigned char ][ !!! *6* !!! ][ 106 ][ 27 ][ 21 ]] - [[ int->string ][ !!! *12* !!! ][ 122 ][ 31 ][ 21 ]] - [[ short->string ][ !!! *12* !!! ][ 136 ][ 29 ][ 20 ]] - [[ long int->string ][ !!! *12* !!! ][ 127 ][ 32 ][ 19 ]] - [[ long long->string ][ !!! *12* !!! ][ 121 ][ 32 ][ 21 ]] - [[ unsigned int->string ][ !!! *12* !!! ][ 133 ][ 32 ][ 19 ]] - [[ unsigned short->string ][ !!! *12* !!! ][ 126 ][ 33 ][ 20 ]] - [[ unsigned long int->string ][ !!! *11* !!! ][ 126 ][ 34 ][ 19 ]] - [[ unsigned long long->string ][ !!! *12* !!! ][ 125 ][ 28 ][ 21 ]] - [[ float->string ][ 47 ][ 183 ][ 86 ][ !!! *43* !!! ]] - [[ double->string ][ 57 ][ 184 ][ 90 ][ !!! *42* !!! ]] - [[ long double->string ][ 64 ][ 199 ][ 87 ][ !!! *46* !!! ]] - [[ char*->char ][ !!! *<1* !!! ][ 95 ][ 10 ][ 8 ]] - [[ char*->signed char ][ !!! *<1* !!! ][ 90 ][ 12 ][ 9 ]] - [[ char*->unsigned char ][ !!! *<1* !!! ][ 93 ][ 12 ][ 9 ]] - [[ char*->int ][ !!! *6* !!! ][ 108 ][ 24 ][ 14 ]] - [[ char*->short ][ !!! *6* !!! ][ 106 ][ 23 ][ 14 ]] - [[ char*->long int ][ !!! *7* !!! ][ 107 ][ 24 ][ 17 ]] - [[ char*->long long ][ !!! *7* !!! ][ 109 ][ 25 ][ 17 ]] - [[ char*->unsigned int ][ !!! *6* !!! ][ 104 ][ 23 ][ 17 ]] - [[ char*->unsigned short ][ !!! *6* !!! ][ 102 ][ 22 ][ 17 ]] - [[ char*->unsigned long int ][ !!! *7* !!! ][ 107 ][ 23 ][ 17 ]] - [[ char*->unsigned long long ][ !!! *7* !!! ][ 115 ][ 26 ][ 14 ]] - [[ char*->float ][ !!! *12* !!! ][ 150 ][ 56 ][ 30 ]] - [[ char*->double ][ !!! *12* !!! ][ 165 ][ 66 ][ 32 ]] - [[ char*->long double ][ 116 ][ 173 ][ 66 ][ !!! *37* !!! ]] - [[ char*->string ][ !!! *7* !!! ][ 120 ][ 28 ][ --- ]] - [[ char*->container::string ][ !!! *2* !!! ][ 108 ][ 26 ][ --- ]] - [[ unsigned char*->char ][ !!! *<1* !!! ][ 90 ][ 12 ][ 8 ]] - [[ unsigned char*->signed char ][ !!! *<1* !!! ][ 91 ][ 11 ][ 9 ]] - [[ unsigned char*->unsigned char ][ !!! *<1* !!! ][ 91 ][ 12 ][ 9 ]] - [[ unsigned char*->int ][ !!! *6* !!! ][ 106 ][ 24 ][ 14 ]] - [[ unsigned char*->short ][ !!! *6* !!! ][ 108 ][ 24 ][ 14 ]] - [[ unsigned char*->long int ][ !!! *7* !!! ][ 116 ][ 23 ][ 14 ]] - [[ unsigned char*->long long ][ !!! *7* !!! ][ 108 ][ 28 ][ 14 ]] - [[ unsigned char*->unsigned int ][ !!! *6* !!! ][ 107 ][ 22 ][ 14 ]] - [[ unsigned char*->unsigned short ][ !!! *6* !!! ][ 105 ][ 21 ][ 16 ]] - [[ unsigned char*->unsigned long int ][ !!! *7* !!! ][ 106 ][ 25 ][ 16 ]] - [[ unsigned char*->unsigned long long ][ !!! *7* !!! ][ 105 ][ 24 ][ 17 ]] - [[ unsigned char*->float ][ !!! *14* !!! ][ 150 ][ 57 ][ 33 ]] - [[ unsigned char*->double ][ !!! *14* !!! ][ 171 ][ 72 ][ 34 ]] - [[ unsigned char*->long double ][ 118 ][ 171 ][ 73 ][ !!! *38* !!! ]] - [[ unsigned char*->string ][ !!! *8* !!! ][ 120 ][ 29 ][ --- ]] - [[ unsigned char*->container::string ][ !!! *3* !!! ][ 114 ][ 26 ][ --- ]] - [[ signed char*->char ][ !!! *<1* !!! ][ 92 ][ 12 ][ 8 ]] - [[ signed char*->signed char ][ !!! *<1* !!! ][ 92 ][ 12 ][ 9 ]] - [[ signed char*->unsigned char ][ !!! *<1* !!! ][ 91 ][ 14 ][ 9 ]] - [[ signed char*->int ][ !!! *6* !!! ][ 109 ][ 22 ][ 15 ]] - [[ signed char*->short ][ !!! *6* !!! ][ 106 ][ 24 ][ 17 ]] - [[ signed char*->long int ][ !!! *7* !!! ][ 107 ][ 24 ][ 16 ]] - [[ signed char*->long long ][ !!! *7* !!! ][ 106 ][ 24 ][ 14 ]] - [[ signed char*->unsigned int ][ !!! *6* !!! ][ 106 ][ 22 ][ 14 ]] - [[ signed char*->unsigned short ][ !!! *6* !!! ][ 104 ][ 20 ][ 14 ]] - [[ signed char*->unsigned long int ][ !!! *7* !!! ][ 105 ][ 22 ][ 16 ]] - [[ signed char*->unsigned long long ][ !!! *7* !!! ][ 108 ][ 24 ][ 15 ]] - [[ signed char*->float ][ !!! *14* !!! ][ 147 ][ 54 ][ 32 ]] - [[ signed char*->double ][ !!! *14* !!! ][ 170 ][ 68 ][ 37 ]] - [[ signed char*->long double ][ 133 ][ 167 ][ 66 ][ !!! *37* !!! ]] - [[ signed char*->string ][ !!! *8* !!! ][ 119 ][ 30 ][ --- ]] - [[ signed char*->container::string ][ !!! *3* !!! ][ 108 ][ 24 ][ --- ]] - [[ iterator_range->char ][ !!! *<1* !!! ][ 98 ][ 13 ][ 8 ]] - [[ iterator_range->signed char ][ !!! *<1* !!! ][ 98 ][ 15 ][ 9 ]] - [[ iterator_range->unsigned char ][ !!! *<1* !!! ][ 97 ][ 15 ][ 9 ]] - [[ iterator_range->int ][ !!! *6* !!! ][ 107 ][ 27 ][ 14 ]] - [[ iterator_range->short ][ !!! *5* !!! ][ 109 ][ 23 ][ 14 ]] - [[ iterator_range->long int ][ !!! *7* !!! ][ 109 ][ 22 ][ 14 ]] - [[ iterator_range->long long ][ !!! *7* !!! ][ 107 ][ 24 ][ 14 ]] - [[ iterator_range->unsigned int ][ !!! *6* !!! ][ 120 ][ 23 ][ 14 ]] - [[ iterator_range->unsigned short ][ !!! *5* !!! ][ 104 ][ 21 ][ 17 ]] - [[ iterator_range->unsigned long int ][ !!! *8* !!! ][ 108 ][ 25 ][ 16 ]] - [[ iterator_range->unsigned long long ][ !!! *7* !!! ][ 106 ][ 25 ][ 15 ]] - [[ iterator_range->float ][ !!! *13* !!! ][ 132 ][ 41 ][ 32 ]] - [[ iterator_range->double ][ !!! *12* !!! ][ 136 ][ 45 ][ 32 ]] - [[ iterator_range->long double ][ 113 ][ 138 ][ 50 ][ !!! *36* !!! ]] - [[ iterator_range->string ][ !!! *7* !!! ][ 114 ][ 33 ][ --- ]] - [[ iterator_range->container::string ][ !!! *2* !!! ][ 105 ][ 24 ][ --- ]] - [[ int->int ][ !!! *<1* !!! ][ 112 ][ 31 ][ --- ]] - [[ float->double ][ !!! *<1* !!! ][ 233 ][ 199 ][ --- ]] - [[ char->signed char ][ !!! *<1* !!! ][ 129 ][ 10 ][ --- ]] -] -[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 3e2e53f..c9d4a59 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -69,12 +69,12 @@ namespace boost { // exception used to indicate runtime lexical_cast failure class BOOST_SYMBOL_VISIBLE bad_lexical_cast : - // workaround MSVC bug with std::bad_cast when _HAS_EXCEPTIONS == 0 -#if defined(BOOST_MSVC) && defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS - public std::exception -#else - public std::bad_cast -#endif + // workaround MSVC bug with std::bad_cast when _HAS_EXCEPTIONS == 0 +#if defined(BOOST_MSVC) && defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS + public std::exception +#else + public std::bad_cast +#endif #if defined(__BORLANDC__) && BOOST_WORKAROUND( __BORLANDC__, < 0x560 ) // under bcc32 5.5.1 bad_cast doesn't derive from exception @@ -134,10 +134,16 @@ namespace boost } } // namespace boost -#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) && !defined(__SUNPRO_CC) +#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) && !defined(__SUNPRO_CC) && !defined(__PGIC__) #include #include + +#if !defined(BOOST_NO_CXX11_HDR_ARRAY) && defined(BOOST_HAS_TR1_ARRAY) +#include +#endif + +#include #include #include #include @@ -168,13 +174,13 @@ namespace boost { { typedef CharT type; }; - + template <> struct widest_char< not_a_character_type, not_a_character_type > { typedef char type; }; - } + } namespace detail // is_char_or_wchar<...> and stream_char<...> templates { @@ -224,42 +230,68 @@ namespace boost { typedef char type; }; - template + template struct stream_char { typedef BOOST_DEDUCED_TYPENAME stream_char::type type; }; - template + template struct stream_char { typedef BOOST_DEDUCED_TYPENAME stream_char::type type; }; - template + template struct stream_char > { typedef BOOST_DEDUCED_TYPENAME stream_char::type type; }; - - template + + template struct stream_char > { typedef BOOST_DEDUCED_TYPENAME stream_char::type type; }; - template + template struct stream_char< std::basic_string > { typedef CharT type; }; - template + template struct stream_char< ::boost::container::basic_string > { typedef CharT type; }; + template + struct stream_char > + { + typedef BOOST_DEDUCED_TYPENAME stream_char::type type; + }; + + template + struct stream_char > + { + typedef BOOST_DEDUCED_TYPENAME stream_char::type type; + }; + +#if !defined(BOOST_NO_CXX11_HDR_ARRAY) && defined(BOOST_HAS_TR1_ARRAY) + template + struct stream_char > + { + typedef BOOST_DEDUCED_TYPENAME stream_char::type type; + }; + + template + struct stream_char > + { + typedef BOOST_DEDUCED_TYPENAME stream_char::type type; + }; +#endif // !defined(BOOST_NO_CXX11_HDR_ARRAY) && defined(BOOST_HAS_TR1_ARRAY) + #if !defined(BOOST_LCAST_NO_WCHAR_T) && defined(BOOST_NO_INTRINSIC_WCHAR_T) template<> struct stream_char @@ -430,7 +462,7 @@ namespace boost { // -1.23456789e-123456 // ^ sign // ^ leading digit - // ^ decimal point + // ^ decimal point // ^^^^^^^^ lcast_precision::value // ^ "e" // ^ exponent sign @@ -1259,7 +1291,6 @@ namespace boost { return true; } -#ifndef BOOST_LCAST_NO_WCHAR_T template bool shl_char_array(T const* str) { @@ -1268,7 +1299,13 @@ namespace boost { "Use boost::locale instead" ); return shl_input_streamable(str); } -#endif + + bool shl_char_array_limited(CharT const* str, std::size_t max_size) + { + start = const_cast(str); + finish = std::find(start, start + max_size, static_cast(0)); + return true; + } template bool shl_input_streamable(InputStreamable& input) @@ -1403,14 +1440,14 @@ namespace boost { { start = rng.begin(); finish = rng.end(); - return true; + return true; } - + bool operator<<(const iterator_range& rng) { start = const_cast(rng.begin()); finish = const_cast(rng.end()); - return true; + return true; } bool operator<<(const iterator_range& rng) @@ -1494,8 +1531,58 @@ namespace boost { return shl_real_type(static_cast(val), start, finish); #endif } + + template + bool operator<<(boost::array const& input) + { return shl_char_array_limited(input.begin(), N); } - template + template + bool operator<<(boost::array const& input) + { return ((*this) << reinterpret_cast const& >(input)); } + + template + bool operator<<(boost::array const& input) + { return ((*this) << reinterpret_cast const& >(input)); } + + template + bool operator<<(boost::array const& input) + { return shl_char_array_limited(input.begin(), N); } + + template + bool operator<<(boost::array const& input) + { return ((*this) << reinterpret_cast const& >(input)); } + + template + bool operator<<(boost::array const& input) + { return ((*this) << reinterpret_cast const& >(input)); } + +#if !defined(BOOST_NO_CXX11_HDR_ARRAY) && defined(BOOST_HAS_TR1_ARRAY) + template + bool operator<<(std::array const& input) + { return shl_char_array_limited(input.begin(), N); } + + template + bool operator<<(std::array const& input) + { return ((*this) << reinterpret_cast const& >(input)); } + + template + bool operator<<(std::array const& input) + { return ((*this) << reinterpret_cast const& >(input)); } + + template + bool operator<<(std::array const& input) + { return shl_char_array_limited(input.begin(), N); } + + template + bool operator<<(std::array const& input) + { return ((*this) << reinterpret_cast const& >(input)); } + + template + bool operator<<(std::array const& input) + { return ((*this) << reinterpret_cast const& >(input)); } +#endif // !defined(BOOST_NO_CXX11_HDR_ARRAY) && defined(BOOST_HAS_TR1_ARRAY) + + template bool operator<<(const InStreamable& input) { return shl_input_streamable(input); } /************************************ HELPER FUNCTIONS FOR OPERATORS >> ( ... ) ********************************/ @@ -1674,6 +1761,70 @@ namespace boost { template bool operator>>(::boost::container::basic_string& str) { str.assign(start, finish); return true; } + + private: + template + bool shr_std_array(ArrayT& output, boost::mpl::bool_ /*is_T_char_tag*/) + { + using namespace std; + const std::size_t size = finish - start; + if (size > N - 1) { // `-1` because we need to store \0 at the end + return false; + } + + memcpy(output.begin(), start, size * sizeof(CharT)); + *(output.begin() + size) = static_cast(0); + return true; + } + + template + bool shr_std_array(ArrayT& output, boost::mpl::bool_ /*is_T_char_tag*/) + { + return shr_using_base_class(output); // Array consist of non character types or unmatching character type + } + public: + + template + bool operator>>(boost::array& output) + { + typedef boost::mpl::bool_ tag_type; + return shr_std_array(output, tag_type()); + } + + template + bool operator>>(boost::array& output) + { + return ((*this) >> reinterpret_cast& >(output)); + } + + template + bool operator>>(boost::array& output) + { + return ((*this) >> reinterpret_cast& >(output)); + } + +#if !defined(BOOST_NO_CXX11_HDR_ARRAY) && defined(BOOST_HAS_TR1_ARRAY) + template + bool operator>>(std::array& output) + { + typedef boost::mpl::bool_ tag_type; + return shr_std_array(output, tag_type()); + } + + template + bool operator>>(std::array& output) + { + return ((*this) >> reinterpret_cast& >(output)); + } + + template + bool operator>>(std::array& in) + { + return ((*this) >> reinterpret_cast& >(output)); + } +#endif // !defined(BOOST_NO_CXX11_HDR_ARRAY) && defined(BOOST_HAS_TR1_ARRAY) + + /* * case "-0" || "0" || "+0" : output = false; return true; * case "1" || "+1": output = true; return true; @@ -1857,11 +2008,11 @@ namespace boost { }; - // this metafunction evaluates to true, if we have optimized comnversion - // from Float type to Char array. + // this metafunction evaluates to true, if we have optimized comnversion + // from Float type to Char array. // Must be in sync with lexical_stream_limited_src::shl_real_type(...) template - struct is_this_float_conversion_optimized + struct is_this_float_conversion_optimized { typedef ::boost::type_traits::ice_and< ::boost::is_float::value, @@ -1937,11 +2088,6 @@ namespace boost { "Your compiler does not have full support for char32_t" ); #endif - typedef detail::lcast_src_length lcast_src_length; - std::size_t const src_len = lcast_src_length::value; - char_type buf[src_len + 1]; - lcast_src_length::check_coverage(); - typedef BOOST_DEDUCED_TYPENAME ::boost::detail::deduce_char_traits< char_type, Target, Source >::type traits; @@ -1959,20 +2105,29 @@ namespace boost { ::boost::detail::is_char_or_wchar::value > is_source_input_optimized_t; + // Target type must be default constructible + Target result; + // If we have an optimized conversion for // Source, we do not need to construct stringbuf. const bool requires_stringbuf = ::boost::type_traits::ice_or< is_string_widening_required_t::value, ::boost::type_traits::ice_not< is_source_input_optimized_t::value >::value >::value; + + typedef detail::lexical_stream_limited_src interpreter_type; - detail::lexical_stream_limited_src - interpreter(buf, buf + src_len); + typedef detail::lcast_src_length lcast_src_length; + std::size_t const src_len = lcast_src_length::value; + char_type buf[src_len + 1]; + lcast_src_length::check_coverage(); + + interpreter_type interpreter(buf, buf + src_len); - Target result; // Disabling ADL, by directly specifying operators. if(!(interpreter.operator <<(arg) && interpreter.operator >>(result))) BOOST_LCAST_THROW_BAD_CAST(Source, Target); + return result; } }; @@ -2252,10 +2407,10 @@ namespace boost { template Target lexical_cast(Source arg) { - typedef typename detail::widest_char< - BOOST_DEDUCED_TYPENAME detail::stream_char::type - , BOOST_DEDUCED_TYPENAME detail::stream_char::type - >::type char_type; + typedef typename detail::widest_char< + BOOST_DEDUCED_TYPENAME detail::stream_char::type + , BOOST_DEDUCED_TYPENAME detail::stream_char::type + >::type char_type; typedef std::char_traits traits; detail::lexical_stream interpreter; diff --git a/lexical_cast_test.cpp b/lexical_cast_test.cpp index 844ee71..e7adc86 100644 --- a/lexical_cast_test.cpp +++ b/lexical_cast_test.cpp @@ -4,7 +4,7 @@ // // Copyright Terje Sletteb and Kevlin Henney, 2005. // Copyright Alexander Nasonov, 2006. -// Copyright Antony Polukhin, 2011. +// Copyright Antony Polukhin, 2011-2012. // // Distributed under the Boost // Software License, Version 1.0. (See accompanying file @@ -57,13 +57,6 @@ struct my_allocator : std::allocator { }; -// Test all 65536 values if true: -bool const lcast_test_small_integral_types_completely = false; - -// lcast_integral_test_counter: use when testing all values of an integral -// types is not possible. Max. portable value is 32767. -int const lcast_integral_test_counter=1000; - using namespace boost; void test_conversion_to_char(); @@ -80,18 +73,6 @@ void test_conversion_from_wstring(); void test_conversion_to_wstring(); void test_bad_lexical_cast(); void test_no_whitespace_stripping(); -void test_conversion_from_to_short(); -void test_conversion_from_to_ushort(); -void test_conversion_from_to_int(); -void test_conversion_from_to_uint(); -void test_conversion_from_to_long(); -void test_conversion_from_to_ulong(); -void test_conversion_from_to_intmax_t(); -void test_conversion_from_to_uintmax_t(); -#ifdef LCAST_TEST_LONGLONG -void test_conversion_from_to_longlong(); -void test_conversion_from_to_ulonglong(); -#endif #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION void test_traits(); void test_wtraits(); @@ -107,7 +88,6 @@ void test_char16_conversions(); void test_char32_conversions(); #endif - unit_test::test_suite *init_unit_test_suite(int, char *[]) { unit_test::test_suite *suite = @@ -128,18 +108,6 @@ unit_test::test_suite *init_unit_test_suite(int, char *[]) #endif suite->add(BOOST_TEST_CASE(test_bad_lexical_cast)); suite->add(BOOST_TEST_CASE(test_no_whitespace_stripping)); - suite->add(BOOST_TEST_CASE(&test_conversion_from_to_short)); - suite->add(BOOST_TEST_CASE(&test_conversion_from_to_ushort)); - suite->add(BOOST_TEST_CASE(&test_conversion_from_to_int)); - suite->add(BOOST_TEST_CASE(&test_conversion_from_to_uint)); - suite->add(BOOST_TEST_CASE(&test_conversion_from_to_long)); - suite->add(BOOST_TEST_CASE(&test_conversion_from_to_ulong)); - suite->add(BOOST_TEST_CASE(&test_conversion_from_to_intmax_t)); - suite->add(BOOST_TEST_CASE(&test_conversion_from_to_uintmax_t)); -#ifdef LCAST_TEST_LONGLONG - suite->add(BOOST_TEST_CASE(&test_conversion_from_to_longlong)); - suite->add(BOOST_TEST_CASE(&test_conversion_from_to_ulonglong)); -#endif #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION suite->add(BOOST_TEST_CASE(&test_traits)); suite->add(BOOST_TEST_CASE(&test_wtraits)); @@ -399,6 +367,7 @@ void test_conversion_to_wchar_t() BOOST_CHECK_THROW( lexical_cast(std::wstring(L"Test")), bad_lexical_cast); #endif + BOOST_CHECK(true); } void test_conversion_from_wstring() @@ -417,6 +386,7 @@ void test_conversion_from_wstring() BOOST_CHECK_THROW( lexical_cast(std::wstring(L"Test")), bad_lexical_cast); #endif + BOOST_CHECK(true); } void test_conversion_to_wstring() @@ -441,6 +411,7 @@ void test_conversion_to_wstring() BOOST_CHECK(L" " == lexical_cast(std::wstring(L" "))); BOOST_CHECK(L"" == lexical_cast(std::wstring(L""))); #endif + BOOST_CHECK(true); } void test_bad_lexical_cast() @@ -464,444 +435,6 @@ void test_no_whitespace_stripping() BOOST_CHECK_THROW(lexical_cast("123 "), bad_lexical_cast); } -// 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_integral_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_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() -{ - T t = 0; - BOOST_CHECK(lexical_cast(t) == t); - - // Next two variables are used to supress warnings. - int st = 32767; unsigned int ut = st; - t = st; - BOOST_CHECK(lexical_cast(t) == st); - BOOST_CHECK(lexical_cast(t) == ut); - BOOST_CHECK(lexical_cast(t) == st); - BOOST_CHECK(lexical_cast(t) == ut); - BOOST_CHECK(lexical_cast(t) == st); - BOOST_CHECK(lexical_cast(t) == ut); - - t = (std::numeric_limits::max)(); - BOOST_CHECK(lexical_cast(t) == t); - - t = (std::numeric_limits::min)(); - BOOST_CHECK(lexical_cast(t) == t); -} - -template -void test_conversion_from_integral_to_string(CharT) -{ - typedef std::numeric_limits limits; - typedef std::basic_string string_type; - - T t; - - t = (limits::min)(); - BOOST_CHECK(lexical_cast(t) == to_str(t)); - - t = (limits::max)(); - BOOST_CHECK(lexical_cast(t) == to_str(t)); - - if(limits::digits <= 16 && lcast_test_small_integral_types_completely) - // min and max have already been tested. - for(t = 1 + (limits::min)(); t != (limits::max)(); ++t) - BOOST_CHECK(lexical_cast(t) == to_str(t)); - else - { - T const min_val = (limits::min)(); - T const max_val = (limits::max)(); - T const half_max_val = max_val / 2; - T const cnt = lcast_integral_test_counter; // to supress warnings - unsigned int const counter = cnt < half_max_val ? cnt : half_max_val; - - unsigned int i; - - // Test values around min: - t = min_val; - for(i = 0; i < counter; ++i, ++t) - BOOST_CHECK(lexical_cast(t) == to_str(t)); - - // Test values around max: - t = max_val; - for(i = 0; i < counter; ++i, --t) - BOOST_CHECK(lexical_cast(t) == to_str(t)); - - // Test values around zero: - if(limits::is_signed) - for(t = static_cast(-counter); t < static_cast(counter); ++t) - BOOST_CHECK(lexical_cast(t) == to_str(t)); - - // Test values around 100, 1000, 10000, ... - T ten_power = 100; - for(int e = 2; e <= limits::digits10; ++e, ten_power *= 10) - { - // ten_power + 100 probably never overflows - for(t = ten_power - 100; t != ten_power + 100; ++t) - BOOST_CHECK(lexical_cast(t) == to_str(t)); - } - } -} - -template -void test_conversion_from_string_to_integral(CharT) -{ - typedef std::numeric_limits limits; - typedef std::basic_string string_type; - - string_type s; - string_type const zero = to_str(0); - string_type const nine = to_str(9); - T const min_val = (limits::min)(); - T const max_val = (limits::max)(); - - s = to_str(min_val); - BOOST_CHECK_EQUAL(lexical_cast(s), min_val); - if(limits::is_signed) - { - 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); - { - 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) - // min and max have already been tested. - for(T t = 1 + min_val; t != max_val; ++t) - BOOST_CHECK(lexical_cast(to_str(t)) == t); - else - { - T const half_max_val = max_val / 2; - T const cnt = lcast_integral_test_counter; // to supress warnings - unsigned int const counter = cnt < half_max_val ? cnt : half_max_val; - - T t; - unsigned int i; - - // Test values around min: - t = min_val; - for(i = 0; i < counter; ++i, ++t) - BOOST_CHECK(lexical_cast(to_str(t)) == t); - - // Test values around max: - t = max_val; - for(i = 0; i < counter; ++i, --t) - BOOST_CHECK(lexical_cast(to_str(t)) == t); - - // Test values around zero: - if(limits::is_signed) - for(t = static_cast(-counter); t < static_cast(counter); ++t) - BOOST_CHECK(lexical_cast(to_str(t)) == t); - - // Test values around 100, 1000, 10000, ... - T ten_power = 100; - for(int e = 2; e <= limits::digits10; ++e, ten_power *= 10) - { - // ten_power + 100 probably never overflows - for(t = ten_power - 100; t != ten_power + 100; ++t) - BOOST_CHECK(lexical_cast(to_str(t)) == t); - } - } -} - -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); - - // Exception must not be thrown, when we are using no separators at all - BOOST_CHECK( lexical_cast("30000") == static_cast(30000) ); - } - - test_conversion_from_integral_to_integral(); - test_conversion_from_integral_to_string('0'); - test_conversion_from_string_to_integral('0'); -#if !defined(BOOST_LCAST_NO_WCHAR_T) - test_conversion_from_integral_to_string(L'0'); - test_conversion_from_string_to_integral(L'0'); -#endif -} - -struct restore_oldloc -{ - std::locale oldloc; - ~restore_oldloc() { std::locale::global(oldloc); } -}; - -template -void test_conversion_from_to_integral() -{ - 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 -#if !defined(BOOST_NO_CHAR16_T) && !defined(BOOST_NO_UNICODE_LITERALS) - char16_t const u16zero = u'0'; - test_conversion_from_integral_to_char(u16zero); - test_conversion_from_char_to_integral(u16zero); -#endif -#if !defined(BOOST_NO_CHAR32_T) && !defined(BOOST_NO_UNICODE_LITERALS) - 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)); - 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); - - 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 - - // Overflow test case from David W. Birdsall - std::string must_owerflow_str = "160000000000000000000"; - std::string must_owerflow_negative_str = "-160000000000000000000"; - for (int i = 0; i < 15; ++i) { - BOOST_CHECK_THROW(lexical_cast(must_owerflow_str), bad_lexical_cast); - BOOST_CHECK_THROW(lexical_cast(must_owerflow_negative_str), bad_lexical_cast); - - must_owerflow_str += '0'; - must_owerflow_negative_str += '0'; - } - - 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_integral_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_integral_for_locale(); - - if(grouping1.empty() && grouping2.empty()) - BOOST_TEST_MESSAGE("Formatting with thousands_sep has not been tested"); -} - -void test_conversion_from_to_short() -{ - test_conversion_from_to_integral(); -} - -void test_conversion_from_to_ushort() -{ - test_conversion_from_to_integral(); -} - -void test_conversion_from_to_int() -{ - test_conversion_from_to_integral(); -} - -void test_conversion_from_to_uint() -{ - test_conversion_from_to_integral(); -} - -void test_conversion_from_to_long() -{ - test_conversion_from_to_integral(); -} - -void test_conversion_from_to_ulong() -{ - test_conversion_from_to_integral(); -} - -void test_conversion_from_to_intmax_t() -{ - test_conversion_from_to_integral(); -} - -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(); -} - -#elif defined(BOOST_HAS_MS_INT64) - -void test_conversion_from_to_longlong() -{ - test_conversion_from_to_integral<__int64>(); -} - -void test_conversion_from_to_ulonglong() -{ - test_conversion_from_to_integral(); -} - -#endif #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION void test_traits() @@ -960,6 +493,7 @@ void test_wallocator() #endif + void test_char_types_conversions() { const char c_arr[] = "Test array of chars"; @@ -1040,3 +574,4 @@ void test_char32_conversions() } #endif + diff --git a/perf/performance_test.cpp b/perf/performance_test.cpp index 8640bc4..7fbac4f 100644 --- a/perf/performance_test.cpp +++ b/perf/performance_test.cpp @@ -13,6 +13,7 @@ #define BOOST_CHRONO_HEADER_ONLY #include + #include #include #include @@ -21,6 +22,13 @@ // File to output data std::fstream fout; +namespace boost { +inline std::istream& operator>> (std::istream& in, boost::array& res) { + in >> res.begin(); + return in; +} +} + template static inline void test_lexical(const InT& in_val) { OutT out_val = boost::lexical_cast(in_val); @@ -37,6 +45,28 @@ static inline void test_ss_constr(const InT& in_val) { if (ss.fail()) throw std::logic_error("descr"); } +template +static inline void test_ss_constr(const boost::array& in_val) { + OutT out_val; + std::stringstream ss; + ss << in_val.begin(); + if (ss.fail()) throw std::logic_error("descr"); + ss >> out_val; + if (ss.fail()) throw std::logic_error("descr"); +} + +template +static inline void test_ss_noconstr(StringStreamT& ss, const boost::array& in_val) { + OutT out_val; + ss << in_val.begin(); // ss is an instance of std::stringstream + if (ss.fail()) throw std::logic_error("descr"); + ss >> out_val; + if (ss.fail()) throw std::logic_error("descr"); + /* reseting std::stringstream to use it again */ + ss.str(std::string()); + ss.clear(); +} + template static inline void test_ss_noconstr(StringStreamT& ss, const InT& in_val) { OutT out_val; @@ -64,6 +94,12 @@ struct structure_sprintf { }; struct structure_sscanf { + template + static inline void test(BufferT* /*buffer*/, const boost::array& in_val, const char* const conv) { + OutT out_val; + sscanf(in_val.cbegin(), conv, &out_val); + } + template static inline void test(BufferT* /*buffer*/, const InT& in_val, const char* const conv) { OutT out_val; @@ -229,7 +265,7 @@ void string_like_test_set(const std::string& from) { perf_test(from + "->float", conv("1.123"), "%f"); perf_test(from + "->double", conv("1.123"), "%lf"); perf_test(from + "->long double", conv("1.123"), "%Lf"); - + perf_test, ssc_t>(from + "->array", conv("1.123"), "%s"); perf_test(from + "->string", conv("string"), "%Lf"); perf_test(from + "->container::string" @@ -268,6 +304,14 @@ struct to_iterator_range { } }; +struct to_array_50 { + boost::array operator()(const char* const c) const { + boost::array ret; + std::strcpy(ret.begin(), c); + return ret; + } +}; + int main(int argc, char** argv) { BOOST_ASSERT(argc >= 2); std::string output_path(argv[1]); @@ -310,6 +354,7 @@ int main(int argc, char** argv) { string_like_test_set("unsigned char*"); string_like_test_set("signed char*"); string_like_test_set("iterator_range"); + string_like_test_set("array"); perf_test("int->int", 100, ""); perf_test("float->double", 100.0f, ""); diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index f8ee0d3..f77a845 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -47,5 +47,7 @@ test-suite conversion gcc-4.7:-fno-exceptions ] [ run lexical_cast_iterator_range_test.cpp ] + [ run lexical_cast_arrays_test.cpp ] + [ run lexical_cast_integral_types_test.cpp ] ; diff --git a/test/implicit_cast.cpp b/test/implicit_cast.cpp index 8c3bc52..0cad067 100644 --- a/test/implicit_cast.cpp +++ b/test/implicit_cast.cpp @@ -28,7 +28,7 @@ int main() type f = check_return(boost::implicit_cast("hello")); type z = check_return(boost::implicit_cast(foo("hello"))); - + // warning supression: (void)x; (void)f; diff --git a/test/implicit_cast_fail.cpp b/test/implicit_cast_fail.cpp index 80143da..a7867a1 100644 --- a/test/implicit_cast_fail.cpp +++ b/test/implicit_cast_fail.cpp @@ -19,4 +19,6 @@ struct foo int test_main(int, char*[]) { foo x = implicit_cast("foobar"); + (void)x; // warning suppression. + return 0; } diff --git a/test/lexical_cast_arrays_test.cpp b/test/lexical_cast_arrays_test.cpp new file mode 100644 index 0000000..6aff2d9 --- /dev/null +++ b/test/lexical_cast_arrays_test.cpp @@ -0,0 +1,367 @@ +// Testing boost::lexical_cast with boost::container::string. +// +// See http://www.boost.org for most recent version, including documentation. +// +// Copyright Antony Polukhin, 2012. +// +// Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). + +#include + +#include + +#include + +void testing_boost_array_output_conversion(); +void testing_std_array_output_conversion(); + +void testing_boost_array_input_conversion(); +void testing_std_array_input_conversion(); + +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::array and std::array"); + + suite->add(BOOST_TEST_CASE(testing_boost_array_output_conversion)); + suite->add(BOOST_TEST_CASE(testing_std_array_output_conversion)); + suite->add(BOOST_TEST_CASE(testing_boost_array_input_conversion)); + suite->add(BOOST_TEST_CASE(testing_std_array_input_conversion)); + + return suite; +} + +template