@@ -1884,6 +1884,8 @@ private:
1884
1884
operator ==(const basic_string<char , char_traits<char >, _Alloc>& __lhs,
1885
1885
const basic_string<char , char_traits<char >, _Alloc>& __rhs) _NOEXCEPT;
1886
1886
1887
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __shrink_or_extend (size_type __target_capacity);
1888
+
1887
1889
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS bool
1888
1890
__is_long () const _NOEXCEPT {
1889
1891
if (__libcpp_is_constant_evaluated () && __builtin_constant_p (__rep_.__l .__is_long_ )) {
@@ -2078,21 +2080,6 @@ private:
2078
2080
#endif
2079
2081
}
2080
2082
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
-
2096
2083
template <size_type __a>
2097
2084
static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type __align_it (size_type __s) _NOEXCEPT {
2098
2085
return (__s + (__a - 1 )) & ~(__a - 1 );
@@ -3371,16 +3358,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::re
3371
3358
if (__requested_capacity <= capacity ())
3372
3359
return ;
3373
3360
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));
3384
3362
}
3385
3363
3386
3364
template <class _CharT , class _Traits , class _Allocator >
@@ -3389,46 +3367,69 @@ inline _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocat
3389
3367
if (__target_capacity == capacity ())
3390
3368
return ;
3391
3369
3392
- _LIBCPP_ASSERT_INTERNAL (__is_long (), " Trying to shrink small string" );
3370
+ __shrink_or_extend (__target_capacity);
3371
+ }
3393
3372
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 ();
3405
3380
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.
3406
3399
#if _LIBCPP_HAS_EXCEPTIONS
3407
- try {
3400
+ try {
3408
3401
#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 ;
3427
3413
#if _LIBCPP_HAS_EXCEPTIONS
3428
- } catch (...) {
3429
- return ;
3430
- }
3414
+ } catch (...) {
3415
+ return ;
3416
+ }
3431
3417
#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);
3432
3433
}
3433
3434
3434
3435
template <class _CharT , class _Traits , class _Allocator >
0 commit comments