Changeset 73118


Ignore:
Timestamp:
Jul 15, 2011, 11:20:11 AM (6 years ago)
Author:
Antony Polukhin
Message:

Fixes #5689. Added code to work with Inf and NaN on any platform

Location:
trunk
Files:
1 added
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/boost/lexical_cast.hpp

    r72972 r73118  
    2525#include <istream>
    2626#include <string>
     27#include <cstring>
    2728#include <typeinfo>
    2829#include <exception>
     
    732733    }
    733734
     735    namespace detail
     736    {
     737        /* Returns true and sets the correct value if found NaN or Inf. */
     738        template <class CharT, class T>
     739        inline bool parse_inf_nan_impl(const CharT* begin, const CharT* end, T& value
     740            , const CharT* lc_NAN, const CharT* lc_nan
     741            , const CharT* lc_INFINITY, const CharT* lc_infinity
     742            , const CharT opening_brace, const CharT closing_brace)
     743        {
     744            using namespace std;
     745            const wchar_t minus = lcast_char_constants<wchar_t>::minus;
     746            const wchar_t plus = lcast_char_constants<wchar_t>::plus;
     747            const int inifinity_size = 8;
     748
     749            bool has_minus = false;
     750            /* Parsing +/- */
     751            if( *begin == minus)
     752            {
     753                ++ begin;
     754                has_minus = true;
     755            }
     756            else if( *begin == plus ) ++begin;
     757
     758            if( end-begin < 3 ) return false;
     759            if( !memcmp(begin, lc_nan, 3*sizeof(CharT)) || !memcmp(begin, lc_NAN, 3*sizeof(CharT)) )
     760            {
     761                begin += 3;
     762                if (end != begin) /* It is 'nan(...)' or some bad input*/
     763                {
     764                    if(end-begin<2) return false; // bad input
     765                    -- end;
     766                    if( *begin != opening_brace || *end != closing_brace) return false; // bad input
     767                }
     768
     769                if( !has_minus ) value = std::numeric_limits<T>::quiet_NaN();
     770                else value = -std::numeric_limits<T>::quiet_NaN();
     771                return true;
     772            } else
     773            if (( /* 'INF' or 'inf' */
     774                  end-begin==3
     775                  &&
     776                  (!memcmp(begin, lc_infinity, 3*sizeof(CharT)) || !memcmp(begin, lc_INFINITY, 3*sizeof(CharT)))
     777                )
     778                ||
     779                ( /* 'INFINITY' or 'infinity' */
     780                  end-begin==inifinity_size
     781                  &&
     782                  (!memcmp(begin, lc_infinity, inifinity_size)|| !memcmp(begin, lc_INFINITY, inifinity_size))
     783                )
     784             )
     785            {
     786                if( !has_minus ) value = std::numeric_limits<T>::infinity();
     787                else value = -std::numeric_limits<T>::infinity();
     788                return true;
     789            }
     790
     791            return false;
     792        }
     793
     794#ifndef BOOST_LCAST_NO_WCHAR_T
     795        template <class T>
     796        bool parse_inf_nan(const wchar_t* begin, const wchar_t* end, T& value)
     797        {
     798            return parse_inf_nan_impl(begin, end, value
     799                               , L"NAN", L"nan"
     800                               , L"INFINITY", L"infinity"
     801                               , L'(', L')');
     802        }
     803#endif
     804
     805        template <class CharT, class T>
     806        bool parse_inf_nan(const CharT* begin, const CharT* end, T& value)
     807        {
     808            return parse_inf_nan_impl(begin, end, value
     809                               , "NAN", "nan"
     810                               , "INFINITY", "infinity"
     811                               , '(', ')');
     812        }
     813
     814        template <class T>
     815        bool put_inf_nan(wchar_t* begin, wchar_t*& end, const T& value)
     816        {
     817            using namespace std;
     818            if (value != value)
     819            {
     820                memcpy(begin,L"nan", sizeof(L"nan"));
     821                end = begin + 3;
     822                return true;
     823            } else if ( value > numeric_limits<T>::max() )
     824            {
     825                memcpy(begin,L"inf", sizeof(L"inf"));
     826                end = begin + 3;
     827                return true;
     828            } else if ( value < -numeric_limits<T>::max() )
     829            {
     830                memcpy(begin,L"-inf", sizeof(L"-inf"));
     831                end = begin + 4;
     832                return true;
     833            }
     834
     835            return false;
     836        }
     837
     838        template <class CharT, class T>
     839        bool put_inf_nan(CharT* begin, CharT*& end, const T& value)
     840        {
     841            using namespace std;
     842            if (value != value)
     843            {
     844                memcpy(begin,"nan", sizeof("nan"));
     845                end = begin + 3;
     846                return true;
     847            } else if ( value > numeric_limits<T>::max() )
     848            {
     849                memcpy(begin,"inf", sizeof("inf"));
     850                end = begin + 3;
     851                return true;
     852            } else if ( value < -numeric_limits<T>::max() )
     853            {
     854                memcpy(begin,"-inf", sizeof("-inf"));
     855                end = begin + 4;
     856                return true;
     857            }
     858
     859            return false;
     860        }
     861
     862    }
     863
     864
    734865    namespace detail // lcast_ret_float
    735866    {
     
    782913
    783914            value = 0.0;
     915
     916            if (parse_inf_nan(begin, end, value)) return true;
    784917
    785918            typedef typename Traits::int_type int_type;
     
    11051238            bool lcast_put(const OutputStreamable& input)
    11061239            {
     1240                if(put_inf_nan(start, finish, input)) return true;
    11071241                this->setp(start, finish);
    11081242                std::basic_ostream<CharT> stream(static_cast<Base*>(this));
     
    13431477            template <class T>
    13441478            bool float_types_converter_internal(T& output, int /*tag*/) {
     1479
     1480                if (parse_inf_nan(start, finish, output)) return true;
     1481
    13451482                bool return_value = convert_using_base_class(output);
    13461483
    13471484                /* Some compilers and libraries successfully
    1348                  * parse 'inf', 'INFINITY', '1.0E', '1.0E-'...
     1485                 * parse '1.0E', '1.0E-'...
    13491486                 * We are trying to provide a unified behaviour,
    13501487                 * so we just forbid such conversions (as some
     
    13571494                if ( return_value &&
    13581495                     (
    1359                         output > (std::numeric_limits<T>::max)()     // +inf
    1360                         || output < -(std::numeric_limits<T>::max)() // -inf
    1361                         || output != output                          // NaN
    1362                         || *(finish-1) == lowercase_e                // 1.0e
     1496                        *(finish-1) == lowercase_e                   // 1.0e
    13631497                        || *(finish-1) == capital_e                  // 1.0E
    13641498                        || *(finish-1) == minus                      // 1.0e- or 1.0E-
  • trunk/libs/conversion/lexical_cast.htm

    r72954 r73118  
    270270<h3>July 2011:</h3>
    271271<ul type="square">
     272    <li>Added code to work with Inf and NaN on any platform.</li>
    272273    <li>Better performance and less memory usage for conversions to float type (and to double type, if sizeof(double)&lt;sizeof(long double)).</li>
    273274</ul>
  • trunk/libs/conversion/lexical_cast_test.cpp

    r72972 r73118  
    4141    && !(defined(BOOST_MSVC) && BOOST_MSVC < 1300)
    4242#define LCAST_TEST_LONGLONG
     43#endif
     44
     45#if defined(BOOST_NO_STRINGSTREAM) || defined(BOOST_NO_STD_WSTRING)
     46#define BOOST_LCAST_NO_WCHAR_T
    4347#endif
    4448
  • trunk/libs/conversion/test/Jamfile.v2

    r72925 r73118  
    2828    [ run lexical_cast_wchars_test.cpp ../../test/build//boost_unit_test_framework/<link>static ]
    2929    [ run lexical_cast_float_types_test.cpp ../../test/build//boost_unit_test_framework/<link>static ]
     30    [ run lexical_cast_inf_nan_test.cpp ../../test/build//boost_unit_test_framework/<link>static ]
    3031  ;
    3132
  • trunk/libs/conversion/test/lexical_cast_float_types_test.cpp

    r72955 r73118  
    242242    CHECK_CLOSE_ABS_DIFF(.34, test_t);
    243243    CHECK_CLOSE_ABS_DIFF(.34e10, test_t);
    244 
    245 //    BOOST_CHECK(lexical_cast<test_t>("-inf") == -std::numeric_limits<test_t>::infinity() );
    246 //    BOOST_CHECK(lexical_cast<test_t>("-INF") == -std::numeric_limits<test_t>::infinity() );
    247 //    BOOST_CHECK(lexical_cast<test_t>("+inf") == std::numeric_limits<test_t>::infinity() );
    248 //    BOOST_CHECK(lexical_cast<test_t>("infinity") == std::numeric_limits<test_t>::infinity() );
    249 //
    250 //    BOOST_CHECK(lexical_cast<test_t>("nan") == std::numeric_limits<test_t>::quiet_NaN() );
    251 //    BOOST_CHECK(lexical_cast<test_t>("NaN") == std::numeric_limits<test_t>::quiet_NaN() );
    252 
    253     BOOST_CHECK_THROW(lexical_cast<test_t>("-inf"), bad_lexical_cast );
    254     BOOST_CHECK_THROW(lexical_cast<test_t>("-INF"), bad_lexical_cast);
    255     BOOST_CHECK_THROW(lexical_cast<test_t>("+inf"), bad_lexical_cast);
    256     BOOST_CHECK_THROW(lexical_cast<test_t>("infinity"), bad_lexical_cast);
    257     BOOST_CHECK_THROW(lexical_cast<test_t>("nan"), bad_lexical_cast);
    258     BOOST_CHECK_THROW(lexical_cast<test_t>("NaN"), bad_lexical_cast);
    259 
    260244
    261245    BOOST_CHECK_THROW(lexical_cast<test_t>("-1.e"), bad_lexical_cast);
     
    381365
    382366    TEST_TO_FROM_CAST_AROUND( 0.0 );
    383 
    384 //    TEST_TO_FROM_CAST_AROUND( std::numeric_limits<test_t>::infinity() );
    385 //    TEST_TO_FROM_CAST_AROUND( -std::numeric_limits<test_t>::infinity() );
    386 //    TEST_TO_FROM_CAST_AROUND( std::numeric_limits<test_t>::quiet_NaN() );
    387367
    388368    long double val1;
Note: See TracChangeset for help on using the changeset viewer.