Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r73118 - in trunk: boost libs/conversion libs/conversion/test
From: antoshkka_at_[hidden]
Date: 2011-07-15 07:20:12


Author: apolukhin
Date: 2011-07-15 07:20:11 EDT (Fri, 15 Jul 2011)
New Revision: 73118
URL: http://svn.boost.org/trac/boost/changeset/73118

Log:
Fixes #5689. Added code to work with Inf and NaN on any platform
Added:
   trunk/libs/conversion/test/lexical_cast_inf_nan_test.cpp (contents, props changed)
Text files modified:
   trunk/boost/lexical_cast.hpp | 144 ++++++++++++++++++++++++++++++++++++++-
   trunk/libs/conversion/lexical_cast.htm | 1
   trunk/libs/conversion/lexical_cast_test.cpp | 4 +
   trunk/libs/conversion/test/Jamfile.v2 | 1
   trunk/libs/conversion/test/lexical_cast_float_types_test.cpp | 20 -----
   5 files changed, 145 insertions(+), 25 deletions(-)

Modified: trunk/boost/lexical_cast.hpp
==============================================================================
--- trunk/boost/lexical_cast.hpp (original)
+++ trunk/boost/lexical_cast.hpp 2011-07-15 07:20:11 EDT (Fri, 15 Jul 2011)
@@ -24,6 +24,7 @@
 #include <cstddef>
 #include <istream>
 #include <string>
+#include <cstring>
 #include <typeinfo>
 #include <exception>
 #include <cmath>
@@ -731,6 +732,136 @@
         }
     }
 
+ namespace detail
+ {
+ /* Returns true and sets the correct value if found NaN or Inf. */
+ template <class CharT, class T>
+ inline bool parse_inf_nan_impl(const CharT* begin, const CharT* end, T& value
+ , const CharT* lc_NAN, const CharT* lc_nan
+ , const CharT* lc_INFINITY, const CharT* lc_infinity
+ , const CharT opening_brace, const CharT closing_brace)
+ {
+ using namespace std;
+ const wchar_t minus = lcast_char_constants<wchar_t>::minus;
+ const wchar_t plus = lcast_char_constants<wchar_t>::plus;
+ const int inifinity_size = 8;
+
+ bool has_minus = false;
+ /* Parsing +/- */
+ if( *begin == minus)
+ {
+ ++ begin;
+ has_minus = true;
+ }
+ else if( *begin == plus ) ++begin;
+
+ if( end-begin < 3 ) return false;
+ if( !memcmp(begin, lc_nan, 3*sizeof(CharT)) || !memcmp(begin, lc_NAN, 3*sizeof(CharT)) )
+ {
+ begin += 3;
+ if (end != begin) /* It is 'nan(...)' or some bad input*/
+ {
+ if(end-begin<2) return false; // bad input
+ -- end;
+ if( *begin != opening_brace || *end != closing_brace) return false; // bad input
+ }
+
+ if( !has_minus ) value = std::numeric_limits<T>::quiet_NaN();
+ else value = -std::numeric_limits<T>::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<T>::infinity();
+ else value = -std::numeric_limits<T>::infinity();
+ return true;
+ }
+
+ return false;
+ }
+
+#ifndef BOOST_LCAST_NO_WCHAR_T
+ template <class T>
+ bool parse_inf_nan(const wchar_t* begin, const wchar_t* end, T& value)
+ {
+ return parse_inf_nan_impl(begin, end, value
+ , L"NAN", L"nan"
+ , L"INFINITY", L"infinity"
+ , L'(', L')');
+ }
+#endif
+
+ template <class CharT, class T>
+ bool parse_inf_nan(const CharT* begin, const CharT* end, T& value)
+ {
+ return parse_inf_nan_impl(begin, end, value
+ , "NAN", "nan"
+ , "INFINITY", "infinity"
+ , '(', ')');
+ }
+
+ template <class T>
+ bool put_inf_nan(wchar_t* begin, wchar_t*& end, const T& value)
+ {
+ using namespace std;
+ if (value != value)
+ {
+ memcpy(begin,L"nan", sizeof(L"nan"));
+ end = begin + 3;
+ return true;
+ } else if ( value > numeric_limits<T>::max() )
+ {
+ memcpy(begin,L"inf", sizeof(L"inf"));
+ end = begin + 3;
+ return true;
+ } else if ( value < -numeric_limits<T>::max() )
+ {
+ memcpy(begin,L"-inf", sizeof(L"-inf"));
+ end = begin + 4;
+ return true;
+ }
+
+ return false;
+ }
+
+ template <class CharT, class T>
+ bool put_inf_nan(CharT* begin, CharT*& end, const T& value)
+ {
+ using namespace std;
+ if (value != value)
+ {
+ memcpy(begin,"nan", sizeof("nan"));
+ end = begin + 3;
+ return true;
+ } else if ( value > numeric_limits<T>::max() )
+ {
+ memcpy(begin,"inf", sizeof("inf"));
+ end = begin + 3;
+ return true;
+ } else if ( value < -numeric_limits<T>::max() )
+ {
+ memcpy(begin,"-inf", sizeof("-inf"));
+ end = begin + 4;
+ return true;
+ }
+
+ return false;
+ }
+
+ }
+
+
     namespace detail // lcast_ret_float
     {
         template <class T>
@@ -782,6 +913,8 @@
 
             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<T>::type mantissa_type;
             int_type const zero = Traits::to_int_type(czero);
@@ -1104,6 +1237,7 @@
             template<class OutputStreamable>
             bool lcast_put(const OutputStreamable& input)
             {
+ if(put_inf_nan(start, finish, input)) return true;
                 this->setp(start, finish);
                 std::basic_ostream<CharT> stream(static_cast<Base*>(this));
                 lcast_set_precision(stream, static_cast<OutputStreamable*>(0));
@@ -1342,10 +1476,13 @@
             // Not optimised converter
             template <class T>
             bool float_types_converter_internal(T& output, int /*tag*/) {
+
+ if (parse_inf_nan(start, finish, output)) return true;
+
                 bool return_value = convert_using_base_class(output);
 
                 /* Some compilers and libraries successfully
- * parse 'inf', 'INFINITY', '1.0E', '1.0E-'...
+ * parse '1.0E', '1.0E-'...
                  * We are trying to provide a unified behaviour,
                  * so we just forbid such conversions (as some
                  * of the most popular compilers/libraries do)
@@ -1356,10 +1493,7 @@
                 CharT const lowercase_e = lcast_char_constants<CharT>::lowercase_e;
                 if ( return_value &&
                      (
- output > (std::numeric_limits<T>::max)() // +inf
- || output < -(std::numeric_limits<T>::max)() // -inf
- || output != output // NaN
- || *(finish-1) == lowercase_e // 1.0e
+ *(finish-1) == lowercase_e // 1.0e
                         || *(finish-1) == capital_e // 1.0E
                         || *(finish-1) == minus // 1.0e- or 1.0E-
                         || *(finish-1) == plus // 1.0e+ or 1.0E+

Modified: trunk/libs/conversion/lexical_cast.htm
==============================================================================
--- trunk/libs/conversion/lexical_cast.htm (original)
+++ trunk/libs/conversion/lexical_cast.htm 2011-07-15 07:20:11 EDT (Fri, 15 Jul 2011)
@@ -269,6 +269,7 @@
 <h2><a name="changes">Changes</a></h2>
 <h3>July 2011:</h3>
 <ul type="square">
+ <li>Added code to work with Inf and NaN on any platform.</li>
     <li>Better performance and less memory usage for conversions to float type (and to double type, if sizeof(double)&lt;sizeof(long double)).</li>
 </ul>
 <h3>May 2011:</h3>

Modified: trunk/libs/conversion/lexical_cast_test.cpp
==============================================================================
--- trunk/libs/conversion/lexical_cast_test.cpp (original)
+++ trunk/libs/conversion/lexical_cast_test.cpp 2011-07-15 07:20:11 EDT (Fri, 15 Jul 2011)
@@ -42,6 +42,10 @@
 #define LCAST_TEST_LONGLONG
 #endif
 
+#if defined(BOOST_NO_STRINGSTREAM) || defined(BOOST_NO_STD_WSTRING)
+#define BOOST_LCAST_NO_WCHAR_T
+#endif
+
 template<class CharT>
 struct my_traits : std::char_traits<CharT>
 {

Modified: trunk/libs/conversion/test/Jamfile.v2
==============================================================================
--- trunk/libs/conversion/test/Jamfile.v2 (original)
+++ trunk/libs/conversion/test/Jamfile.v2 2011-07-15 07:20:11 EDT (Fri, 15 Jul 2011)
@@ -27,6 +27,7 @@
     [ run lexical_cast_vc8_bug_test.cpp ../../test/build//boost_unit_test_framework/<link>static ]
     [ run lexical_cast_wchars_test.cpp ../../test/build//boost_unit_test_framework/<link>static ]
     [ run lexical_cast_float_types_test.cpp ../../test/build//boost_unit_test_framework/<link>static ]
+ [ run lexical_cast_inf_nan_test.cpp ../../test/build//boost_unit_test_framework/<link>static ]
   ;
 
       

Modified: trunk/libs/conversion/test/lexical_cast_float_types_test.cpp
==============================================================================
--- trunk/libs/conversion/test/lexical_cast_float_types_test.cpp (original)
+++ trunk/libs/conversion/test/lexical_cast_float_types_test.cpp 2011-07-15 07:20:11 EDT (Fri, 15 Jul 2011)
@@ -242,22 +242,6 @@
     CHECK_CLOSE_ABS_DIFF(.34, test_t);
     CHECK_CLOSE_ABS_DIFF(.34e10, test_t);
 
-// BOOST_CHECK(lexical_cast<test_t>("-inf") == -std::numeric_limits<test_t>::infinity() );
-// BOOST_CHECK(lexical_cast<test_t>("-INF") == -std::numeric_limits<test_t>::infinity() );
-// BOOST_CHECK(lexical_cast<test_t>("+inf") == std::numeric_limits<test_t>::infinity() );
-// BOOST_CHECK(lexical_cast<test_t>("infinity") == std::numeric_limits<test_t>::infinity() );
-//
-// BOOST_CHECK(lexical_cast<test_t>("nan") == std::numeric_limits<test_t>::quiet_NaN() );
-// BOOST_CHECK(lexical_cast<test_t>("NaN") == std::numeric_limits<test_t>::quiet_NaN() );
-
- BOOST_CHECK_THROW(lexical_cast<test_t>("-inf"), bad_lexical_cast );
- BOOST_CHECK_THROW(lexical_cast<test_t>("-INF"), bad_lexical_cast);
- BOOST_CHECK_THROW(lexical_cast<test_t>("+inf"), bad_lexical_cast);
- BOOST_CHECK_THROW(lexical_cast<test_t>("infinity"), bad_lexical_cast);
- BOOST_CHECK_THROW(lexical_cast<test_t>("nan"), bad_lexical_cast);
- BOOST_CHECK_THROW(lexical_cast<test_t>("NaN"), bad_lexical_cast);
-
-
     BOOST_CHECK_THROW(lexical_cast<test_t>("-1.e"), bad_lexical_cast);
     BOOST_CHECK_THROW(lexical_cast<test_t>("-1.E"), bad_lexical_cast);
     BOOST_CHECK_THROW(lexical_cast<test_t>("1.e"), bad_lexical_cast);
@@ -381,10 +365,6 @@
 
     TEST_TO_FROM_CAST_AROUND( 0.0 );
 
-// TEST_TO_FROM_CAST_AROUND( std::numeric_limits<test_t>::infinity() );
-// TEST_TO_FROM_CAST_AROUND( -std::numeric_limits<test_t>::infinity() );
-// TEST_TO_FROM_CAST_AROUND( std::numeric_limits<test_t>::quiet_NaN() );
-
     long double val1;
     for(val1 = 1.0e-10L; val1 < 1e11; val1*=10 )
         TEST_TO_FROM_CAST_AROUND( val1 );

Added: trunk/libs/conversion/test/lexical_cast_inf_nan_test.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/conversion/test/lexical_cast_inf_nan_test.cpp 2011-07-15 07:20:11 EDT (Fri, 15 Jul 2011)
@@ -0,0 +1,109 @@
+// Unit test for boost::lexical_cast.
+//
+// See http://www.boost.org for most recent version, including documentation.
+//
+// Copyright Antony Polukhin, 2011.
+//
+// Distributed under the Boost
+// Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt).
+
+#include <boost/config.hpp>
+
+#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 <boost/lexical_cast.hpp>
+
+#include <boost/cstdint.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/test/floating_point_comparison.hpp>
+
+#if defined(BOOST_NO_STRINGSTREAM) || defined(BOOST_NO_STD_WSTRING)
+#define BOOST_LCAST_NO_WCHAR_T
+#endif
+
+using namespace boost;
+
+template <class T>
+void test_inf_nan_templated()
+{
+ typedef T test_t;
+
+ BOOST_CHECK(lexical_cast<test_t>("inf") > (std::numeric_limits<test_t >::max)() );
+ BOOST_CHECK(lexical_cast<test_t>("INF") > (std::numeric_limits<test_t >::max)() );
+
+ BOOST_CHECK(lexical_cast<test_t>("-inf") < -(std::numeric_limits<test_t >::max)() );
+ BOOST_CHECK(lexical_cast<test_t>("-INF") < -(std::numeric_limits<test_t >::max)() );
+
+ BOOST_CHECK(lexical_cast<test_t>("+inf") > (std::numeric_limits<test_t >::max)() );
+ BOOST_CHECK(lexical_cast<test_t>("+INF") > (std::numeric_limits<test_t >::max)() );
+
+ BOOST_CHECK(lexical_cast<test_t>("infinity") > (std::numeric_limits<test_t >::max)() );
+ BOOST_CHECK(lexical_cast<test_t>("INFINITY") > (std::numeric_limits<test_t >::max)() );
+
+ BOOST_CHECK(lexical_cast<test_t>("-infinity") < -(std::numeric_limits<test_t >::max)() );
+ BOOST_CHECK(lexical_cast<test_t>("-INFINITY") < -(std::numeric_limits<test_t >::max)() );
+
+ BOOST_CHECK(lexical_cast<test_t>("+infinity") > (std::numeric_limits<test_t >::max)() );
+ BOOST_CHECK(lexical_cast<test_t>("+INFINITY") > (std::numeric_limits<test_t >::max)() );
+
+ BOOST_CHECK( lexical_cast<test_t>("nan") != lexical_cast<test_t>("nan") );
+ BOOST_CHECK( lexical_cast<test_t>("NAN") != lexical_cast<test_t>("NAN") );
+
+ BOOST_CHECK( lexical_cast<test_t>("-nan") != lexical_cast<test_t>("-nan") );
+ BOOST_CHECK( lexical_cast<test_t>("-NAN") != lexical_cast<test_t>("-NAN") );
+
+ BOOST_CHECK( lexical_cast<test_t>("+nan") != lexical_cast<test_t>("+nan") );
+ BOOST_CHECK( lexical_cast<test_t>("+NAN") != lexical_cast<test_t>("+NAN") );
+
+ BOOST_CHECK( lexical_cast<test_t>("nan()") != lexical_cast<test_t>("nan()") );
+ BOOST_CHECK( lexical_cast<test_t>("NAN(some string)") != lexical_cast<test_t>("NAN(some string)") );
+ BOOST_CHECK_THROW( lexical_cast<test_t>("NAN(some string"), bad_lexical_cast );
+
+ BOOST_CHECK(lexical_cast<std::string>( -std::numeric_limits<test_t >::infinity()) == "-inf" );
+ BOOST_CHECK(lexical_cast<std::string>( std::numeric_limits<test_t >::infinity()) == "inf" );
+ BOOST_CHECK(lexical_cast<std::string>( std::numeric_limits<test_t >::quiet_NaN()) == "nan" );
+
+#ifndef BOOST_LCAST_NO_WCHAR_T
+ BOOST_CHECK(lexical_cast<test_t>(L"inf") > (std::numeric_limits<test_t >::max)() );
+ BOOST_CHECK(lexical_cast<test_t>(L"INF") > (std::numeric_limits<test_t >::max)() );
+
+ BOOST_CHECK( lexical_cast<test_t>(L"nan") != lexical_cast<test_t>(L"nan") );
+ BOOST_CHECK( lexical_cast<test_t>(L"NAN") != lexical_cast<test_t>(L"NAN") );
+
+ BOOST_CHECK(lexical_cast<std::wstring>( -std::numeric_limits<test_t >::infinity()) == L"-inf" );
+ BOOST_CHECK(lexical_cast<std::wstring>( std::numeric_limits<test_t >::infinity()) == L"inf" );
+ BOOST_CHECK(lexical_cast<std::wstring>( std::numeric_limits<test_t >::quiet_NaN()) == L"nan" );
+
+#endif
+}
+
+void test_inf_nan_float()
+{
+ test_inf_nan_templated<float >();
+}
+
+void test_inf_nan_double()
+{
+ test_inf_nan_templated<double >();
+}
+
+void test_inf_nan_long_double()
+{
+ test_inf_nan_templated<long double >();
+}
+
+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;
+}


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk