PR libstdc++/28277 (partial: collate bits)
authorPaolo Carlini <pcarlini@suse.de>
Tue, 11 Jul 2006 11:21:38 +0000 (11:21 +0000)
committerPaolo Carlini <paolo@gcc.gnu.org>
Tue, 11 Jul 2006 11:21:38 +0000 (11:21 +0000)
2006-07-11  Paolo Carlini  <pcarlini@suse.de>

PR libstdc++/28277 (partial: collate bits)
* include/bits/locale_facets.tcc (collate<>::do_transform(
const _CharT*, const _CharT*)): Avoid __builtin_alloca with no
limit; also avoid multiple calls (in a loop).
* testsuite/22_locale/collate/transform/char/28277.cc: New.
* testsuite/22_locale/collate/transform/wchar_t/28277.cc: Likewise.

From-SVN: r115332

libstdc++-v3/ChangeLog
libstdc++-v3/include/bits/locale_facets.tcc
libstdc++-v3/testsuite/22_locale/collate/transform/char/28277.cc [new file with mode: 0644]
libstdc++-v3/testsuite/22_locale/collate/transform/wchar_t/28277.cc [new file with mode: 0644]

index 774b3df9a0a72682921e6911c0d3dc28234f9eb8..249e6ac3c861d85af66cebfb694e510ac885826e 100644 (file)
@@ -1,3 +1,12 @@
+2006-07-11  Paolo Carlini  <pcarlini@suse.de>
+
+       PR libstdc++/28277 (partial: collate bits)
+       * include/bits/locale_facets.tcc (collate<>::do_transform(
+       const _CharT*, const _CharT*)): Avoid __builtin_alloca with no
+       limit; also avoid multiple calls (in a loop).
+       * testsuite/22_locale/collate/transform/char/28277.cc: New.
+       * testsuite/22_locale/collate/transform/wchar_t/28277.cc: Likewise.
+
 2006-07-10  Mike Stump  <mrs@apple.com>
 
        * libsupc++/eh_globals.cc (~__eh_globals_init): Unset _M_init.
index a889e0134ecabcf93681eeca945addfcbb726281..ad45863ee85b25523a2750f97008326c476eb6d8 100644 (file)
@@ -2455,43 +2455,62 @@ _GLIBCXX_END_LDBL_NAMESPACE
     collate<_CharT>::
     do_transform(const _CharT* __lo, const _CharT* __hi) const
     {
-      // strxfrm assumes zero-terminated strings so we make a copy
-      string_type __str(__lo, __hi);
+      string_type __ret;
 
-      const _CharT* __p = __str.c_str();
-      const _CharT* __pend = __str.data() + __str.length();
+      // Use alloca for an _M_transform temporary buffer up to an arbitrary,
+      // but limited, asize, to avoid abusing the stack.  Otherwise fall back
+      // to dynamic memory allocation.  This means splitting the computation
+      // itself in hunks:  a size <= 8k (thus <= 16k asize) appear sufficient
+      // for optimal performance.
+      const size_t __size = std::min(size_t(__hi - __lo), size_t(8192));
+      const size_t __asize = 2 * __size;
 
-      size_t __len = (__hi - __lo) * 2;
+      size_t __len = __asize;
 
-      string_type __ret;
+      _CharT* __c =
+       static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT) * __len));
 
-      // strxfrm stops when it sees a nul character so we break
-      // the string into zero-terminated substrings and pass those
-      // to strxfrm.
-      for (;;)
+      for (size_t __hunk = __size; __lo < __hi;
+          __lo += __hunk, __hunk = std::min(size_t(__hi - __lo), __hunk))
        {
-         // First try a buffer perhaps big enough.
-         _CharT* __c =
-           static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT) * __len));
-         size_t __res = _M_transform(__c, __p, __len);
-         // If the buffer was not large enough, try again with the
-         // correct size.
-         if (__res >= __len)
+         // strxfrm assumes zero-terminated strings so we make a copy
+         const string_type __str(__lo, __lo + __hunk);
+
+         const _CharT* __p = __str.c_str();
+         const _CharT* __pend = __str.data() + __hunk;
+
+         // strxfrm stops when it sees a nul character so we break
+         // the string into zero-terminated substrings and pass those
+         // to strxfrm.
+         for (;;)
            {
-             __len = __res + 1;
-             __c = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT)
-                                                         * __len));
-             __res = _M_transform(__c, __p, __len);
-           }
+             // First try a buffer perhaps big enough.
+             size_t __res = _M_transform(__c, __p, __len);
+             // If the buffer was not large enough, try again with the
+             // correct size.
+             if (__res >= __len)
+               {
+                 if (__len > __asize)
+                   delete [] __c;
+                 __len = __res + 1;
+                 __c = new _CharT[__len];
+                 __res = _M_transform(__c, __p, __len);
+               }
 
-         __ret.append(__c, __res);
-         __p += char_traits<_CharT>::length(__p);
-         if (__p == __pend)
-           return __ret;
+             __ret.append(__c, __res);
+             __p += char_traits<_CharT>::length(__p);
+             if (__p == __pend)
+               break;
 
-         __p++;
-         __ret.push_back(_CharT());
+             __p++;
+             __ret.push_back(_CharT());
+           }
        }
+
+      if (__len > __asize)
+       delete [] __c;
+
+      return __ret;
     }
 
   template<typename _CharT>
diff --git a/libstdc++-v3/testsuite/22_locale/collate/transform/char/28277.cc b/libstdc++-v3/testsuite/22_locale/collate/transform/char/28277.cc
new file mode 100644 (file)
index 0000000..c81cdaa
--- /dev/null
@@ -0,0 +1,52 @@
+// 2006-07-11  Paolo Carlini  <pcarlini@suse.de>
+
+// Copyright (C) 2006 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+// USA.
+
+// 22.2.4.1.1 collate members
+
+#include <locale>
+#include <testsuite_hooks.h>
+
+// libstdc++/28277
+void test01()
+{
+  using namespace std;
+  typedef collate<char>::string_type string_type;
+
+  bool test __attribute__((unused)) = true;
+
+  // basic construction
+  locale loc_c = locale::classic();
+
+  // cache the collate facets
+  const collate<char>& coll_c = use_facet<collate<char> >(loc_c); 
+
+  const string_type sstr(10000000, 'a');
+
+  const string_type dstr = coll_c.transform(sstr.data(),
+                                           sstr.data() + sstr.size());
+
+  VERIFY( dstr == sstr );
+}
+
+int main()
+{
+  test01();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/22_locale/collate/transform/wchar_t/28277.cc b/libstdc++-v3/testsuite/22_locale/collate/transform/wchar_t/28277.cc
new file mode 100644 (file)
index 0000000..3a9fbb9
--- /dev/null
@@ -0,0 +1,52 @@
+// 2006-07-11  Paolo Carlini  <pcarlini@suse.de>
+
+// Copyright (C) 2006 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+// USA.
+
+// 22.2.4.1.1 collate members
+
+#include <locale>
+#include <testsuite_hooks.h>
+
+// libstdc++/28277
+void test01()
+{
+  using namespace std;
+  typedef collate<wchar_t>::string_type string_type;
+
+  bool test __attribute__((unused)) = true;
+
+  // basic construction
+  locale loc_c = locale::classic();
+
+  // cache the collate facets
+  const collate<wchar_t>& coll_c = use_facet<collate<wchar_t> >(loc_c); 
+
+  const string_type sstr(10000000, L'a');
+
+  const string_type dstr = coll_c.transform(sstr.data(),
+                                           sstr.data() + sstr.size());
+
+  VERIFY( dstr == sstr );
+}
+
+int main()
+{
+  test01();
+  return 0;
+}