@@ -1874,8 +1874,6 @@ private:
1874
1874
operator ==(const basic_string<char , char_traits<char >, _Alloc>& __lhs,
1875
1875
const basic_string<char , char_traits<char >, _Alloc>& __rhs) _NOEXCEPT;
1876
1876
1877
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __shrink_or_extend (size_type __target_capacity);
1878
-
1879
1877
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS bool
1880
1878
__is_long () const _NOEXCEPT {
1881
1879
if (__libcpp_is_constant_evaluated () && __builtin_constant_p (__rep_.__l .__is_long_ )) {
@@ -2070,6 +2068,21 @@ private:
2070
2068
#endif
2071
2069
}
2072
2070
2071
+ // Disable ASan annotations and enable them again when going out of scope. It is assumed that the string is in a valid
2072
+ // state at that point, so `size()` can be called safely.
2073
+ struct [[__nodiscard__]] __annotation_guard {
2074
+ __annotation_guard (const __annotation_guard&) = delete ;
2075
+ __annotation_guard& operator =(const __annotation_guard&) = delete ;
2076
+
2077
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __annotation_guard (basic_string& __str) : __str_ (__str) {
2078
+ __str_.__annotate_delete ();
2079
+ }
2080
+
2081
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 ~__annotation_guard () { __str_.__annotate_new (__str_.size ()); }
2082
+
2083
+ basic_string& __str_;
2084
+ };
2085
+
2073
2086
template <size_type __a>
2074
2087
static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type __align_it (size_type __s) _NOEXCEPT {
2075
2088
return (__s + (__a - 1 )) & ~(__a - 1 );
@@ -3348,7 +3361,16 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::re
3348
3361
if (__requested_capacity <= capacity ())
3349
3362
return ;
3350
3363
3351
- __shrink_or_extend (__recommend (__requested_capacity));
3364
+ __annotation_guard __g (*this );
3365
+ auto __allocation = std::__allocate_at_least (__alloc_, __recommend (__requested_capacity) + 1 );
3366
+ auto __size = size ();
3367
+ __begin_lifetime (__allocation.ptr , __allocation.count );
3368
+ traits_type::copy (std::__to_address (__allocation.ptr ), data (), __size + 1 );
3369
+ if (__is_long ())
3370
+ __alloc_traits::deallocate (__alloc_, __get_long_pointer (), __get_long_size () + 1 );
3371
+ __set_long_cap (__allocation.count );
3372
+ __set_long_size (__size);
3373
+ __set_long_pointer (__allocation.ptr );
3352
3374
}
3353
3375
3354
3376
template <class _CharT , class _Traits , class _Allocator >
@@ -3357,70 +3379,46 @@ inline _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocat
3357
3379
if (__target_capacity == capacity ())
3358
3380
return ;
3359
3381
3360
- __shrink_or_extend (__target_capacity);
3361
- }
3382
+ _LIBCPP_ASSERT_INTERNAL (__is_long (), " Trying to shrink small string" );
3362
3383
3363
- template <class _CharT , class _Traits , class _Allocator >
3364
- inline _LIBCPP_CONSTEXPR_SINCE_CXX20 void
3365
- basic_string<_CharT, _Traits, _Allocator>::__shrink_or_extend (size_type __target_capacity) {
3366
- __annotate_delete ();
3367
- size_type __cap = capacity ();
3368
- size_type __sz = size ();
3369
-
3370
- pointer __new_data, __p;
3371
- bool __was_long, __now_long;
3384
+ // We're a long string and we're shrinking into the small buffer.
3372
3385
if (__fits_in_sso (__target_capacity)) {
3373
- __was_long = true ;
3374
- __now_long = false ;
3375
- __new_data = __get_short_pointer ();
3376
- __p = __get_long_pointer ();
3377
- } else {
3378
- if (__target_capacity > __cap) {
3379
- // Extend
3380
- // - called from reserve should propagate the exception thrown.
3381
- auto __allocation = std::__allocate_at_least (__alloc_, __target_capacity + 1 );
3382
- __new_data = __allocation.ptr ;
3383
- __target_capacity = __allocation.count - 1 ;
3384
- } else {
3385
- // Shrink
3386
- // - called from shrink_to_fit should not throw.
3387
- // - called from reserve may throw but is not required to.
3386
+ __annotation_guard __g (*this );
3387
+ auto __ptr = __get_long_pointer ();
3388
+ auto __size = __get_long_size ();
3389
+ auto __cap = __get_long_cap ();
3390
+ traits_type::copy (std::__to_address (__get_short_pointer ()), std::__to_address (__ptr), __size + 1 );
3391
+ __set_short_size (__size);
3392
+ __alloc_traits::deallocate (__alloc_, __ptr, __cap);
3393
+ return ;
3394
+ }
3395
+
3388
3396
#if _LIBCPP_HAS_EXCEPTIONS
3389
- try {
3397
+ try {
3390
3398
#endif // _LIBCPP_HAS_EXCEPTIONS
3391
- auto __allocation = std::__allocate_at_least (__alloc_, __target_capacity + 1 );
3392
-
3393
- // The Standard mandates shrink_to_fit() does not increase the capacity.
3394
- // With equal capacity keep the existing buffer. This avoids extra work
3395
- // due to swapping the elements.
3396
- if (__allocation.count - 1 > __target_capacity) {
3397
- __alloc_traits::deallocate (__alloc_, __allocation.ptr , __allocation.count );
3398
- __annotate_new (__sz); // Undoes the __annotate_delete()
3399
- return ;
3400
- }
3401
- __new_data = __allocation.ptr ;
3402
- __target_capacity = __allocation.count - 1 ;
3399
+ __annotation_guard __g (*this );
3400
+ auto __size = size ();
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 > __target_capacity) {
3407
+ __alloc_traits::deallocate (__alloc_, __allocation.ptr , __allocation.count );
3408
+ return ;
3409
+ }
3410
+
3411
+ __begin_lifetime (__allocation.ptr , __allocation.count );
3412
+ auto __ptr = __get_long_pointer ();
3413
+ traits_type::copy (std::__to_address (__allocation.ptr ), std::__to_address (__ptr), __size + 1 );
3414
+ __alloc_traits::deallocate (__alloc_, __ptr, __get_long_cap ());
3415
+ __set_long_cap (__allocation.count );
3416
+ __set_long_pointer (__allocation.ptr );
3403
3417
#if _LIBCPP_HAS_EXCEPTIONS
3404
- } catch (...) {
3405
- return ;
3406
- }
3418
+ } catch (...) {
3419
+ return ;
3420
+ }
3407
3421
#endif // _LIBCPP_HAS_EXCEPTIONS
3408
- }
3409
- __begin_lifetime (__new_data, __target_capacity + 1 );
3410
- __now_long = true ;
3411
- __was_long = __is_long ();
3412
- __p = __get_pointer ();
3413
- }
3414
- traits_type::copy (std::__to_address (__new_data), std::__to_address (__p), size () + 1 );
3415
- if (__was_long)
3416
- __alloc_traits::deallocate (__alloc_, __p, __cap + 1 );
3417
- if (__now_long) {
3418
- __set_long_cap (__target_capacity + 1 );
3419
- __set_long_size (__sz);
3420
- __set_long_pointer (__new_data);
3421
- } else
3422
- __set_short_size (__sz);
3423
- __annotate_new (__sz);
3424
3422
}
3425
3423
3426
3424
template <class _CharT , class _Traits , class _Allocator >
0 commit comments