Updated.
On 05/29/2018 09:53 AM, Mikhail Kashkarov wrote: > Add option to disable c++11 std::string small-string optimization usage. > > * include/bits/basic_string.h [_GLIBCXX_DISABLE_STRING_SSO_USAGE]: > (basic_string::_M_is_local, basic_string::_M_destroy) > (basic_string::basic_string, basic_string::basic_string(const _Alloc&)) > (basic_string::basic_string(basic_string&&)) > (basic_string::basic_string(basic_string&&, const _Alloc&)) > (basic_string::operator=(const basic_string&)) > (basic_string::operator=(basic_string&&)) > (basic_string::clear()): Disable usage of _M_local_buf if > _GLIBCXX_DISABLE_STRING_SSO_USAGE is defined. > * include/bits/basic_string.tcc [_GLIBCXX_DISABLE_STRING_SSO_USAGE]: > (basic_string::_M_construct, basic_string::reserve) > (basic_string::_M_replace): Disable usage of _M_local_buf if > _GLIBCXX_DISABLE_STRING_SSO_USAGE is defined. > * testsuite/basic_string/allocator/char/copy_assign.cc: Support for > std::string without SSO. > * testsuite/basic_string/allocator/wchar_t/copy_assign.cc: Likewise. > * testsuite/21_strings/basic_string/init-list.cc: Likewise. > * testsuite/rand/assoc/rand_regression_test.hpp: Likewise. > * testsuite/rand/priority_queue/rand_regression_test.hpp: Likewise. > -- Best regards, Kashkarov Mikhail Samsung R&D Institute Russia
From 49c34919fba3000d751ac505b498eb6b21b0f4b3 Mon Sep 17 00:00:00 2001 From: Mikhail Kashkarov <m.kashka...@partner.samsung.com> Date: Fri, 8 Jun 2018 12:22:33 +0300 Subject: [PATCH 1/2] Add option to disable c++11 std::basic_string SSO optimization. * include/bits/basic_string.h [_GLIBCXX_DISABLE_STRING_SSO_USAGE]: (basic_string::_M_is_local()) (basic_string::_M_destroy(size_type __size)) (basic_string::basic_string()) (basic_string::basic_string(const _Alloc& __a)) (basic_string::basic_string(basic_string&& __str)) (basic_string::basic_string(basic_string&& __str, const _Alloc& __a)) (basic_string::operator=(const basic_string& __str)) (basic_string::operator=(basic_string&& __str)) (basic_string::clear()): Disable usage of _M_local_buf if _GLIBCXX_DISABLE_STRING_SSO_USAGE is defined. * include/bits/basic_string.tcc [_GLIBCXX_DISABLE_STRING_SSO_USAGE]: (basic_string::_M_construct, basic_string::reserve) (basic_string::_M_replace): Disable usage of _M_local_buf if _GLIBCXX_DISABLE_STRING_SSO_USAGE is defined. * testsuite/basic_string/allocator/char/copy_assign.cc: Support for std::string without SSO. * testsuite/basic_string/allocator/wchar_t/copy_assign.cc: Likewise. * testsuite/21_strings/basic_string/init-list.cc: Likewise. * testsuite/rand/assoc/rand_regression_test.hpp: Likewise. * testsuite/rand/priority_queue/rand_regression_test.hpp: Likewise. --- libstdc++-v3/include/bits/basic_string.h | 104 +++++++++++++++++++-- libstdc++-v3/include/bits/basic_string.tcc | 46 ++++++++- .../basic_string/allocator/char/copy_assign.cc | 4 + .../basic_string/allocator/wchar_t/copy_assign.cc | 4 + .../testsuite/21_strings/basic_string/init-list.cc | 2 + .../regression/rand/assoc/rand_regression_test.hpp | 5 + .../rand/priority_queue/rand_regression_test.hpp | 5 + 7 files changed, 156 insertions(+), 14 deletions(-) diff --git a/libstdc++-v3/include/bits/basic_string.h b/libstdc++-v3/include/bits/basic_string.h index 5bffa1c..9d971c0 100644 --- a/libstdc++-v3/include/bits/basic_string.h +++ b/libstdc++-v3/include/bits/basic_string.h @@ -208,7 +208,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 bool _M_is_local() const - { return _M_data() == _M_local_data(); } + { +#if _GLIBCXX_DISABLE_STRING_SSO_USAGE + return false; +#else + return _M_data() == _M_local_data(); +#endif + } // Create & Destroy pointer @@ -223,7 +229,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 void _M_destroy(size_type __size) throw() - { _Alloc_traits::deallocate(_M_get_allocator(), _M_data(), __size + 1); } + { +#if _GLIBCXX_DISABLE_STRING_SSO_USAGE + if (!_M_allocated_capacity) + return; +#endif + _Alloc_traits::deallocate(_M_get_allocator(), _M_data(), __size + 1); + } // _M_construct_aux is used to implement the 21.3.1 para 15 which // requires special behaviour if _InIterator is an integral type @@ -420,7 +432,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 basic_string() _GLIBCXX_NOEXCEPT_IF(is_nothrow_default_constructible<_Alloc>::value) : _M_dataplus(_M_local_data()) - { _M_set_length(0); } + { +#if _GLIBCXX_DISABLE_STRING_SSO_USAGE + _M_length(0); + _M_capacity(0); +#else + _M_set_length(0); +#endif + } /** * @brief Construct an empty string using allocator @a a. @@ -428,7 +447,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 explicit basic_string(const _Alloc& __a) _GLIBCXX_NOEXCEPT : _M_dataplus(_M_local_data(), __a) - { _M_set_length(0); } + { +#if _GLIBCXX_DISABLE_STRING_SSO_USAGE + _M_length(0); + _M_capacity(0); +#else + _M_set_length(0); +#endif + } /** * @brief Construct string with copy of value of @a __str. @@ -531,12 +557,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 basic_string(basic_string&& __str) noexcept : _M_dataplus(_M_local_data(), std::move(__str._M_get_allocator())) { +#if !_GLIBCXX_DISABLE_STRING_SSO_USAGE if (__str._M_is_local()) { traits_type::copy(_M_local_buf, __str._M_local_buf, _S_local_capacity + 1); } else +#endif { _M_data(__str._M_data()); _M_capacity(__str._M_allocated_capacity); @@ -546,8 +574,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 // basic_stringbuf relies on writing into unallocated capacity so // we mess up the contents if we put a '\0' in the string. _M_length(__str.length()); +#if _GLIBCXX_DISABLE_STRING_SSO_USAGE + __str._M_data(nullptr); + __str._M_length(0); + __str._M_capacity(0); +#else __str._M_data(__str._M_local_data()); __str._M_set_length(0); +#endif } /** @@ -567,6 +601,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 noexcept(_Alloc_traits::_S_always_equal()) : _M_dataplus(_M_local_data(), __a) { +#if !_GLIBCXX_DISABLE_STRING_SSO_USAGE if (__str._M_is_local()) { traits_type::copy(_M_local_buf, __str._M_local_buf, @@ -574,14 +609,23 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 _M_length(__str.length()); __str._M_set_length(0); } - else if (_Alloc_traits::_S_always_equal() + else +#endif + if (_Alloc_traits::_S_always_equal() || __str.get_allocator() == __a) { _M_data(__str._M_data()); _M_length(__str.length()); _M_capacity(__str._M_allocated_capacity); +#if _GLIBCXX_DISABLE_STRING_SSO_USAGE + __str._M_data(nullptr); + __str._M_length(0); + __str._M_capacity(0); +#else __str._M_data(__str._M_local_buf); __str._M_set_length(0); +#endif + } else _M_construct(__str.begin(), __str.end()); @@ -661,6 +705,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 { // Propagating allocator cannot free existing storage so must // deallocate it before replacing current allocator. +#if !_GLIBCXX_DISABLE_STRING_SSO_USAGE if (__str.size() <= _S_local_capacity) { _M_destroy(_M_allocated_capacity); @@ -668,14 +713,21 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 _M_set_length(0); } else +#endif { const auto __len = __str.size(); auto __alloc = __str._M_get_allocator(); +#if _GLIBCXX_DISABLE_STRING_SSO_USAGE + const auto __new_cap = __len > size_type(_S_local_capacity) + ? __len : size_type(_S_local_capacity); +#else + const auto __new_cap = __len; +#endif // If this allocation throws there are no effects: - auto __ptr = _Alloc_traits::allocate(__alloc, __len + 1); + auto __ptr = _Alloc_traits::allocate(__alloc, __new_cap + 1); _M_destroy(_M_allocated_capacity); _M_data(__ptr); - _M_capacity(__len); + _M_capacity(__new_cap); _M_set_length(__len); } } @@ -728,8 +780,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 { // Destroy existing storage before replacing allocator. _M_destroy(_M_allocated_capacity); +#if _GLIBCXX_DISABLE_STRING_SSO_USAGE + _M_length(0); + _M_capacity(0); +#else _M_data(_M_local_data()); _M_set_length(0); +#endif } // Replace allocator if POCMA is true. std::__alloc_on_move(_M_get_allocator(), __str._M_get_allocator()); @@ -740,15 +797,26 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 { pointer __data = nullptr; size_type __capacity; +#if _GLIBCXX_DISABLE_STRING_SSO_USAGE + size_type __length; +#endif if (!_M_is_local()) { if (_Alloc_traits::_S_always_equal()) { __data = _M_data(); __capacity = _M_allocated_capacity; +#if _GLIBCXX_DISABLE_STRING_SSO_USAGE + __length = _M_string_length; +#endif } - else + else { _M_destroy(_M_allocated_capacity); +#if _GLIBCXX_DISABLE_STRING_SSO_USAGE + _M_length(0); + _M_capacity(0); +#endif + } } _M_data(__str._M_data()); @@ -758,9 +826,19 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 { __str._M_data(__data); __str._M_capacity(__capacity); +#if _GLIBCXX_DISABLE_STRING_SSO_USAGE + __str._M_length(__length); +#endif } - else + else { +#if _GLIBCXX_DISABLE_STRING_SSO_USAGE + __str._M_data(nullptr); + __str._M_length(0); + __str._M_capacity(0); +#else __str._M_data(__str._M_local_buf); +#endif + } } else assign(__str); @@ -1002,7 +1080,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 */ void clear() _GLIBCXX_NOEXCEPT - { _M_set_length(0); } + { +#if _GLIBCXX_DISABLE_STRING_SSO_USAGE + _M_allocated_capacity ? _M_set_length(0) : _M_length(0); +#else + _M_set_length(0); +#endif + } /** * Returns true if the %string is empty. Equivalent to diff --git a/libstdc++-v3/include/bits/basic_string.tcc b/libstdc++-v3/include/bits/basic_string.tcc index be8815c..6b6c7eb 100644 --- a/libstdc++-v3/include/bits/basic_string.tcc +++ b/libstdc++-v3/include/bits/basic_string.tcc @@ -137,6 +137,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION if (__capacity > max_size()) std::__throw_length_error(__N("basic_string::_M_create")); + // The below implements an exponential growth policy, necessary to // meet amortized linear time requirements of the library: see // http://gcc.gnu.org/ml/libstdc++/2001-07/msg00085.html. @@ -165,7 +166,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION std::input_iterator_tag) { size_type __len = 0; +#if _GLIBCXX_DISABLE_STRING_SSO_USAGE + size_type __capacity = size_type(0); + _M_capacity(0); +#else size_type __capacity = size_type(_S_local_capacity); +#endif while (__beg != __end && __len < __capacity) { @@ -181,6 +187,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { // Allocate more space. __capacity = __len + 1; +#if _GLIBCXX_DISABLE_STRING_SSO_USAGE + if (__capacity < size_type(_S_local_capacity)) + __capacity = size_type(_S_local_capacity); +#endif pointer __another = _M_create(__capacity, __len); this->_S_copy(__another, _M_data(), __len); _M_dispose(); @@ -213,11 +223,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION "_M_construct null not valid")); size_type __dnew = static_cast<size_type>(std::distance(__beg, __end)); + size_type __new_capacity = __dnew; +#if _GLIBCXX_DISABLE_STRING_SSO_USAGE + if (__new_capacity < size_type(_S_local_capacity)) + __new_capacity = size_type(_S_local_capacity); +#endif +#if !_GLIBCXX_DISABLE_STRING_SSO_USAGE if (__dnew > size_type(_S_local_capacity)) +#endif { - _M_data(_M_create(__dnew, size_type(0))); - _M_capacity(__dnew); + _M_data(_M_create(__new_capacity, size_type(0))); + _M_capacity(__new_capacity); } // Check for out_of_range and length_error exceptions. @@ -237,10 +254,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION basic_string<_CharT, _Traits, _Alloc>:: _M_construct(size_type __n, _CharT __c) { + size_type __new_capacity = __n; +#if _GLIBCXX_DISABLE_STRING_SSO_USAGE + if (__new_capacity < size_type(_S_local_capacity)) + __new_capacity = size_type(_S_local_capacity); +#endif + +#if !_GLIBCXX_DISABLE_STRING_SSO_USAGE if (__n > size_type(_S_local_capacity)) +#endif { - _M_data(_M_create(__n, size_type(0))); - _M_capacity(__n); + _M_data(_M_create(__new_capacity, size_type(0))); + _M_capacity(__new_capacity); } if (__n) @@ -271,7 +296,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION if (__rsize) this->_S_copy(_M_data(), __str._M_data(), __rsize); +#if _GLIBCXX_DISABLE_STRING_SSO_USAGE + _M_allocated_capacity ? _M_set_length(__rsize) : _M_length(__rsize); +#else _M_set_length(__rsize); +#endif } } @@ -287,8 +316,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION const size_type __capacity = capacity(); if (__res != __capacity) { +#if !_GLIBCXX_DISABLE_STRING_SSO_USAGE if (__res > __capacity || __res > size_type(_S_local_capacity)) +#endif { pointer __tmp = _M_create(__res, __capacity); this->_S_copy(__tmp, _M_data(), length() + 1); @@ -296,12 +327,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_data(__tmp); _M_capacity(__res); } +#if !_GLIBCXX_DISABLE_STRING_SSO_USAGE else if (!_M_is_local()) { this->_S_copy(_M_local_data(), _M_data(), length() + 1); _M_destroy(__capacity); _M_data(_M_local_data()); } +#endif } } @@ -465,7 +498,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION else this->_M_mutate(__pos, __len1, __s, __len2); +#if _GLIBCXX_DISABLE_STRING_SSO_USAGE + this->_M_allocated_capacity ? this->_M_set_length(__new_size) : + this->_M_length(__new_size); +#else this->_M_set_length(__new_size); +#endif return *this; } diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/allocator/char/copy_assign.cc b/libstdc++-v3/testsuite/21_strings/basic_string/allocator/char/copy_assign.cc index 2e4a71e..91a8f88 100644 --- a/libstdc++-v3/testsuite/21_strings/basic_string/allocator/char/copy_assign.cc +++ b/libstdc++-v3/testsuite/21_strings/basic_string/allocator/char/copy_assign.cc @@ -122,7 +122,11 @@ void test03() VERIFY( v1 == s1 ); VERIFY( v1.get_allocator() == a1 ); +#if !_GLIBCXX_DISABLE_STRING_SSO_USAGE throw_alloc::set_limit(1); // Allow one more allocation (and no more). +#else + throw_alloc::set_limit(2); // Allow allocations if sso is disabled +#endif test_type v3(s1, a1); // No allocation when allocators are equal and capacity is sufficient: VERIFY( v1.capacity() >= v3.size() ); diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/allocator/wchar_t/copy_assign.cc b/libstdc++-v3/testsuite/21_strings/basic_string/allocator/wchar_t/copy_assign.cc index 5de9c9e..70c1461 100644 --- a/libstdc++-v3/testsuite/21_strings/basic_string/allocator/wchar_t/copy_assign.cc +++ b/libstdc++-v3/testsuite/21_strings/basic_string/allocator/wchar_t/copy_assign.cc @@ -122,7 +122,11 @@ void test03() VERIFY( v1 == s1 ); VERIFY( v1.get_allocator() == a1 ); +#if !_GLIBCXX_DISABLE_STRING_SSO_USAGE throw_alloc::set_limit(1); // Allow one more allocation (and no more). +#else + throw_alloc::set_limit(2); // Allow allocations if sso is disabled +#endif test_type v3(s1, a1); // No allocation when allocators are equal and capacity is sufficient: VERIFY( v1.capacity() >= v3.size() ); diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/init-list.cc b/libstdc++-v3/testsuite/21_strings/basic_string/init-list.cc index 2cc9cff..b1e0333 100644 --- a/libstdc++-v3/testsuite/21_strings/basic_string/init-list.cc +++ b/libstdc++-v3/testsuite/21_strings/basic_string/init-list.cc @@ -62,7 +62,9 @@ void test01(void) int main() { +#if !_GLIBCXX_DISABLE_STRING_SSO_USAGE __gnu_test::set_memory_limits(); +#endif test01(); return 0; } diff --git a/libstdc++-v3/testsuite/util/regression/rand/assoc/rand_regression_test.hpp b/libstdc++-v3/testsuite/util/regression/rand/assoc/rand_regression_test.hpp index 274a70c..c645d19 100644 --- a/libstdc++-v3/testsuite/util/regression/rand/assoc/rand_regression_test.hpp +++ b/libstdc++-v3/testsuite/util/regression/rand/assoc/rand_regression_test.hpp @@ -105,7 +105,12 @@ namespace detail size_t n = iter; size_t m = keys; size_t sd = twister_rand_gen::get_time_determined_seed(); + // Without SSO string can allocate memory when sso-string would not. +#if _GLIBCXX_DISABLE_STRING_SSO_USAGE + double tp = 0.0; +#else double tp = 0.2; +#endif double ip = 0.6; double ep = 0.2; double cp = 0.001; diff --git a/libstdc++-v3/testsuite/util/regression/rand/priority_queue/rand_regression_test.hpp b/libstdc++-v3/testsuite/util/regression/rand/priority_queue/rand_regression_test.hpp index 62eb19a..ca6e197 100644 --- a/libstdc++-v3/testsuite/util/regression/rand/priority_queue/rand_regression_test.hpp +++ b/libstdc++-v3/testsuite/util/regression/rand/priority_queue/rand_regression_test.hpp @@ -104,7 +104,12 @@ namespace detail size_t n = iter; size_t m = keys; size_t sd = twister_rand_gen::get_time_determined_seed(); + // Without SSO string can allocate memory when sso-string would not. +#if _GLIBCXX_DISABLE_STRING_SSO_USAGE + double tp = 0.0; +#else double tp = 0.2; +#endif double ip = 0.6; double dp = 0.1; double ep = 0.2; -- 2.7.4