[libcxx-commits] [libcxx] [libc++] Optimize basic_string::append(Iter, Iter) (PR #169794)
Louis Dionne via libcxx-commits
libcxx-commits at lists.llvm.org
Tue Dec 2 09:18:04 PST 2025
================
@@ -1440,24 +1440,51 @@ public:
template <class _ForwardIterator, __enable_if_t<__has_forward_iterator_category<_ForwardIterator>::value, int> = 0>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string&
append(_ForwardIterator __first, _ForwardIterator __last) {
- size_type __sz = size();
- size_type __cap = capacity();
- size_type __n = static_cast<size_type>(std::distance(__first, __last));
+ const size_type __size = size();
+ const size_type __cap = capacity();
+ const size_type __n = static_cast<size_type>(std::distance(__first, __last));
if (__n == 0)
return *this;
- if (__string_is_trivial_iterator_v<_ForwardIterator> && !__addr_in_range(*__first)) {
- if (__cap - __sz < __n)
- __grow_by_without_replace(__cap, __sz + __n - __cap, __sz, __sz, 0);
- __annotate_increase(__n);
- auto __end = __copy_non_overlapping_range(__first, __last, std::__to_address(__get_pointer() + __sz));
- traits_type::assign(*__end, value_type());
- __set_size(__sz + __n);
- return *this;
+ __annotate_delete();
+ auto __asan_guard = std::__make_scope_guard(__annotate_new_size(*this));
+
+ if (__n > __cap - __size) {
+ __long __buffer = __allocate_long_buffer(__alloc_, __get_amortized_growth_capacity(__size + __n));
+ __buffer.__size_ = __size + __n;
----------------
ldionne wrote:
Semantically, that's what we have:
```suggestion
const size_type __new_size = __size + __n;
const size_type __new_capacity = __get_amortized_growth_capacity(__new_size);
__long __buffer = __allocate_long_buffer(__alloc_, __new_size, __new_capacity);
```
It might not be necessary to actually name `__new_size`, but I think it would make sense for the API to allow us to write this.
The other way I can see to achieve the same result without losing the fact that we're doing amortized growth at the call site would be:
```c++
struct __amortized_growth_strategy_t {};
__long __buffer = __allocate_long_buffer(__alloc_, __size + __n, __amortized_growth_strategy_t{});
```
and then
```c++
_LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX20 __long
__allocate_long_buffer(_Allocator& __alloc, size_type __size, __amortized_growth_strategy_t) {
_LIBCPP_ASSERT_INTERNAL(!__fits_in_sso(__size),
"Trying to allocate long buffer for a size what would fit into the small buffer");
size_type const __capacity = has-amortized-growth-strategy ? __get_amortized_growth_capacity(__size) : __size;
auto __buffer = std::__allocate_at_least(__alloc, __align_allocation_size(__capacity));
if (__libcpp_is_constant_evaluated()) {
for (size_type __i = 0; __i != __buffer.count; ++__i)
std::__construct_at(std::addressof(__buffer.ptr[__i]));
}
return __long(__buffer, __size);
}
```
https://github.com/llvm/llvm-project/pull/169794
More information about the libcxx-commits
mailing list