This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
Draft patch for libstdc++/21209
- From: Paolo Carlini <pcarlini at suse dot de>
- To: libstdc++ <libstdc++ at gcc dot gnu dot org>
- Date: Mon, 25 Apr 2005 20:49:02 +0200
- Subject: Draft patch for libstdc++/21209
Hi,
before proceeding with the final refiements, wanted to show you what I'm
preparing for this issue (i.e., *signed* integer overflow in
_M_extract_int). Basically, the idea is using *only* unsigned types in
the main parsing loop. In order to do that, I construct, via the
auxiliary template __to_unsigned_type, an unsigned type suited for each
signed type that we have to process (e.g., for long -> unsigned long),
then, at the end, I adjust the sign and assign the number to the "return
value" __v. Performance seems ok, even a tad (2-3%) faster than the
current code, and regression tests + some additional tests seems ok,
indeed. If nobody finds any serious flaw, I will go ahead along this
way, adding maybe a comment and a generic additional num_get testcase
exercising the parsing of numeric_limits<>::max and min.
Paolo.
///////////////////
diff -prN libstdc++-v3-orig/include/bits/locale_facets.tcc libstdc++-v3/include/bits/locale_facets.tcc
*** libstdc++-v3-orig/include/bits/locale_facets.tcc Sun Apr 17 16:30:36 2005
--- libstdc++-v3/include/bits/locale_facets.tcc Mon Apr 25 20:05:52 2005
*************** namespace std
*** 440,445 ****
--- 440,459 ----
return __beg;
}
+ template<typename _ValueT>
+ struct __to_unsigned_type
+ { typedef _ValueT __type; };
+
+ template<>
+ struct __to_unsigned_type<long>
+ { typedef unsigned long __type; };
+
+ #ifdef _GLIBCXX_USE_LONG_LONG
+ template<>
+ struct __to_unsigned_type<long long>
+ { typedef unsigned long long __type; };
+ #endif
+
template<typename _CharT, typename _InIter>
template<typename _ValueT>
_InIter
*************** namespace std
*** 447,454 ****
_M_extract_int(_InIter __beg, _InIter __end, ios_base& __io,
ios_base::iostate& __err, _ValueT& __v) const
{
! typedef char_traits<_CharT> __traits_type;
! typedef typename numpunct<_CharT>::__cache_type __cache_type;
__use_cache<__cache_type> __uc;
const locale& __loc = __io._M_getloc();
const __cache_type* __lc = __uc(__loc);
--- 461,469 ----
_M_extract_int(_InIter __beg, _InIter __end, ios_base& __io,
ios_base::iostate& __err, _ValueT& __v) const
{
! typedef char_traits<_CharT> __traits_type;
! typedef typename __to_unsigned_type<_ValueT>::__type __unsigned_type;
! typedef typename numpunct<_CharT>::__cache_type __cache_type;
__use_cache<__cache_type> __uc;
const locale& __loc = __io._M_getloc();
const __cache_type* __lc = __uc(__loc);
*************** namespace std
*** 536,638 ****
__found_grouping.reserve(32);
int __sep_pos = 0;
bool __overflow = false;
! _ValueT __result = 0;
const char_type* __q;
const char_type* __lit_zero = __lit + __num_base::_S_izero;
! if (__negative)
{
! const _ValueT __min = numeric_limits<_ValueT>::min() / __base;
! while (!__testeof)
{
! // According to 22.2.2.1.2, p8-9, first look for thousands_sep
! // and decimal_point.
! if (__lc->_M_use_grouping && __c == __lc->_M_thousands_sep)
{
! // NB: Thousands separator at the beginning of a string
! // is a no-no, as is two consecutive thousands separators.
! if (__sep_pos)
! {
! __found_grouping += static_cast<char>(__sep_pos);
! __sep_pos = 0;
! }
! else
! {
! __err |= ios_base::failbit;
! break;
! }
}
! else if (__c == __lc->_M_decimal_point)
! break;
! else if ((__q = __traits_type::find(__lit_zero, __len, __c)))
{
! int __digit = __q - __lit_zero;
! if (__digit > 15)
! __digit -= 6;
! if (__result < __min)
! __overflow = true;
! else
! {
! const _ValueT __new_result = (__result * __base
! - __digit);
! __overflow |= __new_result > __result;
! __result = __new_result;
! ++__sep_pos;
! }
}
- else
- // Not a valid input item.
- break;
-
- if (++__beg != __end)
- __c = *__beg;
- else
- __testeof = true;
}
! }
! else
! {
! const _ValueT __max = numeric_limits<_ValueT>::max() / __base;
! while (!__testeof)
{
! if (__lc->_M_use_grouping && __c == __lc->_M_thousands_sep)
! {
! if (__sep_pos)
! {
! __found_grouping += static_cast<char>(__sep_pos);
! __sep_pos = 0;
! }
! else
! {
! __err |= ios_base::failbit;
! break;
! }
! }
! else if (__c == __lc->_M_decimal_point)
! break;
! else if ((__q = __traits_type::find(__lit_zero, __len, __c)))
{
! int __digit = __q - __lit_zero;
! if (__digit > 15)
! __digit -= 6;
! if (__result > __max)
! __overflow = true;
! else
! {
! const _ValueT __new_result = (__result * __base
! + __digit);
! __overflow |= __new_result < __result;
! __result = __new_result;
! ++__sep_pos;
! }
}
- else
- break;
-
- if (++__beg != __end)
- __c = *__beg;
- else
- __testeof = true;
}
}
// Digit grouping is checked. If grouping and found_grouping don't
--- 551,606 ----
__found_grouping.reserve(32);
int __sep_pos = 0;
bool __overflow = false;
! const __unsigned_type __max = __negative ?
! -numeric_limits<_ValueT>::min() : numeric_limits<_ValueT>::max();
! const __unsigned_type __smax = __max / __base;
! __unsigned_type __result = 0;
const char_type* __q;
const char_type* __lit_zero = __lit + __num_base::_S_izero;
! while (!__testeof)
{
! // According to 22.2.2.1.2, p8-9, first look for thousands_sep
! // and decimal_point.
! if (__lc->_M_use_grouping && __c == __lc->_M_thousands_sep)
{
! // NB: Thousands separator at the beginning of a string
! // is a no-no, as is two consecutive thousands separators.
! if (__sep_pos)
{
! __found_grouping += static_cast<char>(__sep_pos);
! __sep_pos = 0;
}
! else
{
! __err |= ios_base::failbit;
! break;
}
}
! else if (__c == __lc->_M_decimal_point)
! break;
! else if ((__q = __traits_type::find(__lit_zero, __len, __c)))
{
! unsigned __digit = __q - __lit_zero;
! if (__digit > 15)
! __digit -= 6;
! if (__result > __smax)
! __overflow = true;
! else
{
! __result *= __base;
! __overflow |= __result > __max - __digit;
! __result += __digit;
! ++__sep_pos;
}
}
+ else
+ // Not a valid input item.
+ break;
+
+ if (++__beg != __end)
+ __c = *__beg;
+ else
+ __testeof = true;
}
// Digit grouping is checked. If grouping and found_grouping don't
*************** namespace std
*** 650,656 ****
if (!(__err & ios_base::failbit) && !__overflow
&& (__sep_pos || __found_zero || __found_grouping.size()))
! __v = __result;
else
__err |= ios_base::failbit;
--- 618,624 ----
if (!(__err & ios_base::failbit) && !__overflow
&& (__sep_pos || __found_zero || __found_grouping.size()))
! __v = __negative ? -__result : __result;
else
__err |= ios_base::failbit;