248 using allocator_traits = std::allocator_traits<Allocator>;
252 using size_type =
typename allocator_traits::size_type;
253 using difference_type =
typename allocator_traits::difference_type;
256 using pointer =
typename allocator_traits::pointer;
257 using const_pointer =
typename allocator_traits::const_pointer;
260 using reverse_iterator = std::reverse_iterator<iterator>;
261 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
264 PLUGIFY_NO_UNIQUE_ADDRESS
271 constexpr static size_type growth_factor = 2;
273 constexpr void copy_constructor(
const vector& other) {
274 const size_type capacity = other.capacity();
275 _begin = allocator_traits::allocate(_allocator, capacity);
276 std::uninitialized_copy(other.begin(), other.end(), begin());
277 _end = _begin + other.size();
278 _capacity = _begin + capacity;
281 template<std::input_iterator InputIterator>
283 const size_type
count =
static_cast<size_type
>(std::distance(
first,
last));
284 _begin = allocator_traits::allocate(_allocator,
count);
285 std::uninitialized_copy(
first,
last, _begin);
286 _capacity = _begin +
count;
287 _end = _begin +
count;
290 constexpr bool is_full()
const {
291 return _end == _capacity;
294 constexpr size_type calculate_new_capacity()
const {
300 return begin() + (
iter - cbegin());
311 PLUGIFY_ASSERT(
new_capacity >=
old_size,
"plg::vector::reallocate(): resulted vector size would exceed size()", std::length_error);
317 std::uninitialized_move(_begin, _end,
new_begin);
318 std::destroy(_begin, _end);
319 allocator_traits::deallocate(_allocator, _begin, capacity());
326 constexpr void emplace_at_end(
const F&
construct) {
328 reallocate(calculate_new_capacity(),
construct);
335 constexpr void resize_to(size_type
count,
const V&
value) {
336 if (
count < size()) {
337 std::destroy(_begin +
count, _end);
338 _end = _begin +
count;
339 }
else if (
count > size()) {
341 auto construct = [&](pointer
const data) {
342 if constexpr (std::is_same_v<V, T>) {
345 std::uninitialized_value_construct(data +
old_size, data +
count);
348 if (
count > capacity()) {
353 _end = _begin +
count;
357 constexpr void swap_without_allocator(
vector&& other)
noexcept {
359 swap(_begin, other._begin);
360 swap(_end, other._end);
361 swap(_capacity, other._capacity);
366 constexpr vector()
noexcept(std::is_nothrow_default_constructible<Allocator>::value)
367 : _allocator(
Allocator()), _begin{
nullptr}, _end{
nullptr}, _capacity{
nullptr} {
371 : _allocator(
allocator), _begin{
nullptr}, _end{
nullptr}, _capacity{
nullptr} {
375 : _allocator(
allocator), _begin{
nullptr}, _end{
nullptr}, _capacity{
nullptr} {
376 PLUGIFY_ASSERT(
count <= max_size(),
"plg::vector::vector(): constructed vector size would exceed max_size()", std::length_error);
377 _begin = allocator_traits::allocate(_allocator,
count);
378 std::uninitialized_fill_n(_begin,
count,
value);
379 _capacity = _begin +
count;
380 _end = _begin +
count;
384 : _allocator(
allocator), _begin{
nullptr}, _end{
nullptr}, _capacity{
nullptr} {
385 PLUGIFY_ASSERT(
count <= max_size(),
"plg::vector::vector(): constructed vector size would exceed max_size()", std::length_error);
386 _begin = allocator_traits::allocate(_allocator,
count);
387 std::uninitialized_value_construct_n(_begin,
count);
388 _capacity = _begin +
count;
389 _end = _begin +
count;
392 template<std::input_iterator InputIterator>
394 : _allocator(
allocator), _begin{
nullptr}, _end{
nullptr}, _capacity{
nullptr} {
395 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);
400 : _allocator(other.get_allocator()), _begin{
nullptr}, _end{
nullptr}, _capacity{
nullptr} {
401 copy_constructor(other);
405 : _allocator(
allocator), _begin{
nullptr}, _end{
nullptr}, _capacity{
nullptr} {
406 copy_constructor(other);
409 constexpr vector(
vector&& other)
noexcept(std::is_nothrow_move_constructible<Allocator>::value)
410 : _allocator(
Allocator()), _begin{
nullptr}, _end{
nullptr}, _capacity{
nullptr} {
415 : _allocator(
allocator), _begin{
nullptr}, _end{
nullptr}, _capacity{
nullptr} {
416 if constexpr (allocator_traits::is_always_equal::value) {
417 swap_without_allocator(std::move(other));
419 if (get_allocator() == other.get_allocator()) {
420 swap_without_allocator(std::move(other));
422 const size_type capacity = other.capacity();
423 _begin = allocator_traits::allocate(_allocator, capacity);
424 std::uninitialized_move(other.begin(), other.end(), begin());
425 _end = _begin + other.size();
426 _capacity = _begin + capacity;
432 : _allocator(
allocator), _begin{
nullptr}, _end{
nullptr}, _capacity{
nullptr} {
433 PLUGIFY_ASSERT(
list.size() <= max_size(),
"plg::vector::vector(): constructed vector size would exceed max_size()", std::length_error);
434 range_constructor(
list.begin(),
list.end());
437#if PLUGIFY_VECTOR_CONTAINERS_RANGES
438 template<detail::vector_compatible_range<T> Range>
440 :
vector(std::ranges::begin(range), std::ranges::end(range),
alloc) {}
445 std::destroy(_begin, _end);
446 allocator_traits::deallocate(_allocator, _begin, capacity());
456 if constexpr (allocator_traits::propagate_on_container_copy_assignment::value) {
457 if constexpr (!allocator_traits::is_always_equal::value) {
458 if (get_allocator() != other.get_allocator()) {
459 allocator_traits::deallocate(_allocator, _begin, capacity());
462 _allocator = other.get_allocator();
465 assign(other.begin(), other.end());
470 std::allocator_traits<Allocator>::propagate_on_container_move_assignment::value ||
471 std::allocator_traits<Allocator>::is_always_equal::value) {
477 if constexpr (allocator_traits::propagate_on_container_move_assignment::value) {
478 if constexpr (!allocator_traits::is_always_equal::value) {
479 if (get_allocator() != other.get_allocator()) {
480 allocator_traits::deallocate(_allocator, _begin, capacity());
483 _allocator = other.get_allocator();
486 if constexpr (allocator_traits::propagate_on_container_move_assignment::value || allocator_traits::is_always_equal::value) {
487 swap_without_allocator(std::move(other));
489 if (get_allocator() == other.get_allocator()) {
490 swap_without_allocator(std::move(other));
492 assign(std::make_move_iterator(other.begin()), std::make_move_iterator(other.end()));
499 constexpr vector& operator=(std::initializer_list<T>
list) {
505 constexpr void assign(size_type
count,
const T&
value) {
506 PLUGIFY_ASSERT(
count <= max_size(),
"plg::vector::assign(): resulted vector size would exceed max_size()", std::length_error);
507 if (
count > capacity()) {
508 pointer
const new_begin = allocator_traits::allocate(_allocator,
count);
510 std::destroy(_begin, _end);
511 allocator_traits::deallocate(_allocator, _begin, capacity());
513 _capacity = _begin +
count;
514 }
else if (size() >=
count) {
516 std::destroy(_begin +
count, _end);
518 std::fill_n(_begin, size(),
value);
519 std::uninitialized_fill_n(_begin + size(),
count - size(),
value);
521 _end = _begin +
count;
524 template<std::input_iterator InputIterator>
526 const size_type
count =
static_cast<size_type
>(std::distance(
first,
last));
527 PLUGIFY_ASSERT(
count <= max_size(),
"plg::vector::assign(): resulted vector size would exceed max_size()", std::length_error);
528 if (
count > capacity()) {
529 pointer
const new_begin = allocator_traits::allocate(_allocator,
count);
531 std::destroy(_begin, _end);
532 allocator_traits::deallocate(_allocator, _begin, capacity());
534 _capacity = _begin +
count;
535 }
else if (size() >=
count) {
537 std::destroy(_begin +
count, _end);
540 std::uninitialized_copy(
first + size(),
last, _begin + size());
542 _end = _begin +
count;
545 constexpr void assign(std::initializer_list<T>
list) {
549#if PLUGIFY_VECTOR_CONTAINERS_RANGES
550 template<detail::vector_compatible_range<T> Range>
552 assign(std::ranges::begin(range), std::ranges::end(range));
563 PLUGIFY_ASSERT(
position < size(),
"plg::vector::at(): input index is out of bounds", std::out_of_range);
568 PLUGIFY_ASSERT(
position < size(),
"plg::vector::at(): input index is out of bounds", std::out_of_range);
581 PLUGIFY_ASSERT(!empty(),
"plg::vector::front(): vector is empty", std::length_error);
586 PLUGIFY_ASSERT(!empty(),
"plg::vector::front(): vector is empty", std::length_error);
591 PLUGIFY_ASSERT(!empty(),
"plg::vector::back(): vector is empty", std::length_error);
596 PLUGIFY_ASSERT(!empty(),
"plg::vector::back(): vector is empty", std::length_error);
600 constexpr T* data()
noexcept {
604 constexpr const T* data()
const noexcept {
609 constexpr iterator begin()
noexcept {
633 constexpr reverse_iterator rbegin()
noexcept {
634 return reverse_iterator(_end);
637 constexpr const_reverse_iterator rbegin()
const noexcept {
638 return const_reverse_iterator(_end);
641 constexpr const_reverse_iterator crbegin()
const noexcept {
642 return const_reverse_iterator(_end);
645 constexpr reverse_iterator rend()
noexcept {
646 return reverse_iterator(_begin);
649 constexpr const_reverse_iterator rend()
const noexcept {
650 return const_reverse_iterator(_begin);
653 constexpr const_reverse_iterator crend()
const noexcept {
654 return const_reverse_iterator(_begin);
658 constexpr bool empty()
const {
659 return (_begin == _end);
662 constexpr size_type size()
const noexcept {
663 return static_cast<size_type
>(_end - _begin);
666 constexpr size_type max_size()
const noexcept {
667 return allocator_traits::max_size(_allocator);
671 PLUGIFY_ASSERT(
new_capacity <= max_size(),
"plg::vector::reserve(): allocated memory size would exceed max_size()", std::length_error);
677 constexpr size_type capacity()
const noexcept {
678 return static_cast<size_type
>(_capacity - _begin);
681 constexpr void shrink_to_fit() {
686 constexpr void clear()
noexcept {
687 std::destroy(_begin, _end);
700 const size_type
sz = size();
702 PLUGIFY_ASSERT(
new_size <= max_size(),
"plg::vector::insert(): resulted vector size would exceed max_size()", std::length_error);
704 PLUGIFY_ASSERT(
position_distance <=
sz,
"plg::vector::insert(): pos out of range", std::out_of_range);
713 std::destroy(_begin, _end);
714 allocator_traits::deallocate(_allocator, _begin, capacity());
720 std::uninitialized_fill_n(_end,
count,
value);
728 template<std::input_iterator InputIterator>
730 const size_type
sz = size();
731 const size_type
count =
static_cast<size_type
>(std::distance(
first,
last));
733 PLUGIFY_ASSERT(
new_size <= max_size(),
"plg::vector::insert(): resulted vector size would exceed max_size()", std::length_error);
735 PLUGIFY_ASSERT(
position_distance <=
sz,
"plg::vector::insert(): pos out of range", std::out_of_range);
744 std::destroy(_begin, _end);
745 allocator_traits::deallocate(_allocator, _begin, capacity());
751 std::uninitialized_copy(
first,
last, _end);
763#if PLUGIFY_VECTOR_CONTAINERS_RANGES
764 template<detail::vector_compatible_range<T> Range>
766 return insert(pos - begin(), std::ranges::begin(range), std::ranges::end(range));
770 template<
typename...
Args>
772 const size_type
sz = size();
774 PLUGIFY_ASSERT(
new_size <= max_size(),
"plg::vector::emplace(): resulted vector size would exceed max_size()", std::length_error);
776 PLUGIFY_ASSERT(
position_distance <=
sz,
"plg::vector::emplace(): pos out of range", std::out_of_range);
778 emplace_back(std::forward<Args>(
args)...);
781 const size_type
new_capacity = calculate_new_capacity();
788 std::destroy(_begin, _end);
789 allocator_traits::deallocate(_allocator, _begin, capacity());
795 std::construct_at(_end, std::forward<Args>(
args)...);
809 std::destroy_at(_end);
814 PLUGIFY_ASSERT(
first <=
last,
"plg::vector::erase(): called with invalid range", std::out_of_range);
822 std::destroy(_end, _end +
static_cast<size_type
>(std::distance(
first,
last)));
827 constexpr void push_back(
const T&
value) {
828 const size_type
sz = size();
829 PLUGIFY_ASSERT(
sz + 1 <= max_size(),
"plg::vector::push_back(): resulted vector size would exceed max_size()", std::length_error);
830 emplace_at_end([&](pointer
const data) {
831 std::construct_at(data +
sz,
value);
836 constexpr void push_back(
T&&
value) {
837 const size_type
sz = size();
838 PLUGIFY_ASSERT(
sz + 1 <= max_size(),
"plg::vector::push_back(): resulted vector size would exceed max_size()", std::length_error);
839 emplace_at_end([&](pointer
const data) {
840 std::construct_at(data +
sz, std::move(
value));
845 template<
typename...
Args>
847 const size_type
sz = size();
848 PLUGIFY_ASSERT(
sz + 1 <= max_size(),
"plg::vector::emplace_back(): resulted vector size would exceed max_size()", std::length_error);
849 emplace_at_end([&](pointer
const data) {
850 std::construct_at(data +
sz, std::forward<Args>(
args)...);
856 constexpr void pop_back() {
857 PLUGIFY_ASSERT(!empty(),
"plg::vector::pop_back(): vector is empty", std::length_error);
859 std::destroy_at(_end);
862 constexpr void resize(size_type
count) {
863 PLUGIFY_ASSERT(
count <= max_size(),
"plg::vector::resize(): allocated memory size would exceed max_size()", std::length_error);
867 constexpr void resize(size_type
count,
const T&
value) {
868 PLUGIFY_ASSERT(
count <= max_size(),
"plg::vector::resize(): allocated memory size would exceed max_size()", std::length_error);
878 push_back(std::move(
value));
883 insert(end(), other.begin(), other.end());
892 insert(end(), std::make_move_iterator(other.begin()), std::make_move_iterator(other.end()));
896#if PLUGIFY_VECTOR_CONTAINERS_RANGES
897 template<detail::vector_compatible_range<T> Range>
899 return insert(end(), std::ranges::begin(range), std::ranges::end(range));
903 constexpr void swap(
vector& other)
noexcept(std::allocator_traits<Allocator>::propagate_on_container_swap::value || std::allocator_traits<Allocator>::is_always_equal::value) {
905 if constexpr (allocator_traits::propagate_on_container_swap::value) {
906 swap(_allocator, other._allocator);
908 swap(_begin, other._begin);
909 swap(_end, other._end);
910 swap(_capacity, other._capacity);
913 constexpr std::span<const T> span()
const noexcept {
914 return std::span<const T>(data(), size());
917 constexpr std::span<T> span()
noexcept {
918 return std::span<T>(data(), size());
921 template<
size_type Size>
922 constexpr std::span<T, Size> span_size() {
923 PLUGIFY_ASSERT(size() ==
Size,
"plg::vector::span_size(): const_span_size argument does not match size of vector", std::length_error);
924 return std::span<T, Size>(data(), size());
927 template<
size_type Size>
928 constexpr std::span<const T, Size> const_span_size()
const {
929 PLUGIFY_ASSERT(size() ==
Size,
"plg::vector::const_span_size(): const_span_size argument does not match size of vector", std::length_error);
930 return std::span<const T, Size>(data(), size());
933 constexpr std::span<const std::byte> byte_span()
const noexcept {
934 return std::as_bytes(span());
937 constexpr std::span<std::byte> byte_span()
noexcept {
938 return std::as_writable_bytes(span());
941 constexpr bool contains(
const T&
elem)
const {
942 return std::find(begin(), end(),
elem) != end();
947 return std::find_if(begin(), end(),
predicate) != end();
950 constexpr auto find(
const T&
value)
const {
951 return std::find(begin(), end(),
value);
954 constexpr auto find(
const T&
value) {
955 return std::find(begin(), end(),
value);
960 return std::find_if(begin(), end(),
predicate);
965 return std::find_if(begin(), end(),
predicate);
968 constexpr std::optional<size_type> find_index(
const T&
value) {
969 const auto iter = std::find(begin(), end(),
value);
973 return iter - begin();
977 constexpr std::optional<size_type> find_index(
const T&
value)
const {
978 const auto iter = std::find(begin(), end(),
value);
982 return iter - begin();
987 constexpr std::optional<size_type> find_index_if(
F predicate) {
992 return iter - begin();
997 constexpr std::optional<size_type> find_index_if(
F predicate)
const {
1002 return iter - begin();