From e3c0c0989b614b5ce3e968ff49a12eaddebc0d76 Mon Sep 17 00:00:00 2001 From: Paolo Carlini Date: Fri, 12 Dec 2003 19:44:17 +0000 Subject: [PATCH] re PR libstdc++/13341 (ctype::do_narrow(wchar_t, char) is slow) 2003-12-12 Paolo Carlini Benjamin Kosnik PR libstdc++/13341 * include/bits/locale_facets.h (ctype): Declare _M_initialize_ctype() and _M_narrow_ok, _M_narrow and _M_widen. * src/ctype.cc (ctype::ctype(size_t), ctype::ctype(__c_locale, size_t)): Use _M_initialize_ctype to fill _M_narrow and _M_widen. (ctype_byname::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. Co-Authored-By: Benjamin Kosnik From-SVN: r74580 --- libstdc++-v3/ChangeLog | 19 ++++++ .../config/locale/generic/ctype_members.cc | 63 +++++++++++++++++--- libstdc++-v3/config/locale/gnu/ctype_members.cc | 69 ++++++++++++++++++---- libstdc++-v3/include/bits/locale_facets.h | 9 +++ libstdc++-v3/src/ctype.cc | 13 +++- .../testsuite/performance/narrow_widen_wchar_t.cc | 59 ++++++++++++++++++ 6 files changed, 210 insertions(+), 22 deletions(-) create mode 100644 libstdc++-v3/testsuite/performance/narrow_widen_wchar_t.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 8c5a764..27e23bf 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,22 @@ +2003-12-12 Paolo Carlini + Benjamin Kosnik + + PR libstdc++/13341 + * include/bits/locale_facets.h (ctype): Declare + _M_initialize_ctype() and _M_narrow_ok, _M_narrow and _M_widen. + * src/ctype.cc (ctype::ctype(size_t), + ctype::ctype(__c_locale, size_t)): Use + _M_initialize_ctype to fill _M_narrow and _M_widen. + (ctype_byname::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. + 2003-12-12 Jonathan Wakely * docs/html/faq/index.txt: Regenerate after adding tags. diff --git a/libstdc++-v3/config/locale/generic/ctype_members.cc b/libstdc++-v3/config/locale/generic/ctype_members.cc index 71175f1..517df4c 100644 --- a/libstdc++-v3/config/locale/generic/ctype_members.cc +++ b/libstdc++-v3/config/locale/generic/ctype_members.cc @@ -185,7 +185,12 @@ namespace std wchar_t ctype:: do_widen(char __c) const - { return btowc(static_cast(__c)); } + { + const unsigned char __uc = static_cast(__c); + if (__uc < 128) + return _M_widen[__uc]; + return btowc(__uc); + } const char* ctype:: @@ -193,7 +198,11 @@ namespace std { while (__lo < __hi) { - *__dest = btowc(static_cast(*__lo)); + const unsigned char __uc = static_cast(*__lo); + if (__uc < 128) + *__dest = _M_widen[__uc]; + else + *__dest = btowc(__uc); ++__lo; ++__dest; } @@ -204,7 +213,9 @@ namespace std ctype:: do_narrow(wchar_t __wc, char __dfault) const { - int __c = wctob(__wc); + if (__wc >= 0 && __wc < 128 && _M_narrow_ok) + return _M_narrow[__wc]; + const int __c = wctob(__wc); return (__c == EOF ? __dfault : static_cast(__c)); } @@ -213,14 +224,48 @@ namespace std do_narrow(const wchar_t* __lo, const wchar_t* __hi, char __dfault, char* __dest) const { - while (__lo < __hi) + 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(__c)); + } + ++__lo; + ++__dest; + } + else + while (__lo < __hi) + { + const int __c = wctob(*__lo); + *__dest = (__c == EOF ? __dfault : static_cast(__c)); + ++__lo; + ++__dest; + } + return __hi; + } + + void + ctype::_M_initialize_ctype() + { + wint_t __i; + for (__i = 0; __i < 128; ++__i) { - int __c = wctob(*__lo); - *__dest = (__c == EOF ? __dfault : static_cast(__c)); - ++__lo; - ++__dest; + const int __c = wctob(__i); + if (__c == EOF) + break; + else + _M_narrow[__i] = static_cast(__c); } - return __hi; + 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 --git a/libstdc++-v3/config/locale/gnu/ctype_members.cc b/libstdc++-v3/config/locale/gnu/ctype_members.cc index a5394b5..673b511 100644 --- a/libstdc++-v3/config/locale/gnu/ctype_members.cc +++ b/libstdc++-v3/config/locale/gnu/ctype_members.cc @@ -192,14 +192,17 @@ namespace std ctype:: do_widen(char __c) const { + const unsigned char __uc = static_cast(__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 - wchar_t __ret = btowc(static_cast(__c)); + const wchar_t __wc = btowc(__uc); #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2) __uselocale(__old); #endif - return __ret; + return __wc; } const char* @@ -211,7 +214,11 @@ namespace std #endif while (__lo < __hi) { - *__dest = btowc(static_cast(*__lo)); + const unsigned char __uc = static_cast(*__lo); + if (__uc < 128) + *__dest = _M_widen[__uc]; + else + *__dest = btowc(__uc); ++__lo; ++__dest; } @@ -225,10 +232,12 @@ namespace std ctype:: 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 - int __c = wctob(__wc); + const int __c = wctob(__wc); #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2) __uselocale(__old); #endif @@ -243,17 +252,57 @@ namespace std #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2) __c_locale __old = __uselocale(_M_c_locale_ctype); #endif - while (__lo < __hi) + 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(__c)); + } + ++__lo; + ++__dest; + } + else + while (__lo < __hi) + { + const int __c = wctob(*__lo); + *__dest = (__c == EOF ? __dfault : static_cast(__c)); + ++__lo; + ++__dest; + } +#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2) + __uselocale(__old); +#endif + return __hi; + } + + void + ctype::_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) { - int __c = wctob(*__lo); - *__dest = (__c == EOF ? __dfault : static_cast(__c)); - ++__lo; - ++__dest; + const int __c = wctob(__i); + if (__c == EOF) + break; + else + _M_narrow[__i] = static_cast(__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 - return __hi; } #endif // _GLIBCXX_USE_WCHAR_T } diff --git a/libstdc++-v3/include/bits/locale_facets.h b/libstdc++-v3/include/bits/locale_facets.h index a61ac9f..7a24b9b 100644 --- a/libstdc++-v3/include/bits/locale_facets.h +++ b/libstdc++-v3/include/bits/locale_facets.h @@ -446,6 +446,11 @@ namespace std 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; @@ -500,6 +505,10 @@ namespace std 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 --git a/libstdc++-v3/src/ctype.cc b/libstdc++-v3/src/ctype.cc index 7fb5c2d..b0888c5 100644 --- a/libstdc++-v3/src/ctype.cc +++ b/libstdc++-v3/src/ctype.cc @@ -87,11 +87,17 @@ namespace std #ifdef _GLIBCXX_USE_WCHAR_T ctype::ctype(size_t __refs) : __ctype_abstract_base(__refs) - { _M_c_locale_ctype = _S_get_c_locale(); } + { + _M_c_locale_ctype = _S_get_c_locale(); + _M_initialize_ctype(); + } ctype::ctype(__c_locale __cloc, size_t __refs) : __ctype_abstract_base(__refs) - { _M_c_locale_ctype = _S_clone_c_locale(__cloc); } + { + _M_c_locale_ctype = _S_clone_c_locale(__cloc); + _M_initialize_ctype(); + } ctype::~ctype() { _S_destroy_c_locale(_M_c_locale_ctype); } @@ -103,7 +109,8 @@ namespace std 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); + _S_create_c_locale(_M_c_locale_ctype, __s); + _M_initialize_ctype(); } } #endif diff --git a/libstdc++-v3/testsuite/performance/narrow_widen_wchar_t.cc b/libstdc++-v3/testsuite/performance/narrow_widen_wchar_t.cc new file mode 100644 index 0000000..1081bf5 --- /dev/null +++ b/libstdc++-v3/testsuite/performance/narrow_widen_wchar_t.cc @@ -0,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 +#include + +int main() +{ + using namespace std; + using namespace __gnu_test; + + time_counter time; + resource_counter resource; + const long iters = 200000000; + + locale loc; + const ctype& ct = use_facet >(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; +} -- 2.7.4