lexical_cast.hpp improvements: better overflow detections for float conversions, more const modifiers (refs #9046)

[SVN r85512]
This commit is contained in:
Antony Polukhin
2013-08-29 11:41:28 +00:00
parent 297b115e6c
commit b5552e351c

View File

@@ -891,14 +891,11 @@ namespace boost {
const CharT plus = lcast_char_constants<CharT>::plus; const CharT plus = lcast_char_constants<CharT>::plus;
const int inifinity_size = 8; const int inifinity_size = 8;
bool has_minus = false;
/* Parsing +/- */ /* Parsing +/- */
if( *begin == minus) bool const has_minus = (*begin == minus);
{ if (has_minus || *begin == plus) {
++ begin; ++ begin;
has_minus = true;
} }
else if( *begin == plus ) ++begin;
if( end-begin < 3 ) return false; if( end-begin < 3 ) return false;
if( lc_iequal(begin, lc_nan, lc_NAN, 3) ) if( lc_iequal(begin, lc_nan, lc_NAN, 3) )
@@ -1075,6 +1072,25 @@ namespace boost {
template<class Traits, class T, class CharT> template<class Traits, class T, class CharT>
inline bool lcast_ret_float(T& value, const CharT* begin, const CharT* end) inline bool lcast_ret_float(T& value, const CharT* begin, const CharT* end)
{ {
value = static_cast<T>(0);
if (begin == end) return false;
if (parse_inf_nan(begin, end, value)) return true;
CharT const czero = lcast_char_constants<CharT>::zero;
CharT const minus = lcast_char_constants<CharT>::minus;
CharT const plus = lcast_char_constants<CharT>::plus;
CharT const capital_e = lcast_char_constants<CharT>::capital_e;
CharT const lowercase_e = lcast_char_constants<CharT>::lowercase_e;
typedef BOOST_DEDUCED_TYPENAME Traits::int_type int_type;
int_type const zero = Traits::to_int_type(czero);
/* Getting the plus/minus sign */
bool const has_minus = Traits::eq(*begin, minus);
if (has_minus || Traits::eq(*begin, plus)) {
++ begin;
if (begin == end) return false;
}
#ifndef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE #ifndef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE
std::locale loc; std::locale loc;
@@ -1094,43 +1110,17 @@ namespace boost {
CharT const decimal_point = lcast_char_constants<CharT>::c_decimal_separator; CharT const decimal_point = lcast_char_constants<CharT>::c_decimal_separator;
#endif #endif
CharT const czero = lcast_char_constants<CharT>::zero;
CharT const minus = lcast_char_constants<CharT>::minus;
CharT const plus = lcast_char_constants<CharT>::plus;
CharT const capital_e = lcast_char_constants<CharT>::capital_e;
CharT const lowercase_e = lcast_char_constants<CharT>::lowercase_e;
value = static_cast<T>(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;
typedef BOOST_DEDUCED_TYPENAME mantissa_holder_type<T>::wide_result_t wide_result_t;
int_type const zero = Traits::to_int_type(czero);
if (begin == end) return false;
/* Getting the plus/minus sign */
bool has_minus = false;
if (Traits::eq(*begin, minus) ) {
++ begin;
has_minus = true;
if (begin == end) return false;
} else if (Traits::eq(*begin, plus) ) {
++begin;
if (begin == end) return false;
}
bool found_decimal = false; bool found_decimal = false;
bool found_number_before_exp = false; bool found_number_before_exp = false;
int pow_of_10 = 0; typedef int pow_of_10_t;
pow_of_10_t pow_of_10 = 0;
typedef BOOST_DEDUCED_TYPENAME mantissa_holder_type<T>::type mantissa_type;
mantissa_type mantissa=0; mantissa_type mantissa=0;
bool is_mantissa_full = false; bool is_mantissa_full = false;
char length_since_last_delim = 0; char length_since_last_delim = 0;
while ( begin != end ) while (begin != end) {
{
if (found_decimal) { if (found_decimal) {
/* We allow no thousand_separators after decimal point */ /* We allow no thousand_separators after decimal point */
@@ -1157,15 +1147,14 @@ namespace boost {
* occur, them we only increase multiplyer * occur, them we only increase multiplyer
*/ */
const mantissa_type tmp_sub_value = static_cast<mantissa_type>(*begin - zero); const mantissa_type tmp_sub_value = static_cast<mantissa_type>(*begin - zero);
if( !(is_mantissa_full if( is_mantissa_full
|| ((std::numeric_limits<mantissa_type>::max)() - tmp_sub_value) / 10u < mantissa) || ((std::numeric_limits<mantissa_type>::max)() - tmp_sub_value) / 10u < mantissa
) )
{
mantissa = static_cast<mantissa_type>(mantissa * 10 + tmp_sub_value);
} else
{ {
is_mantissa_full = true; is_mantissa_full = true;
++ pow_of_10; ++ pow_of_10;
} else {
mantissa = static_cast<mantissa_type>(mantissa * 10 + tmp_sub_value);
} }
found_number_before_exp = true; found_number_before_exp = true;
@@ -1188,12 +1177,12 @@ namespace boost {
) return false; ) return false;
#endif #endif
if(Traits::eq(*begin, decimal_point)) { if (Traits::eq(*begin, decimal_point)) {
++ begin; ++ begin;
found_decimal = true; found_decimal = true;
if (!found_number_before_exp && begin==end) return false; if (!found_number_before_exp && begin==end) return false;
continue; continue;
}else { } else {
if (!found_number_before_exp) return false; if (!found_number_before_exp) return false;
break; break;
} }
@@ -1245,48 +1234,44 @@ namespace boost {
++ begin; ++ begin;
if ( begin == end ) return false; if ( begin == end ) return false;
bool exp_has_minus = false; bool const exp_has_minus = Traits::eq(*begin, minus);
if(Traits::eq(*begin, minus)) { if (exp_has_minus || Traits::eq(*begin, plus)) {
exp_has_minus = true;
++ begin; ++ begin;
if ( begin == end ) return false; if (begin == end) return false;
} else if (Traits::eq(*begin, plus)) {
++ begin;
if ( begin == end ) return false;
} }
int exp_pow_of_10 = 0; pow_of_10_t exp_pow_of_10 = 0;
while ( begin != end ) while (begin != end) {
{ pow_of_10_t const sub_value = *begin - zero;
if ( *begin < czero
|| *begin >= czero + 10 if ( *begin < czero || *begin >= czero + 10
|| exp_pow_of_10 * 10 < exp_pow_of_10) /* Overflows are checked lower more precisely*/ || ((std::numeric_limits<pow_of_10_t>::max)() - sub_value) / 10 < exp_pow_of_10)
return false; return false;
exp_pow_of_10 *= 10; exp_pow_of_10 *= 10;
exp_pow_of_10 += *begin - zero; exp_pow_of_10 += sub_value;
++ begin; ++ begin;
}; };
if ( exp_pow_of_10 ) { if (exp_has_minus) {
/* Overflows are checked lower */ if ((std::numeric_limits<pow_of_10_t>::min)() + exp_pow_of_10 > pow_of_10)
if ( exp_has_minus ) { return false; // failed overflow check
pow_of_10 -= exp_pow_of_10; pow_of_10 -= exp_pow_of_10;
} else { } else {
pow_of_10 += exp_pow_of_10; if ((std::numeric_limits<pow_of_10_t>::max)() - exp_pow_of_10 < pow_of_10)
} return false; // failed overflow check
pow_of_10 += exp_pow_of_10;
} }
} }
/* We need a more accurate algorithm... We can not use current algorithm /* We need a more accurate algorithm... We can not use current algorithm
* with long doubles (and with doubles if sizeof(double)==sizeof(long double)). * with long doubles (and with doubles if sizeof(double)==sizeof(long double)).
*/ */
typedef BOOST_DEDUCED_TYPENAME mantissa_holder_type<T>::wide_result_t wide_result_t;
const wide_result_t result = std::pow(static_cast<wide_result_t>(10.0), pow_of_10) * mantissa; const wide_result_t result = std::pow(static_cast<wide_result_t>(10.0), pow_of_10) * mantissa;
value = static_cast<T>( has_minus ? (boost::math::changesign)(result) : result); value = static_cast<T>( has_minus ? (boost::math::changesign)(result) : result);
if ( (boost::math::isinf)(value) || (boost::math::isnan)(value) ) return false; return !((boost::math::isinf)(value) || (boost::math::isnan)(value));
return true;
} }
// Unsilence buggy MS warnings like C4244: '+=' : conversion from 'int' to 'unsigned short', possible loss of data // Unsilence buggy MS warnings like C4244: '+=' : conversion from 'int' to 'unsigned short', possible loss of data
#if defined(_MSC_VER) && (_MSC_VER == 1400) #if defined(_MSC_VER) && (_MSC_VER == 1400)
@@ -1805,15 +1790,10 @@ namespace boost {
if (start == finish) return false; if (start == finish) return false;
CharT const minus = lcast_char_constants<CharT>::minus; CharT const minus = lcast_char_constants<CharT>::minus;
CharT const plus = lcast_char_constants<CharT>::plus; CharT const plus = lcast_char_constants<CharT>::plus;
bool has_minus = false; bool const has_minus = Traits::eq(minus, *start);
/* We won`t use `start' any more, so no need in decrementing it after */ /* We won`t use `start' any more, so no need in decrementing it after */
if ( Traits::eq(minus,*start) ) if (has_minus || Traits::eq(plus, *start)) {
{
++start;
has_minus = true;
} else if ( Traits::eq( plus, *start ) )
{
++start; ++start;
} }
@@ -1833,16 +1813,11 @@ namespace boost {
CharT const minus = lcast_char_constants<CharT>::minus; CharT const minus = lcast_char_constants<CharT>::minus;
CharT const plus = lcast_char_constants<CharT>::plus; CharT const plus = lcast_char_constants<CharT>::plus;
typedef BOOST_DEDUCED_TYPENAME make_unsigned<Type>::type utype; typedef BOOST_DEDUCED_TYPENAME make_unsigned<Type>::type utype;
utype out_tmp =0; utype out_tmp = 0;
bool has_minus = false; bool const has_minus = Traits::eq(minus, *start);
/* We won`t use `start' any more, so no need in decrementing it after */ /* We won`t use `start' any more, so no need in decrementing it after */
if ( Traits::eq(minus,*start) ) if (has_minus || Traits::eq(plus, *start)) {
{
++start;
has_minus = true;
} else if ( Traits::eq(plus, *start) )
{
++start; ++start;
} }