Skip to content

Commit cf86ee2

Browse files
committed
[libc++][NFC] Simplify the implementation of reserve() and shrink_to_fit()
1 parent ac5a201 commit cf86ee2

File tree

1 file changed

+62
-62
lines changed

1 file changed

+62
-62
lines changed

libcxx/include/string

Lines changed: 62 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1874,8 +1874,6 @@ private:
18741874
operator==(const basic_string<char, char_traits<char>, _Alloc>& __lhs,
18751875
const basic_string<char, char_traits<char>, _Alloc>& __rhs) _NOEXCEPT;
18761876

1877-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __shrink_or_extend(size_type __target_capacity);
1878-
18791877
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS bool
18801878
__is_long() const _NOEXCEPT {
18811879
if (__libcpp_is_constant_evaluated() && __builtin_constant_p(__rep_.__l.__is_long_)) {
@@ -2060,6 +2058,21 @@ private:
20602058
#endif
20612059
}
20622060

2061+
// Disable ASan annotations and enable them again when going out of scope. It is assumed that the string is in a valid
2062+
// state at that point, so `size()` can be called safely.
2063+
struct [[__nodiscard__]] __annotation_guard {
2064+
__annotation_guard(const __annotation_guard&) = delete;
2065+
__annotation_guard& operator=(const __annotation_guard&) = delete;
2066+
2067+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __annotation_guard(basic_string& __str) : __str_(__str) {
2068+
__str_.__annotate_delete();
2069+
}
2070+
2071+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 ~__annotation_guard() { __str_.__annotate_new(__str_.size()); }
2072+
2073+
basic_string& __str_;
2074+
};
2075+
20632076
template <size_type __a>
20642077
static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type __align_it(size_type __s) _NOEXCEPT {
20652078
return (__s + (__a - 1)) & ~(__a - 1);
@@ -3340,7 +3353,16 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::re
33403353
if (__target_capacity == capacity())
33413354
return;
33423355

3343-
__shrink_or_extend(__target_capacity);
3356+
__annotation_guard __g(*this);
3357+
auto __allocation = std::__allocate_at_least(__alloc_, __target_capacity + 1);
3358+
auto __size = size();
3359+
__begin_lifetime(__allocation.ptr, __allocation.count);
3360+
traits_type::copy(std::__to_address(__allocation.ptr), data(), __size + 1);
3361+
if (__is_long())
3362+
__alloc_traits::deallocate(__alloc_, __get_long_pointer(), __get_long_size() + 1);
3363+
__set_long_cap(__allocation.count);
3364+
__set_long_size(__size);
3365+
__set_long_pointer(__allocation.ptr);
33443366
}
33453367

33463368
template <class _CharT, class _Traits, class _Allocator>
@@ -3349,70 +3371,48 @@ inline _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocat
33493371
if (__target_capacity == capacity())
33503372
return;
33513373

3352-
__shrink_or_extend(__target_capacity);
3353-
}
3354-
3355-
template <class _CharT, class _Traits, class _Allocator>
3356-
inline _LIBCPP_CONSTEXPR_SINCE_CXX20 void
3357-
basic_string<_CharT, _Traits, _Allocator>::__shrink_or_extend(size_type __target_capacity) {
3358-
__annotate_delete();
3359-
size_type __cap = capacity();
3360-
size_type __sz = size();
3361-
3362-
pointer __new_data, __p;
3363-
bool __was_long, __now_long;
33643374
if (__fits_in_sso(__target_capacity)) {
3365-
__was_long = true;
3366-
__now_long = false;
3367-
__new_data = __get_short_pointer();
3368-
__p = __get_long_pointer();
3369-
} else {
3370-
if (__target_capacity > __cap) {
3371-
// Extend
3372-
// - called from reserve should propagate the exception thrown.
3373-
auto __allocation = std::__allocate_at_least(__alloc_, __target_capacity + 1);
3374-
__new_data = __allocation.ptr;
3375-
__target_capacity = __allocation.count - 1;
3376-
} else {
3377-
// Shrink
3378-
// - called from shrink_to_fit should not throw.
3379-
// - called from reserve may throw but is not required to.
3375+
if (!__is_long())
3376+
return;
3377+
__annotation_guard __g(*this);
3378+
auto __ptr = __get_long_pointer();
3379+
auto __size = __get_long_size();
3380+
auto __cap = __get_long_cap();
3381+
traits_type::copy(std::__to_address(__get_short_pointer()), data(), __size + 1);
3382+
__alloc_traits::deallocate(__alloc_, __ptr, __cap);
3383+
__set_short_size(__size);
3384+
return;
3385+
}
3386+
3387+
// Shrink
3388+
// - called from shrink_to_fit should not throw.
3389+
// - called from reserve may throw but is not required to.
33803390
#if _LIBCPP_HAS_EXCEPTIONS
3381-
try {
3391+
try {
33823392
#endif // _LIBCPP_HAS_EXCEPTIONS
3383-
auto __allocation = std::__allocate_at_least(__alloc_, __target_capacity + 1);
3384-
3385-
// The Standard mandates shrink_to_fit() does not increase the capacity.
3386-
// With equal capacity keep the existing buffer. This avoids extra work
3387-
// due to swapping the elements.
3388-
if (__allocation.count - 1 > __target_capacity) {
3389-
__alloc_traits::deallocate(__alloc_, __allocation.ptr, __allocation.count);
3390-
__annotate_new(__sz); // Undoes the __annotate_delete()
3391-
return;
3392-
}
3393-
__new_data = __allocation.ptr;
3394-
__target_capacity = __allocation.count - 1;
3393+
__annotation_guard __g(*this);
3394+
auto __size = size();
3395+
auto __allocation = std::__allocate_at_least(__alloc_, __target_capacity + 1);
3396+
3397+
// The Standard mandates shrink_to_fit() does not increase the capacity.
3398+
// With equal capacity keep the existing buffer. This avoids extra work
3399+
// due to swapping the elements.
3400+
if (__allocation.count - 1 > __target_capacity) {
3401+
__alloc_traits::deallocate(__alloc_, __allocation.ptr, __allocation.count);
3402+
__annotate_new(__size); // Undoes the __annotate_delete()
3403+
return;
3404+
}
3405+
3406+
__begin_lifetime(__allocation.ptr, __allocation.count);
3407+
traits_type::copy(std::__to_address(__allocation.ptr), data(), size() + 1);
3408+
__alloc_traits::deallocate(__alloc_, __get_long_pointer(), __get_long_cap());
3409+
__set_long_cap(__allocation.count);
3410+
__set_long_pointer(__allocation.ptr);
33953411
#if _LIBCPP_HAS_EXCEPTIONS
3396-
} catch (...) {
3397-
return;
3398-
}
3412+
} catch (...) {
3413+
return;
3414+
}
33993415
#endif // _LIBCPP_HAS_EXCEPTIONS
3400-
}
3401-
__begin_lifetime(__new_data, __target_capacity + 1);
3402-
__now_long = true;
3403-
__was_long = __is_long();
3404-
__p = __get_pointer();
3405-
}
3406-
traits_type::copy(std::__to_address(__new_data), std::__to_address(__p), size() + 1);
3407-
if (__was_long)
3408-
__alloc_traits::deallocate(__alloc_, __p, __cap + 1);
3409-
if (__now_long) {
3410-
__set_long_cap(__target_capacity + 1);
3411-
__set_long_size(__sz);
3412-
__set_long_pointer(__new_data);
3413-
} else
3414-
__set_short_size(__sz);
3415-
__annotate_new(__sz);
34163416
}
34173417

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

0 commit comments

Comments
 (0)