259 using allocator_traits = std::allocator_traits<Allocator>;
263 using size_type =
typename allocator_traits::size_type;
264 using difference_type =
typename allocator_traits::difference_type;
267 using pointer =
typename allocator_traits::pointer;
268 using const_pointer =
typename allocator_traits::const_pointer;
271 using reverse_iterator = std::reverse_iterator<iterator>;
272 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
275 PLUGIFY_NO_UNIQUE_ADDRESS
282 constexpr static size_type growth_factor = 2;
284 constexpr void copy_constructor(
const vector&
other) {
285 const size_type capacity =
other.capacity();
286 _begin = allocator_traits::allocate(_allocator, capacity);
287 std::uninitialized_copy(
other.begin(),
other.end(), begin());
288 _end = _begin +
other.size();
289 _capacity = _begin + capacity;
292 template<PLUGIFY_INPUT_ITERATOR InputIterator>
294 const size_type
count =
static_cast<size_type
>(std::distance(
first,
last));
295 _begin = allocator_traits::allocate(_allocator,
count);
296 std::uninitialized_copy(
first,
last, _begin);
297 _capacity = _begin +
count;
298 _end = _begin +
count;
301 [[
nodiscard]]
constexpr bool is_full()
const {
302 return _end == _capacity;
305 [[
nodiscard]]
constexpr size_type calculate_new_capacity()
const {
311 return begin() + (
iter - cbegin());
322 PLUGIFY_ASSERT(
new_capacity >=
old_size,
"plg::vector::reallocate(): resulted vector size would exceed size()", std::length_error);
328 std::uninitialized_move(_begin, _end,
new_begin);
329 std::destroy(_begin, _end);
330 allocator_traits::deallocate(_allocator, _begin, capacity());
337 constexpr void emplace_at_end(
const F&
construct) {
339 reallocate(calculate_new_capacity(),
construct);
346 constexpr void resize_to(size_type
count,
const V&
value) {
347 if (
count < size()) {
348 std::destroy(_begin +
count, _end);
349 _end = _begin +
count;
350 }
else if (
count > size()) {
352 auto construct = [&](pointer
const data) {
353 if constexpr (std::is_same_v<V, T>) {
356 std::uninitialized_value_construct(data +
old_size, data +
count);
359 if (
count > capacity()) {
364 _end = _begin +
count;
368 constexpr void swap_without_allocator(
vector&&
other)
noexcept {
370 swap(_begin,
other._begin);
371 swap(_end,
other._end);
372 swap(_capacity,
other._capacity);
377 constexpr vector()
noexcept(std::is_nothrow_default_constructible<Allocator>::value)
378 : _allocator(
Allocator()), _begin{
nullptr}, _end{
nullptr}, _capacity{
nullptr} {
382 : _allocator(
allocator), _begin{
nullptr}, _end{
nullptr}, _capacity{
nullptr} {
386 : _allocator(
allocator), _begin{
nullptr}, _end{
nullptr}, _capacity{
nullptr} {
387 PLUGIFY_ASSERT(
count <= max_size(),
"plg::vector::vector(): constructed vector size would exceed max_size()", std::length_error);
388 _begin = allocator_traits::allocate(_allocator,
count);
389 std::uninitialized_fill_n(_begin,
count,
value);
390 _capacity = _begin +
count;
391 _end = _begin +
count;
395 : _allocator(
allocator), _begin{
nullptr}, _end{
nullptr}, _capacity{
nullptr} {
396 PLUGIFY_ASSERT(
count <= max_size(),
"plg::vector::vector(): constructed vector size would exceed max_size()", std::length_error);
397 _begin = allocator_traits::allocate(_allocator,
count);
398 std::uninitialized_value_construct_n(_begin,
count);
399 _capacity = _begin +
count;
400 _end = _begin +
count;
403 template<PLUGIFY_INPUT_ITERATOR InputIterator>
405 : _allocator(
allocator), _begin{
nullptr}, _end{
nullptr}, _capacity{
nullptr} {
406 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);
411 : _allocator(
other.get_allocator()), _begin{
nullptr}, _end{
nullptr}, _capacity{
nullptr} {
412 copy_constructor(
other);
416 : _allocator(
allocator), _begin{
nullptr}, _end{
nullptr}, _capacity{
nullptr} {
417 copy_constructor(
other);
420 constexpr vector(
vector&&
other)
noexcept(std::is_nothrow_move_constructible<Allocator>::value)
421 : _allocator(
Allocator()), _begin{
nullptr}, _end{
nullptr}, _capacity{
nullptr} {
426 : _allocator(
allocator), _begin{
nullptr}, _end{
nullptr}, _capacity{
nullptr} {
427 if constexpr (allocator_traits::is_always_equal::value) {
428 swap_without_allocator(std::move(
other));
430 if (get_allocator() ==
other.get_allocator()) {
431 swap_without_allocator(std::move(
other));
433 const size_type capacity =
other.capacity();
434 _begin = allocator_traits::allocate(_allocator, capacity);
435 std::uninitialized_move(
other.begin(),
other.end(), begin());
436 _end = _begin +
other.size();
437 _capacity = _begin + capacity;
443 : _allocator(
allocator), _begin{
nullptr}, _end{
nullptr}, _capacity{
nullptr} {
444 PLUGIFY_ASSERT(
list.size() <= max_size(),
"plg::vector::vector(): constructed vector size would exceed max_size()", std::length_error);
445 range_constructor(
list.begin(),
list.end());
448#if PLUGIFY_VECTOR_CONTAINERS_RANGES
449 template<detail::vector_compatible_range<T> Range>
451 :
vector(std::ranges::begin(range), std::ranges::end(range),
alloc) {}
455#if __cpp_constexpr >= 201907L
459 std::destroy(_begin, _end);
460 allocator_traits::deallocate(_allocator, _begin, capacity());
470 if constexpr (allocator_traits::propagate_on_container_copy_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();
484 std::allocator_traits<Allocator>::propagate_on_container_move_assignment::value ||
485 std::allocator_traits<Allocator>::is_always_equal::value) {
491 if constexpr (allocator_traits::propagate_on_container_move_assignment::value) {
492 if constexpr (!allocator_traits::is_always_equal::value) {
493 if (get_allocator() !=
other.get_allocator()) {
494 allocator_traits::deallocate(_allocator, _begin, capacity());
497 _allocator =
other.get_allocator();
500 if constexpr (allocator_traits::propagate_on_container_move_assignment::value || allocator_traits::is_always_equal::value) {
501 swap_without_allocator(std::move(
other));
503 if (get_allocator() ==
other.get_allocator()) {
504 swap_without_allocator(std::move(
other));
506 assign(std::make_move_iterator(
other.begin()), std::make_move_iterator(
other.end()));
513 constexpr vector& operator=(std::initializer_list<T>
list) {
519 constexpr void assign(size_type
count,
const T&
value) {
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);
524 std::destroy(_begin, _end);
525 allocator_traits::deallocate(_allocator, _begin, capacity());
527 _capacity = _begin +
count;
528 }
else if (size() >=
count) {
530 std::destroy(_begin +
count, _end);
532 std::fill_n(_begin, size(),
value);
533 std::uninitialized_fill_n(_begin + size(),
count - size(),
value);
535 _end = _begin +
count;
538 template<PLUGIFY_INPUT_ITERATOR InputIterator>
540 const size_type
count =
static_cast<size_type
>(std::distance(
first,
last));
541 PLUGIFY_ASSERT(
count <= max_size(),
"plg::vector::assign(): resulted vector size would exceed max_size()", std::length_error);
542 if (
count > capacity()) {
543 pointer
const new_begin = allocator_traits::allocate(_allocator,
count);
545 std::destroy(_begin, _end);
546 allocator_traits::deallocate(_allocator, _begin, capacity());
548 _capacity = _begin +
count;
549 }
else if (size() >=
count) {
551 std::destroy(_begin +
count, _end);
554 std::uninitialized_copy(
first + size(),
last, _begin + size());
556 _end = _begin +
count;
559 constexpr void assign(std::initializer_list<T>
list) {
563#if PLUGIFY_VECTOR_CONTAINERS_RANGES
564 template<detail::vector_compatible_range<T> Range>
566 assign(std::ranges::begin(range), std::ranges::end(range));
577 PLUGIFY_ASSERT(
position < size(),
"plg::vector::at(): input index is out of bounds", std::out_of_range);
582 PLUGIFY_ASSERT(
position < size(),
"plg::vector::at(): input index is out of bounds", std::out_of_range);
595 PLUGIFY_ASSERT(!empty(),
"plg::vector::front(): vector is empty", std::length_error);
600 PLUGIFY_ASSERT(!empty(),
"plg::vector::front(): vector is empty", std::length_error);
605 PLUGIFY_ASSERT(!empty(),
"plg::vector::back(): vector is empty", std::length_error);
610 PLUGIFY_ASSERT(!empty(),
"plg::vector::back(): vector is empty", std::length_error);
618 [[
nodiscard]]
constexpr const T* data()
const noexcept {
647 [[
nodiscard]]
constexpr reverse_iterator rbegin()
noexcept {
648 return reverse_iterator(_end);
651 [[
nodiscard]]
constexpr const_reverse_iterator rbegin()
const noexcept {
652 return const_reverse_iterator(_end);
655 [[
nodiscard]]
constexpr const_reverse_iterator crbegin()
const noexcept {
656 return const_reverse_iterator(_end);
659 [[
nodiscard]]
constexpr reverse_iterator rend()
noexcept {
660 return reverse_iterator(_begin);
663 [[
nodiscard]]
constexpr const_reverse_iterator rend()
const noexcept {
664 return const_reverse_iterator(_begin);
667 [[
nodiscard]]
constexpr const_reverse_iterator crend()
const noexcept {
668 return const_reverse_iterator(_begin);
672 [[
nodiscard]]
constexpr bool empty()
const {
673 return (_begin == _end);
676 [[
nodiscard]]
constexpr size_type size()
const noexcept {
677 return static_cast<size_type
>(_end - _begin);
680 [[
nodiscard]]
constexpr size_type max_size()
const noexcept {
681 return allocator_traits::max_size(_allocator);
685 PLUGIFY_ASSERT(
new_capacity <= max_size(),
"plg::vector::reserve(): allocated memory size would exceed max_size()", std::length_error);
691 [[
nodiscard]]
constexpr size_type capacity()
const noexcept {
692 return static_cast<size_type
>(_capacity - _begin);
695 constexpr void shrink_to_fit() {
700 constexpr void clear()
noexcept {
701 std::destroy(_begin, _end);
714 const size_type
sz = size();
716 PLUGIFY_ASSERT(
new_size <= max_size(),
"plg::vector::insert(): resulted vector size would exceed max_size()", std::length_error);
718 PLUGIFY_ASSERT(
position_distance <=
sz,
"plg::vector::insert(): pos out of range", std::out_of_range);
727 std::destroy(_begin, _end);
728 allocator_traits::deallocate(_allocator, _begin, capacity());
734 std::uninitialized_fill_n(_end,
count,
value);
742 template<PLUGIFY_INPUT_ITERATOR InputIterator>
744 const size_type
sz = size();
745 const size_type
count =
static_cast<size_type
>(std::distance(
first,
last));
747 PLUGIFY_ASSERT(
new_size <= max_size(),
"plg::vector::insert(): resulted vector size would exceed max_size()", std::length_error);
749 PLUGIFY_ASSERT(
position_distance <=
sz,
"plg::vector::insert(): pos out of range", std::out_of_range);
758 std::destroy(_begin, _end);
759 allocator_traits::deallocate(_allocator, _begin, capacity());
765 std::uninitialized_copy(
first,
last, _end);
777#if PLUGIFY_VECTOR_CONTAINERS_RANGES
778 template<detail::vector_compatible_range<T> Range>
780 return insert(pos - begin(), std::ranges::begin(range), std::ranges::end(range));
784 template<
typename...
Args>
786 const size_type
sz = size();
788 PLUGIFY_ASSERT(
new_size <= max_size(),
"plg::vector::emplace(): resulted vector size would exceed max_size()", std::length_error);
790 PLUGIFY_ASSERT(
position_distance <=
sz,
"plg::vector::emplace(): pos out of range", std::out_of_range);
792 emplace_back(std::forward<Args>(
args)...);
795 const size_type
new_capacity = calculate_new_capacity();
802 std::destroy(_begin, _end);
803 allocator_traits::deallocate(_allocator, _begin, capacity());
809 PLUGIFY_CONSTRUCT_AT(_end, std::forward<Args>(
args)...);
823 std::destroy_at(_end);
828 PLUGIFY_ASSERT(
first <=
last,
"plg::vector::erase(): called with invalid range", std::out_of_range);
836 std::destroy(_end, _end +
static_cast<size_type
>(std::distance(
first,
last)));
841 constexpr void push_back(
const T&
value) {
842 const size_type
sz = size();
843 PLUGIFY_ASSERT(
sz + 1 <= max_size(),
"plg::vector::push_back(): resulted vector size would exceed max_size()", std::length_error);
844 emplace_at_end([&](pointer
const data) {
845 PLUGIFY_CONSTRUCT_AT(data +
sz,
value);
850 constexpr void push_back(
T&&
value) {
851 const size_type
sz = size();
852 PLUGIFY_ASSERT(
sz + 1 <= max_size(),
"plg::vector::push_back(): resulted vector size would exceed max_size()", std::length_error);
853 emplace_at_end([&](pointer
const data) {
854 PLUGIFY_CONSTRUCT_AT(data +
sz, std::move(
value));
859 template<
typename...
Args>
861 const size_type
sz = size();
862 PLUGIFY_ASSERT(
sz + 1 <= max_size(),
"plg::vector::emplace_back(): resulted vector size would exceed max_size()", std::length_error);
863 emplace_at_end([&](pointer
const data) {
864 PLUGIFY_CONSTRUCT_AT(data +
sz, std::forward<Args>(
args)...);
870 constexpr void pop_back() {
871 PLUGIFY_ASSERT(!empty(),
"plg::vector::pop_back(): vector is empty", std::length_error);
873 std::destroy_at(_end);
876 constexpr void resize(size_type
count) {
877 PLUGIFY_ASSERT(
count <= max_size(),
"plg::vector::resize(): allocated memory size would exceed max_size()", std::length_error);
881 constexpr void resize(size_type
count,
const T&
value) {
882 PLUGIFY_ASSERT(
count <= max_size(),
"plg::vector::resize(): allocated memory size would exceed max_size()", std::length_error);
892 push_back(std::move(
value));
906 insert(end(), std::make_move_iterator(
other.begin()), std::make_move_iterator(
other.end()));
910#if PLUGIFY_VECTOR_CONTAINERS_RANGES
911 template<detail::vector_compatible_range<T> Range>
913 return insert(end(), std::ranges::begin(range), std::ranges::end(range));
917 constexpr void swap(
vector&
other)
noexcept(std::allocator_traits<Allocator>::propagate_on_container_swap::value || std::allocator_traits<Allocator>::is_always_equal::value) {
919 if constexpr (allocator_traits::propagate_on_container_swap::value) {
920 swap(_allocator,
other._allocator);
922 swap(_begin,
other._begin);
923 swap(_end,
other._end);
924 swap(_capacity,
other._capacity);
928 constexpr operator std::span<T>()
const noexcept {
929 return std::span<T>(data(), size());
931 constexpr operator std::span<const T>()
const noexcept {
932 return std::span<const T>(data(), size());
935 constexpr std::span<const T>
span()
const noexcept {
936 return std::span<const T>(data(), size());
939 constexpr std::span<T>
span()
noexcept {
940 return std::span<T>(data(), size());
943 constexpr std::span<const T>
const_span()
const noexcept {
944 return std::span<const T>(data(), size());
947 template<
size_type Size>
949 PLUGIFY_ASSERT(size() ==
Size,
"plg::vector::span_size(): const_span_size argument does not match size of vector", std::length_error);
950 return std::span<T, Size>(data(), size());
953 template<
size_type Size>
955 PLUGIFY_ASSERT(size() ==
Size,
"plg::vector::const_span_size(): const_span_size argument does not match size of vector", std::length_error);
956 return std::span<const T, Size>(data(), size());
960 return std::as_bytes(
span());
964 return std::as_writable_bytes(
span());
968 return std::as_bytes(
span());
973 return std::find(begin(), end(),
elem) != end();
978 return std::find_if(begin(), end(),
predicate) != end();
982 return std::find(begin(), end(),
value);
986 return std::find(begin(), end(),
value);
991 return std::find_if(begin(), end(),
predicate);
996 return std::find_if(begin(), end(),
predicate);
999 [[
nodiscard]]
constexpr std::optional<size_type> find_index(
const T&
value) {
1000 const auto iter = std::find(begin(), end(),
value);
1001 if (
iter == end()) {
1004 return iter - begin();
1008 [[
nodiscard]]
constexpr std::optional<size_type> find_index(
const T&
value)
const {
1009 const auto iter = std::find(begin(), end(),
value);
1010 if (
iter == end()) {
1013 return iter - begin();
1017 template<
typename F>
1020 if (
iter == end()) {
1023 return iter - begin();
1027 template<
typename F>
1030 if (
iter == end()) {
1033 return iter - begin();