diff options
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 0352bf49fdc..3b0900670ce 100644 --- a/libstdc++-v3/include/bits/basic_string.h +++ b/libstdc++-v3/include/bits/basic_string.h @@ -168,7 +168,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 @@ -183,7 +189,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 @@ -380,7 +392,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. @@ -388,7 +407,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. @@ -476,12 +502,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); @@ -491,8 +519,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 } /** @@ -512,6 +546,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, @@ -519,14 +554,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()); @@ -572,6 +616,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); @@ -579,14 +624,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); } } @@ -639,8 +691,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()); @@ -651,15 +708,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()); @@ -669,9 +737,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); @@ -895,7 +973,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 2b6644d1c49..8195dede2bf 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 645e3cb7bfe..8bbad6f798f 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 @@ -123,7 +123,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 01cdba4eead..12237f44080 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 @@ -123,7 +123,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 067bbfda5c7..f2e36d2b261 100644 --- a/libstdc++-v3/testsuite/21_strings/basic_string/init-list.cc +++ b/libstdc++-v3/testsuite/21_strings/basic_string/init-list.cc @@ -66,7 +66,9 @@ int 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 5c9d0c67124..06c700c576a 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 7c1cd19a18e..6fd601a9ac0 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; |