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).