tvanslyke updated this revision to Diff 130775.
tvanslyke added a comment.

Since `__clear_and_shrink()` is private the test covers copy and move 
assignment.  I also ran the libcxx/strings/basic.string and std/strings tests 
with a hard-coded `assert(__invariants());` at the end of 
`__clear_and_shrink()` and saw no failures.

I don't have commit access myself so I've added the test to the diff.


https://reviews.llvm.org/D41976

Files:
  include/string
  
test/libcxx/strings/basic.string/string.modifiers/copy_assign_move_assign_db1.pass.cpp

Index: test/libcxx/strings/basic.string/string.modifiers/copy_assign_move_assign_db1.pass.cpp
===================================================================
--- test/libcxx/strings/basic.string/string.modifiers/copy_assign_move_assign_db1.pass.cpp
+++ test/libcxx/strings/basic.string/string.modifiers/copy_assign_move_assign_db1.pass.cpp
@@ -0,0 +1,66 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// <string>
+
+// Call __clear_and_shrink() and ensure string invariants hold
+
+#if _LIBCPP_DEBUG >= 1
+
+#define _LIBCPP_ASSERT(x, m) ((x) ? (void)0 : std::exit(0))
+
+#include <string>
+#include <cassert>
+
+int main()
+{
+    std::string l = "Long string so that allocation definitely, for sure, absolutely happens. Probably.";
+    std::string l2 = l;
+    std::string s = "short";
+    std::string s2 = s;
+    std::string empty = "";
+
+    assert(l.__invariants());
+    assert(s.__invariants());
+    assert(l2.__invariants());
+    assert(s2.__invariants());
+    assert(empty.__invariants());
+    
+    
+    s2 = empty;
+    assert(s2.__invariants());
+    assert(s2.size() == 0);
+    assert(empty.__invariants());
+    s2 = empty;
+    assert(s2.__invariants());
+    assert(s2.size() == 0);
+    assert(empty.__invariants());
+
+    { 
+    std::string::size_type cap = l.capacity();
+    l = empty;
+    assert(l.__invariants());
+    assert(l.size() == 0);
+    assert(empty.__invariants());
+    cap = l2.capacity();
+    l2 = std::move(empty);
+    assert(l2.capacity() < cap);
+    assert(l2.__invariants());
+    assert(l2.size() == 0);
+    assert(empty.__invariants());
+    }
+}
+
+#else
+
+int main()
+{
+}
+
+#endif
Index: include/string
===================================================================
--- include/string
+++ include/string
@@ -1407,24 +1407,34 @@
                       __alloc_traits::propagate_on_container_copy_assignment::value>());}
 
     _LIBCPP_INLINE_VISIBILITY
+    void __clear_and_shrink() 
+        {
+            clear();
+            if(__is_long())
+            {
+                __alloc_traits::deallocate(__alloc(), __get_long_pointer(), capacity() + 1);
+                __set_long_cap(0);
+                __set_short_size(0);
+            }
+        } 
+
+    _LIBCPP_INLINE_VISIBILITY
     void __copy_assign_alloc(const basic_string& __str, true_type)
         {
             if (__alloc() == __str.__alloc())
                 __alloc() = __str.__alloc();
             else
             {
                 if (!__str.__is_long())
                 {
-                    clear();
-                    shrink_to_fit();
+                    __clear_and_shrink();
                     __alloc() = __str.__alloc();
                 }
                 else
                 {
                     allocator_type __a = __str.__alloc();
                     pointer __p = __alloc_traits::allocate(__a, __str.__get_long_cap());
-                    clear();
-                    shrink_to_fit();
+                    __clear_and_shrink();
                     __alloc() = _VSTD::move(__a);
                     __set_long_pointer(__p);
                     __set_long_cap(__str.__get_long_cap());
@@ -2102,8 +2112,7 @@
     _NOEXCEPT_(is_nothrow_move_assignable<allocator_type>::value)
 #endif
 {
-    clear();
-    shrink_to_fit();
+    __clear_and_shrink();
     __r_.first() = __str.__r_.first();
     __move_assign_alloc(__str);
     __str.__zero();
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to