This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
Draft patch for libstdc++/20914
- From: Paolo Carlini <pcarlini at suse dot de>
- To: libstdc++ <libstdc++ at gcc dot gnu dot org>
- Date: Sat, 09 Apr 2005 18:29:19 +0200
- Subject: 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;
+ }