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]

Re: [Patch] Fix libstdc++/13341 (speed-up <wchar_t>::do_narrow/widen)


Benjamin Kosnik wrote:

Hmmm. Just a thought: instead of storing an array of int, why don't you
just store an array of char, and don't cache at all if you run into an
error when constructing the cache?

*Very* nice idea! Probably it didn't occur to me since I didn't realize that in the exceedingly most common case, wctob never returns EOF for values in the range 0-127!

Anyway, your suggestion, besides reducing the memory consumption, also
allows for a faster array version.

Updated patch below, tested, as usual, both gnu/generic on x86-linux.

Paolo.

/////////////
2003-12-11  Paolo Carlini  <pcarlini@suse.de>
	    Benjamin Kosnik  <bkoz@redhat.com>

	PR libstdc++/13341
	* include/bits/locale_facets.h (ctype<wchar_t>): Declare
	_M_initialize_ctype and define _M_narrow and _M_widen.
	* src/ctype.cc (ctype<wchar_t>::ctype(size_t),
	ctype<wchar_t>::ctype(__c_locale, size_t)): Call 
	_M_initialize_ctype to fill _M_narrow and _M_widen.
	(ctype_byname<wchar_t>::ctype_byname(const char*, size_t)):
	Likewise.
	* config/locale/generic/ctype_members.cc (do_narrow, do_widen)
	Use _M_narrow and _M_widen when possible, instead of calling
	wctob and btowc, respectively.
	(_M_initialize_ctype): Define, it fills at construction time
	_M_narrow and _M_widen.
	* config/locale/gnu/ctype_members.cc: Likewise.
	* testsuite/performance/narrow_widen_wchar_t.cc: New.
diff -prN libstdc++-v3-orig/config/locale/generic/ctype_members.cc libstdc++-v3/config/locale/generic/ctype_members.cc
*** libstdc++-v3-orig/config/locale/generic/ctype_members.cc	Wed Oct 22 20:58:30 2003
--- libstdc++-v3/config/locale/generic/ctype_members.cc	Fri Dec 12 10:30:35 2003
*************** namespace std
*** 185,191 ****
    wchar_t
    ctype<wchar_t>::
    do_widen(char __c) const
!   { return btowc(static_cast<unsigned char>(__c)); }
    
    const char* 
    ctype<wchar_t>::
--- 185,196 ----
    wchar_t
    ctype<wchar_t>::
    do_widen(char __c) const
!   { 
!     const unsigned char __uc = static_cast<unsigned char>(__c);
!     if (__uc < 128)
!       return _M_widen[__uc];
!     return btowc(__uc);
!   }
    
    const char* 
    ctype<wchar_t>::
*************** namespace std
*** 193,199 ****
    {
      while (__lo < __hi)
        {
! 	*__dest = btowc(static_cast<unsigned char>(*__lo));
  	++__lo;
  	++__dest;
        }
--- 198,208 ----
    {
      while (__lo < __hi)
        {
! 	const unsigned char __uc = static_cast<unsigned char>(*__lo);	
! 	if (__uc < 128)
! 	  *__dest = _M_widen[__uc];
! 	else
! 	  *__dest = btowc(__uc);	
  	++__lo;
  	++__dest;
        }
*************** namespace std
*** 204,210 ****
    ctype<wchar_t>::
    do_narrow(wchar_t __wc, char __dfault) const
    { 
!     int __c = wctob(__wc);
      return (__c == EOF ? __dfault : static_cast<char>(__c)); 
    }
  
--- 213,221 ----
    ctype<wchar_t>::
    do_narrow(wchar_t __wc, char __dfault) const
    { 
!     if (__wc >= 0 && __wc < 128 && _M_narrow_ok)
!       return _M_narrow[__wc];
!     const int __c = wctob(__wc);
      return (__c == EOF ? __dfault : static_cast<char>(__c)); 
    }
  
*************** namespace std
*** 213,226 ****
    do_narrow(const wchar_t* __lo, const wchar_t* __hi, char __dfault, 
  	    char* __dest) const
    {
!     while (__lo < __hi)
        {
! 	int __c = wctob(*__lo);
! 	*__dest = (__c == EOF ? __dfault : static_cast<char>(__c));
! 	++__lo;
! 	++__dest;
        }
!     return __hi;
    }
  #endif //  _GLIBCXX_USE_WCHAR_T
  }
--- 224,271 ----
    do_narrow(const wchar_t* __lo, const wchar_t* __hi, char __dfault, 
  	    char* __dest) const
    {
!     if (_M_narrow_ok)
!       while (__lo < __hi)
! 	{
! 	  if (*__lo >= 0 && *__lo < 128)
! 	    *__dest = _M_narrow[*__lo];
! 	  else
! 	    {
! 	      const int __c = wctob(*__lo);
! 	      *__dest = (__c == EOF ? __dfault : static_cast<char>(__c));
! 	    }
! 	  ++__lo;
! 	  ++__dest;
! 	}
!     else
!       while (__lo < __hi)
! 	{
! 	  const int __c = wctob(*__lo);
! 	  *__dest = (__c == EOF ? __dfault : static_cast<char>(__c));
! 	  ++__lo;
! 	  ++__dest;
! 	}
!     return __hi;
!   }
! 
!   void
!   ctype<wchar_t>::_M_initialize_ctype()
!   {
!     wint_t __i;
!     for (__i = 0; __i < 128; ++__i)
        {
! 	const int __c = wctob(__i);
! 	if (__c == EOF)
! 	  break;
! 	else
! 	  _M_narrow[__i] = static_cast<char>(__c);
        }
!     if (__i == 128)
!       _M_narrow_ok = true;
!     else
!       _M_narrow_ok = false;
!     for (int __i = 0; __i < 128; ++__i)
!       _M_widen[__i] = btowc(__i);
    }
  #endif //  _GLIBCXX_USE_WCHAR_T
  }
diff -prN libstdc++-v3-orig/config/locale/gnu/ctype_members.cc libstdc++-v3/config/locale/gnu/ctype_members.cc
*** libstdc++-v3-orig/config/locale/gnu/ctype_members.cc	Wed Oct 22 20:58:30 2003
--- libstdc++-v3/config/locale/gnu/ctype_members.cc	Fri Dec 12 10:30:05 2003
*************** namespace std
*** 192,205 ****
    ctype<wchar_t>::
    do_widen(char __c) const
    {
  #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
      __c_locale __old = __uselocale(_M_c_locale_ctype);
  #endif
!     wchar_t __ret = btowc(static_cast<unsigned char>(__c));
  #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
      __uselocale(__old);
  #endif
!     return __ret;
    }
  
    const char* 
--- 192,208 ----
    ctype<wchar_t>::
    do_widen(char __c) const
    {
+     const unsigned char __uc = static_cast<unsigned char>(__c);
+     if (__uc < 128)
+       return _M_widen[__uc];
  #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
      __c_locale __old = __uselocale(_M_c_locale_ctype);
  #endif
!     const wchar_t __wc = btowc(__uc);
  #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
      __uselocale(__old);
  #endif
!     return __wc;
    }
  
    const char* 
*************** namespace std
*** 211,217 ****
  #endif
      while (__lo < __hi)
        {
! 	*__dest = btowc(static_cast<unsigned char>(*__lo));
  	++__lo;
  	++__dest;
        }
--- 214,224 ----
  #endif
      while (__lo < __hi)
        {
! 	const unsigned char __uc = static_cast<unsigned char>(*__lo);	
! 	if (__uc < 128)
! 	  *__dest = _M_widen[__uc];
! 	else
! 	  *__dest = btowc(__uc);	
  	++__lo;
  	++__dest;
        }
*************** namespace std
*** 225,234 ****
    ctype<wchar_t>::
    do_narrow(wchar_t __wc, char __dfault) const
    { 
  #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
      __c_locale __old = __uselocale(_M_c_locale_ctype);
  #endif
!     int __c = wctob(__wc);
  #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
      __uselocale(__old);
  #endif
--- 232,243 ----
    ctype<wchar_t>::
    do_narrow(wchar_t __wc, char __dfault) const
    { 
+     if (__wc >= 0 && __wc < 128 && _M_narrow_ok)
+       return _M_narrow[__wc];
  #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
      __c_locale __old = __uselocale(_M_c_locale_ctype);
  #endif
!     const int __c = wctob(__wc);
  #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
      __uselocale(__old);
  #endif
*************** namespace std
*** 243,259 ****
  #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
      __c_locale __old = __uselocale(_M_c_locale_ctype);
  #endif
!     while (__lo < __hi)
        {
! 	int __c = wctob(*__lo);
! 	*__dest = (__c == EOF ? __dfault : static_cast<char>(__c));
! 	++__lo;
! 	++__dest;
        }
  #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
      __uselocale(__old);
  #endif
-     return __hi;
    }
  #endif //  _GLIBCXX_USE_WCHAR_T
  }
--- 252,308 ----
  #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
      __c_locale __old = __uselocale(_M_c_locale_ctype);
  #endif
!     if (_M_narrow_ok)
!       while (__lo < __hi)
! 	{
! 	  if (*__lo >= 0 && *__lo < 128)
! 	    *__dest = _M_narrow[*__lo];
! 	  else
! 	    {
! 	      const int __c = wctob(*__lo);
! 	      *__dest = (__c == EOF ? __dfault : static_cast<char>(__c));
! 	    }
! 	  ++__lo;
! 	  ++__dest;
! 	}
!     else
!       while (__lo < __hi)
! 	{
! 	  const int __c = wctob(*__lo);
! 	  *__dest = (__c == EOF ? __dfault : static_cast<char>(__c));
! 	  ++__lo;
! 	  ++__dest;
! 	}
! #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
!     __uselocale(__old);
! #endif
!     return __hi;
!   }
! 
!   void
!   ctype<wchar_t>::_M_initialize_ctype()
!   {
! #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
!     __c_locale __old = __uselocale(_M_c_locale_ctype);
! #endif
!     wint_t __i;
!     for (__i = 0; __i < 128; ++__i)
        {
! 	const int __c = wctob(__i);
! 	if (__c == EOF)
! 	  break;
! 	else
! 	  _M_narrow[__i] = static_cast<char>(__c);
        }
+     if (__i == 128)
+       _M_narrow_ok = true;
+     else
+       _M_narrow_ok = false;
+     for (int __i = 0; __i < 128; ++__i)
+       _M_widen[__i] = btowc(__i);
  #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
      __uselocale(__old);
  #endif
    }
  #endif //  _GLIBCXX_USE_WCHAR_T
  }
diff -prN libstdc++-v3-orig/include/bits/locale_facets.h libstdc++-v3/include/bits/locale_facets.h
*** libstdc++-v3-orig/include/bits/locale_facets.h	Mon Dec  8 16:37:02 2003
--- libstdc++-v3/include/bits/locale_facets.h	Fri Dec 12 09:47:06 2003
*************** namespace std
*** 446,451 ****
--- 446,456 ----
      protected:
        __c_locale		_M_c_locale_ctype;
  
+       // Pre-computed narrowed and widened chars in the range 0-127.
+       bool                      _M_narrow_ok;      
+       char                      _M_narrow[128];
+       wint_t                    _M_widen[128];
+ 
      public:
        // Data Members:
        static locale::id        	id;
*************** namespace std
*** 500,505 ****
--- 505,514 ----
        virtual const char_type*
        do_narrow(const char_type* __lo, const char_type* __hi,
  		char __dfault, char* __dest) const;
+ 
+       // For use at construction time only.
+       void 
+       _M_initialize_ctype();
      };
  
    template<>
diff -prN libstdc++-v3-orig/src/ctype.cc libstdc++-v3/src/ctype.cc
*** libstdc++-v3-orig/src/ctype.cc	Wed Oct 22 20:58:31 2003
--- libstdc++-v3/src/ctype.cc	Thu Dec 11 20:00:07 2003
*************** namespace std 
*** 87,97 ****
  #ifdef _GLIBCXX_USE_WCHAR_T
    ctype<wchar_t>::ctype(size_t __refs) 
    : __ctype_abstract_base<wchar_t>(__refs)
!   { _M_c_locale_ctype = _S_get_c_locale(); }
  
    ctype<wchar_t>::ctype(__c_locale __cloc, size_t __refs) 
    : __ctype_abstract_base<wchar_t>(__refs) 
!   { _M_c_locale_ctype = _S_clone_c_locale(__cloc); }
  
    ctype<wchar_t>::~ctype() 
    { _S_destroy_c_locale(_M_c_locale_ctype); }
--- 87,103 ----
  #ifdef _GLIBCXX_USE_WCHAR_T
    ctype<wchar_t>::ctype(size_t __refs) 
    : __ctype_abstract_base<wchar_t>(__refs)
!   { 
!     _M_c_locale_ctype = _S_get_c_locale();
!     _M_initialize_ctype();
!   }
  
    ctype<wchar_t>::ctype(__c_locale __cloc, size_t __refs) 
    : __ctype_abstract_base<wchar_t>(__refs) 
!   {
!     _M_c_locale_ctype = _S_clone_c_locale(__cloc);
!     _M_initialize_ctype();
!   }
  
    ctype<wchar_t>::~ctype() 
    { _S_destroy_c_locale(_M_c_locale_ctype); }
*************** namespace std 
*** 103,109 ****
        if (std::strcmp(__s, "C") != 0 && std::strcmp(__s, "POSIX") != 0)
  	{
  	  _S_destroy_c_locale(_M_c_locale_ctype);
! 	  _S_create_c_locale(_M_c_locale_ctype, __s); 
  	}
      }
  #endif
--- 109,116 ----
        if (std::strcmp(__s, "C") != 0 && std::strcmp(__s, "POSIX") != 0)
  	{
  	  _S_destroy_c_locale(_M_c_locale_ctype);
! 	  _S_create_c_locale(_M_c_locale_ctype, __s);
! 	  _M_initialize_ctype();
  	}
      }
  #endif
diff -prN libstdc++-v3-orig/testsuite/performance/narrow_widen_wchar_t.cc libstdc++-v3/testsuite/performance/narrow_widen_wchar_t.cc
*** libstdc++-v3-orig/testsuite/performance/narrow_widen_wchar_t.cc	Thu Jan  1 01:00:00 1970
--- libstdc++-v3/testsuite/performance/narrow_widen_wchar_t.cc	Thu Dec 11 16:27:12 2003
***************
*** 0 ****
--- 1,59 ----
+ // Copyright (C) 2003 Free Software Foundation, Inc.
+ //
+ // 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.
+ 
+ // As a special exception, you may use this file as part of a free software
+ // library without restriction.  Specifically, if other files instantiate
+ // templates or use macros or inline functions from this file, or you compile
+ // this file and link it with other files to produce an executable, this
+ // file does not by itself cause the resulting executable to be covered by
+ // the GNU General Public License.  This exception does not however
+ // invalidate any other reasons why the executable file might be covered by
+ // the GNU General Public License.
+ 
+ #include <locale>
+ #include <testsuite_performance.h>
+ 
+ int main()
+ {
+   using namespace std;
+   using namespace __gnu_test;
+ 
+   time_counter time;
+   resource_counter resource;
+   const long iters = 200000000;
+ 
+   locale loc;
+   const ctype<wchar_t>& ct = use_facet<ctype<wchar_t> >(loc);
+ 
+   // narrow
+   start_counters(time, resource);
+   for (long i = 0; i < iters; ++i)
+     ct.narrow(i % 128, '*');
+   stop_counters(time, resource);
+   report_performance(__FILE__, "narrow", time, resource);
+   clear_counters(time, resource);
+ 
+   // widen
+   start_counters(time, resource);
+   for (long i = 0; i < iters; ++i)
+     ct.widen(i % 128);
+   stop_counters(time, resource);
+   report_performance(__FILE__, "widen", time, resource);
+ 
+   return 0;
+ }

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