In !_GLIBCXX_USE_CXX11_ABI implementation, string::clear() calls
_M_mutate(), which could allocate memory as we do COW. This hurts
performance when string::clear() is on the hot path.
This patch improves it by using _S_empty_rep directly when
_GLIBCXX_FULLY_DYNAMIC_STRING is not enabled. And Linux distro like
Fedora doesn't enable this, this is why we caught it.
The copy-and-clear test shows it improves by 50%.
Ran all testsuites on Linux-x64.
2016-09-13 Cong Wang <[email protected]>
PR libstdc++/77582
* libstdc++-v3/include/bits/basic_string.h: Change inline to a declaration.
* libstdc++-v3/include/bits/basic_string.tcc: Inline the
implementation based on _M_mutate, and use _S_empty_rep when possible.
* libstdc++-v3/testsuite/performance/21_strings/copy_and_clear.cc: New.
diff --git a/libstdc++-v3/include/bits/basic_string.h
b/libstdc++-v3/include/bits/basic_string.h
index e823f13..94d1df2 100644
--- a/libstdc++-v3/include/bits/basic_string.h
+++ b/libstdc++-v3/include/bits/basic_string.h
@@ -3686,8 +3686,7 @@ _GLIBCXX_END_NAMESPACE_CXX11
*/
// PR 56166: this should not throw.
void
- clear()
- { _M_mutate(0, this->size(), 0); }
+ clear();
/**
* 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 0080d2b..935932e 100644
--- a/libstdc++-v3/include/bits/basic_string.tcc
+++ b/libstdc++-v3/include/bits/basic_string.tcc
@@ -966,6 +966,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _CharT, typename _Traits, typename _Alloc>
void
basic_string<_CharT, _Traits, _Alloc>::
+ clear()
+ {
+ if (_M_rep()->_M_is_shared())
+ {
+ const allocator_type __a = get_allocator();
+ _Rep* __r;
+
+#if _GLIBCXX_FULLY_DYNAMIC_STRING == 0
+ __r = &_S_empty_rep();
+#else
+ // Must reallocate.
+ __r = _Rep::_S_create(0, this->capacity(), __a);
+#endif
+ _M_rep()->_M_dispose(__a);
+ _M_data(__r->_M_refdata());
+ }
+ _M_rep()->_M_set_length_and_sharable(0);
+ }
+
+ template<typename _CharT, typename _Traits, typename _Alloc>
+ void
+ basic_string<_CharT, _Traits, _Alloc>::
swap(basic_string& __s)
{
if (_M_rep()->_M_is_leaked())
diff --git a/libstdc++-v3/testsuite/performance/21_strings/copy_and_clear.cc
b/libstdc++-v3/testsuite/performance/21_strings/copy_and_clear.cc
new file mode 100644
index 0000000..708f053
--- /dev/null
+++ b/libstdc++-v3/testsuite/performance/21_strings/copy_and_clear.cc
@@ -0,0 +1,49 @@
+// Copyright (C) 2006-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
+// <http://www.gnu.org/licenses/>.
+
+
+#include <string>
+#include <testsuite_performance.h>
+
+void benchmark(long len)
+{
+ using namespace std;
+ using namespace __gnu_test;
+
+ time_counter time;
+ resource_counter resource;
+
+ start_counters(time, resource);
+ for (long i = 0; i < len; ++i)
+ {
+ string ss1("1");
+ string ss2(ss1);
+ ss1.clear();
+ }
+ stop_counters(time, resource);
+
+ report_performance(__FILE__, "", time, resource);
+ clear_counters(time, resource);
+}
+
+int main()
+{
+ benchmark(1000000);
+ benchmark(10000000);
+ benchmark(100000000);
+ return 0;
+}