Skip to content

Commit 59f57be

Browse files
committed
Revert "[libc++] Simplify the implementation of reserve() and shrink_to_fit() (#113453)"
This reverts commit d648eed. Breaks anything that relies on sized deallocation, e.g. asan and tcmalloc.
1 parent e04d754 commit 59f57be

File tree

1 file changed

+60
-59
lines changed

1 file changed

+60
-59
lines changed

libcxx/include/string

Lines changed: 60 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1884,6 +1884,8 @@ private:
18841884
operator==(const basic_string<char, char_traits<char>, _Alloc>& __lhs,
18851885
const basic_string<char, char_traits<char>, _Alloc>& __rhs) _NOEXCEPT;
18861886

1887+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __shrink_or_extend(size_type __target_capacity);
1888+
18871889
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS bool
18881890
__is_long() const _NOEXCEPT {
18891891
if (__libcpp_is_constant_evaluated() && __builtin_constant_p(__rep_.__l.__is_long_)) {
@@ -2078,21 +2080,6 @@ private:
20782080
#endif
20792081
}
20802082

2081-
// Disable ASan annotations and enable them again when going out of scope. It is assumed that the string is in a valid
2082-
// state at that point, so `size()` can be called safely.
2083-
struct [[__nodiscard__]] __annotation_guard {
2084-
__annotation_guard(const __annotation_guard&) = delete;
2085-
__annotation_guard& operator=(const __annotation_guard&) = delete;
2086-
2087-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __annotation_guard(basic_string& __str) : __str_(__str) {
2088-
__str_.__annotate_delete();
2089-
}
2090-
2091-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 ~__annotation_guard() { __str_.__annotate_new(__str_.size()); }
2092-
2093-
basic_string& __str_;
2094-
};
2095-
20962083
template <size_type __a>
20972084
static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type __align_it(size_type __s) _NOEXCEPT {
20982085
return (__s + (__a - 1)) & ~(__a - 1);
@@ -3371,16 +3358,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::re
33713358
if (__requested_capacity <= capacity())
33723359
return;
33733360

3374-
__annotation_guard __g(*this);
3375-
auto __allocation = std::__allocate_at_least(__alloc_, __recommend(__requested_capacity) + 1);
3376-
auto __size = size();
3377-
__begin_lifetime(__allocation.ptr, __allocation.count);
3378-
traits_type::copy(std::__to_address(__allocation.ptr), data(), __size + 1);
3379-
if (__is_long())
3380-
__alloc_traits::deallocate(__alloc_, __get_long_pointer(), __get_long_size() + 1);
3381-
__set_long_cap(__allocation.count);
3382-
__set_long_size(__size);
3383-
__set_long_pointer(__allocation.ptr);
3361+
__shrink_or_extend(__recommend(__requested_capacity));
33843362
}
33853363

33863364
template <class _CharT, class _Traits, class _Allocator>
@@ -3389,46 +3367,69 @@ inline _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocat
33893367
if (__target_capacity == capacity())
33903368
return;
33913369

3392-
_LIBCPP_ASSERT_INTERNAL(__is_long(), "Trying to shrink small string");
3370+
__shrink_or_extend(__target_capacity);
3371+
}
33933372

3394-
// We're a long string and we're shrinking into the small buffer.
3395-
if (__fits_in_sso(__target_capacity)) {
3396-
__annotation_guard __g(*this);
3397-
auto __ptr = __get_long_pointer();
3398-
auto __size = __get_long_size();
3399-
auto __cap = __get_long_cap();
3400-
traits_type::copy(std::__to_address(__get_short_pointer()), std::__to_address(__ptr), __size + 1);
3401-
__set_short_size(__size);
3402-
__alloc_traits::deallocate(__alloc_, __ptr, __cap);
3403-
return;
3404-
}
3373+
template <class _CharT, class _Traits, class _Allocator>
3374+
inline _LIBCPP_CONSTEXPR_SINCE_CXX20 void
3375+
basic_string<_CharT, _Traits, _Allocator>::__shrink_or_extend(size_type __target_capacity) {
3376+
__annotate_delete();
3377+
auto __guard = std::__make_scope_guard(__annotate_new_size(*this));
3378+
size_type __cap = capacity();
3379+
size_type __sz = size();
34053380

3381+
pointer __new_data, __p;
3382+
bool __was_long, __now_long;
3383+
if (__fits_in_sso(__target_capacity)) {
3384+
__was_long = true;
3385+
__now_long = false;
3386+
__new_data = __get_short_pointer();
3387+
__p = __get_long_pointer();
3388+
} else {
3389+
if (__target_capacity > __cap) {
3390+
// Extend
3391+
// - called from reserve should propagate the exception thrown.
3392+
auto __allocation = std::__allocate_at_least(__alloc_, __target_capacity + 1);
3393+
__new_data = __allocation.ptr;
3394+
__target_capacity = __allocation.count - 1;
3395+
} else {
3396+
// Shrink
3397+
// - called from shrink_to_fit should not throw.
3398+
// - called from reserve may throw but is not required to.
34063399
#if _LIBCPP_HAS_EXCEPTIONS
3407-
try {
3400+
try {
34083401
#endif // _LIBCPP_HAS_EXCEPTIONS
3409-
__annotation_guard __g(*this);
3410-
auto __size = size();
3411-
auto __allocation = std::__allocate_at_least(__alloc_, __target_capacity + 1);
3412-
3413-
// The Standard mandates shrink_to_fit() does not increase the capacity.
3414-
// With equal capacity keep the existing buffer. This avoids extra work
3415-
// due to swapping the elements.
3416-
if (__allocation.count - 1 > capacity()) {
3417-
__alloc_traits::deallocate(__alloc_, __allocation.ptr, __allocation.count);
3418-
return;
3419-
}
3420-
3421-
__begin_lifetime(__allocation.ptr, __allocation.count);
3422-
auto __ptr = __get_long_pointer();
3423-
traits_type::copy(std::__to_address(__allocation.ptr), std::__to_address(__ptr), __size + 1);
3424-
__alloc_traits::deallocate(__alloc_, __ptr, __get_long_cap());
3425-
__set_long_cap(__allocation.count);
3426-
__set_long_pointer(__allocation.ptr);
3402+
auto __allocation = std::__allocate_at_least(__alloc_, __target_capacity + 1);
3403+
3404+
// The Standard mandates shrink_to_fit() does not increase the capacity.
3405+
// With equal capacity keep the existing buffer. This avoids extra work
3406+
// due to swapping the elements.
3407+
if (__allocation.count - 1 > capacity()) {
3408+
__alloc_traits::deallocate(__alloc_, __allocation.ptr, __allocation.count);
3409+
return;
3410+
}
3411+
__new_data = __allocation.ptr;
3412+
__target_capacity = __allocation.count - 1;
34273413
#if _LIBCPP_HAS_EXCEPTIONS
3428-
} catch (...) {
3429-
return;
3430-
}
3414+
} catch (...) {
3415+
return;
3416+
}
34313417
#endif // _LIBCPP_HAS_EXCEPTIONS
3418+
}
3419+
__begin_lifetime(__new_data, __target_capacity + 1);
3420+
__now_long = true;
3421+
__was_long = __is_long();
3422+
__p = __get_pointer();
3423+
}
3424+
traits_type::copy(std::__to_address(__new_data), std::__to_address(__p), size() + 1);
3425+
if (__was_long)
3426+
__alloc_traits::deallocate(__alloc_, __p, __cap + 1);
3427+
if (__now_long) {
3428+
__set_long_cap(__target_capacity + 1);
3429+
__set_long_size(__sz);
3430+
__set_long_pointer(__new_data);
3431+
} else
3432+
__set_short_size(__sz);
34323433
}
34333434

34343435
template <class _CharT, class _Traits, class _Allocator>

0 commit comments

Comments
 (0)