aboutsummaryrefslogtreecommitdiff
path: root/libstdc++-v3
diff options
context:
space:
mode:
authorFrançois Dumont <fdumont@gcc.gnu.org>2023-01-04 19:34:21 +0100
committerFrançois Dumont <fdumont@gcc.gnu.org>2023-02-04 14:03:54 +0100
commit540a22d243966d1b882db26b17fe674467e2a169 (patch)
tree3d5616980078acbf6d95ed2f778b91d566d6bb87 /libstdc++-v3
parent49e52115b09b477382fef6f04fd7b4d1641f902c (diff)
downloadgcc-540a22d243966d1b882db26b17fe674467e2a169.zip
gcc-540a22d243966d1b882db26b17fe674467e2a169.tar.gz
gcc-540a22d243966d1b882db26b17fe674467e2a169.tar.bz2
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.
Diffstat (limited to 'libstdc++-v3')
-rw-r--r--libstdc++-v3/include/bits/basic_string.h11
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/allocator/char/move_assign.cc52
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 aa01826..c81dc0d 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 cc58348e..21e0b1c 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;
}