Partially inline basic_string::operator=(const basic_string&)
Summary:
This change partially inlines operator=(const basic_string&) where both the input and current instance are short strings, making the assignment a fixed length inlined memcpy.
Assignments where either of the strings are long are delegate to __assign_no_alias<__is_short>(), which is templated for the long / short branch already observed in the caller.
Stable:
```
--------------------------------------------------------------------------------
Benchmark Time CPU Iterations
--------------------------------------------------------------------------------
BM_StringAssignStr_Empty_Opaque 2.65 ns 2.66 ns 263745536
BM_StringAssignStr_Empty_Transparent 2.95 ns 2.96 ns 236494848
BM_StringAssignStr_Small_Opaque 2.93 ns 2.94 ns 237301760
BM_StringAssignStr_Small_Transparent 2.69 ns 2.69 ns 265809920
BM_StringAssignStr_Large_Opaque 19.6 ns 19.6 ns 35573760
BM_StringAssignStr_Large_Transparent 19.1 ns 19.1 ns 36716544
BM_StringAssignStr_Huge_Opaque 1901 ns 1901 ns 364544
BM_StringAssignStr_Huge_Transparent 1889 ns 1889 ns 360448
```
Unstable
```
--------------------------------------------------------------------------------
Benchmark Time CPU Iterations
--------------------------------------------------------------------------------
BM_StringAssignStr_Empty_Opaque 1.29 ns 1.29 ns 540454912
BM_StringAssignStr_Empty_Transparent 1.11 ns 1.12 ns 628482048
BM_StringAssignStr_Small_Opaque 1.29 ns 1.29 ns 541216768
BM_StringAssignStr_Small_Transparent 1.11 ns 1.11 ns 629469184
BM_StringAssignStr_Large_Opaque 15.6 ns 15.6 ns 44945408
BM_StringAssignStr_Large_Transparent 14.9 ns 14.9 ns 46764032
BM_StringAssignStr_Huge_Opaque 1713 ns 1713 ns 401408
BM_StringAssignStr_Huge_Transparent 1704 ns 1704 ns 397312
```
Subscribers: libcxx-commits
Tags: #libc
Differential Revision: https://reviews.llvm.org/D75211
Cr-Mirrored-From: https://chromium.googlesource.com/external/github.com/llvm/llvm-project
Cr-Mirrored-Commit: f87d30cba2b54a9083a0b276ad97d645c4b8b16c
diff --git a/include/string b/include/string
index 2c90dae..7688d3f 100644
--- a/include/string
+++ b/include/string
@@ -1571,6 +1571,12 @@
size_type __n_copy, size_type __n_del,
size_type __n_add, const value_type* __p_new_stuff);
+ // __assign_no_alias is invoked for assignment operations where we
+ // have proof that the input does not alias the current instance.
+ // For example, operator=(basic_string) performs a 'self' check.
+ template <bool __is_short>
+ void __assign_no_alias(const value_type* __s, size_type __n);
+
_LIBCPP_INLINE_VISIBILITY
void __erase_to_end(size_type __pos);
@@ -2203,6 +2209,23 @@
// assign
template <class _CharT, class _Traits, class _Allocator>
+template <bool __is_short>
+void basic_string<_CharT, _Traits, _Allocator>::__assign_no_alias(
+ const value_type* __s, size_type __n) {
+ size_type __cap = __is_short ? __min_cap : __get_long_cap();
+ if (__n < __cap) {
+ pointer __p = __is_short ? __get_short_pointer() : __get_long_pointer();
+ __is_short ? __set_short_size(__n) : __set_long_size(__n);
+ traits_type::copy(_VSTD::__to_address(__p), __s, __n);
+ traits_type::assign(__p[__n], value_type());
+ __invalidate_iterators_past(__n);
+ } else {
+ size_type __sz = __is_short ? __get_short_size() : __get_long_size();
+ __grow_by_and_replace(__cap - 1, __n - __cap + 1, __sz, 0, __sz, __n, __s);
+ }
+}
+
+template <class _CharT, class _Traits, class _Allocator>
basic_string<_CharT, _Traits, _Allocator>&
basic_string<_CharT, _Traits, _Allocator>::assign(const value_type* __s, size_type __n)
{
@@ -2268,16 +2291,19 @@
basic_string<_CharT, _Traits, _Allocator>&
basic_string<_CharT, _Traits, _Allocator>::operator=(const basic_string& __str)
{
- if (this != &__str)
- {
- __copy_assign_alloc(__str);
- const bool __str_is_long = __str.__is_long(); // Force single branch
- if (__is_long() || __str_is_long) {
- return assign(__str.data(), __str.size());
- }
+ if (this != &__str) {
+ __copy_assign_alloc(__str);
+ if (!__is_long()) {
+ if (!__str.__is_long()) {
__r_.first().__r = __str.__r_.first().__r;
+ } else {
+ __assign_no_alias<true>(__str.data(), __str.size());
+ }
+ } else {
+ __assign_no_alias<false>(__str.data(), __str.size());
}
- return *this;
+ }
+ return *this;
}
#ifndef _LIBCPP_CXX03_LANG