@@ -1882,8 +1882,6 @@ public:
1882
1882
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __clear_and_shrink () _NOEXCEPT;
1883
1883
1884
1884
private:
1885
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __shrink_or_extend (size_type __target_capacity);
1886
-
1887
1885
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS bool
1888
1886
__is_long () const _NOEXCEPT {
1889
1887
if (__libcpp_is_constant_evaluated () && __builtin_constant_p (__rep_.__l .__is_long_ )) {
@@ -2079,6 +2077,21 @@ private:
2079
2077
# endif
2080
2078
}
2081
2079
2080
+ // Disable ASan annotations and enable them again when going out of scope. It is assumed that the string is in a valid
2081
+ // state at that point, so `size()` can be called safely.
2082
+ struct [[__nodiscard__]] __annotation_guard {
2083
+ __annotation_guard (const __annotation_guard&) = delete ;
2084
+ __annotation_guard& operator =(const __annotation_guard&) = delete ;
2085
+
2086
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __annotation_guard (basic_string& __str) : __str_ (__str) {
2087
+ __str_.__annotate_delete ();
2088
+ }
2089
+
2090
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 ~__annotation_guard () { __str_.__annotate_new (__str_.size ()); }
2091
+
2092
+ basic_string& __str_;
2093
+ };
2094
+
2082
2095
template <size_type __a>
2083
2096
static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type __align_it (size_type __s) _NOEXCEPT {
2084
2097
return (__s + (__a - 1 )) & ~(__a - 1 );
@@ -3357,7 +3370,16 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::re
3357
3370
if (__requested_capacity <= capacity ())
3358
3371
return ;
3359
3372
3360
- __shrink_or_extend (__recommend (__requested_capacity));
3373
+ __annotation_guard __g (*this );
3374
+ auto __allocation = std::__allocate_at_least (__alloc_, __recommend (__requested_capacity) + 1 );
3375
+ auto __size = size ();
3376
+ __begin_lifetime (__allocation.ptr , __allocation.count );
3377
+ traits_type::copy (std::__to_address (__allocation.ptr ), data (), __size + 1 );
3378
+ if (__is_long ())
3379
+ __alloc_traits::deallocate (__alloc_, __get_long_pointer (), __get_long_cap ());
3380
+ __set_long_cap (__allocation.count );
3381
+ __set_long_size (__size);
3382
+ __set_long_pointer (__allocation.ptr );
3361
3383
}
3362
3384
3363
3385
template <class _CharT , class _Traits , class _Allocator >
@@ -3366,69 +3388,46 @@ inline _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocat
3366
3388
if (__target_capacity == capacity ())
3367
3389
return ;
3368
3390
3369
- __shrink_or_extend (__target_capacity);
3370
- }
3391
+ _LIBCPP_ASSERT_INTERNAL (__is_long (), " Trying to shrink small string" );
3371
3392
3372
- template <class _CharT , class _Traits , class _Allocator >
3373
- inline _LIBCPP_CONSTEXPR_SINCE_CXX20 void
3374
- basic_string<_CharT, _Traits, _Allocator>::__shrink_or_extend (size_type __target_capacity) {
3375
- __annotate_delete ();
3376
- auto __guard = std::__make_scope_guard (__annotate_new_size (*this ));
3377
- size_type __cap = capacity ();
3378
- size_type __sz = size ();
3379
-
3380
- pointer __new_data, __p;
3381
- bool __was_long, __now_long;
3393
+ // We're a long string and we're shrinking into the small buffer.
3382
3394
if (__fits_in_sso (__target_capacity)) {
3383
- __was_long = true ;
3384
- __now_long = false ;
3385
- __new_data = __get_short_pointer ();
3386
- __p = __get_long_pointer ();
3387
- } else {
3388
- if (__target_capacity > __cap) {
3389
- // Extend
3390
- // - called from reserve should propagate the exception thrown.
3391
- auto __allocation = std::__allocate_at_least (__alloc_, __target_capacity + 1 );
3392
- __new_data = __allocation.ptr ;
3393
- __target_capacity = __allocation.count - 1 ;
3394
- } else {
3395
- // Shrink
3396
- // - called from shrink_to_fit should not throw.
3397
- // - called from reserve may throw but is not required to.
3395
+ __annotation_guard __g (*this );
3396
+ auto __ptr = __get_long_pointer ();
3397
+ auto __size = __get_long_size ();
3398
+ auto __cap = __get_long_cap ();
3399
+ traits_type::copy (std::__to_address (__get_short_pointer ()), std::__to_address (__ptr), __size + 1 );
3400
+ __set_short_size (__size);
3401
+ __alloc_traits::deallocate (__alloc_, __ptr, __cap);
3402
+ return ;
3403
+ }
3404
+
3398
3405
# if _LIBCPP_HAS_EXCEPTIONS
3399
- try {
3406
+ try {
3400
3407
# endif // _LIBCPP_HAS_EXCEPTIONS
3401
- auto __allocation = std::__allocate_at_least (__alloc_, __target_capacity + 1 );
3402
-
3403
- // The Standard mandates shrink_to_fit() does not increase the capacity.
3404
- // With equal capacity keep the existing buffer. This avoids extra work
3405
- // due to swapping the elements.
3406
- if (__allocation.count - 1 > capacity ()) {
3407
- __alloc_traits::deallocate (__alloc_, __allocation.ptr , __allocation.count );
3408
- return ;
3409
- }
3410
- __new_data = __allocation.ptr ;
3411
- __target_capacity = __allocation.count - 1 ;
3408
+ __annotation_guard __g (*this );
3409
+ auto __size = size ();
3410
+ auto __allocation = std::__allocate_at_least (__alloc_, __target_capacity + 1 );
3411
+
3412
+ // The Standard mandates shrink_to_fit() does not increase the capacity.
3413
+ // With equal capacity keep the existing buffer. This avoids extra work
3414
+ // due to swapping the elements.
3415
+ if (__allocation.count - 1 > capacity ()) {
3416
+ __alloc_traits::deallocate (__alloc_, __allocation.ptr , __allocation.count );
3417
+ return ;
3418
+ }
3419
+
3420
+ __begin_lifetime (__allocation.ptr , __allocation.count );
3421
+ auto __ptr = __get_long_pointer ();
3422
+ traits_type::copy (std::__to_address (__allocation.ptr ), std::__to_address (__ptr), __size + 1 );
3423
+ __alloc_traits::deallocate (__alloc_, __ptr, __get_long_cap ());
3424
+ __set_long_cap (__allocation.count );
3425
+ __set_long_pointer (__allocation.ptr );
3412
3426
# if _LIBCPP_HAS_EXCEPTIONS
3413
- } catch (...) {
3414
- return ;
3415
- }
3427
+ } catch (...) {
3428
+ return ;
3429
+ }
3416
3430
# endif // _LIBCPP_HAS_EXCEPTIONS
3417
- }
3418
- __begin_lifetime (__new_data, __target_capacity + 1 );
3419
- __now_long = true ;
3420
- __was_long = __is_long ();
3421
- __p = __get_pointer ();
3422
- }
3423
- traits_type::copy (std::__to_address (__new_data), std::__to_address (__p), size () + 1 );
3424
- if (__was_long)
3425
- __alloc_traits::deallocate (__alloc_, __p, __cap + 1 );
3426
- if (__now_long) {
3427
- __set_long_cap (__target_capacity + 1 );
3428
- __set_long_size (__sz);
3429
- __set_long_pointer (__new_data);
3430
- } else
3431
- __set_short_size (__sz);
3432
3431
}
3433
3432
3434
3433
template <class _CharT , class _Traits , class _Allocator >
0 commit comments