3434#include < __memory/allocator.h>
3535#include < __memory/allocator_traits.h>
3636#include < __memory/compressed_pair.h>
37+ #include < __memory/destroy.h>
38+ #include < __memory/is_trivially_allocator_relocatable.h>
3739#include < __memory/noexcept_move_assign_container.h>
3840#include < __memory/pointer_traits.h>
3941#include < __memory/swap_allocator.h>
4042#include < __memory/temp_value.h>
4143#include < __memory/uninitialized_algorithms.h>
44+ #include < __memory/uninitialized_relocate.h>
4245#include < __ranges/access.h>
4346#include < __ranges/concepts.h>
4447#include < __ranges/container_compatible_range.h>
@@ -472,11 +475,68 @@ class _LIBCPP_TEMPLATE_VIS vector {
472475 this ->__destruct_at_end (this ->__end_ - 1 );
473476 }
474477
475- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator insert (const_iterator __position, const_reference __x);
478+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator insert (const_iterator __position, const_reference __x) {
479+ return emplace (std::move (__position), __x);
480+ }
476481
477- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator insert (const_iterator __position, value_type&& __x);
482+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator insert (const_iterator __position, value_type&& __x) {
483+ return emplace (std::move (__position), std::move (__x));
484+ }
478485 template <class ... _Args>
479- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator emplace (const_iterator __position, _Args&&... __args);
486+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator emplace (const_iterator __cposition, _Args&&... __args) {
487+ iterator __position = begin () + (__cposition - cbegin ());
488+ if (__end_ < __cap_) {
489+ if (__position == end ()) {
490+ allocator_traits<_Allocator>::construct (
491+ __alloc_, std::__to_address (__position), std::forward<_Args>(__args)...);
492+ ++__end_;
493+ } else {
494+ // Construct a temporary value on the stack, so that in case this throws we haven't modified
495+ // the vector yet. This also takes care of the corner case where we'd be trying to insert
496+ // from an element located in the vector itself, in which case we'd otherwise have to be
497+ // careful about reference invalidation if we didn't make a temporary value.
498+ __temporary_emplace_value<value_type> __tmp (__alloc_, std::forward<_Args>(__args)...);
499+ auto __guard = std::__make_exception_guard ([&] {
500+ std::allocator_traits<_Allocator>::destroy (__alloc_, __tmp.__address ());
501+ });
502+
503+ // Open up a gap inside the vector by relocating everything to the right and insert the new
504+ // element into the right spot.
505+ //
506+ // If this fails, the relocation operation guarantees that the whole tail of the vector has
507+ // been destroyed. So we set the "new end" of the vector accordingly, which means we basically
508+ // erased the whole tail of the vector. This provides the basic exception guarantee.
509+ try {
510+ std::__uninitialized_allocator_relocate_backward (__alloc_, __position, end (), __position + 1 );
511+ } catch (...) {
512+ __end_ = __to_pointer (__position);
513+ throw ;
514+ }
515+
516+ // Relocate the temporary value into its final location. If that throws, we know from __allocator_relocate_at
517+ // that the temporary will have been destroyed, but we must still clear the tail of the vector, since otherwise
518+ // we'd leave a gap in the middle of the vector.
519+ __guard.__complete (); // we know the temporary value gets destroyed by the relocation no matter what happens
520+ try {
521+ std::__allocator_relocate_at (__alloc_, __tmp.__address (), std::__to_address (__position));
522+ } catch (...) {
523+ std::__allocator_destroy (__alloc_, __position + 1 , end () + 1 );
524+ __end_ = __to_pointer (__position);
525+ throw ;
526+ }
527+
528+ ++__end_;
529+ }
530+ __annotate_increase (1 );
531+ return __position;
532+ } else {
533+ __split_buffer<value_type, allocator_type&> __v (__recommend (size () + 1 ), __position - begin (), __alloc_);
534+ __v.emplace_back (std::forward<_Args>(__args)...);
535+ pointer __p = __to_pointer (__position);
536+ __p = __swap_out_circular_buffer (__v, __p);
537+ return __make_iter (__p);
538+ }
539+ }
480540
481541 _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator
482542 insert (const_iterator __position, size_type __n, const_reference __x);
@@ -520,8 +580,40 @@ class _LIBCPP_TEMPLATE_VIS vector {
520580 }
521581#endif
522582
523- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator erase (const_iterator __position);
524- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator erase (const_iterator __first, const_iterator __last);
583+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator erase (const_iterator __position) {
584+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS (
585+ __position != end (), " vector::erase(iterator) called with a non-dereferenceable iterator" );
586+ return erase (__position, __position + 1 );
587+ }
588+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator erase (const_iterator __cfirst, const_iterator __clast) {
589+ _LIBCPP_ASSERT_VALID_INPUT_RANGE (__cfirst <= __clast, " vector::erase(first, last) called with invalid range" );
590+
591+ iterator __first = begin () + std::distance (cbegin (), __cfirst);
592+ iterator __last = begin () + std::distance (cbegin (), __clast);
593+ if (__first == __last)
594+ return __last;
595+
596+ auto const __n = std::distance (__first, __last);
597+
598+ // If the value_type is nothrow relocatable, we destroy the range being erased and we relocate the tail
599+ // of the vector into the created gap. This is especially efficient if the elements are trivially relocatable.
600+ // Otherwise, we use the standard technique with move-assignments.
601+ //
602+ // Note that unlike vector::insert, we can't use relocation when it is potentially throwing, because
603+ // vector::erase is required not to throw an exception unless T's assignment operator throws. So we
604+ // can bypass the assignment with a relocation, but only when that definitely doesn't throw.
605+ if constexpr (__is_nothrow_allocator_relocatable<_Allocator, value_type>::value) {
606+ std::__allocator_destroy (__alloc_, __first, __last);
607+ std::__uninitialized_allocator_relocate (__alloc_, __last, end (), __first);
608+ } else {
609+ auto __new_end = std::move (__last, end (), __first);
610+ std::__allocator_destroy (__alloc_, __new_end, end ());
611+ }
612+
613+ __end_ -= __n;
614+ __annotate_shrink (size () + __n);
615+ return __first;
616+ }
525617
526618 _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void clear () _NOEXCEPT {
527619 size_type __old_size = size ();
@@ -662,6 +754,11 @@ class _LIBCPP_TEMPLATE_VIS vector {
662754 __annotate_shrink (__old_size);
663755 }
664756
757+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer __to_pointer (iterator __it) const {
758+ auto __index = __it - begin ();
759+ return this ->__begin_ + __index;
760+ }
761+
665762 template <class ... _Args>
666763 _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI inline pointer __emplace_back_slow_path (_Args&&... __args);
667764
@@ -1115,28 +1212,6 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 inline
11151212#endif
11161213}
11171214
1118- template <class _Tp , class _Allocator >
1119- _LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI typename vector<_Tp, _Allocator>::iterator
1120- vector<_Tp, _Allocator>::erase (const_iterator __position) {
1121- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS (
1122- __position != end (), " vector::erase(iterator) called with a non-dereferenceable iterator" );
1123- difference_type __ps = __position - cbegin ();
1124- pointer __p = this ->__begin_ + __ps;
1125- this ->__destruct_at_end (std::move (__p + 1 , this ->__end_ , __p));
1126- return __make_iter (__p);
1127- }
1128-
1129- template <class _Tp , class _Allocator >
1130- _LIBCPP_CONSTEXPR_SINCE_CXX20 typename vector<_Tp, _Allocator>::iterator
1131- vector<_Tp, _Allocator>::erase (const_iterator __first, const_iterator __last) {
1132- _LIBCPP_ASSERT_VALID_INPUT_RANGE (__first <= __last, " vector::erase(first, last) called with invalid range" );
1133- pointer __p = this ->__begin_ + (__first - begin ());
1134- if (__first != __last) {
1135- this ->__destruct_at_end (std::move (__p + (__last - __first), this ->__end_ , __p));
1136- }
1137- return __make_iter (__p);
1138- }
1139-
11401215template <class _Tp , class _Allocator >
11411216_LIBCPP_CONSTEXPR_SINCE_CXX20 void
11421217vector<_Tp, _Allocator>::__move_range (pointer __from_s, pointer __from_e, pointer __to) {
@@ -1152,68 +1227,6 @@ vector<_Tp, _Allocator>::__move_range(pointer __from_s, pointer __from_e, pointe
11521227 std::move_backward (__from_s, __from_s + __n, __old_last);
11531228}
11541229
1155- template <class _Tp , class _Allocator >
1156- _LIBCPP_CONSTEXPR_SINCE_CXX20 typename vector<_Tp, _Allocator>::iterator
1157- vector<_Tp, _Allocator>::insert (const_iterator __position, const_reference __x) {
1158- pointer __p = this ->__begin_ + (__position - begin ());
1159- if (this ->__end_ < this ->__cap_ ) {
1160- if (__p == this ->__end_ ) {
1161- __construct_one_at_end (__x);
1162- } else {
1163- __move_range (__p, this ->__end_ , __p + 1 );
1164- const_pointer __xr = pointer_traits<const_pointer>::pointer_to (__x);
1165- if (std::__is_pointer_in_range (std::__to_address (__p), std::__to_address (__end_), std::addressof (__x)))
1166- ++__xr;
1167- *__p = *__xr;
1168- }
1169- } else {
1170- __split_buffer<value_type, allocator_type&> __v (__recommend (size () + 1 ), __p - this ->__begin_ , this ->__alloc_ );
1171- __v.emplace_back (__x);
1172- __p = __swap_out_circular_buffer (__v, __p);
1173- }
1174- return __make_iter (__p);
1175- }
1176-
1177- template <class _Tp , class _Allocator >
1178- _LIBCPP_CONSTEXPR_SINCE_CXX20 typename vector<_Tp, _Allocator>::iterator
1179- vector<_Tp, _Allocator>::insert (const_iterator __position, value_type&& __x) {
1180- pointer __p = this ->__begin_ + (__position - begin ());
1181- if (this ->__end_ < this ->__cap_ ) {
1182- if (__p == this ->__end_ ) {
1183- __construct_one_at_end (std::move (__x));
1184- } else {
1185- __move_range (__p, this ->__end_ , __p + 1 );
1186- *__p = std::move (__x);
1187- }
1188- } else {
1189- __split_buffer<value_type, allocator_type&> __v (__recommend (size () + 1 ), __p - this ->__begin_ , this ->__alloc_ );
1190- __v.emplace_back (std::move (__x));
1191- __p = __swap_out_circular_buffer (__v, __p);
1192- }
1193- return __make_iter (__p);
1194- }
1195-
1196- template <class _Tp , class _Allocator >
1197- template <class ... _Args>
1198- _LIBCPP_CONSTEXPR_SINCE_CXX20 typename vector<_Tp, _Allocator>::iterator
1199- vector<_Tp, _Allocator>::emplace (const_iterator __position, _Args&&... __args) {
1200- pointer __p = this ->__begin_ + (__position - begin ());
1201- if (this ->__end_ < this ->__cap_ ) {
1202- if (__p == this ->__end_ ) {
1203- __construct_one_at_end (std::forward<_Args>(__args)...);
1204- } else {
1205- __temp_value<value_type, _Allocator> __tmp (this ->__alloc_ , std::forward<_Args>(__args)...);
1206- __move_range (__p, this ->__end_ , __p + 1 );
1207- *__p = std::move (__tmp.get ());
1208- }
1209- } else {
1210- __split_buffer<value_type, allocator_type&> __v (__recommend (size () + 1 ), __p - this ->__begin_ , this ->__alloc_ );
1211- __v.emplace_back (std::forward<_Args>(__args)...);
1212- __p = __swap_out_circular_buffer (__v, __p);
1213- }
1214- return __make_iter (__p);
1215- }
1216-
12171230template <class _Tp , class _Allocator >
12181231_LIBCPP_CONSTEXPR_SINCE_CXX20 typename vector<_Tp, _Allocator>::iterator
12191232vector<_Tp, _Allocator>::insert (const_iterator __position, size_type __n, const_reference __x) {
0 commit comments