8#include <initializer_list>
12#include <memory_resource>
18#include "plg/allocator.hpp"
19#include "plg/guards.hpp"
20#include "plg/split_buffer.hpp"
21#include "plg/uninitialized.hpp"
24#if PLUGIFY_COMPILER_CLANG
25# pragma clang system_header
26#elif PLUGIFY_COMPILER_GCC
27# pragma GCC system_header
33 template <
class T,
class Alloc>
35 using allocator_traits = std::allocator_traits<Alloc>;
40 PLUGIFY_NO_UNIQUE_ADDRESS
Alloc& a;
43 return std::addressof(v);
50 template <
class...
Args>
51 PLUGIFY_NO_CFI
constexpr
54 allocator_traits::construct(a, addr(), std::forward<Args>(
args)...);
58 allocator_traits::destroy(a, addr());
63 template <
class T,
class Allocator = allocator<T>>
65 template <
class U,
class Alloc>
73 using alloc_traits = std::allocator_traits<allocator_type>;
74 using reference = value_type&;
75 using const_reference =
const value_type&;
76 using size_type =
typename alloc_traits::size_type;
77 using difference_type =
typename alloc_traits::difference_type;
78 using pointer =
typename alloc_traits::pointer;
79 using const_pointer =
typename alloc_traits::const_pointer;
80 using iterator = pointer;
81 using const_iterator = const_pointer;
82 using reverse_iterator = std::reverse_iterator<iterator>;
83 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
87 std::is_same_v<typename allocator_type::value_type, value_type>,
88 "Allocator::value_type must be same type as value_type"
94 constexpr vector()
noexcept(std::is_nothrow_default_constructible_v<allocator_type>) =
default;
100 constexpr explicit vector(size_type n) {
101 auto guard = make_exception_guard(destroy_vector(*
this));
110 explicit vector(size_type n,
const allocator_type& a)
112 auto guard = make_exception_guard(destroy_vector(*
this));
120 constexpr vector(size_type n,
const value_type& x) {
121 auto guard = make_exception_guard(destroy_vector(*
this));
124 construct_at_end(n, x);
130 vector(size_type n,
const value_type& x,
const allocator_type& a)
132 auto guard = make_exception_guard(destroy_vector(*
this));
135 construct_at_end(n, x);
140 template<std::input_iterator InputIterator>
146 template<std::input_iterator InputIterator>
153 template <std::forward_iterator ForwardIterator>
156 size_type n =
static_cast<size_type
>(std::distance(
first,
last));
160 template <std::forward_iterator ForwardIterator>
164 size_type n =
static_cast<size_type
>(std::distance(
first,
last));
169 template <container_compatible_range<T> Range>
173 const allocator_type&
alloc = allocator_type()
175 if constexpr (std::ranges::forward_range<Range> || std::ranges::sized_range<Range>) {
176 auto n =
static_cast<size_type
>(std::ranges::distance(range));
177 init_with_size(std::ranges::begin(range), std::ranges::end(range), n);
180 init_with_sentinel(std::ranges::begin(range), std::ranges::end(range));
186 class destroy_vector {
188 constexpr explicit destroy_vector(
vector&
vec)
192 constexpr void operator()() {
193 if (vec_.begin_ !=
nullptr) {
195 vec_.annotate_delete();
196 alloc_traits::deallocate(vec_.alloc_, vec_.begin_, vec_.capacity());
206 destroy_vector (*
this)();
210 : alloc_(alloc_traits::select_on_container_copy_construction(x.alloc_)) {
211 init_with_size(x.begin_, x.end_, x.size());
215 vector(
const vector& x,
const std::type_identity_t<allocator_type>& a)
217 init_with_size(x.begin_, x.end_, x.size());
222 constexpr vector(std::initializer_list<value_type>
il) {
223 init_with_size(
il.begin(),
il.end(),
il.size());
227 vector(std::initializer_list<value_type>
il,
const allocator_type& a)
229 init_with_size(
il.begin(),
il.end(),
il.size());
233 operator=(std::initializer_list<value_type>
il) {
234 assign(
il.begin(),
il.end());
241 vector(
vector&& x,
const std::type_identity_t<allocator_type>& a);
244 std::allocator_traits<Allocator>::propagate_on_container_move_assignment::value ||
245 std::allocator_traits<Allocator>::is_always_equal::value)
249 std::integral_constant<bool, alloc_traits::propagate_on_container_move_assignment::value>()
254 template<std::input_iterator InputIterator>
260 template <std::forward_iterator ForwardIterator>
267 template <container_compatible_range<T> Range>
269 if constexpr (std::ranges::forward_range<Range> || std::ranges::sized_range<Range>) {
270 auto n =
static_cast<size_type
>(std::ranges::distance(range));
271 assign_with_size(std::ranges::begin(range), std::ranges::end(range), n);
274 assign_with_sentinel(std::ranges::begin(range), std::ranges::end(range));
280 assign(size_type n, const_reference
u);
283 assign(std::initializer_list<value_type>
il) {
284 assign(
il.begin(),
il.end());
288 get_allocator()
const noexcept {
295 [[
nodiscard]]
constexpr iterator begin()
noexcept {
296 return make_iter(add_alignment_assumption(this->begin_));
300 begin()
const noexcept {
301 return make_iter(add_alignment_assumption(this->begin_));
304 [[
nodiscard]]
constexpr iterator end()
noexcept {
305 return make_iter(add_alignment_assumption(this->end_));
309 end()
const noexcept {
310 return make_iter(add_alignment_assumption(this->end_));
315 return reverse_iterator(end());
318 [[
nodiscard]]
constexpr const_reverse_iterator
319 rbegin()
const noexcept {
320 return const_reverse_iterator(end());
325 return reverse_iterator(begin());
328 [[
nodiscard]]
constexpr const_reverse_iterator
329 rend()
const noexcept {
330 return const_reverse_iterator(begin());
334 cbegin()
const noexcept {
339 cend()
const noexcept {
343 [[
nodiscard]]
constexpr const_reverse_iterator
344 crbegin()
const noexcept {
348 [[
nodiscard]]
constexpr const_reverse_iterator
349 crend()
const noexcept {
356 [[
nodiscard]]
constexpr size_type size()
const noexcept {
357 return static_cast<size_type
>(this->end_ - this->begin_);
361 capacity()
const noexcept {
362 return static_cast<size_type
>(this->cap_ - this->begin_);
366 empty()
const noexcept {
367 return this->begin_ == this->end_;
371 max_size()
const noexcept {
372 return std::min<size_type>(
373 alloc_traits::max_size(this->alloc_),
374 std::numeric_limits<difference_type>::max()
378 constexpr void reserve(size_type n);
379 constexpr void shrink_to_fit()
noexcept;
385 operator[](size_type n)
noexcept {
387 return this->begin_[n];
391 operator[](size_type n)
const noexcept {
393 return this->begin_[n];
396 [[
nodiscard]]
constexpr reference at(size_type n) {
398 this->throw_out_of_range();
400 return this->begin_[n];
404 at(size_type n)
const {
406 this->throw_out_of_range();
408 return this->begin_[n];
411 [[
nodiscard]]
constexpr reference front()
noexcept {
413 return *this->begin_;
417 front()
const noexcept {
419 return *this->begin_;
422 [[
nodiscard]]
constexpr reference back()
noexcept {
424 return *(this->end_ - 1);
428 back()
const noexcept {
430 return *(this->end_ - 1);
438 return std::to_address(this->begin_);
441 [[
nodiscard]]
constexpr const value_type*
442 data()
const noexcept {
443 return std::to_address(this->begin_);
449 constexpr void push_back(const_reference x) {
453 constexpr void push_back(value_type&& x) {
454 emplace_back(std::move(x));
457 template <
class...
Args>
462 template <
class...
Args>
464 emplace_back_assume_capacity(
Args&&...
args) {
467 "We assume that we have enough space to insert an element at the end of the vector"
469 ConstructTransaction
tx(*
this, 1);
470 alloc_traits::construct(this->alloc_, std::to_address(
tx.pos_), std::forward<Args>(
args)...);
475 template <container_compatible_range<T> Range>
481 constexpr void pop_back() {
482 PLUGIFY_ASSERT(!empty(),
"vector::pop_back called on an empty vector");
483 this->destruct_at_end(this->end_ - 1);
487 insert(const_iterator
position, const_reference x);
490 insert(const_iterator
position, value_type&& x);
491 template <
class...
Args>
496 insert(const_iterator
position, size_type n, const_reference x);
498 template<std::input_iterator InputIterator>
504 template <std::forward_iterator ForwardIterator>
511 template <container_compatible_range<T> Range>
514 if constexpr (std::ranges::forward_range<Range> || std::ranges::sized_range<Range>) {
515 auto n =
static_cast<size_type
>(std::ranges::distance(range));
516 return insert_with_size(
position, std::ranges::begin(range), std::ranges::end(range), n);
519 return insert_with_sentinel(
position, std::ranges::begin(range), std::ranges::end(range));
525 insert(const_iterator
position, std::initializer_list<value_type>
il) {
529 constexpr iterator erase(const_iterator
position);
531 erase(const_iterator
first, const_iterator
last);
533 constexpr void clear()
noexcept {
535 base_destruct_at_end(this->begin_);
539 constexpr void resize(size_type
sz);
541 resize(size_type
sz, const_reference x);
543 constexpr void swap(
vector&)
noexcept;
545 constexpr bool invariants()
const;
548 pointer begin_ =
nullptr;
549 pointer end_ =
nullptr;
550 pointer cap_ =
nullptr;
551 PLUGIFY_NO_UNIQUE_ADDRESS
552 allocator_type alloc_;
561 constexpr void vallocate(size_type n) {
562 if (n > max_size()) {
563 this->throw_length_error();
565 auto allocation = allocate_at_least(this->alloc_, n);
572 constexpr void vdeallocate()
noexcept;
573 constexpr size_type recommend(size_type
new_size)
const;
574 constexpr void construct_at_end(size_type n);
576 construct_at_end(size_type n, const_reference x);
578 template <
class InputIterator,
class Sentinel>
581 auto guard = make_exception_guard(destroy_vector(*
this));
585 construct_at_end(std::move(
first), std::move(
last), n);
591 template <
class InputIterator,
class Sentinel>
594 auto guard = make_exception_guard(destroy_vector(*
this));
597 emplace_back(*
first);
603 template <
class Iterator,
class Sentinel>
610 template <
class Iterator,
class Sentinel>
614 template <
class Iterator>
615 requires (!std::same_as<decltype(*std::declval<Iterator&>())&&, value_type&&>)
625 template <
class Iterator>
626 requires (std::same_as<decltype(*std::declval<Iterator&>())&&, value_type&&>)
630 if constexpr (!std::forward_iterator<Iterator>) {
640 template <
class InputIterator,
class Sentinel>
644 template <
class Iterator,
class Sentinel>
648 template <
class InputIterator,
class Sentinel>
652 constexpr void append(size_type n);
654 append(size_type n, const_reference x);
656 constexpr iterator make_iter(pointer
p)
noexcept {
660 constexpr const_iterator make_iter(const_pointer
p)
const noexcept {
661 return const_iterator(
p);
671 move_assign(
vector&
c, std::true_type)
noexcept(std::is_nothrow_move_assignable<allocator_type>::value);
673 move_assign(
vector&
c, std::false_type)
noexcept(alloc_traits::is_always_equal::value);
676 destruct_at_end(pointer
new_last)
noexcept {
682 template <
class...
Args>
683 constexpr inline pointer
684 emplace_back_slow_path(
Args&&...
args);
695 annotate_contiguous_container(
704 annotate_contiguous_container(data() + capacity(), data() +
current_size);
707 constexpr void annotate_delete()
const noexcept {
708 annotate_contiguous_container(data() + size(), data() + capacity());
712 annotate_increase(size_type n)
const noexcept {
713 annotate_contiguous_container(data() + size(), data() + size() + n);
717 annotate_shrink(size_type
old_size)
const noexcept {
718 annotate_contiguous_container(data() +
old_size, data() + size());
721 struct ConstructTransaction {
723 explicit ConstructTransaction(
vector& v, size_type n)
726 , new_end_(v.end_ + n) {
727 v.annotate_increase(n);
730 constexpr ~ConstructTransaction() {
732 if (pos_ != new_end_) {
733 v_.annotate_shrink(new_end_ - v_.begin_);
739 const const_pointer new_end_;
741 ConstructTransaction(
const ConstructTransaction&) =
delete;
742 ConstructTransaction& operator=(
const ConstructTransaction&) =
delete;
746 base_destruct_at_end(pointer
new_last)
noexcept {
749 alloc_traits::destroy(this->alloc_, std::to_address(--
soon_to_be_end));
754 constexpr void copy_assign_alloc(
const vector&
c) {
757 std::integral_constant<bool, alloc_traits::propagate_on_container_copy_assignment::value>()
762 move_assign_alloc(
vector&
c)
noexcept(
763 !alloc_traits::propagate_on_container_move_assignment::value
764 || std::is_nothrow_move_assignable<allocator_type>::value
768 std::integral_constant<bool, alloc_traits::propagate_on_container_move_assignment::value>()
772 [[
noreturn]]
static void throw_length_error() {
773 PLUGIFY_THROW(
"allocated memory size would exceed max_size()", std::length_error);
776 [[
noreturn]]
static void throw_out_of_range() {
777 PLUGIFY_THROW(
"input index is out of bounds", std::out_of_range);
781 copy_assign_alloc(
const vector&
c, std::true_type) {
782 if (this->alloc_ !=
c.alloc_) {
785 alloc_traits::deallocate(this->alloc_, this->begin_, capacity());
786 this->begin_ = this->end_ = this->cap_ =
nullptr;
788 this->alloc_ =
c.alloc_;
792 copy_assign_alloc(
const vector&, std::false_type) {
796 move_assign_alloc(
vector&
c, std::true_type)
noexcept(
797 std::is_nothrow_move_assignable_v<allocator_type>
799 this->alloc_ = std::move(
c.alloc_);
803 move_assign_alloc(
vector&, std::false_type)
noexcept {
806 template <
class Ptr = po
inter>
807 requires(std::is_pointer_v<Ptr>)
808 static constexpr PLUGIFY_NO_CFI pointer add_alignment_assumption(
Ptr p)
noexcept {
809 if (!std::is_constant_evaluated()) {
810 return static_cast<pointer
>(std::assume_aligned<alignof(decltype(*p))>(
p));
815 template <
class Ptr = po
inter>
816 requires(!std::is_pointer_v<Ptr>)
817 static constexpr PLUGIFY_NO_CFI pointer add_alignment_assumption(
Ptr p)
noexcept {
849 std::ranges::input_range
Range,
858 template <
class T,
class Allocator>
863 uninitialized_allocator_relocate(
865 std::to_address(begin_),
866 std::to_address(end_),
873 v.set_data(v.begin());
874 annotate_new(size());
882 template <
class T,
class Allocator>
883 constexpr typename vector<T, Allocator>::pointer
884 vector<T, Allocator>::swap_out_circular_buffer(
885 split_buffer<value_type, allocator_type&>& v,
889 pointer ret = v.begin();
893 uninitialized_allocator_relocate(
896 std::to_address(end_),
897 std::to_address(v.end())
899 auto relocated_so_far = end_ - p;
900 v.set_sentinel(v.end() + relocated_so_far);
902 auto new_begin = v.begin() - (p - begin_);
904 uninitialized_allocator_relocate(
906 std::to_address(begin_),
908 std::to_address(new_begin)
910 v.set_valid_range(new_begin, v.end());
913 v.set_data(v.begin());
914 annotate_new(size());
918 template <
class T,
class Allocator>
919 constexpr void vector<T, Allocator>::vdeallocate() noexcept {
920 if (this->begin_ !=
nullptr) {
923 alloc_traits::deallocate(this->alloc_, this->begin_, capacity());
924 this->begin_ = this->end_ = this->cap_ =
nullptr;
929 template <
class T,
class Allocator>
931 typename vector<T, Allocator>::size_type
932 vector<T, Allocator>::recommend(size_type new_size)
const {
933 const size_type ms = max_size();
935 this->throw_length_error();
937 const size_type cap = capacity();
941 return std::max<size_type>(2 * cap, new_size);
949 template <
class T,
class Allocator>
950 constexpr void vector<T, Allocator>::construct_at_end(size_type n) {
951 ConstructTransaction tx(*
this, n);
952 const_pointer new_end = tx.new_end_;
953 for (pointer pos = tx.pos_; pos != new_end; tx.pos_ = ++pos) {
954 alloc_traits::construct(this->alloc_, std::to_address(pos));
964 template <
class T,
class Allocator>
965 constexpr inline void
966 vector<T, Allocator>::construct_at_end(size_type n, const_reference x) {
967 ConstructTransaction tx(*
this, n);
968 const_pointer new_end = tx.new_end_;
969 for (pointer pos = tx.pos_; pos != new_end; tx.pos_ = ++pos) {
970 alloc_traits::construct(this->alloc_, std::to_address(pos), x);
974 template <
class T,
class Allocator>
975 template <
class InputIterator,
class Sentinel>
977 vector<T, Allocator>::construct_at_end(InputIterator first, Sentinel last, size_type n) {
978 ConstructTransaction tx(*
this, n);
979 tx.pos_ = uninitialized_allocator_copy(
991 template <
class T,
class Allocator>
992 constexpr void vector<T, Allocator>::append(size_type n) {
993 if (
static_cast<size_type
>(this->cap_ - this->end_) >= n) {
994 this->construct_at_end(n);
996 split_buffer<value_type, allocator_type&> v(recommend(size() + n), size(), this->alloc_);
997 v.construct_at_end(n);
998 swap_out_circular_buffer(v);
1006 template <
class T,
class Allocator>
1008 vector<T, Allocator>::append(size_type n, const_reference x) {
1009 if (
static_cast<size_type
>(this->cap_ - this->end_) >= n) {
1010 this->construct_at_end(n, x);
1012 split_buffer<value_type, allocator_type&> v(recommend(size() + n), size(), this->alloc_);
1013 v.construct_at_end(n, x);
1014 swap_out_circular_buffer(v);
1018 template <
class T,
class Allocator>
1020 vector<T, Allocator>::vector(vector&& x) noexcept
1021 : alloc_(std::move(x.alloc_)) {
1022 this->begin_ = x.begin_;
1023 this->end_ = x.end_;
1024 this->cap_ = x.cap_;
1025 x.begin_ = x.end_ = x.cap_ =
nullptr;
1028 template <
class T,
class Allocator>
1030 vector<T, Allocator>::vector(vector&& x,
const std::type_identity_t<allocator_type>& a)
1032 if (a == x.alloc_) {
1033 this->begin_ = x.begin_;
1034 this->end_ = x.end_;
1035 this->cap_ = x.cap_;
1036 x.begin_ = x.end_ = x.cap_ =
nullptr;
1038 using Ip = std::move_iterator<iterator>;
1039 init_with_size(Ip(x.begin()), Ip(x.end()), x.size());
1043 template <
class T,
class Allocator>
1045 vector<T, Allocator>::move_assign(vector& c, std::false_type)
noexcept(
1046 alloc_traits::is_always_equal::value
1048 if (this->alloc_ != c.alloc_) {
1049 using Ip = std::move_iterator<iterator>;
1050 assign(Ip(c.begin()), Ip(c.end()));
1052 move_assign(c, std::true_type());
1056 template <
class T,
class Allocator>
1058 vector<T, Allocator>::move_assign(vector& c, std::true_type)
noexcept(
1059 std::is_nothrow_move_assignable<allocator_type>::value
1062 move_assign_alloc(c);
1063 this->begin_ = c.begin_;
1064 this->end_ = c.end_;
1065 this->cap_ = c.cap_;
1066 c.begin_ = c.end_ = c.cap_ =
nullptr;
1069 template <
class T,
class Allocator>
1070 constexpr inline vector<T, Allocator>&
1071 vector<T, Allocator>::operator=(
const vector& x) {
1072 if (
this != std::addressof(x)) {
1073 copy_assign_alloc(x);
1074 assign(x.begin_, x.end_);
1079 template <
class T,
class Allocator>
1080 template <
class Iterator,
class Sentinel>
1082 vector<T, Allocator>::assign_with_sentinel(Iterator first, Sentinel last) {
1083 pointer cur = begin_;
1084 for (; first != last && cur != end_; ++first, (void) ++cur) {
1088 destruct_at_end(cur);
1090 for (; first != last; ++first) {
1091 emplace_back(*first);
1096 template <
class T,
class Allocator>
1097 template <
class Iterator,
class Sentinel>
1099 vector<T, Allocator>::assign_with_size(Iterator first, Sentinel last, difference_type n) {
1100 size_type new_size =
static_cast<size_type
>(n);
1101 if (new_size <= capacity()) {
1102 if (new_size > size()) {
1103#if PLUGIFY_HAS_CXX23
1104 auto mid = std::ranges::copy_n(std::move(first), size(), this->begin_).in;
1105 construct_at_end(std::move(mid), std::move(last), new_size - size());
1107 Iterator mid = std::next(first, size());
1108 std::copy(first, mid, this->begin_);
1109 construct_at_end(mid, last, new_size - size());
1112 pointer m = std::copy(std::move(first), last, this->begin_);
1113 this->destruct_at_end(m);
1117 vallocate(recommend(new_size));
1118 construct_at_end(std::move(first), std::move(last), new_size);
1122 template <
class T,
class Allocator>
1124 vector<T, Allocator>::assign(size_type n, const_reference u) {
1125 if (n <= capacity()) {
1126 size_type s = size();
1127 std::fill_n(this->begin_, std::min(n, s), u);
1129 construct_at_end(n - s, u);
1131 this->destruct_at_end(this->begin_ + n);
1135 vallocate(recommend(
static_cast<size_type
>(n)));
1136 construct_at_end(n, u);
1140 template <
class T,
class Allocator>
1141 constexpr void vector<T, Allocator>::reserve(size_type n) {
1142 if (n > capacity()) {
1143 if (n > max_size()) {
1144 this->throw_length_error();
1146 split_buffer<value_type, allocator_type&> v(n, size(), this->alloc_);
1147 swap_out_circular_buffer(v);
1151 template <
class T,
class Allocator>
1152 constexpr void vector<T, Allocator>::shrink_to_fit() noexcept {
1153 if (capacity() > size()) {
1154#if PLUGIFY_HAS_EXCEPTIONS
1157 split_buffer<value_type, allocator_type&> v(size(), size(), this->alloc_);
1161 if (v.capacity() < capacity()) {
1162 swap_out_circular_buffer(v);
1164#if PLUGIFY_HAS_EXCEPTIONS
1171 template <
class T,
class Allocator>
1172 template <
class... Args>
1173 constexpr typename vector<T, Allocator>::pointer
1174 vector<T, Allocator>::emplace_back_slow_path(Args&&... args) {
1175 split_buffer<value_type, allocator_type&> v(recommend(size() + 1), size(), this->alloc_);
1177 pointer end = v.end();
1178 alloc_traits::construct(this->alloc_, std::to_address(end), std::forward<Args>(args)...);
1179 v.set_sentinel(++end);
1180 swap_out_circular_buffer(v);
1187 template <
class If,
class Else>
1189 if_likely_else(
bool cond, If _if, Else _else) {
1190 if (__builtin_constant_p(cond)) {
1197 if (cond) [[likely]] {
1205 template <
class T,
class Allocator>
1206 template <
class... Args>
1208 typename vector<T, Allocator>::reference
1209 vector<T, Allocator>::emplace_back(Args&&... args) {
1210 pointer end = this->end_;
1214 emplace_back_assume_capacity(std::forward<Args>(args)...);
1217 [&] { end = emplace_back_slow_path(std::forward<Args>(args)...); }
1224 template <
class T,
class Allocator>
1226 typename vector<T, Allocator>::iterator
1227 vector<T, Allocator>::erase(const_iterator position) {
1230 "vector::erase(iterator) called with a non-dereferenceable iterator"
1232 difference_type ps = position - cbegin();
1233 pointer p = this->begin_ + ps;
1234 this->destruct_at_end(std::move(p + 1, this->end_, p));
1235 return make_iter(p);
1238 template <
class T,
class Allocator>
1239 constexpr typename vector<T, Allocator>::iterator
1240 vector<T, Allocator>::erase(const_iterator first, const_iterator last) {
1243 "vector::erase(first, last) called with invalid range"
1245 pointer p = this->begin_ + (first - begin());
1246 if (first != last) {
1247 this->destruct_at_end(std::move(p + (last - first), this->end_, p));
1249 return make_iter(p);
1252 template <
class T,
class Allocator>
1254 vector<T, Allocator>::move_range(pointer from_s, pointer from_e, pointer to) {
1255 pointer old_last = this->end_;
1256 difference_type n = old_last - to;
1258 pointer i = from_s + n;
1259 ConstructTransaction tx(*
this, from_e - i);
1260 for (pointer pos = tx.pos_; i < from_e; ++i, (void) ++pos, tx.pos_ = pos) {
1261 alloc_traits::construct(this->alloc_, std::to_address(pos), std::move(*i));
1264 std::move_backward(from_s, from_s + n, old_last);
1267 template <
class T,
class Allocator>
1268 constexpr typename vector<T, Allocator>::iterator
1269 vector<T, Allocator>::insert(const_iterator position, const_reference x) {
1270 pointer p = this->begin_ + (position - begin());
1271 if (this->end_ < this->cap_) {
1272 if (p == this->end_) {
1273 emplace_back_assume_capacity(x);
1275 move_range(p, this->end_, p + 1);
1276 const_pointer xr = std::pointer_traits<const_pointer>::pointer_to(x);
1277 if (is_pointer_in_range(
1279 std::to_address(end_),
1287 split_buffer<value_type, allocator_type&> v(
1288 recommend(size() + 1),
1293 p = swap_out_circular_buffer(v, p);
1295 return make_iter(p);
1298 template <
class T,
class Allocator>
1299 constexpr typename vector<T, Allocator>::iterator
1300 vector<T, Allocator>::insert(const_iterator position, value_type&& x) {
1301 pointer p = this->begin_ + (position - begin());
1302 if (this->end_ < this->cap_) {
1303 if (p == this->end_) {
1304 emplace_back_assume_capacity(std::move(x));
1306 move_range(p, this->end_, p + 1);
1310 split_buffer<value_type, allocator_type&> v(
1311 recommend(size() + 1),
1315 v.emplace_back(std::move(x));
1316 p = swap_out_circular_buffer(v, p);
1318 return make_iter(p);
1321 template <
class T,
class Allocator>
1322 template <
class... Args>
1323 constexpr typename vector<T, Allocator>::iterator
1324 vector<T, Allocator>::emplace(const_iterator position, Args&&... args) {
1325 pointer p = this->begin_ + (position - begin());
1326 if (this->end_ < this->cap_) {
1327 if (p == this->end_) {
1328 emplace_back_assume_capacity(std::forward<Args>(args)...);
1330 detail::temp_value<value_type, Allocator> tmp(this->alloc_, std::forward<Args>(args)...);
1331 move_range(p, this->end_, p + 1);
1332 *p = std::move(tmp.get());
1335 split_buffer<value_type, allocator_type&> v(
1336 recommend(size() + 1),
1340 v.emplace_back(std::forward<Args>(args)...);
1341 p = swap_out_circular_buffer(v, p);
1343 return make_iter(p);
1346 template <
class T,
class Allocator>
1347 constexpr typename vector<T, Allocator>::iterator
1348 vector<T, Allocator>::insert(const_iterator position, size_type n, const_reference x) {
1349 pointer p = this->begin_ + (position - begin());
1351 if (n <=
static_cast<size_type
>(this->cap_ - this->end_)) {
1352 size_type old_n = n;
1353 pointer old_last = this->end_;
1354 if (n >
static_cast<size_type
>(this->end_ - p)) {
1355 size_type cx = n - (this->end_ - p);
1356 construct_at_end(cx, x);
1360 move_range(p, old_last, p + old_n);
1361 const_pointer xr = std::pointer_traits<const_pointer>::pointer_to(x);
1362 if (is_pointer_in_range(
1364 std::to_address(end_),
1369 std::fill_n(p, n, *xr);
1372 split_buffer<value_type, allocator_type&> v(
1373 recommend(size() + n),
1377 v.construct_at_end(n, x);
1378 p = swap_out_circular_buffer(v, p);
1381 return make_iter(p);
1384 template <
class T,
class Allocator>
1385 template <
class InputIterator,
class Sentinel>
1386 constexpr typename vector<T, Allocator>::iterator
1387 vector<T, Allocator>::insert_with_sentinel(
1388 const_iterator position,
1389 InputIterator first,
1392 difference_type off = position - begin();
1393 pointer p = this->begin_ + off;
1394 pointer old_last = this->end_;
1395 for (; this->end_ != this->cap_ && first != last; ++first) {
1396 emplace_back_assume_capacity(*first);
1399 if (first == last) {
1400 (void) std::rotate(p, old_last, this->end_);
1402 split_buffer<value_type, allocator_type&> v(alloc_);
1403 auto guard = make_exception_guard(
1404 AllocatorDestroyRangeReverse<allocator_type, pointer>(alloc_, old_last, this->end_)
1406 v.construct_at_end_with_sentinel(std::move(first), std::move(last));
1407 split_buffer<value_type, allocator_type&> merged(
1408 recommend(size() + v.size()),
1412 uninitialized_allocator_relocate(
1414 std::to_address(old_last),
1415 std::to_address(this->end_),
1416 std::to_address(merged.end())
1420 merged.set_sentinel(merged.end() + (this->end_ - old_last));
1421 this->end_ = old_last;
1422 uninitialized_allocator_relocate(
1424 std::to_address(v.begin()),
1425 std::to_address(v.end()),
1426 std::to_address(merged.end())
1428 merged.set_sentinel(merged.size() + v.size());
1429 v.set_sentinel(v.begin());
1430 p = swap_out_circular_buffer(merged, p);
1432 return make_iter(p);
1435 template <
class T,
class Allocator>
1436 template <
class Iterator,
class Sentinel>
1437 constexpr typename vector<T, Allocator>::iterator
1438 vector<T, Allocator>::insert_with_size(
1439 const_iterator position,
1444 pointer p = this->begin_ + (position - begin());
1446 if (n <= this->cap_ - this->end_) {
1447 pointer old_last = this->end_;
1448 difference_type dx = this->end_ - p;
1450#if PLUGIFY_HAS_CXX23
1451 if constexpr (!std::forward_iterator<Iterator>) {
1452 construct_at_end(std::move(first), std::move(last), n);
1453 std::rotate(p, old_last, this->end_);
1457 Iterator m = std::next(first, dx);
1458 construct_at_end(m, last, n - dx);
1460 move_range(p, old_last, p + n);
1461 insert_assign_n_unchecked(first, dx, p);
1465 move_range(p, old_last, p + n);
1466 insert_assign_n_unchecked(std::move(first), n, p);
1469 split_buffer<value_type, allocator_type&> v(
1470 recommend(size() + n),
1474 v.construct_at_end_with_size(std::move(first), n);
1475 p = swap_out_circular_buffer(v, p);
1478 return make_iter(p);
1481 template <
class T,
class Allocator>
1482 constexpr void vector<T, Allocator>::resize(size_type sz) {
1483 size_type cs = size();
1485 this->append(sz - cs);
1486 }
else if (cs > sz) {
1487 this->destruct_at_end(this->begin_ + sz);
1491 template <
class T,
class Allocator>
1493 vector<T, Allocator>::resize(size_type sz, const_reference x) {
1494 size_type cs = size();
1496 this->append(sz - cs, x);
1497 }
else if (cs > sz) {
1498 this->destruct_at_end(this->begin_ + sz);
1502 template <
class T,
class Allocator>
1503 constexpr void vector<T, Allocator>::swap(vector& x)
1507 alloc_traits::propagate_on_container_swap::value || this->alloc_ == x.alloc_,
1508 "vector::swap: Either propagate_on_container_swap must be true"
1509 " or the allocators must compare equal"
1511 std::swap(this->begin_, x.begin_);
1512 std::swap(this->end_, x.end_);
1513 std::swap(this->cap_, x.cap_);
1514 swap_allocator(this->alloc_, x.alloc_);
1517 template <
class T,
class Allocator>
1518 constexpr bool vector<T, Allocator>::invariants()
const {
1519 if (this->begin_ ==
nullptr) {
1520 if (this->end_ !=
nullptr || this->cap_ !=
nullptr) {
1524 if (this->begin_ > this->end_) {
1527 if (this->begin_ == this->cap_) {
1530 if (this->end_ > this->cap_) {
1538 template<
typename T,
typename Allocator>
1539 constexpr bool operator==(
const vector<T, Allocator>& lhs,
const vector<T, Allocator>& rhs) {
1540 return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin());
1543 template<
typename T,
typename Allocator>
1544 constexpr auto operator<=>(
const vector<T, Allocator>& lhs,
const vector<T, Allocator>& rhs) {
1545 return std::lexicographical_compare_three_way(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
1549 template<
typename T,
typename Allocator>
1550 constexpr void swap(vector<T, Allocator>& lhs, vector<T, Allocator>& rhs)
noexcept(
noexcept(lhs.swap(rhs))) {
1554 template<
typename T,
typename Allocator,
typename U>
1555 constexpr vector<T, Allocator>::size_type erase(vector<T, Allocator>& c,
const U& value) {
1556 auto it = std::remove(c.begin(), c.end(), value);
1557 auto r = std::distance(it, c.end());
1558 c.erase(it, c.end());
1562 template<
typename T,
typename Allocator,
typename Pred>
1563 constexpr vector<T, Allocator>::size_type erase_if(vector<T, Allocator>& c, Pred pred) {
1564 auto it = std::remove_if(c.begin(), c.end(), pred);
1565 auto r = std::distance(it, c.end());
1566 c.erase(it, c.end());
1571 template<
typename T>