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]

[PATCH,RFC] Change __convert_from_v to use snprintf and use it


Hi,

I went ahead and implemented what I presented in my previous message.

Indeed, it seems to me that using snprintf, allows for a /much/ cleaner allocation of the
memory required for the various staging buffers. As part of the work I have also fixed the
problem with money_put, of course.

Please let me know what do you think of it, if perhaps may be only viable for the head,
being to invasive. Tested i686-pc-linux-gnu.

Ciao,
Paolo.

/////////////////

2002-03-17  Paolo Carlini  <pcarlini@unitus.it>

        * include/bits/locale_facets.tcc
        (__convert_from_v): Change to use snprintf.
        (num_put::_M_convert_float): Use the new __convert_from_v.
        (num_put::_M_convert_int): Same.
        (money_put::do_put(long double)): Same.
        * src/locale-inst.cc (__convert_from_v): Adjust declarations.

        * include/bits/locale_facets.tcc
        (money_put::do_put(string)): Fix dimensioning of the buffer
        used to add the grouping chars.

        * testsuite/22_locale/money_put_members_char.cc: Add test06.
        * testsuite/22_locale/money_put_members_char.cc: Ditto.

        * include/bits/locale_facets.tcc
        (collate::do_transform): Simplify.

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 Mon Mar 11 00:51:31 2002
--- libstdc++-v3/include/bits/locale_facets.tcc Sun Mar 17 14:56:35 2002
*************** namespace std
*** 613,643 ****
   // we get the full available precision.
   const int __max_digits = numeric_limits<_ValueT>::digits10 + 1;
   streamsize __prec = __io.precision();
!  // Protect against sprintf() buffer overflows.
   if (__prec > static_cast<streamsize>(__max_digits))
     __prec = static_cast<streamsize>(__max_digits);

   // Long enough for the max format spec.
   char __fbuf[16];

!  // Consider the possibility of long ios_base::fixed outputs
!  const bool __fixed = __io.flags() & ios_base::fixed;
!  const int __max_exp = numeric_limits<_ValueT>::max_exponent10;
!  // ios_base::fixed outputs may need up to __max_exp+1 chars
!  // for the integer part + up to __max_digits chars for the
!  // fractional part + 3 chars for sign, decimal point, '\0'. On
!  // the other hand, for non-fixed outputs __max_digits*3 chars
!  // are largely sufficient.
!  const int __cs_size = __fixed ? __max_exp + __max_digits + 4
!                                : __max_digits * 3;
   char* __cs = static_cast<char*>(__builtin_alloca(__cs_size));

   int __len;
   // [22.2.2.2.2] Stage 1, numeric conversion to character.
!  if (_S_format_float(__io, __fbuf, __mod, __prec))
!    __len = __convert_from_v(__cs, __fbuf, __v, _S_c_locale, __prec);
   else
!    __len = __convert_from_v(__cs, __fbuf, __v, _S_c_locale);
   return _M_widen_float(__s, __io, __fill, __cs, __len);
        }

--- 613,648 ----
   // we get the full available precision.
   const int __max_digits = numeric_limits<_ValueT>::digits10 + 1;
   streamsize __prec = __io.precision();
!
   if (__prec > static_cast<streamsize>(__max_digits))
     __prec = static_cast<streamsize>(__max_digits);

   // Long enough for the max format spec.
   char __fbuf[16];

!  // First try a buffer perhaps big enough.
!  int __cs_size = __max_digits * 3;
   char* __cs = static_cast<char*>(__builtin_alloca(__cs_size));

   int __len;
   // [22.2.2.2.2] Stage 1, numeric conversion to character.
!  const bool __fp = _S_format_float(__io, __fbuf, __mod, __prec);
!  if (__fp)
!    __len = __convert_from_v(__cs, __cs_size, __fbuf, __v, _S_c_locale, __prec);
   else
!    __len = __convert_from_v(__cs, __cs_size, __fbuf, __v, _S_c_locale);
!
!  // If the buffer was not large enough, try again with the correct size.
!  if (__len >= __cs_size)
!    {
!      __cs_size = __len + 1;
!      __cs = static_cast<char*>(__builtin_alloca(__cs_size));
!      if (__fp)
!        __len = __convert_from_v(__cs, __cs_size, __fbuf, __v, _S_c_locale, __prec);
!      else
!        __len = __convert_from_v(__cs, __cs_size, __fbuf, __v, _S_c_locale);
!    }
!
   return _M_widen_float(__s, __io, __fill, __cs, __len);
        }

*************** namespace std
*** 649,661 ****
         char __modl, _ValueT __v) const
        {
   // [22.2.2.2.2] Stage 1, numeric conversion to character.
-  // Leave room for "+/-," "0x," and commas. This size is
-  // arbitrary, but should work.
-  char __cs[64];
   // Long enough for the max format spec.
   char __fbuf[16];
   _S_format_int(__io, __fbuf, __mod, __modl);
!  int __len = __convert_from_v(__cs, __fbuf, __v, _S_c_locale);
   return _M_widen_int(__s, __io, __fill, __cs, __len);
        }

--- 654,673 ----
         char __modl, _ValueT __v) const
        {
   // [22.2.2.2.2] Stage 1, numeric conversion to character.
   // Long enough for the max format spec.
   char __fbuf[16];
   _S_format_int(__io, __fbuf, __mod, __modl);
!  // First try a buffer perhaps big enough.
!  int __cs_size = 64;
!  char* __cs = static_cast<char*>(__builtin_alloca(__cs_size));
!  int __len = __convert_from_v(__cs, __cs_size, __fbuf, __v, _S_c_locale);
!  // If the buffer was not large enough, try again with the correct size.
!  if (__len >= __cs_size)
!    {
!      __cs_size = __len + 1;
!      __cs = static_cast<char*>(__builtin_alloca(__cs_size));
!      __len = __convert_from_v(__cs, __cs_size, __fbuf, __v, _S_c_locale);
!    }
   return _M_widen_int(__s, __io, __fill, __cs, __len);
        }

*************** namespace std
*** 1111,1120 ****
      {
        const locale __loc = __io.getloc();
        const ctype<_CharT>& __ctype = use_facet<ctype<_CharT> >(__loc);
!       const int __n = numeric_limits<long double>::digits10;
!       char* __cs = static_cast<char*>(__builtin_alloca(sizeof(char) * __n));
!       _CharT* __ws = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT) * __n));
!       int __len = __convert_from_v(__cs, "%.01Lf", __units, _S_c_locale);
        __ctype.widen(__cs, __cs + __len, __ws);
        string_type __digits(__ws);
        return this->do_put(__s, __intl, __io, __fill, __digits);
--- 1123,1140 ----
      {
        const locale __loc = __io.getloc();
        const ctype<_CharT>& __ctype = use_facet<ctype<_CharT> >(__loc);
!       // First try a buffer perhaps big enough.
!       int __cs_size = 64;
!       char* __cs = static_cast<char*>(__builtin_alloca(sizeof(char) * __cs_size));
!       int __len = __convert_from_v(__cs, __cs_size, "%.01Lf", __units, _S_c_locale);
!       // If the buffer was not large enough, try again with the correct size.
!       if (__len >= __cs_size)
!  {
!    __cs_size = __len + 1;
!    __cs = static_cast<char*>(__builtin_alloca(sizeof(char) * __cs_size));
!    __len = __convert_from_v(__cs, __cs_size, "%.01Lf", __units, _S_c_locale);
!  }
!       _CharT* __ws = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT) * __cs_size));

        __ctype.widen(__cs, __cs + __len, __ws);
        string_type __digits(__ws);
        return this->do_put(__s, __intl, __io, __fill, __digits);
*************** namespace std
*** 1206,1212 ****
                    : __mpf.thousands_sep();
      const char* __gbeg = __grouping.c_str();
      const char* __gend = __gbeg + __grouping.size();
!     const int __n = numeric_limits<long double>::digits10 * 2;
      _CharT* __ws2 = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT) * __n));
      _CharT* __ws_end = __add_grouping(__ws2, __sep, __gbeg,
            __gend, __beg, __end);
--- 1226,1232 ----
                    : __mpf.thousands_sep();
      const char* __gbeg = __grouping.c_str();
      const char* __gend = __gbeg + __grouping.size();
!     const int __n = (__end - __beg) * 2;
      _CharT* __ws2 = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT) * __n));
      _CharT* __ws_end = __add_grouping(__ws2, __sep, __gbeg,
            __gend, __beg, __end);
*************** namespace std
*** 1863,1872 ****
        // If the buffer was not large enough, try again with the correct size.
        if (__res >= __len)
   {
!    _CharT* __c2 =
!      static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT) * (__res + 1)));
!    _M_transform_helper(__c2, __lo, __res + 1);
!    return string_type(__c2);
   }
        return string_type(__c);
      }
--- 1883,1890 ----
        // If the buffer was not large enough, try again with the correct size.
        if (__res >= __len)
   {
!    __c = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT) * (__res + 1)));
!    _M_transform_helper(__c, __lo, __res + 1);
   }
        return string_type(__c);
      }
*************** namespace std
*** 1894,1908 ****
    // Convert numeric value of type _Tv to string and return length of string.
    template<typename _Tv>
      int
!     __convert_from_v(char* __out, const char* __fmt, _Tv __v,
         const __c_locale&, int __prec = -1)
      {
        int __ret;
        const char* __old = setlocale(LC_ALL, "C");
        if (__prec >= 0)
!  __ret = sprintf(__out, __fmt, __prec, __v);
        else
!  __ret = sprintf(__out, __fmt, __v);
        setlocale(LC_ALL, __old);
        return __ret;
      }
--- 1912,1926 ----
    // Convert numeric value of type _Tv to string and return length of string.
    template<typename _Tv>
      int
!     __convert_from_v(char* __out, const int __size, const char* __fmt, _Tv __v,
         const __c_locale&, int __prec = -1)
      {
        int __ret;
        const char* __old = setlocale(LC_ALL, "C");
        if (__prec >= 0)
!  __ret = snprintf(__out, __size, __fmt, __prec, __v);
        else
!  __ret = snprintf(__out, __size, __fmt, __v);
        setlocale(LC_ALL, __old);
        return __ret;
      }
diff -prN libstdc++-v3-orig/src/locale-inst.cc libstdc++-v3/src/locale-inst.cc
*** libstdc++-v3-orig/src/locale-inst.cc Fri Mar  8 07:05:20 2002
--- libstdc++-v3/src/locale-inst.cc Sun Mar 17 15:03:01 2002
*************** namespace std
*** 461,488 ****

    template
      int
!     __convert_from_v(char*, const char*, double, const __c_locale&, int);

    template
      int
!     __convert_from_v(char*, const char*, long double, const __c_locale&, int);

    template
      int
!     __convert_from_v(char*, const char*, long, const __c_locale&, int);

    template
      int
!     __convert_from_v(char*, const char*, unsigned long,
         const __c_locale&, int);

    template
      int
!     __convert_from_v(char*, const char*, long long, const __c_locale&, int);

    template
      int
!     __convert_from_v(char*, const char*, unsigned long long,
         const __c_locale&, int);

    template
--- 461,488 ----

    template
      int
!     __convert_from_v(char*, const int, const char*, double, const __c_locale&, int);

    template
      int
!     __convert_from_v(char*, const int, const char*, long double, const __c_locale&,
int);

    template
      int
!     __convert_from_v(char*, const int, const char*, long, const __c_locale&, int);

    template
      int
!     __convert_from_v(char*, const int, const char*, unsigned long,
         const __c_locale&, int);

    template
      int
!     __convert_from_v(char*, const int, const char*, long long, const __c_locale&, int);

    template
      int
!     __convert_from_v(char*, const int, const char*, unsigned long long,
         const __c_locale&, int);

    template
diff -prN libstdc++-v3-orig/testsuite/22_locale/money_put_members_char.cc
libstdc++-v3/testsuite/22_locale/money_put_members_char.cc
*** libstdc++-v3-orig/testsuite/22_locale/money_put_members_char.cc Wed Feb 20 22:06:40
2002
--- libstdc++-v3/testsuite/22_locale/money_put_members_char.cc Sun Mar 17 14:03:41 2002
*************** void test02()
*** 226,232 ****
    oss.setf(ios_base::showbase);

    oss.str(empty);
!  iterator_type os_it03 = mon_put.put(oss.rdbuf(), true, oss, ' ', digits1);
    string result3 = oss.str();
    VERIFY( result3 == "7.200.000.000,00 DEM ");

--- 226,232 ----
    oss.setf(ios_base::showbase);

    oss.str(empty);
!   iterator_type os_it03 = mon_put.put(oss.rdbuf(), true, oss, ' ', digits1);
    string result3 = oss.str();
    VERIFY( result3 == "7.200.000.000,00 DEM ");

*************** void test05()
*** 341,346 ****
--- 341,373 ----
    VERIFY( fmt.str() == "*(1,234.56)" );
  }

+ struct My_money_io_2 : public std::moneypunct<char,false>
+ {
+   char_type do_thousands_sep() const { return ','; }
+   std::string do_grouping() const { return "\001"; }
+ };
+
+ // Make sure we can output a very big amount of money (with grouping too).
+ void test06()
+ {
+   using namespace std;
+   typedef ostreambuf_iterator<char> OutIt;
+
+   locale loc(locale::classic(), new My_money_io_2);
+
+   bool intl = false;
+
+   long double val = 1e50L;
+   const money_put<char,OutIt>& mp  =
+     use_facet<money_put<char, OutIt> >(loc);
+
+   ostringstream fmt;
+   fmt.imbue(loc);
+   OutIt out(fmt);
+   mp.put(out,intl,fmt,'*',val);
+   VERIFY( fmt );
+ }
+
  int main()
  {
    test01();
*************** int main()
*** 348,352 ****
--- 375,380 ----
    test03();
    test04();
    test05();
+   test06();
    return 0;
  }
diff -prN libstdc++-v3-orig/testsuite/22_locale/money_put_members_wchar_t.cc
libstdc++-v3/testsuite/22_locale/money_put_members_wchar_t.cc
*** libstdc++-v3-orig/testsuite/22_locale/money_put_members_wchar_t.cc Wed Feb 20 22:06:40
2002
--- libstdc++-v3/testsuite/22_locale/money_put_members_wchar_t.cc Sun Mar 17 14:03:49 2002

*************** void test02()
*** 226,232 ****
    oss.setf(ios_base::showbase);

    oss.str(empty);
!  iterator_type os_it03 = mon_put.put(oss.rdbuf(), true, oss, ' ', digits1);
    wstring result3 = oss.str();
    VERIFY( result3 == L"7.200.000.000,00 DEM ");

--- 226,232 ----
    oss.setf(ios_base::showbase);

    oss.str(empty);
!   iterator_type os_it03 = mon_put.put(oss.rdbuf(), true, oss, ' ', digits1);
    wstring result3 = oss.str();
    VERIFY( result3 == L"7.200.000.000,00 DEM ");

*************** void test05()
*** 340,345 ****
--- 340,372 ----
    mp.put(out,intl,fmt,L'*',val);
    VERIFY( fmt.str() == L"*(1,234.56)" );
  }
+
+ struct My_money_io_2 : public std::moneypunct<wchar_t,false>
+ {
+   char_type do_thousands_sep() const { return L','; }
+   std::string do_grouping() const { return "\001"; }
+ };
+
+ // Make sure we can output a very big amount of money (with grouping too).
+ void test06()
+ {
+   using namespace std;
+   typedef ostreambuf_iterator<wchar_t> OutIt;
+
+   locale loc(locale::classic(), new My_money_io_2);
+
+   bool intl = false;
+
+   long double val = 1e50L;
+   const money_put<wchar_t,OutIt>& mp  =
+     use_facet<money_put<wchar_t, OutIt> >(loc);
+
+   wostringstream fmt;
+   fmt.imbue(loc);
+   OutIt out(fmt);
+   mp.put(out,intl,fmt,'*',val);
+   VERIFY( fmt );
+ }
  #endif

  int main()
*************** int main()
*** 350,355 ****
--- 377,383 ----
    test03();
    test04();
    test05();
+   test06();
  #endif
    return 0;
  }



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