summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMikhail Kashkarov <m.kashkarov@partner.samsung.com>2018-06-08 12:22:33 +0300
committerMikhail Kashkarov <m.kashkarov@partner.samsung.com>2018-06-28 10:02:50 +0300
commitac526093f22cdc8c77919a25ff7b36a47a0f46bb (patch)
tree8943edf00ceb05b99bfb40bb08254dbd4010ba25
parentdc3d9ea9327d64a014f17758c94615ff3de7c75d (diff)
downloadlinaro-gcc-sandbox/mkashkarov/disable_string_sso.tar.gz
linaro-gcc-sandbox/mkashkarov/disable_string_sso.tar.bz2
linaro-gcc-sandbox/mkashkarov/disable_string_sso.zip
Add option to disable c++11 std::basic_string SSO optimization.sandbox/mkashkarov/disable_string_sso
* 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.
-rw-r--r--libstdc++-v3/include/bits/basic_string.h104
-rw-r--r--libstdc++-v3/include/bits/basic_string.tcc46
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/allocator/char/copy_assign.cc4
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/allocator/wchar_t/copy_assign.cc4
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/init-list.cc2
-rw-r--r--libstdc++-v3/testsuite/util/regression/rand/assoc/rand_regression_test.hpp5
-rw-r--r--libstdc++-v3/testsuite/util/regression/rand/priority_queue/rand_regression_test.hpp5
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;