From 2b588cbf15d89fae557dc03221e67ee4d61d43d2 Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Thu, 8 Mar 2018 21:15:26 +0000 Subject: [PATCH] Low-hanging fruit optimization in string::__move_assign(). shrink_to_fit() ends up doing a lot work to get information that we already know since we just called clear(). This change seems concise enough to be worth the couple extra lines and my benchmarks show that it is indeed a pretty decent win. It looks like the same thing is going on twice in __copy_assign_alloc(), but I didn't want to go overboard since this is my first contribution to llvm/libc++. Patch by Timothy VanSlyke! Differential Revision: https://reviews.llvm.org/D41976 git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@327064 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/string | 27 ++++++++--- .../clear_and_shrink_db1.pass.cpp | 48 +++++++++++++++++++ 2 files changed, 69 insertions(+), 6 deletions(-) create mode 100644 test/libcxx/strings/basic.string/string.modifiers/clear_and_shrink_db1.pass.cpp diff --git a/include/string b/include/string index e8ec709c2..2630799c0 100644 --- a/include/string +++ b/include/string @@ -1257,6 +1257,8 @@ public: _LIBCPP_INLINE_VISIBILITY bool __invariants() const; + _LIBCPP_INLINE_VISIBILITY void __clear_and_shrink(); + _LIBCPP_INLINE_VISIBILITY bool __is_long() const _NOEXCEPT {return bool(__r_.first().__s.__size_ & __short_mask);} @@ -1426,16 +1428,14 @@ private: { 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()); @@ -2125,8 +2125,7 @@ basic_string<_CharT, _Traits, _Allocator>::__move_assign(basic_string& __str, tr _NOEXCEPT_(is_nothrow_move_assignable::value) #endif { - clear(); - shrink_to_fit(); + __clear_and_shrink(); __r_.first() = __str.__r_.first(); __move_assign_alloc(__str); __str.__zero(); @@ -3579,6 +3578,22 @@ basic_string<_CharT, _Traits, _Allocator>::__invariants() const return true; } +// __clear_and_shrink + +template +inline _LIBCPP_INLINE_VISIBILITY +void +basic_string<_CharT, _Traits, _Allocator>::__clear_and_shrink() +{ + clear(); + if(__is_long()) + { + __alloc_traits::deallocate(__alloc(), __get_long_pointer(), capacity() + 1); + __set_long_cap(0); + __set_short_size(0); + } +} + // operator== template diff --git a/test/libcxx/strings/basic.string/string.modifiers/clear_and_shrink_db1.pass.cpp b/test/libcxx/strings/basic.string/string.modifiers/clear_and_shrink_db1.pass.cpp new file mode 100644 index 000000000..b7e278b75 --- /dev/null +++ b/test/libcxx/strings/basic.string/string.modifiers/clear_and_shrink_db1.pass.cpp @@ -0,0 +1,48 @@ +//===----------------------------------------------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +// + +// 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 +#include + +int main() +{ + std::string l = "Long string so that allocation definitely, for sure, absolutely happens. Probably."; + std::string s = "short"; + + assert(l.__invariants()); + assert(s.__invariants()); + + s.__clear_and_shrink(); + assert(s.__invariants()); + assert(s.size() == 0); + + { + std::string::size_type cap = l.capacity(); + l.__clear_and_shrink(); + assert(l.__invariants()); + assert(l.size() == 0); + assert(l.capacity() < cap); + } +} + +#else + +int main() +{ +} + +#endif