mirror of
https://github.com/boostorg/conversion.git
synced 2025-08-05 15:34:29 +02:00
lexical_cast.hpp improvements: better overflow detections for float conversions, more const
modifiers (refs #9046)
[SVN r85512]
This commit is contained in:
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user