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++/20914


Hi,

before leaving, wanted to show you what I'm preparing for this rather
serious issue, albeit not a regression. I'm sorry for that: some time
ago I noticed something fishy in this area but then got distracted.
Turns out that our library has never got really right the grouping of
numbers introduced by a sign. For instance, in the "de_DE" locale, for
-200000 we obtain -.200.000, that is a bogus separator at beginning.
This happens because the grouping code is passed sign + actual digits,
instead of the digits only, as should be.

Anyway, I have the draft below which passes testing and mean to refine
when I'm back, target 4.0.1: beware that the second half of it is mostly
reformatting + robustification of my previous patch. The performance
should not be measurably affected but the code becomes a little more
ugly, suggestions for cleaning it up (within the current ABI, of course)
are of course welcome.

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	Sat Apr  9 02:08:56 2005
--- libstdc++-v3/include/bits/locale_facets.tcc	Sat Apr  9 17:06:45 2005
***************
*** 1,6 ****
  // Locale support -*- C++ -*-
  
! // Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
  // Free Software Foundation, Inc.
  //
  // This file is part of the GNU ISO C++ Library.  This library is free
--- 1,6 ----
  // Locale support -*- C++ -*-
  
! // Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
  // Free Software Foundation, Inc.
  //
  // This file is part of the GNU ISO C++ Library.  This library is free
*************** namespace std
*** 960,991 ****
      void
      num_put<_CharT, _OutIter>::
      _M_group_int(const char* __grouping, size_t __grouping_size, _CharT __sep,
! 		 ios_base& __io, _CharT* __new, _CharT* __cs, int& __len) const
      {
!       // By itself __add_grouping cannot deal correctly with __cs when
!       // ios::showbase is set and ios_base::oct || ios_base::hex.
!       // Therefore we take care "by hand" of the initial 0, 0x or 0X.
!       // However, remember that the latter do not occur if the number
!       // printed is '0' (__len == 1).
!       streamsize __off = 0;
!       const ios_base::fmtflags __basefield = __io.flags()
! 	                                     & ios_base::basefield;
!       if ((__io.flags() & ios_base::showbase) && __len > 1)
! 	if (__basefield == ios_base::oct)
! 	  {
! 	    __off = 1;
! 	    __new[0] = __cs[0];
! 	  }
! 	else if (__basefield == ios_base::hex)
! 	  {
! 	    __off = 2;
! 	    __new[0] = __cs[0];
! 	    __new[1] = __cs[1];
! 	  }
!       _CharT* __p = std::__add_grouping(__new + __off, __sep, __grouping,
! 					__grouping_size, __cs + __off,
! 					__cs + __len);
!       __len = __p - __new;
      }
  
    template<typename _CharT, typename _OutIter>
--- 960,969 ----
      void
      num_put<_CharT, _OutIter>::
      _M_group_int(const char* __grouping, size_t __grouping_size, _CharT __sep,
! 		 ios_base&, _CharT* __new, _CharT* __cs, int& __len) const
      {
!       __len = std::__add_grouping(__new, __sep, __grouping, __grouping_size,
! 				  __cs, __cs + __len) - __new;
      }
  
    template<typename _CharT, typename _OutIter>
*************** namespace std
*** 1019,1026 ****
  	    // number of digits, but no more.
  	    _CharT* __cs2 = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT)
  								  * __len * 2));
  	    _M_group_int(__lc->_M_grouping, __lc->_M_grouping_size,
! 			 __lc->_M_thousands_sep, __io, __cs2, __cs, __len);
  	    __cs = __cs2;
  	  }
  
--- 997,1040 ----
  	    // number of digits, but no more.
  	    _CharT* __cs2 = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT)
  								  * __len * 2));
+ 
+ 	    // __add_grouping cannot deal with __cs when ios::showbase is set
+ 	    // and ios_base::oct || ios_base::hex. Therefore we take care
+ 	    // "by hand" of the initial 0, 0x or 0X - but remember that the
+ 	    // latter do not occur if the number is '0' (__len == 1).
+ 	    // Likewise for an initial + or -.
+ 	    streamsize __off = 0;
+ 	    const ios_base::fmtflags __basefield = __io.flags()
+ 	                                           & ios_base::basefield;
+ 	    if (__len > 1)
+ 	      {
+ 		if (__basefield != ios_base::hex)
+ 		  {
+ 		    if (__basefield != ios_base::oct
+ 			&& (__cs[0] == __lit[__num_base::_S_ominus]
+ 			    || __cs[0] == __lit[__num_base::_S_oplus])
+ 			|| (__basefield == ios_base::oct
+ 			    && (__io.flags() & ios_base::showbase)))
+ 		      {
+ 			__off = 1;
+ 			__cs2[0] = __cs[0];
+ 			__len -= 1;
+ 		      }
+ 		  }
+ 		else if (__io.flags() & ios_base::showbase)
+ 		  {
+ 		    __off = 2;
+ 		    __cs2[0] = __cs[0];
+ 		    __cs2[1] = __cs[1];
+ 		    __len -= 2;
+ 		  }
+ 	      }
+ 
  	    _M_group_int(__lc->_M_grouping, __lc->_M_grouping_size,
! 			 __lc->_M_thousands_sep, __io, __cs2 + __off,
! 			 __cs + __off, __len);
! 	    __len += __off;
! 
  	    __cs = __cs2;
  	  }
  
*************** namespace std
*** 1137,1187 ****
  				      _S_get_c_locale(), __prec);
  #endif
  
!       // [22.2.2.2.2] Stage 2, convert to char_type, using correct
!       // numpunct.decimal_point() values for '.' and adding grouping.
!       const ctype<_CharT>& __ctype = use_facet<ctype<_CharT> >(__loc);
  
!       _CharT* __ws = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT)
! 							   * __len));
!       __ctype.widen(__cs, __cs + __len, __ws);
  
!       // Replace decimal point.
!       const _CharT __cdec = __ctype.widen('.');
!       const _CharT __dec = __lc->_M_decimal_point;
!       const _CharT* __p = char_traits<_CharT>::find(__ws, __len, __cdec);
!       if (__p)
! 	__ws[__p - __ws] = __dec;
  
!       // Add grouping, if necessary.
!       // N.B. Make sure to not group things like 2e20, i.e., no decimal
!       // point, scientific notation.
!       if (__lc->_M_use_grouping
! 	  && (__p || __len < 3 || (__cs[1] != 'e' && __cs[2] != 'e'
! 				   && __cs[1] != 'E' && __cs[2] != 'E')))
! 	{
! 	  // Grouping can add (almost) as many separators as the
! 	  // number of digits, but no more.
! 	  _CharT* __ws2 = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT)
! 								* __len * 2));
! 	  _M_group_float(__lc->_M_grouping, __lc->_M_grouping_size,
! 			 __lc->_M_thousands_sep, __p, __ws2, __ws, __len);
! 	  __ws = __ws2;
! 	}
! 
!       // Pad.
!       const streamsize __w = __io.width();
!       if (__w > static_cast<streamsize>(__len))
! 	{
! 	  _CharT* __ws3 = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT)
! 								* __w));
! 	  _M_pad(__fill, __w, __io, __ws3, __ws, __len);
! 	  __ws = __ws3;
! 	}
!       __io.width(0);
  
!       // [22.2.2.2.2] Stage 4.
!       // Write resulting, fully-formatted string to output iterator.
!       return std::__write(__s, __ws, __len);
        }
  
    template<typename _CharT, typename _OutIter>
--- 1151,1214 ----
  				      _S_get_c_locale(), __prec);
  #endif
  
! 	// [22.2.2.2.2] Stage 2, convert to char_type, using correct
! 	// numpunct.decimal_point() values for '.' and adding grouping.
! 	const ctype<_CharT>& __ctype = use_facet<ctype<_CharT> >(__loc);
  
! 	_CharT* __ws = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT)
! 							     * __len));
! 	__ctype.widen(__cs, __cs + __len, __ws);
! 
! 	// Replace decimal point.
! 	const _CharT __cdec = __ctype.widen('.');
! 	const _CharT __dec = __lc->_M_decimal_point;
! 	const _CharT* __p = char_traits<_CharT>::find(__ws, __len, __cdec);
! 	if (__p)
! 	  __ws[__p - __ws] = __dec;
! 	
! 	// Add grouping, if necessary.
! 	// N.B. Make sure to not group things like 2e20, i.e., no decimal
! 	// point, scientific notation.
! 	if (__lc->_M_use_grouping
! 	    && (__p || __len < 3 || (__cs[1] <= '9' && __cs[2] <= '9'
! 				     && __cs[1] >= '0' && __cs[2] >= '0')))
! 	  {
! 	    // Grouping can add (almost) as many separators as the
! 	    // number of digits, but no more.
! 	    _CharT* __ws2 = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT)
! 								  * __len * 2));
  
! 	    // See _M_insert_int above.
! 	    streamsize __off = 0;
! 	    if (__cs[0] == '-' || __cs[0] == '+')
! 	      {
! 		__off = 1;
! 		__ws2[0] = __ws[0];
! 		__len -= 1;
! 	      }
  
! 	    _M_group_float(__lc->_M_grouping, __lc->_M_grouping_size,
! 			   __lc->_M_thousands_sep, __p, __ws2 + __off,
! 			   __ws + __off, __len);
! 	    __len += __off;
! 	    
! 	    __ws = __ws2;
! 	  }
  
! 	// Pad.
! 	const streamsize __w = __io.width();
! 	if (__w > static_cast<streamsize>(__len))
! 	  {
! 	    _CharT* __ws3 = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT)
! 								  * __w));
! 	    _M_pad(__fill, __w, __io, __ws3, __ws, __len);
! 	    __ws = __ws3;
! 	  }
! 	__io.width(0);
! 	
! 	// [22.2.2.2.2] Stage 4.
! 	// Write resulting, fully-formatted string to output iterator.
! 	return std::__write(__s, __ws, __len);
        }
  
    template<typename _CharT, typename _OutIter>
diff -prN libstdc++-v3-orig/testsuite/22_locale/num_put/put/char/20914.cc libstdc++-v3/testsuite/22_locale/num_put/put/char/20914.cc
*** libstdc++-v3-orig/testsuite/22_locale/num_put/put/char/20914.cc	Thu Jan  1 01:00:00 1970
--- libstdc++-v3/testsuite/22_locale/num_put/put/char/20914.cc	Sat Apr  9 18:03:38 2005
***************
*** 0 ****
--- 1,79 ----
+ // 2005-04-09  Paolo Carlini  <pcarlini@suse.de>
+ 
+ // Copyright (C) 2005 Free Software Foundation
+ //
+ // This file is part of the GNU ISO C++ Library.  This library is free
+ // software; you can redistribute it and/or modify it under the
+ // terms of the GNU General Public License as published by the
+ // Free Software Foundation; either version 2, or (at your option)
+ // any later version.
+ 
+ // This library is distributed in the hope that it will be useful,
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ // GNU General Public License for more details.
+ 
+ // You should have received a copy of the GNU General Public License along
+ // with this library; see the file COPYING.  If not, write to the Free
+ // Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ // USA.
+ 
+ // 22.2.2.2.1  num_put members
+ 
+ #include <locale>
+ #include <sstream>
+ #include <testsuite_hooks.h>
+ 
+ // libstdc++/20914
+ void test01()
+ {
+   using namespace std;
+   bool test __attribute__((unused)) = true;
+ 
+   // A locale that expects grouping.
+   locale loc_de = __gnu_test::try_named_locale("de_DE");
+ 
+   const string empty;
+   string result;
+ 
+   ostringstream oss;
+   oss.imbue(loc_de);
+   const num_put<char>& np = use_facet<num_put<char> >(oss.getloc()); 
+ 
+   long l0 = -300000;
+   long l1 = 300;
+   double d0 = -300000;
+   double d1 = 300;
+ 
+   oss.str(empty);
+   oss.clear();
+   np.put(oss.rdbuf(), oss, '*', l0);
+   result = oss.str();
+   VERIFY( result == "-300.000" );
+ 
+   oss.str(empty);
+   oss.clear();
+   np.put(oss.rdbuf(), oss, '*', d0);
+   result = oss.str();
+   VERIFY( result == "-300.000" );
+ 
+   oss.str(empty);
+   oss.clear();
+   oss.setf(ios::showpos);
+   np.put(oss.rdbuf(), oss, '*', l1);
+   result = oss.str();
+   VERIFY( result == "+300" );
+ 
+   oss.str(empty);
+   oss.clear();
+   oss.setf(ios::showpos);
+   np.put(oss.rdbuf(), oss, '*', d1);
+   result = oss.str();
+   VERIFY( result == "+300" );
+ }
+ 
+ int main()
+ {
+   test01();
+   return 0;
+ }
diff -prN libstdc++-v3-orig/testsuite/22_locale/num_put/put/wchar_t/20914.cc libstdc++-v3/testsuite/22_locale/num_put/put/wchar_t/20914.cc
*** libstdc++-v3-orig/testsuite/22_locale/num_put/put/wchar_t/20914.cc	Thu Jan  1 01:00:00 1970
--- libstdc++-v3/testsuite/22_locale/num_put/put/wchar_t/20914.cc	Sat Apr  9 18:03:52 2005
***************
*** 0 ****
--- 1,79 ----
+ // 2005-04-09  Paolo Carlini  <pcarlini@suse.de>
+ 
+ // Copyright (C) 2005 Free Software Foundation
+ //
+ // This file is part of the GNU ISO C++ Library.  This library is free
+ // software; you can redistribute it and/or modify it under the
+ // terms of the GNU General Public License as published by the
+ // Free Software Foundation; either version 2, or (at your option)
+ // any later version.
+ 
+ // This library is distributed in the hope that it will be useful,
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ // GNU General Public License for more details.
+ 
+ // You should have received a copy of the GNU General Public License along
+ // with this library; see the file COPYING.  If not, write to the Free
+ // Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ // USA.
+ 
+ // 22.2.2.2.1  num_put members
+ 
+ #include <locale>
+ #include <sstream>
+ #include <testsuite_hooks.h>
+ 
+ // libstdc++/20914
+ void test01()
+ {
+   using namespace std;
+   bool test __attribute__((unused)) = true;
+ 
+   // A locale that expects grouping.
+   locale loc_de = __gnu_test::try_named_locale("de_DE");
+ 
+   const wstring empty;
+   wstring result;
+ 
+   wostringstream oss;
+   oss.imbue(loc_de);
+   const num_put<wchar_t>& np = use_facet<num_put<wchar_t> >(oss.getloc()); 
+ 
+   long l0 = -300000;
+   long l1 = 300;
+   double d0 = -300000;
+   double d1 = 300;
+ 
+   oss.str(empty);
+   oss.clear();
+   np.put(oss.rdbuf(), oss, L'*', l0);
+   result = oss.str();
+   VERIFY( result == L"-300.000" );
+ 
+   oss.str(empty);
+   oss.clear();
+   np.put(oss.rdbuf(), oss, L'*', d0);
+   result = oss.str();
+   VERIFY( result == L"-300.000" );
+ 
+   oss.str(empty);
+   oss.clear();
+   oss.setf(ios::showpos);
+   np.put(oss.rdbuf(), oss, L'*', l1);
+   result = oss.str();
+   VERIFY( result == L"+300" );
+ 
+   oss.str(empty);
+   oss.clear();
+   oss.setf(ios::showpos);
+   np.put(oss.rdbuf(), oss, L'*', d1);
+   result = oss.str();
+   VERIFY( result == L"+300" );
+ }
+ 
+ int main()
+ {
+   test01();
+   return 0;
+ }

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