7 #include <initializer_list>
8 #include <memory_resource>
19 #if PLUGIFY_VECTOR_CONTAINERS_RANGES && (__cplusplus <= 202002L || !__has_include(<ranges>) || !defined(__cpp_lib_containers_ranges))
20 # undef PLUGIFY_STRING_CONTAINERS_RANGES
21 # define PLUGIFY_STRING_CONTAINERS_RANGES 0
24 #if PLUGIFY_VECTOR_CONTAINERS_RANGES
28 #include <plugify/macro.hpp>
31 template<
typename Allocator>
33 using allocator_traits = std::allocator_traits<Allocator>;
35 using iterator_category = std::random_access_iterator_tag;
36 using value_type =
typename allocator_traits::value_type;
37 using difference_type = std::ptrdiff_t;
38 using pointer =
typename allocator_traits::pointer;
39 using reference = value_type&;
52 constexpr reference operator*()
const noexcept {
55 constexpr pointer operator->()
const noexcept {
72 constexpr
vector_iterator& operator+=(
const difference_type n) noexcept {
76 constexpr
vector_iterator operator+(
const difference_type n)
const noexcept {
80 constexpr
vector_iterator& operator-=(
const difference_type n) noexcept {
84 constexpr
vector_iterator operator-(
const difference_type n)
const noexcept {
88 constexpr reference operator[](
const difference_type n)
const noexcept {
91 template<
typename Alloc>
93 template<
typename Alloc>
95 template<
typename Alloc>
97 operator const pointer()
const noexcept {
100 pointer base()
const noexcept {
105 template<
typename Allocator>
107 using difference_type =
typename vector_iterator<Allocator>::difference_type;
108 return difference_type(lhs.base() - rhs.base());
110 template<
typename Allocator>
111 constexpr
bool operator==(
const vector_iterator<Allocator>& lhs,
const vector_iterator<Allocator>& rhs) noexcept {
112 return lhs.base() == rhs.base();
114 template<
typename Allocator>
115 constexpr
auto operator<=>(
const vector_iterator<Allocator>& lhs,
const vector_iterator<Allocator>& rhs) noexcept {
116 return lhs.base() <=> rhs.base();
119 template<
typename Allocator>
121 using allocator_traits = std::allocator_traits<Allocator>;
123 using iterator_category = std::random_access_iterator_tag;
124 using value_type =
typename allocator_traits::value_type;
125 using difference_type = std::ptrdiff_t;
126 using pointer =
typename allocator_traits::const_pointer;
127 using reference =
const value_type&;
137 : _current(other.base()) {}
142 constexpr reference operator*()
const noexcept {
145 constexpr pointer operator->()
const noexcept {
178 constexpr reference operator[](
const difference_type n)
const noexcept {
181 template<
typename Alloc>
183 template<
typename Alloc>
185 template<
typename Alloc>
187 template<
typename Alloc>
189 template<
typename Alloc>
191 template<
typename Alloc>
193 operator const pointer()
const noexcept {
196 pointer base()
const noexcept {
201 template<
typename Allocator>
203 using difference_type =
typename vector_const_iterator<Allocator>::difference_type;
204 return difference_type(lhs.base() - rhs.base());
206 template<
typename Allocator>
207 constexpr
bool operator==(
const vector_const_iterator<Allocator>& lhs,
const vector_const_iterator<Allocator>& rhs) noexcept {
208 return lhs.base() == rhs.base();
210 template<
typename Allocator>
211 constexpr
auto operator<=>(
const vector_const_iterator<Allocator>& lhs,
const vector_const_iterator<Allocator>& rhs) noexcept {
212 return lhs.base() <=> rhs.base();
214 template<
typename Allocator>
215 constexpr
typename vector_const_iterator<Allocator>::difference_type operator-(
const vector_const_iterator<Allocator>& lhs,
const vector_iterator<Allocator>& rhs) noexcept {
216 using difference_type =
typename vector_const_iterator<Allocator>::difference_type;
217 return difference_type(lhs.base() - rhs.base());
219 template<
typename Allocator>
220 constexpr
bool operator==(
const vector_const_iterator<Allocator>& lhs,
const vector_iterator<Allocator>& rhs) noexcept {
221 return lhs.base() == rhs.base();
223 template<
typename Allocator>
224 constexpr
auto operator<=>(
const vector_const_iterator<Allocator>& lhs,
const vector_iterator<Allocator>& rhs) noexcept {
225 return lhs.base() <=> rhs.base();
231 #if PLUGIFY_VECTOR_CONTAINERS_RANGES
232 template<
typename Range,
typename Type>
233 concept vector_compatible_range = std::ranges::input_range<Range> && std::convertible_to<std::ranges::range_reference_t<Range>, Type>;
239 template<
typename T,
typename Allocator = std::allocator<T>>
241 using allocator_traits = std::allocator_traits<Allocator>;
243 using value_type = T;
244 using allocator_type = Allocator;
245 using size_type =
typename allocator_traits::size_type;
246 using difference_type =
typename allocator_traits::difference_type;
247 using reference = value_type&;
248 using const_reference =
const value_type&;
249 using pointer =
typename allocator_traits::pointer;
250 using const_pointer =
typename allocator_traits::const_pointer;
253 using reverse_iterator = std::reverse_iterator<iterator>;
254 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
257 PLUGIFY_NO_UNIQUE_ADDRESS
258 allocator_type _allocator;
264 constexpr
static size_type growth_factor = 2;
266 constexpr
void copy_constructor(
const vector& other) {
267 const size_type capacity = other.capacity();
268 _begin = allocator_traits::allocate(_allocator, capacity);
269 std::uninitialized_copy(other.begin(), other.end(), begin());
270 _end = _begin + other.size();
271 _capacity = _begin + capacity;
274 template<std::input_iterator InputIterator>
275 constexpr
void range_constructor(InputIterator first, InputIterator last) {
276 const size_type count =
static_cast<size_type
>(std::distance(first, last));
277 _begin = allocator_traits::allocate(_allocator, count);
278 std::uninitialized_copy(first, last, _begin);
279 _capacity = _begin + count;
280 _end = _begin + count;
283 constexpr
bool is_full()
const {
284 return _end == _capacity;
287 constexpr size_type calculate_new_capacity()
const {
288 const size_type old_capacity = capacity();
289 return old_capacity == 0 ? 1 : growth_factor * old_capacity;
293 return begin() + (iter - cbegin());
296 constexpr
void reallocate(size_type new_capacity) {
297 reallocate(new_capacity, [](pointer
const) {});
301 constexpr
void reallocate(size_type new_capacity,
const F& construct) {
302 const size_type old_size = size();
303 const size_type old_capacity = capacity();
304 PLUGIFY_ASSERT(new_capacity >= old_size,
"plg::vector::reallocate(): resulted vector size would exceed size()", std::length_error);
305 if (new_capacity == old_capacity)
308 pointer
const new_begin = allocator_traits::allocate(_allocator, new_capacity);
309 construct(new_begin);
310 std::uninitialized_move(_begin, _end, new_begin);
311 std::destroy(_begin, _end);
312 allocator_traits::deallocate(_allocator, _begin, capacity());
314 _end = _begin + old_size;
315 _capacity = _begin + new_capacity;
319 constexpr
void emplace_at_end(
const F& construct) {
321 reallocate(calculate_new_capacity(), construct);
328 constexpr
void resize_to(size_type count,
const V& value) {
329 if (count < size()) {
330 std::destroy(_begin + count, _end);
331 _end = _begin + count;
332 }
else if (count > size()) {
333 const size_type old_size = size();
334 auto construct = [&](pointer
const data) {
335 if constexpr (std::is_same_v<V, T>) {
336 std::uninitialized_fill(data + old_size, data + count, value);
338 std::uninitialized_value_construct(data + old_size, data + count);
341 if (count > capacity()) {
342 reallocate(count, construct);
346 _end = _begin + count;
350 constexpr
void swap_without_allocator(
vector&& other) noexcept {
352 swap(_begin, other._begin);
353 swap(_end, other._end);
354 swap(_capacity, other._capacity);
359 constexpr
vector() noexcept(std::is_nothrow_default_constructible<Allocator>::value)
360 : _allocator(Allocator()), _begin{
nullptr}, _end{
nullptr}, _capacity{
nullptr} {
363 constexpr
explicit vector(
const Allocator& allocator) noexcept
364 : _allocator(allocator), _begin{
nullptr}, _end{
nullptr}, _capacity{
nullptr} {
367 constexpr
vector(size_type count,
const T& value,
const Allocator& allocator = Allocator())
368 : _allocator(allocator), _begin{
nullptr}, _end{
nullptr}, _capacity{
nullptr} {
369 PLUGIFY_ASSERT(count <= max_size(),
"plg::vector::vector(): constructed vector size would exceed max_size()", std::length_error);
370 _begin = allocator_traits::allocate(_allocator, count);
371 std::uninitialized_fill_n(_begin, count, value);
372 _capacity = _begin + count;
373 _end = _begin + count;
376 constexpr
explicit vector(size_type count,
const Allocator& allocator = Allocator())
377 : _allocator(allocator), _begin{
nullptr}, _end{
nullptr}, _capacity{
nullptr} {
378 PLUGIFY_ASSERT(count <= max_size(),
"plg::vector::vector(): constructed vector size would exceed max_size()", std::length_error);
379 _begin = allocator_traits::allocate(_allocator, count);
380 std::uninitialized_value_construct_n(_begin, count);
381 _capacity = _begin + count;
382 _end = _begin + count;
385 template<std::input_iterator InputIterator>
386 constexpr
vector(InputIterator first, InputIterator last,
const Allocator& allocator = Allocator())
387 : _allocator(allocator), _begin{
nullptr}, _end{
nullptr}, _capacity{
nullptr} {
388 PLUGIFY_ASSERT(
static_cast<size_type
>(std::distance(first, last)) <= max_size(),
"plg::vector::vector(): constructed vector size would exceed max_size()", std::length_error);
389 range_constructor(first, last);
393 : _allocator(other.get_allocator()), _begin{
nullptr}, _end{
nullptr}, _capacity{
nullptr} {
394 copy_constructor(other);
397 constexpr
vector(
const vector& other,
const Allocator& allocator)
398 : _allocator(allocator), _begin{
nullptr}, _end{
nullptr}, _capacity{
nullptr} {
399 copy_constructor(other);
402 constexpr
vector(
vector&& other) noexcept(std::is_nothrow_move_constructible<Allocator>::value)
403 : _allocator(Allocator()), _begin{
nullptr}, _end{
nullptr}, _capacity{
nullptr} {
407 constexpr
vector(
vector&& other,
const Allocator& allocator)
408 : _allocator(allocator), _begin{
nullptr}, _end{
nullptr}, _capacity{
nullptr} {
409 if constexpr (allocator_traits::is_always_equal::value) {
410 swap_without_allocator(std::move(other));
412 if (get_allocator() == other.get_allocator()) {
413 swap_without_allocator(std::move(other));
415 const size_type capacity = other.capacity();
416 _begin = allocator_traits::allocate(_allocator, capacity);
417 std::uninitialized_move(other.begin(), other.end(), begin());
418 _end = _begin + other.size();
419 _capacity = _begin + capacity;
424 constexpr
vector(std::initializer_list<T> list,
const Allocator& allocator = Allocator())
425 : _allocator(allocator), _begin{
nullptr}, _end{
nullptr}, _capacity{
nullptr} {
426 PLUGIFY_ASSERT(list.size() <= max_size(),
"plg::vector::vector(): constructed vector size would exceed max_size()", std::length_error);
427 range_constructor(list.begin(), list.end());
430 #if PLUGIFY_VECTOR_CONTAINERS_RANGES
431 template<detail::vector_compatible_range<T> Range>
432 constexpr
vector(std::from_range_t, Range&& range,
const Allocator& alloc = Allocator())
433 :
vector(std::ranges::begin(range), std::ranges::end(range), alloc) {}
438 std::destroy(_begin, _end);
439 allocator_traits::deallocate(_allocator, _begin, capacity());
444 if (
this == &other) [[unlikely]] {
449 if constexpr (allocator_traits::propagate_on_container_copy_assignment::value) {
450 if constexpr (!allocator_traits::is_always_equal::value) {
451 if (get_allocator() != other.get_allocator()) {
452 allocator_traits::deallocate(_allocator, _begin, capacity());
455 _allocator = other.get_allocator();
458 assign(other.begin(), other.end());
463 std::allocator_traits<Allocator>::propagate_on_container_move_assignment::value ||
464 std::allocator_traits<Allocator>::is_always_equal::value) {
465 if (
this == &other) [[unlikely]] {
470 if constexpr (allocator_traits::propagate_on_container_move_assignment::value) {
471 if constexpr (!allocator_traits::is_always_equal::value) {
472 if (get_allocator() != other.get_allocator()) {
473 allocator_traits::deallocate(_allocator, _begin, capacity());
476 _allocator = other.get_allocator();
479 if constexpr (allocator_traits::propagate_on_container_move_assignment::value || allocator_traits::is_always_equal::value) {
480 swap_without_allocator(std::move(other));
482 if (get_allocator() == other.get_allocator()) {
483 swap_without_allocator(std::move(other));
485 assign(std::make_move_iterator(other.begin()), std::make_move_iterator(other.end()));
492 constexpr
vector& operator=(std::initializer_list<T> list) {
493 assign(list.begin(), list.end());
498 constexpr
void assign(size_type count,
const T& value) {
499 PLUGIFY_ASSERT(count <= max_size(),
"plg::vector::assign(): resulted vector size would exceed max_size()", std::length_error);
500 if (count > capacity()) {
501 pointer
const new_begin = allocator_traits::allocate(_allocator, count);
502 std::uninitialized_fill_n(new_begin, count, value);
503 std::destroy(_begin, _end);
504 allocator_traits::deallocate(_allocator, _begin, capacity());
506 _capacity = _begin + count;
507 }
else if (size() >= count) {
508 std::fill_n(_begin, count, value);
509 std::destroy(_begin + count, _end);
511 std::fill_n(_begin, size(), value);
512 std::uninitialized_fill_n(_begin + size(), count - size(), value);
514 _end = _begin + count;
517 template<std::input_iterator InputIterator>
518 constexpr
void assign(InputIterator first, InputIterator last) {
519 const size_type count =
static_cast<size_type
>(std::distance(first, last));
520 PLUGIFY_ASSERT(count <= max_size(),
"plg::vector::assign(): resulted vector size would exceed max_size()", std::length_error);
521 if (count > capacity()) {
522 pointer
const new_begin = allocator_traits::allocate(_allocator, count);
523 std::uninitialized_copy(first, last, new_begin);
524 std::destroy(_begin, _end);
525 allocator_traits::deallocate(_allocator, _begin, capacity());
527 _capacity = _begin + count;
528 }
else if (size() >= count) {
529 std::copy(first, last, _begin);
530 std::destroy(_begin + count, _end);
532 std::copy(first, first + size(), _begin);
533 std::uninitialized_copy(first + size(), last, _begin + size());
535 _end = _begin + count;
538 constexpr
void assign(std::initializer_list<T> list) {
539 assign(list.begin(), list.end());
542 #if PLUGIFY_VECTOR_CONTAINERS_RANGES
543 template<detail::vector_compatible_range<T> Range>
544 constexpr
void assign_range(Range&& range) {
545 assign(std::ranges::begin(range), std::ranges::end(range));
550 constexpr allocator_type get_allocator()
const {
555 constexpr reference at(size_type position) {
556 PLUGIFY_ASSERT(position < size(),
"plg::vector::at(): input index is out of bounds", std::out_of_range);
557 return *(_begin + position);
560 constexpr const_reference at(size_type position)
const {
561 PLUGIFY_ASSERT(position < size(),
"plg::vector::at(): input index is out of bounds", std::out_of_range);
562 return *(_begin + position);
565 constexpr reference operator[](size_type position) noexcept {
566 return *(_begin + position);
569 constexpr const_reference operator[](size_type position)
const noexcept {
570 return *(_begin + position);
573 constexpr reference front() {
574 PLUGIFY_ASSERT(!empty(),
"plg::vector::front(): vector is empty", std::length_error);
578 constexpr const_reference front()
const {
579 PLUGIFY_ASSERT(!empty(),
"plg::vector::front(): vector is empty", std::length_error);
583 constexpr reference back() {
584 PLUGIFY_ASSERT(!empty(),
"plg::vector::back(): vector is empty", std::length_error);
588 constexpr const_reference back()
const {
589 PLUGIFY_ASSERT(!empty(),
"plg::vector::back(): vector is empty", std::length_error);
593 constexpr T* data() noexcept {
597 constexpr
const T* data()
const noexcept {
602 constexpr
iterator begin() noexcept {
626 constexpr reverse_iterator rbegin() noexcept {
627 return reverse_iterator(_end);
630 constexpr const_reverse_iterator rbegin()
const noexcept {
631 return const_reverse_iterator(_end);
634 constexpr const_reverse_iterator crbegin()
const noexcept {
635 return const_reverse_iterator(_end);
638 constexpr reverse_iterator rend() noexcept {
639 return reverse_iterator(_begin);
642 constexpr const_reverse_iterator rend()
const noexcept {
643 return const_reverse_iterator(_begin);
646 constexpr const_reverse_iterator crend()
const noexcept {
647 return const_reverse_iterator(_begin);
651 constexpr
bool empty()
const {
652 return (_begin == _end);
655 constexpr size_type size()
const noexcept {
656 return static_cast<size_type
>(_end - _begin);
659 constexpr size_type max_size()
const noexcept {
660 return allocator_traits::max_size(_allocator);
663 constexpr
void reserve(size_type new_capacity) {
664 PLUGIFY_ASSERT(new_capacity <= max_size(),
"plg::vector::reserve(): allocated memory size would exceed max_size()", std::length_error);
665 if (new_capacity > capacity()) {
666 reallocate(new_capacity);
670 constexpr size_type capacity()
const noexcept {
671 return static_cast<size_type
>(_capacity - _begin);
674 constexpr
void shrink_to_fit() {
679 constexpr
void clear() noexcept {
680 std::destroy(_begin, _end);
685 return emplace(position, value);
689 return emplace(position, std::move(value));
693 const size_type sz = size();
694 const size_type new_size = sz + count;
695 PLUGIFY_ASSERT(new_size <= max_size(),
"plg::vector::insert(): resulted vector size would exceed max_size()", std::length_error);
696 const size_type position_distance =
static_cast<size_type
>(position - cbegin());
697 PLUGIFY_ASSERT(position_distance <= sz,
"plg::vector::insert(): pos out of range", std::out_of_range);
699 if (new_size > capacity()) {
700 pointer
const new_begin = allocator_traits::allocate(_allocator, new_size);
701 pointer
const old_position = _begin + position_distance;
702 std::uninitialized_move(_begin, old_position, new_begin);
703 pointer
const new_position = new_begin + position_distance;
704 std::uninitialized_fill_n(new_position, count, value);
705 std::uninitialized_move(old_position, _end, new_position + count);
706 std::destroy(_begin, _end);
707 allocator_traits::deallocate(_allocator, _begin, capacity());
709 _end = _begin + new_size;
712 pointer
const pointer_position = _begin + position_distance;
713 std::uninitialized_fill_n(_end, count, value);
715 std::rotate(pointer_position, _end - count, _end);
718 return begin() + position_distance;
721 template<std::input_iterator InputIterator>
723 const size_type sz = size();
724 const size_type count =
static_cast<size_type
>(std::distance(first, last));
725 const size_type new_size = sz + count;
726 PLUGIFY_ASSERT(new_size <= max_size(),
"plg::vector::insert(): resulted vector size would exceed max_size()", std::length_error);
727 const size_type position_distance =
static_cast<size_type
>(position - cbegin());
728 PLUGIFY_ASSERT(position_distance <= sz,
"plg::vector::insert(): pos out of range", std::out_of_range);
730 if (new_size > capacity()) {
731 pointer
const new_begin = allocator_traits::allocate(_allocator, new_size);
732 pointer
const old_position = _begin + position_distance;
733 pointer
const new_position = new_begin + position_distance;
734 std::uninitialized_move(_begin, old_position, new_begin);
735 std::uninitialized_copy(first, last, new_position);
736 std::uninitialized_move(old_position, _end, new_position + count);
737 std::destroy(_begin, _end);
738 allocator_traits::deallocate(_allocator, _begin, capacity());
740 _end = _begin + new_size;
743 pointer
const pointer_position = _begin + position_distance;
744 std::uninitialized_copy(first, last, _end);
746 std::rotate(pointer_position, _end - count, _end);
749 return begin() + position_distance;
753 return insert(position, list.begin(), list.end());
756 #if PLUGIFY_VECTOR_CONTAINERS_RANGES
757 template<detail::vector_compatible_range<T> Range>
759 return insert(pos - begin(), std::ranges::begin(range), std::ranges::end(range));
763 template<
typename... Args>
765 const size_type sz = size();
766 const size_type new_size = sz + 1;
767 PLUGIFY_ASSERT(new_size <= max_size(),
"plg::vector::emplace(): resulted vector size would exceed max_size()", std::length_error);
768 const size_type position_distance =
static_cast<size_type
>(position - cbegin());
769 PLUGIFY_ASSERT(position_distance <= sz,
"plg::vector::emplace(): pos out of range", std::out_of_range);
770 if (position == cend()) {
771 emplace_back(std::forward<Args>(args)...);
774 const size_type new_capacity = calculate_new_capacity();
775 pointer
const new_begin = allocator_traits::allocate(_allocator, new_capacity);
776 pointer
const old_position = _begin + position_distance;
777 pointer
const new_position = new_begin + position_distance;
778 std::uninitialized_move(_begin, old_position, new_begin);
779 std::construct_at(new_position, std::forward<Args>(args)...);
780 std::uninitialized_move(old_position, _end, new_position + 1);
781 std::destroy(_begin, _end);
782 allocator_traits::deallocate(_allocator, _begin, capacity());
784 _end = _begin + new_size;
785 _capacity = _begin + new_capacity;
787 pointer
const pointer_position = _begin + position_distance;
788 std::construct_at(_end, std::forward<Args>(args)...);
790 std::rotate(pointer_position, _end - 1, _end);
793 return begin() + position_distance;
797 iterator nonconst_position = const_iterator_cast(position);
798 if (nonconst_position + 1 != end()) {
799 std::rotate(nonconst_position, nonconst_position + 1, end());
802 std::destroy_at(_end);
803 return nonconst_position;
807 PLUGIFY_ASSERT(first <= last,
"plg::vector::erase(): called with invalid range", std::out_of_range);
808 iterator nonconst_first = const_iterator_cast(first);
809 iterator nonconst_last = const_iterator_cast(last);
810 if (nonconst_first != nonconst_last) {
811 if (nonconst_last != end()) {
812 std::rotate(nonconst_first, nonconst_last, end());
814 _end = nonconst_first.base() +
static_cast<size_type
>(end() - nonconst_last);
815 std::destroy(_end, _end +
static_cast<size_type
>(std::distance(first, last)));
817 return nonconst_first;
820 constexpr
void push_back(
const T& value) {
821 const size_type sz = size();
822 PLUGIFY_ASSERT(sz + 1 <= max_size(),
"plg::vector::push_back(): resulted vector size would exceed max_size()", std::length_error);
823 emplace_at_end([&](pointer
const data) {
824 std::construct_at(data + sz, value);
829 constexpr
void push_back(T&& value) {
830 const size_type sz = size();
831 PLUGIFY_ASSERT(sz + 1 <= max_size(),
"plg::vector::push_back(): resulted vector size would exceed max_size()", std::length_error);
832 emplace_at_end([&](pointer
const data) {
833 std::construct_at(data + sz, std::move(value));
838 template<
typename... Args>
839 constexpr reference emplace_back(Args&&... args) {
840 const size_type sz = size();
841 PLUGIFY_ASSERT(sz + 1 <= max_size(),
"plg::vector::emplace_back(): resulted vector size would exceed max_size()", std::length_error);
842 emplace_at_end([&](pointer
const data) {
843 std::construct_at(data + sz, std::forward<Args>(args)...);
849 constexpr
void pop_back() {
850 PLUGIFY_ASSERT(!empty(),
"plg::vector::pop_back(): vector is empty", std::length_error);
852 std::destroy_at(_end);
855 constexpr
void resize(size_type count) {
856 PLUGIFY_ASSERT(count <= max_size(),
"plg::vector::resize(): allocated memory size would exceed max_size()", std::length_error);
860 constexpr
void resize(size_type count,
const T& value) {
861 PLUGIFY_ASSERT(count <= max_size(),
"plg::vector::resize(): allocated memory size would exceed max_size()", std::length_error);
862 resize_to(count, value);
865 constexpr
vector& operator+=(
const T& value) {
870 constexpr
vector& operator+=(T&& value) {
871 push_back(std::move(value));
876 insert(end(), other.begin(), other.end());
881 if (
this == &other) [[unlikely]] {
885 insert(end(), std::make_move_iterator(other.begin()), std::make_move_iterator(other.end()));
889 #if PLUGIFY_VECTOR_CONTAINERS_RANGES
890 template<detail::vector_compatible_range<T> Range>
891 constexpr
void append_range(Range&& range) {
892 return insert(end(), std::ranges::begin(range), std::ranges::end(range));
896 constexpr
void swap(
vector& other) noexcept(std::allocator_traits<Allocator>::propagate_on_container_swap::value || std::allocator_traits<Allocator>::is_always_equal::value) {
898 if constexpr (allocator_traits::propagate_on_container_swap::value) {
899 swap(_allocator, other._allocator);
901 swap(_begin, other._begin);
902 swap(_end, other._end);
903 swap(_capacity, other._capacity);
906 constexpr std::span<const T> span()
const noexcept {
907 return std::span<const T>(data(), size());
910 constexpr std::span<T> span() noexcept {
911 return std::span<T>(data(), size());
914 constexpr std::span<const T> const_span()
const noexcept {
915 return std::span<const T>(data(), size());
918 template<
size_type Size>
919 constexpr std::span<T, Size> span_size() noexcept {
920 PLUGIFY_ASSERT(size() == Size,
"plg::vector::span_size(): const_span_size argument does not match size of vector", std::length_error);
921 return std::span<T, Size>(data(), size());
924 template<
size_type Size>
925 constexpr std::span<const T, Size> const_span_size()
const noexcept {
926 PLUGIFY_ASSERT(size() == Size,
"plg::vector::const_span_size(): const_span_size argument does not match size of vector", std::length_error);
927 return std::span<const T, Size>(data(), size());
930 constexpr std::span<const std::byte> byte_span()
const noexcept {
931 return std::as_bytes(span());
934 constexpr std::span<std::byte> byte_span() noexcept {
935 return std::as_writable_bytes(span());
938 constexpr std::span<const std::byte> const_byte_span()
const noexcept {
939 return std::as_bytes(span());
942 constexpr
bool contains(
const T& elem)
const {
943 return std::find(begin(), end(), elem) != end();
947 constexpr
bool contains_if(F predicate) {
948 return std::find_if(begin(), end(), predicate) != end();
951 constexpr
auto find(
const T& value)
const {
952 return std::find(begin(), end(), value);
955 constexpr
auto find(
const T& value) {
956 return std::find(begin(), end(), value);
960 constexpr
auto find_if(F predicate)
const {
961 return std::find_if(begin(), end(), predicate);
965 constexpr
auto find_if(F predicate) {
966 return std::find_if(begin(), end(), predicate);
969 constexpr std::optional<size_type> find_index(
const T& value) {
970 const auto iter = std::find(begin(), end(), value);
974 return iter - begin();
978 constexpr std::optional<size_type> find_index(
const T& value)
const {
979 const auto iter = std::find(begin(), end(), value);
983 return iter - begin();
988 constexpr std::optional<size_type> find_index_if(F predicate) {
989 const auto iter = std::find_if(begin(), end(), predicate);
993 return iter - begin();
998 constexpr std::optional<size_type> find_index_if(F predicate)
const {
999 const auto iter = std::find_if(begin(), end(), predicate);
1000 if (iter == end()) {
1003 return iter - begin();
1009 template<
typename T,
typename Allocator>
1011 return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin());
1014 template<
typename T,
typename Allocator>
1015 constexpr
auto operator<=>(
const vector<T, Allocator>& lhs,
const vector<T, Allocator>& rhs) {
1016 return std::lexicographical_compare_three_way(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
1020 template<
typename T,
typename Allocator>
1021 constexpr
void swap(vector<T, Allocator>& lhs, vector<T, Allocator>& rhs) noexcept(noexcept(lhs.swap(rhs))) {
1025 template<
typename T,
typename Allocator,
typename U>
1026 constexpr
typename vector<T, Allocator>::size_type erase(vector<T, Allocator>& c,
const U& value) {
1027 auto it = std::remove(c.begin(), c.end(), value);
1028 auto r = std::distance(it, c.end());
1029 c.erase(it, c.end());
1033 template<
typename T,
typename Allocator,
typename Pred>
1034 constexpr
typename vector<T, Allocator>::size_type erase_if(vector<T, Allocator>& c, Pred pred) {
1035 auto it = std::remove_if(c.begin(), c.end(), pred);
1036 auto r = std::distance(it, c.end());
1037 c.erase(it, c.end());
1042 template<typename InputIterator, typename Allocator = std::allocator<typename std::iterator_traits<InputIterator>::value_type>>
1043 vector(InputIterator, InputIterator, Allocator = Allocator()) -> vector<typename std::iterator_traits<InputIterator>::value_type, Allocator>;
1046 template<
typename T>