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