From 13190419240ac47394feb896e0ff5f33e9f28906 Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Fri, 23 Sep 2016 18:25:34 +0100 Subject: [PATCH] Avoid reallocation for basic_string::clear() PR libstdc++/56166 PR libstdc++/77582 * include/bits/basic_string.h (basic_string::clear()): Drop reference and use empty rep. * include/ext/rc_string_base.h (__rc_string_base::_M_clear()): Likewise. * testsuite/21_strings/basic_string/56166.cc: New. * testsuite/ext/vstring/modifiers/clear/56166.cc: New. From-SVN: r240447 --- libstdc++-v3/ChangeLog | 9 ++ libstdc++-v3/include/bits/basic_string.h | 14 +++ libstdc++-v3/include/ext/rc_string_base.h | 5 +- .../21_strings/basic_string/56166.cc | 93 ++++++++++++++++++ .../ext/vstring/modifiers/clear/56166.cc | 96 +++++++++++++++++++ 5 files changed, 216 insertions(+), 1 deletion(-) create mode 100644 libstdc++-v3/testsuite/21_strings/basic_string/56166.cc create mode 100644 libstdc++-v3/testsuite/ext/vstring/modifiers/clear/56166.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 80bc018c9bb..22e4d0bfd77 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,14 @@ 2016-09-23 Jonathan Wakely + PR libstdc++/56166 + PR libstdc++/77582 + * include/bits/basic_string.h (basic_string::clear()): Drop reference + and use empty rep. + * include/ext/rc_string_base.h (__rc_string_base::_M_clear()): + Likewise. + * testsuite/21_strings/basic_string/56166.cc: New. + * testsuite/ext/vstring/modifiers/clear/56166.cc: New. + * include/bits/basic_string.h [_GLIBCXX_USE_CXX11_ABI] (basic_string::erase(size_type, size_type)): Add fast path for truncating the string, by calling _M_set_length directly. diff --git a/libstdc++-v3/include/bits/basic_string.h b/libstdc++-v3/include/bits/basic_string.h index 2708cbc60b7..7a4204e41c8 100644 --- a/libstdc++-v3/include/bits/basic_string.h +++ b/libstdc++-v3/include/bits/basic_string.h @@ -3690,10 +3690,24 @@ _GLIBCXX_END_NAMESPACE_CXX11 /** * Erases the string, making it empty. */ +#if _GLIBCXX_FULLY_DYNAMIC_STRING == 0 + void + clear() _GLIBCXX_NOEXCEPT + { + if (_M_rep()->_M_is_shared()) + { + _M_rep()->_M_dispose(this->get_allocator()); + _M_data(_S_empty_rep()._M_refdata()); + } + else + _M_rep()->_M_set_length_and_sharable(0); + } +#else // PR 56166: this should not throw. void clear() { _M_mutate(0, this->size(), 0); } +#endif /** * Returns true if the %string is empty. Equivalent to diff --git a/libstdc++-v3/include/ext/rc_string_base.h b/libstdc++-v3/include/ext/rc_string_base.h index 1c1ed87531f..eab34614946 100644 --- a/libstdc++-v3/include/ext/rc_string_base.h +++ b/libstdc++-v3/include/ext/rc_string_base.h @@ -354,7 +354,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION void _M_clear() - { _M_erase(size_type(0), _M_length()); } + { + _M_dispose(); + _M_data(_S_empty_rep._M_refcopy()); + } bool _M_compare(const __rc_string_base&) const diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/56166.cc b/libstdc++-v3/testsuite/21_strings/basic_string/56166.cc new file mode 100644 index 00000000000..3d4d876dbb1 --- /dev/null +++ b/libstdc++-v3/testsuite/21_strings/basic_string/56166.cc @@ -0,0 +1,93 @@ +// Copyright (C) 2016 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 3, 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 COPYING3. If not see +// . + +// { dg-do run { target c++11 } } + +// libstdc++/56166 + +#ifndef _GLIBCXX_USE_CXX11_ABI +# define _GLIBCXX_USE_CXX11_ABI 0 +#endif +#include +#include + +static int fail_after = -1; + +template + struct Allocator + { + using value_type = T; + + // Need these typedefs because COW string doesn't use allocator_traits. + using pointer = T*; + using const_pointer = const T*; + using reference = T&; + using const_reference = const T&; + using difference_type = long; + using size_type = unsigned long; + template + struct rebind { + using other = Allocator; + }; + + Allocator() { } + + template + Allocator(const Allocator&) { } + + T* allocate(size_type n) + { + if (fail_after >= 0) { + if (fail_after-- == 0) { + throw std::bad_alloc(); + } + } + return (T*)new char[n * sizeof(T)]; + } + + void deallocate(T* p, size_type) + { + delete[] (char*)p; + } + }; + +template + bool operator==(const Allocator&, const Allocator&) { return true; } +template + bool operator!=(const Allocator&, const Allocator&) { return false; } + +using string = std::basic_string, Allocator>; + +string f() +{ + string s1("xxxxxx"); + string s2 = s1; + s1.clear(); + return s2; +} + +int main() +{ + for (int i = 0; i < 10; i++) { + try { + fail_after = i; + f(); + break; + } catch (std::bad_alloc) { + } + } +} diff --git a/libstdc++-v3/testsuite/ext/vstring/modifiers/clear/56166.cc b/libstdc++-v3/testsuite/ext/vstring/modifiers/clear/56166.cc new file mode 100644 index 00000000000..109e6227372 --- /dev/null +++ b/libstdc++-v3/testsuite/ext/vstring/modifiers/clear/56166.cc @@ -0,0 +1,96 @@ +// Copyright (C) 2016 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 3, 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 COPYING3. If not see +// . + +// { dg-do run { target c++11 } } + +// libstdc++/56166 + +#ifndef _GLIBCXX_USE_CXX11_ABI +# define _GLIBCXX_USE_CXX11_ABI 0 +#endif +#include +#include + +static int fail_after = -1; + +template + struct Allocator + { + using value_type = T; + + // Need these typedefs because COW string doesn't use allocator_traits. + using pointer = T*; + using const_pointer = const T*; + using reference = T&; + using const_reference = const T&; + using difference_type = long; + using size_type = unsigned long; + template + struct rebind { + using other = Allocator; + }; + + Allocator() { } + + template + Allocator(const Allocator&) { } + + T* allocate(size_type n) + { + if (fail_after >= 0) { + if (fail_after-- == 0) { + throw std::bad_alloc(); + } + } + return (T*)new char[n * sizeof(T)]; + } + + void deallocate(T* p, size_type) + { + delete[] (char*)p; + } + }; + +template + bool operator==(const Allocator&, const Allocator&) { return true; } +template + bool operator!=(const Allocator&, const Allocator&) { return false; } + + +using string = __gnu_cxx::__versa_string, + Allocator, + __gnu_cxx::__rc_string_base>; + +string f() +{ + string s1("xxxxxx"); + string s2 = s1; + s1.clear(); + return s2; +} + +int main() +{ + for (int i = 0; i < 10; i++) { + try { + fail_after = i; + f(); + break; + } catch (std::bad_alloc) { + } + } +} -- 2.30.2