forked from boostorg/conversion
Fixes #5689. Added code to work with Inf and NaN on any platform
[SVN r73118]
This commit is contained in:
@@ -24,6 +24,7 @@
|
||||
#include <cstddef>
|
||||
#include <istream>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <typeinfo>
|
||||
#include <exception>
|
||||
#include <cmath>
|
||||
@@ -731,6 +732,136 @@ namespace boost
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ namespace boost
|
||||
|
||||
value = 0.0;
|
||||
|
||||
if (parse_inf_nan(begin, end, value)) return true;
|
||||
|
||||
typedef typename Traits::int_type int_type;
|
||||
typedef BOOST_DEDUCED_TYPENAME mantissa_holder_type<T>::type mantissa_type;
|
||||
int_type const zero = Traits::to_int_type(czero);
|
||||
@@ -1104,6 +1237,7 @@ namespace boost
|
||||
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 @@ namespace boost
|
||||
// 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 @@ namespace boost
|
||||
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+
|
||||
|
@@ -269,6 +269,7 @@ Eliminate an overhead of <code>std::locale</code> if your program runs in the "C
|
||||
<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)<sizeof(long double)).</li>
|
||||
</ul>
|
||||
<h3>May 2011:</h3>
|
||||
|
@@ -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>
|
||||
{
|
||||
|
@@ -27,6 +27,7 @@ test-suite conversion
|
||||
[ 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 ]
|
||||
;
|
||||
|
||||
|
||||
|
@@ -242,22 +242,6 @@ void test_converion_to_float_types()
|
||||
CHECK_CLOSE_ABS_DIFF(.34, test_t);
|
||||
CHECK_CLOSE_ABS_DIFF(.34e10, test_t);
|
||||
|
||||
// BOOST_CHECK(lexical_cast<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 @@ void test_converion_from_to_float_types()
|
||||
|
||||
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 );
|
||||
|
109
test/lexical_cast_inf_nan_test.cpp
Executable file
109
test/lexical_cast_inf_nan_test.cpp
Executable file
@@ -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;
|
||||
}
|
Reference in New Issue
Block a user