From 4df9c41de5ca5a3a3d6b27d3945e2d9401f115c5 Mon Sep 17 00:00:00 2001 From: Paolo Carlini Date: Mon, 3 May 2004 12:14:07 +0000 Subject: [PATCH] Optimize locale::_M_impl->_M_names for the most common cases... 2004-05-03 Paolo Carlini Optimize locale::_M_impl->_M_names for the most common cases: !_M_names[0] means unnamed; !_M_names[1] means all the categories the same name (_M_names[0] && _M_names[1] means that the full set of _M_names must be processed, the general case). * include/bits/locale_classes.h (locale::_Impl::_M_check_same_name): Tweak, saving work when !_M_names[1]. (locale::locale(const locale&, _Facet*): Simplify: now just setting _M_names[0] = 0 means unnamed. * src/locale.cc (locale::operator==): Deal first with the common, easy cases, otherwise fall back to locale::name(). (locale::name()): Tweak, if !_M_names[0] just return "*". (locale::_Impl::_Impl(const _Impl&, size_t): Tweak, early stop copying __imp._M_names if !__imp._M_names[0] or !__imp._M_names[1]. * src/locale_init.cc (locale::_Impl::_Impl(size_t)): Tweak. * src/localename.cc (locale::_Impl::_Impl(const char*, size_t): Simplify when !std::strchr, just updating _M_names[0]; clean up. (locale::_Impl::_M_replace_categories): When !_M_names[1] prepare for the general case (full set of names), then do the usual work; clean up. * src/locale.cc (locale::name()): Reserve space in __ret. * src/locale_init.cc (locale::global(const locale&)): Save the name in a temporary. * src/localename.cc (locale::locale(const char*)): Reserve space in __str. From-SVN: r81430 --- libstdc++-v3/ChangeLog | 28 +++++++++++++ libstdc++-v3/include/bits/locale_classes.h | 27 ++++-------- libstdc++-v3/src/locale.cc | 35 ++++++++++------ libstdc++-v3/src/locale_init.cc | 18 ++++---- libstdc++-v3/src/localename.cc | 48 ++++++++++++++-------- 5 files changed, 96 insertions(+), 60 deletions(-) diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index f61c6444e72..ba311c5242a 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,31 @@ +2004-05-03 Paolo Carlini + + Optimize locale::_M_impl->_M_names for the most common cases: + !_M_names[0] means unnamed; !_M_names[1] means all the categories + the same name (_M_names[0] && _M_names[1] means that the full set + of _M_names must be processed, the general case). + * include/bits/locale_classes.h (locale::_Impl::_M_check_same_name): + Tweak, saving work when !_M_names[1]. + (locale::locale(const locale&, _Facet*): Simplify: now just setting + _M_names[0] = 0 means unnamed. + * src/locale.cc (locale::operator==): Deal first with the common, + easy cases, otherwise fall back to locale::name(). + (locale::name()): Tweak, if !_M_names[0] just return "*". + (locale::_Impl::_Impl(const _Impl&, size_t): Tweak, early stop + copying __imp._M_names if !__imp._M_names[0] or !__imp._M_names[1]. + * src/locale_init.cc (locale::_Impl::_Impl(size_t)): Tweak. + * src/localename.cc (locale::_Impl::_Impl(const char*, size_t): + Simplify when !std::strchr, just updating _M_names[0]; clean up. + (locale::_Impl::_M_replace_categories): When !_M_names[1] prepare + for the general case (full set of names), then do the usual work; + clean up. + + * src/locale.cc (locale::name()): Reserve space in __ret. + * src/locale_init.cc (locale::global(const locale&)): Save + the name in a temporary. + * src/localename.cc (locale::locale(const char*)): Reserve space + in __str. + 2004-04-29 Paolo Carlini * src/locale.cc (locale::operator==): Always avoid constructing diff --git a/libstdc++-v3/include/bits/locale_classes.h b/libstdc++-v3/include/bits/locale_classes.h index 926ce209b24..5366d652433 100644 --- a/libstdc++-v3/include/bits/locale_classes.h +++ b/libstdc++-v3/include/bits/locale_classes.h @@ -534,8 +534,10 @@ namespace std _M_check_same_name() { bool __ret = true; - for (size_t __i = 0; __ret && __i < _S_categories_size - 1; ++__i) - __ret = std::strcmp(_M_names[__i], _M_names[__i + 1]) == 0; + if (_M_names[1]) + // We must actually compare all the _M_names: can be all equal! + for (size_t __i = 0; __ret && __i < _S_categories_size - 1; ++__i) + __ret = std::strcmp(_M_names[__i], _M_names[__i + 1]) == 0; return __ret; } @@ -569,30 +571,15 @@ namespace std { _M_impl = new _Impl(*__other._M_impl, 1); - char* _M_tmp_names[_S_categories_size]; - size_t __i = 0; try - { - for (; __i < _S_categories_size; ++__i) - { - _M_tmp_names[__i] = new char[2]; - std::strcpy(_M_tmp_names[__i], "*"); - } - _M_impl->_M_install_facet(&_Facet::id, __f); - } + { _M_impl->_M_install_facet(&_Facet::id, __f); } catch(...) { _M_impl->_M_remove_reference(); - for (size_t __j = 0; __j < __i; ++__j) - delete [] _M_tmp_names[__j]; __throw_exception_again; } - - for (size_t __k = 0; __k < _S_categories_size; ++__k) - { - delete [] _M_impl->_M_names[__k]; - _M_impl->_M_names[__k] = _M_tmp_names[__k]; - } + delete [] _M_impl->_M_names[0]; + _M_impl->_M_names[0] = 0; // Unnamed. } } // namespace std diff --git a/libstdc++-v3/src/locale.cc b/libstdc++-v3/src/locale.cc index af4f34de708..64d0c6227ae 100644 --- a/libstdc++-v3/src/locale.cc +++ b/libstdc++-v3/src/locale.cc @@ -70,15 +70,21 @@ namespace std bool locale::operator==(const locale& __rhs) const throw() { - bool __ret = true; + // Deal first with the common cases, fast to process: refcopies, + // unnamed (i.e., !_M_names[0]), "simple" (!_M_names[1] => all the + // categories same name, i.e., _M_names[0]). Otherwise fall back + // to the general locale::name(). + bool __ret; if (_M_impl == __rhs._M_impl) - ; - else if (!std::strcmp(_M_impl->_M_names[0], "*")) + __ret = true; + else if (!_M_impl->_M_names[0] || !__rhs._M_impl->_M_names[0] + || std::strcmp(_M_impl->_M_names[0], + __rhs._M_impl->_M_names[0]) != 0) __ret = false; + else if (!_M_impl->_M_names[1] && !__rhs._M_impl->_M_names[1]) + __ret = true; else - for (size_t __i = 0; __ret && __i < _S_categories_size; ++__i) - __ret = !std::strcmp(_M_impl->_M_names[__i], - __rhs._M_impl->_M_names[__i]); + __ret = this->name() == __rhs.name(); return __ret; } @@ -95,10 +101,13 @@ namespace std locale::name() const { string __ret; - if (_M_impl->_M_check_same_name()) + if (!_M_impl->_M_names[0]) + __ret = '*'; + else if (_M_impl->_M_check_same_name()) __ret = _M_impl->_M_names[0]; else { + __ret.reserve(128); __ret += _S_categories[0]; __ret += '='; __ret += _M_impl->_M_names[0]; @@ -242,12 +251,13 @@ namespace std for (size_t __i = 0; __i < _S_categories_size; ++__i) _M_names[__i] = 0; - // Name all the categories. - for (size_t __i = 0; __i < _S_categories_size; ++__i) + // Name the categories. + for (size_t __i = 0; (__i < _S_categories_size + && __imp._M_names[__i]); ++__i) { - char* __new = new char[std::strlen(__imp._M_names[__i]) + 1]; - std::strcpy(__new, __imp._M_names[__i]); - _M_names[__i] = __new; + const size_t __len = std::strlen(__imp._M_names[__i]) + 1; + _M_names[__i] = new char[__len]; + std::memcpy(_M_names[__i], __imp._M_names[__i], __len); } } catch(...) @@ -354,7 +364,6 @@ namespace std } } - // locale::id // Definitions for static const data members of locale::id _Atomic_word locale::id::_S_refcount; // init'd to 0 by linker diff --git a/libstdc++-v3/src/locale_init.cc b/libstdc++-v3/src/locale_init.cc index c1dac9f7a7c..d5a337f5b37 100644 --- a/libstdc++-v3/src/locale_init.cc +++ b/libstdc++-v3/src/locale_init.cc @@ -114,9 +114,10 @@ namespace std __glibcxx_mutex_lock(__gnu_internal::locale_global_mutex); _Impl* __old = _S_global; __other._M_impl->_M_add_reference(); - _S_global = __other._M_impl; - if (__other.name() != "*") - setlocale(LC_ALL, __other.name().c_str()); + _S_global = __other._M_impl; + const string __other_name = __other.name(); + if (__other_name != "*") + setlocale(LC_ALL, __other_name.c_str()); __glibcxx_mutex_unlock(__gnu_internal::locale_global_mutex); // Reference count sanity check: one reference removed for the @@ -255,13 +256,12 @@ namespace std for (size_t __i = 0; __i < _M_facets_size; ++__i) _M_facets[__i] = _M_caches[__i] = 0; - // Name all the categories. + // Name the categories. _M_names = new (&name_vec) char*[_S_categories_size]; - for (size_t __i = 0; __i < _S_categories_size; ++__i) - { - _M_names[__i] = new (&name_c[__i]) char[2]; - std::strcpy(_M_names[__i], locale::facet::_S_get_c_name()); - } + _M_names[0] = new (&name_c[0]) char[2]; + std::memcpy(_M_names[0], locale::facet::_S_get_c_name(), 2); + for (size_t __i = 1; __i < _S_categories_size; ++__i) + _M_names[__i] = 0; // This is needed as presently the C++ version of "C" locales // != data in the underlying locale model for __timepunct, diff --git a/libstdc++-v3/src/localename.cc b/libstdc++-v3/src/localename.cc index 4cd1af189fa..ca09b065156 100644 --- a/libstdc++-v3/src/localename.cc +++ b/libstdc++-v3/src/localename.cc @@ -1,4 +1,4 @@ -// Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003 +// 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 @@ -34,7 +34,6 @@ namespace std { using namespace __gnu_cxx; - locale::locale(const char* __s) { if (__s) @@ -95,6 +94,7 @@ namespace std if (__i < _S_categories_size) { string __str; + __str.reserve(128); for (size_t __j = 0; __j < __i; ++__j) { __str += _S_categories[__j]; @@ -199,15 +199,12 @@ namespace std for (size_t __i = 0; __i < _S_categories_size; ++__i) _M_names[__i] = 0; - // Name all the categories. + // Name the categories. const size_t __len = std::strlen(__s); if (!std::strchr(__s, ';')) { - for (size_t __i = 0; __i < _S_categories_size; ++__i) - { - _M_names[__i] = new char[__len + 1]; - std::strcpy(_M_names[__i], __s); - } + _M_names[0] = new char[__len + 1]; + std::memcpy(_M_names[0], __s, __len + 1); } else { @@ -218,10 +215,9 @@ namespace std const char* __end = std::strchr(__beg, ';'); if (!__end) __end = __s + __len; - char* __new = new char[__end - __beg + 1]; - std::memcpy(__new, __beg, __end - __beg); - __new[__end - __beg] = '\0'; - _M_names[__i] = __new; + _M_names[__i] = new char[__end - __beg + 1]; + std::memcpy(_M_names[__i], __beg, __end - __beg); + _M_names[__i][__end - __beg] = '\0'; } } @@ -271,19 +267,35 @@ namespace std locale::_Impl:: _M_replace_categories(const _Impl* __imp, category __cat) { - for (size_t __ix = 0; __ix < _S_categories_size; ++__ix) + category __mask = 1; + const bool __have_names = _M_names[0] && __imp->_M_names[0]; + for (size_t __ix = 0; __ix < _S_categories_size; ++__ix, __mask <<= 1) { - const category __mask = 1 << __ix; if (__mask & __cat) { // Need to replace entry in _M_facets with other locale's info. _M_replace_category(__imp, _S_facet_categories[__ix]); // If both have names, go ahead and mangle. - if (std::strcmp(_M_names[__ix], "*") != 0 - && std::strcmp(__imp->_M_names[__ix], "*") != 0) + if (__have_names) { - char* __new = new char[std::strlen(__imp->_M_names[__ix]) + 1]; - std::strcpy(__new, __imp->_M_names[__ix]); + if (!_M_names[1]) + { + // A full set of _M_names must be prepared, all identical + // to _M_names[0] to begin with. Then, below, a few will + // be replaced by the corresponding __imp->_M_names. I.e., + // not a "simple" locale anymore (see locale::operator==). + const size_t __len = std::strlen(_M_names[0]) + 1; + for (size_t __i = 1; __i < _S_categories_size; ++__i) + { + _M_names[__i] = new char[__len]; + std::memcpy(_M_names[__i], _M_names[0], __len); + } + } + char* __src = __imp->_M_names[__ix] ? __imp->_M_names[__ix] + : __imp->_M_names[0]; + const size_t __len = std::strlen(__src) + 1; + char* __new = new char[__len]; + std::memcpy(__new, __src, __len); delete [] _M_names[__ix]; _M_names[__ix] = __new; } -- 2.30.2