forked from boostorg/conversion
Fix bug introduced by previous commits during conversion of wide character to wide character. Remove duplicate code and add more comments for lcast_ret_unsigned method. Optimize and simplify overflow detection (refs #9046)
[SVN r85486]
This commit is contained in:
@@ -726,7 +726,16 @@ namespace boost {
|
|||||||
namespace detail // lcast_ret_unsigned
|
namespace detail // lcast_ret_unsigned
|
||||||
{
|
{
|
||||||
template <class Traits, class T, class CharT>
|
template <class Traits, class T, class CharT>
|
||||||
inline bool lcast_ret_unsigned(T& value, const CharT* const begin, const CharT* end)
|
class lcast_ret_unsigned {
|
||||||
|
bool m_multiplier_overflowed;
|
||||||
|
T m_multiplier;
|
||||||
|
T& m_value;
|
||||||
|
const CharT* const m_begin;
|
||||||
|
const CharT* m_end;
|
||||||
|
|
||||||
|
public:
|
||||||
|
lcast_ret_unsigned(T& value, const CharT* const begin, const CharT* end) BOOST_NOEXCEPT
|
||||||
|
: m_multiplier_overflowed(false), m_multiplier(1), m_value(value), m_begin(begin), m_end(end)
|
||||||
{
|
{
|
||||||
#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
|
#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
|
||||||
BOOST_STATIC_ASSERT(!std::numeric_limits<T>::is_signed);
|
BOOST_STATIC_ASSERT(!std::numeric_limits<T>::is_signed);
|
||||||
@@ -740,20 +749,26 @@ namespace boost {
|
|||||||
"std::numeric_limits are not specialized for integral type passed to boost::lexical_cast"
|
"std::numeric_limits are not specialized for integral type passed to boost::lexical_cast"
|
||||||
);
|
);
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool convert() {
|
||||||
CharT const czero = lcast_char_constants<CharT>::zero;
|
CharT const czero = lcast_char_constants<CharT>::zero;
|
||||||
--end;
|
--m_end;
|
||||||
value = 0;
|
m_value = static_cast<T>(0);
|
||||||
|
|
||||||
if (begin > end || *end < czero || *end >= czero + 10)
|
if (m_begin > m_end || *m_end < czero || *m_end >= czero + 10)
|
||||||
return false;
|
return false;
|
||||||
value = static_cast<T>(*end - czero);
|
m_value = static_cast<T>(*m_end - czero);
|
||||||
--end;
|
--m_end;
|
||||||
T multiplier = 1;
|
|
||||||
bool multiplier_overflowed = false;
|
|
||||||
|
|
||||||
#ifndef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE
|
#ifdef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE
|
||||||
|
return main_convert_loop();
|
||||||
|
#else
|
||||||
std::locale loc;
|
std::locale loc;
|
||||||
if (loc != std::locale::classic()) {
|
if (loc == std::locale::classic()) {
|
||||||
|
return main_convert_loop();
|
||||||
|
}
|
||||||
|
|
||||||
typedef std::numpunct<CharT> numpunct;
|
typedef std::numpunct<CharT> numpunct;
|
||||||
numpunct const& np = BOOST_USE_FACET(numpunct, loc);
|
numpunct const& np = BOOST_USE_FACET(numpunct, loc);
|
||||||
std::string const& grouping = np.grouping();
|
std::string const& grouping = np.grouping();
|
||||||
@@ -762,35 +777,23 @@ namespace boost {
|
|||||||
/* According to Programming languages - C++
|
/* According to Programming languages - C++
|
||||||
* we MUST check for correct grouping
|
* we MUST check for correct grouping
|
||||||
*/
|
*/
|
||||||
if (grouping_size && grouping[0] > 0)
|
if (!grouping_size || grouping[0] <= 0) {
|
||||||
{
|
return main_convert_loop();
|
||||||
|
}
|
||||||
|
|
||||||
unsigned char current_grouping = 0;
|
unsigned char current_grouping = 0;
|
||||||
CharT const thousands_sep = np.thousands_sep();
|
CharT const thousands_sep = np.thousands_sep();
|
||||||
char remained = static_cast<char>(grouping[current_grouping] - 1);
|
char remained = static_cast<char>(grouping[current_grouping] - 1);
|
||||||
bool shall_we_return = true;
|
|
||||||
|
|
||||||
for(;end>=begin; --end)
|
for (;m_end >= m_begin; --m_end)
|
||||||
{
|
{
|
||||||
if (remained) {
|
if (remained) {
|
||||||
T const multiplier_10 = static_cast<T>(multiplier * 10);
|
if (!main_convert_itaration()) {
|
||||||
if (multiplier_10 / 10 != multiplier) multiplier_overflowed = true;
|
|
||||||
|
|
||||||
T const dig_value = static_cast<T>(*end - czero);
|
|
||||||
T const new_sub_value = static_cast<T>(multiplier_10 * dig_value);
|
|
||||||
|
|
||||||
if (*end < czero || *end >= czero + 10
|
|
||||||
/* detecting overflow */
|
|
||||||
|| (dig_value && new_sub_value / dig_value != multiplier_10)
|
|
||||||
|| static_cast<T>((std::numeric_limits<T>::max)()-new_sub_value) < value
|
|
||||||
|| (multiplier_overflowed && dig_value)
|
|
||||||
)
|
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
value = static_cast<T>(value + new_sub_value);
|
|
||||||
multiplier = static_cast<T>(multiplier * 10);
|
|
||||||
--remained;
|
--remained;
|
||||||
} else {
|
} else {
|
||||||
if ( !Traits::eq(*end, thousands_sep) ) //|| begin == end ) return false;
|
if ( !Traits::eq(*m_end, thousands_sep) ) //|| begin == end ) return false;
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* According to Programming languages - C++
|
* According to Programming languages - C++
|
||||||
@@ -803,44 +806,57 @@ namespace boost {
|
|||||||
* won`t check them for consistency. This will allow us to
|
* won`t check them for consistency. This will allow us to
|
||||||
* work with "C" locale from other locales
|
* work with "C" locale from other locales
|
||||||
*/
|
*/
|
||||||
shall_we_return = false;
|
return main_convert_loop();
|
||||||
break;
|
|
||||||
} else {
|
} else {
|
||||||
if ( begin == end ) return false;
|
if (m_begin == m_end) return false;
|
||||||
if (current_grouping < grouping_size - 1) ++current_grouping;
|
if (current_grouping < grouping_size - 1) ++current_grouping;
|
||||||
remained = grouping[current_grouping];
|
remained = grouping[current_grouping];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} /*for*/
|
||||||
|
|
||||||
if (shall_we_return) return true;
|
return true;
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
{
|
|
||||||
while ( begin <= end )
|
|
||||||
{
|
|
||||||
T const multiplier_10 = static_cast<T>(multiplier * 10);
|
|
||||||
if (multiplier_10 / 10 != multiplier) multiplier_overflowed = true;
|
|
||||||
|
|
||||||
T const dig_value = static_cast<T>(*end - czero);
|
|
||||||
T const new_sub_value = static_cast<T>(multiplier_10 * dig_value);
|
|
||||||
|
|
||||||
if (*end < czero || *end >= czero + 10
|
|
||||||
/* detecting overflow */
|
|
||||||
|| (dig_value && new_sub_value / dig_value != multiplier_10)
|
|
||||||
|| static_cast<T>((std::numeric_limits<T>::max)()-new_sub_value) < value
|
|
||||||
|| (multiplier_overflowed && dig_value)
|
|
||||||
)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
value = static_cast<T>(value + new_sub_value);
|
|
||||||
multiplier = static_cast<T>(multiplier * 10);
|
|
||||||
--end;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Iteration that does not care about grouping/separators and assumes that all
|
||||||
|
// input characters are digits
|
||||||
|
inline bool main_convert_itaration() BOOST_NOEXCEPT {
|
||||||
|
CharT const czero = lcast_char_constants<CharT>::zero;
|
||||||
|
T const maxv = (std::numeric_limits<T>::max)();
|
||||||
|
|
||||||
|
m_multiplier_overflowed = m_multiplier_overflowed || (maxv/10 < m_multiplier);
|
||||||
|
m_multiplier = static_cast<T>(m_multiplier * 10);
|
||||||
|
|
||||||
|
T const dig_value = static_cast<T>(*m_end - czero);
|
||||||
|
T const new_sub_value = static_cast<T>(m_multiplier * dig_value);
|
||||||
|
|
||||||
|
// We must correctly handle situations like `000000000000000000000000000001`.
|
||||||
|
// So we take care of overflow only if `dig_value` is not '0'.
|
||||||
|
if (*m_end < czero || *m_end >= czero + 10 // checking for correct digit
|
||||||
|
|| (dig_value && ( // checking for overflow of ...
|
||||||
|
m_multiplier_overflowed // ... multiplier
|
||||||
|
|| static_cast<T>(maxv / dig_value) < m_multiplier // ... subvalue
|
||||||
|
|| static_cast<T>(maxv - new_sub_value) < m_value // ... whole expression
|
||||||
|
))
|
||||||
|
) return false;
|
||||||
|
|
||||||
|
m_value = static_cast<T>(m_value + new_sub_value);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool main_convert_loop() BOOST_NOEXCEPT {
|
||||||
|
for ( ; m_end >= m_begin; --m_end) {
|
||||||
|
if (!main_convert_itaration()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
@@ -1110,12 +1126,11 @@ namespace boost {
|
|||||||
if (found_decimal) {
|
if (found_decimal) {
|
||||||
/* We allow no thousand_separators after decimal point */
|
/* We allow no thousand_separators after decimal point */
|
||||||
|
|
||||||
mantissa_type tmp_mantissa = mantissa * 10u;
|
const mantissa_type tmp_sub_value = static_cast<mantissa_type>(*begin - zero);
|
||||||
if (Traits::eq(*begin, lowercase_e) || Traits::eq(*begin, capital_e)) break;
|
if (Traits::eq(*begin, lowercase_e) || Traits::eq(*begin, capital_e)) break;
|
||||||
if ( *begin < czero || *begin >= czero + 10 ) return false;
|
if ( *begin < czero || *begin >= czero + 10 ) return false;
|
||||||
if ( is_mantissa_full
|
if ( is_mantissa_full
|
||||||
|| tmp_mantissa / 10u != mantissa
|
|| ((std::numeric_limits<mantissa_type>::max)() - tmp_sub_value) / 10u < mantissa
|
||||||
|| (std::numeric_limits<mantissa_type>::max)()-(*begin - zero) < tmp_mantissa
|
|
||||||
) {
|
) {
|
||||||
is_mantissa_full = true;
|
is_mantissa_full = true;
|
||||||
++ begin;
|
++ begin;
|
||||||
@@ -1123,8 +1138,7 @@ namespace boost {
|
|||||||
}
|
}
|
||||||
|
|
||||||
-- pow_of_10;
|
-- pow_of_10;
|
||||||
mantissa = tmp_mantissa;
|
mantissa = static_cast<mantissa_type>(mantissa * 10 + tmp_sub_value);
|
||||||
mantissa += *begin - zero;
|
|
||||||
|
|
||||||
found_number_before_exp = true;
|
found_number_before_exp = true;
|
||||||
} else {
|
} else {
|
||||||
@@ -1134,14 +1148,12 @@ namespace boost {
|
|||||||
/* Checking for mantissa overflow. If overflow will
|
/* Checking for mantissa overflow. If overflow will
|
||||||
* occur, them we only increase multiplyer
|
* occur, them we only increase multiplyer
|
||||||
*/
|
*/
|
||||||
mantissa_type tmp_mantissa = mantissa * 10u;
|
const mantissa_type tmp_sub_value = static_cast<mantissa_type>(*begin - zero);
|
||||||
if( !is_mantissa_full
|
if( !(is_mantissa_full
|
||||||
&& tmp_mantissa / 10u == mantissa
|
|| ((std::numeric_limits<mantissa_type>::max)() - tmp_sub_value) / 10u < mantissa)
|
||||||
&& (std::numeric_limits<mantissa_type>::max)()-(*begin - zero) >= tmp_mantissa
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
mantissa = tmp_mantissa;
|
mantissa = static_cast<mantissa_type>(mantissa * 10 + tmp_sub_value);
|
||||||
mantissa += *begin - zero;
|
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
is_mantissa_full = true;
|
is_mantissa_full = true;
|
||||||
@@ -1792,7 +1804,7 @@ namespace boost {
|
|||||||
++start;
|
++start;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool const succeed = lcast_ret_unsigned<Traits>(output, start, finish);
|
bool const succeed = lcast_ret_unsigned<Traits, Type, CharT>(output, start, finish).convert();
|
||||||
|
|
||||||
if (has_minus) {
|
if (has_minus) {
|
||||||
output = static_cast<Type>(0u - output);
|
output = static_cast<Type>(0u - output);
|
||||||
@@ -1821,7 +1833,7 @@ namespace boost {
|
|||||||
++start;
|
++start;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool succeed = lcast_ret_unsigned<Traits>(out_tmp, start, finish);
|
bool succeed = lcast_ret_unsigned<Traits, utype, CharT>(out_tmp, start, finish).convert();
|
||||||
if (has_minus) {
|
if (has_minus) {
|
||||||
utype const comp_val = (static_cast<utype>(1) << std::numeric_limits<Type>::digits);
|
utype const comp_val = (static_cast<utype>(1) << std::numeric_limits<Type>::digits);
|
||||||
succeed = succeed && out_tmp<=comp_val;
|
succeed = succeed && out_tmp<=comp_val;
|
||||||
@@ -2114,39 +2126,35 @@ namespace boost {
|
|||||||
template<typename Target, typename Source>
|
template<typename Target, typename Source>
|
||||||
struct is_arithmetic_and_not_xchars
|
struct is_arithmetic_and_not_xchars
|
||||||
{
|
{
|
||||||
BOOST_STATIC_CONSTANT(bool, value =
|
BOOST_STATIC_CONSTANT(bool, value = (
|
||||||
(
|
|
||||||
boost::type_traits::ice_and<
|
boost::type_traits::ice_and<
|
||||||
boost::is_arithmetic<Source>::value,
|
|
||||||
boost::is_arithmetic<Target>::value,
|
|
||||||
boost::type_traits::ice_not<
|
boost::type_traits::ice_not<
|
||||||
boost::detail::is_character<Target>::value
|
boost::detail::is_character<Target>::value
|
||||||
>::value,
|
>::value,
|
||||||
boost::type_traits::ice_not<
|
boost::type_traits::ice_not<
|
||||||
boost::detail::is_character<Source>::value
|
boost::detail::is_character<Source>::value
|
||||||
|
>::value,
|
||||||
|
boost::is_arithmetic<Source>::value,
|
||||||
|
boost::is_arithmetic<Target>::value
|
||||||
>::value
|
>::value
|
||||||
>::value
|
));
|
||||||
)
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* is_xchar_to_xchar<Target, Source>::value is true, when
|
* is_xchar_to_xchar<Target, Source>::value is true,
|
||||||
* Target and Souce are the same char types, or when
|
* Target and Souce are char types of the same size 1 (char, signed char, unsigned char).
|
||||||
* Target and Souce are char types of the same size (signed char, unsigned char).
|
|
||||||
*/
|
*/
|
||||||
template<typename Target, typename Source>
|
template<typename Target, typename Source>
|
||||||
struct is_xchar_to_xchar
|
struct is_xchar_to_xchar
|
||||||
{
|
{
|
||||||
BOOST_STATIC_CONSTANT(bool, value =
|
BOOST_STATIC_CONSTANT(bool, value = (
|
||||||
(
|
|
||||||
boost::type_traits::ice_and<
|
boost::type_traits::ice_and<
|
||||||
boost::type_traits::ice_eq<sizeof(Source), sizeof(Target)>::value,
|
boost::type_traits::ice_eq<sizeof(Source), sizeof(Target)>::value,
|
||||||
|
boost::type_traits::ice_eq<sizeof(Source), sizeof(char)>::value,
|
||||||
boost::detail::is_character<Target>::value,
|
boost::detail::is_character<Target>::value,
|
||||||
boost::detail::is_character<Source>::value
|
boost::detail::is_character<Source>::value
|
||||||
>::value
|
>::value
|
||||||
)
|
));
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Target, typename Source>
|
template<typename Target, typename Source>
|
||||||
@@ -2346,6 +2354,10 @@ namespace boost {
|
|||||||
boost::type_traits::ice_and<
|
boost::type_traits::ice_and<
|
||||||
boost::is_same<Target, src >::value,
|
boost::is_same<Target, src >::value,
|
||||||
boost::detail::is_stdstring<Target >::value
|
boost::detail::is_stdstring<Target >::value
|
||||||
|
>::value,
|
||||||
|
boost::type_traits::ice_and<
|
||||||
|
boost::is_same<Target, src >::value,
|
||||||
|
boost::detail::is_character<Target >::value
|
||||||
>::value
|
>::value
|
||||||
> shall_we_copy_t;
|
> shall_we_copy_t;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user