public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r13-5700] libstdc++: Optimize basic_string move assignment
@ 2023-02-04 13:05 Francois Dumont
0 siblings, 0 replies; only message in thread
From: Francois Dumont @ 2023-02-04 13:05 UTC (permalink / raw)
To: gcc-cvs, libstdc++-cvs
https://gcc.gnu.org/g:540a22d243966d1b882db26b17fe674467e2a169
commit r13-5700-g540a22d243966d1b882db26b17fe674467e2a169
Author: François Dumont <fdumont@gcc.gnu.org>
Date: Wed Jan 4 19:34:21 2023 +0100
libstdc++: Optimize basic_string move assignment
Since resolution of Issue 2593 [1] we can consider that equal allocators
before the propagate-on-move-assignment operations will still be equal
afterward.
So we can extend the optimization of transfering the storage of the move-to
instance to the move-from one that is currently limited to always equal
allocators.
[1] https://cplusplus.github.io/LWG/issue2593
libstdc++-v3/ChangeLog:
* include/bits/basic_string.h (operator=(basic_string&&)): Transfer move-to
storage to the move-from instance when allocators are equal.
* testsuite/21_strings/basic_string/allocator/char/move_assign.cc (test04):
New test case.
Diff:
---
libstdc++-v3/include/bits/basic_string.h | 11 +++--
.../basic_string/allocator/char/move_assign.cc | 52 ++++++++++++++++++++++
2 files changed, 57 insertions(+), 6 deletions(-)
diff --git a/libstdc++-v3/include/bits/basic_string.h b/libstdc++-v3/include/bits/basic_string.h
index aa018262c98..c81dc0d425a 100644
--- a/libstdc++-v3/include/bits/basic_string.h
+++ b/libstdc++-v3/include/bits/basic_string.h
@@ -844,9 +844,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
operator=(basic_string&& __str)
noexcept(_Alloc_traits::_S_nothrow_move())
{
+ const bool __equal_allocs = _Alloc_traits::_S_always_equal()
+ || _M_get_allocator() == __str._M_get_allocator();
if (!_M_is_local() && _Alloc_traits::_S_propagate_on_move_assign()
- && !_Alloc_traits::_S_always_equal()
- && _M_get_allocator() != __str._M_get_allocator())
+ && !__equal_allocs)
{
// Destroy existing storage before replacing allocator.
_M_destroy(_M_allocated_capacity);
@@ -868,16 +869,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
_M_set_length(__str.size());
}
}
- else if (_Alloc_traits::_S_propagate_on_move_assign()
- || _Alloc_traits::_S_always_equal()
- || _M_get_allocator() == __str._M_get_allocator())
+ else if (_Alloc_traits::_S_propagate_on_move_assign() || __equal_allocs)
{
// Just move the allocated pointer, our allocator can free it.
pointer __data = nullptr;
size_type __capacity;
if (!_M_is_local())
{
- if (_Alloc_traits::_S_always_equal())
+ if (__equal_allocs)
{
// __str can reuse our existing storage.
__data = _M_data();
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/allocator/char/move_assign.cc b/libstdc++-v3/testsuite/21_strings/basic_string/allocator/char/move_assign.cc
index cc58348e116..21e0b1cb4f4 100644
--- a/libstdc++-v3/testsuite/21_strings/basic_string/allocator/char/move_assign.cc
+++ b/libstdc++-v3/testsuite/21_strings/basic_string/allocator/char/move_assign.cc
@@ -28,6 +28,8 @@ const C c = 'a';
using traits = std::char_traits<C>;
using __gnu_test::propagating_allocator;
+using __gnu_test::tracker_allocator_counter;
+using __gnu_test::tracker_allocator;
void test01()
{
@@ -146,10 +148,60 @@ void test03()
VERIFY(7 == v8.get_allocator().get_personality());
}
+void test04()
+{
+ typedef propagating_allocator<C, true, tracker_allocator<C>> alloc_type;
+ typedef std::basic_string<C, traits, alloc_type> test_type;
+
+ {
+ tracker_allocator_counter::reset();
+ test_type v1(alloc_type(1));
+ v1 = "abcdefghijklmnopqr10";
+ auto ref_alloc_count = tracker_allocator_counter::get_allocation_count();
+
+ test_type v2(alloc_type(2));
+ v2 = "abcdefghijklmnopqr20";
+ v2 = std::move(v1);
+ VERIFY(1 == v1.get_allocator().get_personality());
+ VERIFY(1 == v2.get_allocator().get_personality());
+
+ VERIFY( tracker_allocator_counter::get_allocation_count() == 2 * ref_alloc_count );
+ VERIFY( tracker_allocator_counter::get_deallocation_count() == ref_alloc_count );
+
+ v1 = "abcdefghijklmnopqr11";
+
+ VERIFY( tracker_allocator_counter::get_allocation_count() == 3 * ref_alloc_count );
+ }
+
+ {
+ tracker_allocator_counter::reset();
+ test_type v1(alloc_type(1));
+ v1 = "abcdefghijklmnopqr10";
+ auto ref_alloc_count = tracker_allocator_counter::get_allocation_count();
+
+ test_type v2(alloc_type(1));
+ v2 = "abcdefghijklmnopqr20";
+ v2 = std::move(v1);
+ VERIFY(1 == v1.get_allocator().get_personality());
+ VERIFY(1 == v2.get_allocator().get_personality());
+
+ VERIFY( tracker_allocator_counter::get_allocation_count() == 2 * ref_alloc_count );
+ VERIFY( tracker_allocator_counter::get_deallocation_count() == 0 );
+
+ v1 = "abcdefghijklmnopqr11";
+
+ VERIFY( tracker_allocator_counter::get_allocation_count() == 2 * ref_alloc_count );
+ }
+
+ VERIFY( tracker_allocator_counter::get_allocation_count() ==
+ tracker_allocator_counter::get_deallocation_count() );
+}
+
int main()
{
test01();
test02();
test03();
+ test04();
return 0;
}
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2023-02-04 13:05 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-02-04 13:05 [gcc r13-5700] libstdc++: Optimize basic_string move assignment Francois Dumont
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).