Skip to content

Commit fb36d07

Browse files
committedMar 8, 2018
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 llvm-svn: 327064
1 parent 145bc6e commit fb36d07

File tree

2 files changed

+69
-6
lines changed

2 files changed

+69
-6
lines changed
 

‎libcxx/include/string

+21-6
Original file line numberDiff line numberDiff line change
@@ -1257,6 +1257,8 @@ public:
12571257

12581258
_LIBCPP_INLINE_VISIBILITY bool __invariants() const;
12591259

1260+
_LIBCPP_INLINE_VISIBILITY void __clear_and_shrink();
1261+
12601262
_LIBCPP_INLINE_VISIBILITY
12611263
bool __is_long() const _NOEXCEPT
12621264
{return bool(__r_.first().__s.__size_ & __short_mask);}
@@ -1426,16 +1428,14 @@ private:
14261428
{
14271429
if (!__str.__is_long())
14281430
{
1429-
clear();
1430-
shrink_to_fit();
1431+
__clear_and_shrink();
14311432
__alloc() = __str.__alloc();
14321433
}
14331434
else
14341435
{
14351436
allocator_type __a = __str.__alloc();
14361437
pointer __p = __alloc_traits::allocate(__a, __str.__get_long_cap());
1437-
clear();
1438-
shrink_to_fit();
1438+
__clear_and_shrink();
14391439
__alloc() = _VSTD::move(__a);
14401440
__set_long_pointer(__p);
14411441
__set_long_cap(__str.__get_long_cap());
@@ -2125,8 +2125,7 @@ basic_string<_CharT, _Traits, _Allocator>::__move_assign(basic_string& __str, tr
21252125
_NOEXCEPT_(is_nothrow_move_assignable<allocator_type>::value)
21262126
#endif
21272127
{
2128-
clear();
2129-
shrink_to_fit();
2128+
__clear_and_shrink();
21302129
__r_.first() = __str.__r_.first();
21312130
__move_assign_alloc(__str);
21322131
__str.__zero();
@@ -3579,6 +3578,22 @@ basic_string<_CharT, _Traits, _Allocator>::__invariants() const
35793578
return true;
35803579
}
35813580

3581+
// __clear_and_shrink
3582+
3583+
template<class _CharT, class _Traits, class _Allocator>
3584+
inline _LIBCPP_INLINE_VISIBILITY
3585+
void
3586+
basic_string<_CharT, _Traits, _Allocator>::__clear_and_shrink()
3587+
{
3588+
clear();
3589+
if(__is_long())
3590+
{
3591+
__alloc_traits::deallocate(__alloc(), __get_long_pointer(), capacity() + 1);
3592+
__set_long_cap(0);
3593+
__set_short_size(0);
3594+
}
3595+
}
3596+
35823597
// operator==
35833598

35843599
template<class _CharT, class _Traits, class _Allocator>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is dual licensed under the MIT and the University of Illinois Open
6+
// Source Licenses. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
// <string>
11+
12+
// Call __clear_and_shrink() and ensure string invariants hold
13+
14+
#if _LIBCPP_DEBUG >= 1
15+
16+
#define _LIBCPP_ASSERT(x, m) ((x) ? (void)0 : std::exit(0))
17+
18+
#include <string>
19+
#include <cassert>
20+
21+
int main()
22+
{
23+
std::string l = "Long string so that allocation definitely, for sure, absolutely happens. Probably.";
24+
std::string s = "short";
25+
26+
assert(l.__invariants());
27+
assert(s.__invariants());
28+
29+
s.__clear_and_shrink();
30+
assert(s.__invariants());
31+
assert(s.size() == 0);
32+
33+
{
34+
std::string::size_type cap = l.capacity();
35+
l.__clear_and_shrink();
36+
assert(l.__invariants());
37+
assert(l.size() == 0);
38+
assert(l.capacity() < cap);
39+
}
40+
}
41+
42+
#else
43+
44+
int main()
45+
{
46+
}
47+
48+
#endif

0 commit comments

Comments
 (0)
Please sign in to comment.