This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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;
  

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]