29 template <
typename TYPE,
typename ALLOC = allocator<TYPE>>
31 static constexpr u_integer BLOCK_MAX_SIZE = 16;
32 static constexpr u_integer POS_INIT = (BLOCK_MAX_SIZE - 1) / 2 + 1;
54 TYPE* blockArrayInit();
61 void blocksListInit();
68 void blocksListDestruct()
noexcept;
82 [[nodiscard]]
u_integer firstAbsIdx()
const;
88 [[nodiscard]]
u_integer lastAbsIdx()
const;
157 [[nodiscard]]
bool growNeeded(
u_integer increment,
bool is_first)
const;
174 void addBlock(
bool is_first);
183 void adjust(
u_integer increment,
bool is_first);
195 mutable TYPE** data_;
196 const blocksList* container_;
221 Iterator(
const Iterator& other);
299 TYPE
get()
const override;
305 void set(
const TYPE& data)
override;
413 Iterator*
ends()
const override;
487 template <
typename TYPE,
typename ALLOC>
488 auto original::blocksList<TYPE, ALLOC>::blocksListInit() ->
void
490 this->map = vector({this->blockArrayInit()});
492 this->first_ = POS_INIT + 1;
493 this->last_ = POS_INIT;
494 this->first_block = this->map.size() / 2;
495 this->last_block = this->map.size() / 2;
498 template <
typename TYPE,
typename ALLOC>
499 auto original::blocksList<TYPE, ALLOC>::blocksListDestruct() noexcept ->
void
501 for (
auto* block : this->map) {
502 for (u_integer i = 0; i < BLOCK_MAX_SIZE; ++i) {
503 this->destroy(&block[i]);
505 this->deallocate(block, BLOCK_MAX_SIZE);
509 template <
typename TYPE,
typename ALLOC>
510 auto original::blocksList<TYPE, ALLOC>::blockArrayInit() -> TYPE* {
511 auto arr = this->allocate(BLOCK_MAX_SIZE);
512 for (u_integer i = 0; i < BLOCK_MAX_SIZE; i++) {
513 this->construct(&arr[i]);
518 template <
typename TYPE,
typename ALLOC>
519 auto original::blocksList<TYPE, ALLOC>::innerIdxToAbsIdx(
const u_integer block,
const u_integer pos) ->
u_integer
521 return block * BLOCK_MAX_SIZE + pos;
524 template <
typename TYPE,
typename ALLOC>
525 auto original::blocksList<TYPE, ALLOC>::firstAbsIdx() const -> u_integer
527 return innerIdxToAbsIdx(this->first_block, this->first_);
530 template <
typename TYPE,
typename ALLOC>
531 auto original::blocksList<TYPE, ALLOC>::lastAbsIdx() const -> u_integer
533 return innerIdxToAbsIdx(this->last_block, this->last_);
536 template <
typename TYPE,
typename ALLOC>
537 auto original::blocksList<TYPE, ALLOC>::absIdxToOuterIdx(
const u_integer absIdx)
const ->
integer
539 return absIdx - this->firstAbsIdx();
542 template <
typename TYPE,
typename ALLOC>
543 auto original::blocksList<TYPE, ALLOC>::outerIdxToAbsIdx(
const integer outerIdx)
const ->
u_integer
545 return this->firstAbsIdx() + outerIdx;
548 template <
typename TYPE,
typename ALLOC>
549 auto original::blocksList<TYPE, ALLOC>::absIdxToInnerIdx(
const u_integer absIdx) -> couple<u_integer, u_integer>
551 return {absIdx / BLOCK_MAX_SIZE, absIdx % BLOCK_MAX_SIZE};
554 template <
typename TYPE,
typename ALLOC>
555 auto original::blocksList<TYPE, ALLOC>::innerIdxOffset(
const u_integer block,
const u_integer pos,
556 const integer offset) -> couple<u_integer, u_integer>
558 return absIdxToInnerIdx(
static_cast<u_integer>(
static_cast<integer>(innerIdxToAbsIdx(block, pos)) + offset));
561 template <
typename TYPE,
typename ALLOC>
562 auto original::blocksList<TYPE, ALLOC>::outerIdxToInnerIdx(
const integer outerIdx)
const -> couple<u_integer, u_integer>
564 return absIdxToInnerIdx(this->outerIdxToAbsIdx(outerIdx));
567 template <
typename TYPE,
typename ALLOC>
568 auto original::blocksList<TYPE, ALLOC>::innerIdxToOuterIdx(
const u_integer block,
const u_integer pos)
const ->
integer
570 return this->absIdxToOuterIdx(innerIdxToAbsIdx(block, pos));
573 template <
typename TYPE,
typename ALLOC>
574 auto original::blocksList<TYPE, ALLOC>::getElem(u_integer block, u_integer pos)
const -> TYPE&
576 return this->map.get(block)[pos];
579 template <
typename TYPE,
typename ALLOC>
580 auto original::blocksList<TYPE, ALLOC>::setElem(u_integer block, u_integer pos,
const TYPE& e) ->
void
582 this->map.get(block)[pos] = e;
585 template <
typename TYPE,
typename ALLOC>
586 auto original::blocksList<TYPE, ALLOC>::growNeeded(
const u_integer increment,
bool is_first)
const ->
bool
588 return is_first ? firstAbsIdx() < increment
589 : lastAbsIdx() + increment > innerIdxToAbsIdx(this->map.size() - 1, BLOCK_MAX_SIZE - 1);
592 template <
typename TYPE,
typename ALLOC>
593 auto original::blocksList<TYPE, ALLOC>::moveElements(
const u_integer start_block,
const u_integer start_pos,
594 const u_integer len,
const integer offset) ->
void
598 for (u_integer i = 0; i < len; i++)
600 auto idx = innerIdxOffset(start_block, start_pos, len - 1 - i);
601 auto idx_offset = innerIdxOffset(start_block, start_pos, len - 1 - i + offset);
602 this->setElem(idx_offset.first(), idx_offset.second(),
603 this->getElem(idx.first(), idx.second()));
607 for (u_integer i = 0; i < len; i++)
609 auto idx = innerIdxOffset(start_block, start_pos, i);
610 auto idx_offset = innerIdxOffset(start_block, start_pos, i + offset);
611 this->setElem(idx_offset.first(), idx_offset.second(),
612 this->getElem(idx.first(), idx.second()));
617 template <
typename TYPE,
typename ALLOC>
618 auto original::blocksList<TYPE, ALLOC>::addBlock(
bool is_first) ->
void
620 auto* new_block = this->blockArrayInit();
621 is_first ? this->map.pushBegin(new_block) : this->map.pushEnd(new_block);
624 template <
typename TYPE,
typename ALLOC>
625 auto original::blocksList<TYPE, ALLOC>::adjust(
const u_integer increment,
const bool is_first) ->
void
627 if (this->growNeeded(increment, is_first)){
628 u_integer new_blocks_cnt = increment / BLOCK_MAX_SIZE + 1;
629 for (u_integer i = 0; i < new_blocks_cnt; ++i) {
630 this->addBlock(is_first);
633 this->first_block += new_blocks_cnt;
634 this->last_block += new_blocks_cnt;
639 template <
typename TYPE,
typename ALLOC>
640 original::blocksList<TYPE, ALLOC>::Iterator::Iterator(
const integer pos,
const integer block, TYPE** data_ptr,
const blocksList* container)
641 : cur_pos(pos), cur_block(block), data_(data_ptr), container_(container) {}
643 template <
typename TYPE,
typename ALLOC>
644 auto original::blocksList<TYPE, ALLOC>::Iterator::equalPtr(
const iterator<TYPE>* other)
const ->
bool
646 auto* other_it =
dynamic_cast<const Iterator*
>(other);
647 return other_it !=
nullptr
648 && this->cur_pos == other_it->cur_pos
649 && this->cur_block == other_it->cur_block
650 && this->data_ == other_it->data_
651 && this->container_ == other_it->container_;
654 template <
typename TYPE,
typename ALLOC>
655 original::blocksList<TYPE, ALLOC>::Iterator::Iterator(
const Iterator& other) : Iterator(0, 0, nullptr, nullptr)
660 template <
typename TYPE,
typename ALLOC>
666 this->cur_pos = other.cur_pos;
667 this->cur_block = other.cur_block;
668 this->data_ = other.data_;
669 this->container_ = other.container_;
673 template <
typename TYPE,
typename ALLOC>
676 return new Iterator(*
this);
679 template <
typename TYPE,
typename ALLOC>
682 return blocksList::innerIdxToAbsIdx(this->cur_block, this->cur_pos) < this->container_->lastAbsIdx();
685 template <
typename TYPE,
typename ALLOC>
688 return blocksList::innerIdxToAbsIdx(this->cur_block, this->cur_pos) > this->container_->firstAbsIdx();
691 template <
typename TYPE,
typename ALLOC>
697 template <
typename TYPE,
typename ALLOC>
703 template <
typename TYPE,
typename ALLOC>
706 auto new_idx = innerIdxOffset(this->cur_block, this->cur_pos, steps);
707 this->cur_block = new_idx.first();
708 this->cur_pos = new_idx.second();
711 template <
typename TYPE,
typename ALLOC>
714 auto new_idx = innerIdxOffset(this->cur_block, this->cur_pos, -steps);
715 this->cur_block = new_idx.first();
716 this->cur_pos = new_idx.second();
719 template <
typename TYPE,
typename ALLOC>
722 auto* other_it =
dynamic_cast<const Iterator*
>(&other);
723 if (other_it ==
nullptr)
724 return this > &other ?
725 std::numeric_limits<integer>::max() :
726 std::numeric_limits<integer>::min();
727 if (this->container_ != other_it->container_)
728 return this->container_ > other_it->container_ ?
729 std::numeric_limits<integer>::max() :
730 std::numeric_limits<integer>::min();
732 return static_cast<integer>(innerIdxToAbsIdx(this->cur_block, this->cur_pos)) -
733 static_cast<integer>(innerIdxToAbsIdx(other_it->cur_block, other_it->cur_pos));
736 template <
typename TYPE,
typename ALLOC>
740 auto* it = this->
clone();
745 template <
typename TYPE,
typename ALLOC>
749 auto* it = this->
clone();
754 template <
typename TYPE,
typename ALLOC>
758 return this->data_[this->cur_block][this->cur_pos];
761 template <
typename TYPE,
typename ALLOC>
765 return this->data_[this->cur_block][this->cur_pos];
768 template <
typename TYPE,
typename ALLOC>
772 this->data_[this->cur_block][this->cur_pos] = data;
775 template <
typename TYPE,
typename ALLOC>
778 return this->container_->innerIdxToOuterIdx(this->cur_block, this->cur_pos) >= 0 &&
779 this->container_->innerIdxToOuterIdx(this->cur_block, this->cur_pos) < this->container_->size();
782 template <
typename TYPE,
typename ALLOC>
785 auto* other_it =
dynamic_cast<const Iterator*
>(other);
786 if (other_it ==
nullptr)
791 template <
typename TYPE,
typename ALLOC>
794 auto* other_it =
dynamic_cast<const Iterator*
>(other);
795 if (other_it ==
nullptr)
800 template <
typename TYPE,
typename ALLOC>
802 return "blocksList::Iterator";
805 template <
typename TYPE,
typename ALLOC>
807 :
baseList<TYPE, ALLOC>(std::move(alloc)), map(), size_(), first_(), last_(), first_block(), last_block()
809 this->blocksListInit();
812 template <
typename TYPE,
typename ALLOC>
814 this->adjust(lst.size(),
false);
815 for (
const auto& e : lst) {
816 auto new_idx = innerIdxOffset(this->last_block, this->last_, 1);
817 this->last_block = new_idx.first();
818 this->last_ = new_idx.second();
819 this->setElem(this->last_block, this->last_, e);
824 template <
typename TYPE,
typename ALLOC>
826 this->adjust(arr.
size(),
false);
827 for (
const auto& e : arr) {
828 auto new_idx = innerIdxOffset(this->last_block, this->last_, 1);
829 this->last_block = new_idx.first();
830 this->last_ = new_idx.second();
831 this->setElem(this->last_block, this->last_, e);
836 template <
typename TYPE,
typename ALLOC>
841 template <
typename TYPE,
typename ALLOC>
843 if (
this == &other)
return *
this;
845 this->blocksListDestruct();
849 auto* block = this->blockArrayInit();
850 for (
u_integer j = 0; j < BLOCK_MAX_SIZE; ++j) {
851 block[j] = other.getElem(i, j);
853 this->map.pushEnd(block);
856 this->first_ = other.first_;
857 this->last_ = other.last_;
858 this->size_ = other.size_;
859 this->first_block = other.first_block;
860 this->last_block = other.last_block;
861 if constexpr (ALLOC::propagate_on_container_copy_assignment::value){
867 template <
typename TYPE,
typename ALLOC>
873 template <
typename TYPE,
typename ALLOC>
879 this->blocksListDestruct();
881 this->map = std::move(other.map);
882 this->first_ = other.first_;
883 this->last_ = other.last_;
884 this->first_block = other.first_block;
885 this->last_block = other.last_block;
886 this->size_ = other.size_;
887 if constexpr (ALLOC::propagate_on_container_move_assignment::value){
888 this->
allocator = std::move(other.allocator);
890 other.blocksListInit();
894 template <
typename TYPE,
typename ALLOC>
898 auto inner_idx = this->outerIdxToInnerIdx(index);
899 return this->getElem(inner_idx.first(), inner_idx.second());
902 template <
typename TYPE,
typename ALLOC>
908 template <
typename TYPE,
typename ALLOC>
910 return new Iterator(this->first_, this->first_block, &this->map.data(),
this);
913 template <
typename TYPE,
typename ALLOC>
915 return new Iterator(this->last_, this->last_block, &this->map.data(),
this);
918 template <
typename TYPE,
typename ALLOC>
922 auto inner_idx = this->outerIdxToInnerIdx(index);
923 return this->getElem(inner_idx.first(), inner_idx.second());
926 template <
typename TYPE,
typename ALLOC>
930 auto inner_idx = this->outerIdxToInnerIdx(index);
931 this->setElem(inner_idx.first(), inner_idx.second(), e);
934 template <
typename TYPE,
typename ALLOC>
937 if (
auto idx = this->outerIdxToInnerIdx(i);
938 this->getElem(idx.first(), idx.second()) == e)
944 template <
typename TYPE,
typename ALLOC>
958 const bool is_first = index <= (this->
size() - 1) / 2;
959 this->adjust(1, is_first);
961 this->moveElements(this->first_block, this->first_, index + 1, -1);
962 auto new_idx = innerIdxOffset(this->first_block, this->first_, -1);
963 this->first_block = new_idx.first();
964 this->first_ = new_idx.second();
966 auto idx = outerIdxToInnerIdx(index);
967 this->moveElements(idx.first(), idx.second(), this->size() - index, 1);
968 auto new_idx = innerIdxOffset(this->last_block, this->last_, 1);
969 this->last_block = new_idx.first();
970 this->last_ = new_idx.second();
973 auto idx = outerIdxToInnerIdx(index);
974 this->setElem(idx.first(), idx.second(), e);
978 template <
typename TYPE,
typename ALLOC>
989 auto idx = outerIdxToInnerIdx(index);
990 TYPE res = this->getElem(idx.first(), idx.second());
991 if (index <= (this->
size() - 1) / 2){
992 moveElements(this->first_block, this->first_, index, 1);
993 auto new_idx = innerIdxOffset(this->first_block, this->first_, 1);
994 this->first_block = new_idx.first();
995 this->first_ = new_idx.second();
997 auto idx_offset = innerIdxOffset(idx.first(), idx.second(), 1);
998 moveElements(idx_offset.first(), idx_offset.second(), this->size() - 1 - index, -1);
999 auto new_idx = innerIdxOffset(this->last_block, this->last_, -1);
1000 this->last_block = new_idx.first();
1001 this->last_ = new_idx.second();
1007 template <
typename TYPE,
typename ALLOC>
1010 this->adjust(1,
true);
1011 auto new_idx = innerIdxOffset(this->first_block, this->first_, -1);
1012 this->first_block = new_idx.first();
1013 this->first_ = new_idx.second();
1014 this->setElem(this->first_block, this->first_, e);
1018 template <
typename TYPE,
typename ALLOC>
1023 TYPE res = this->getElem(this->first_block, this->first_);
1024 auto new_idx = innerIdxOffset(this->first_block, this->first_, 1);
1025 this->first_block = new_idx.first();
1026 this->first_ = new_idx.second();
1031 template <
typename TYPE,
typename ALLOC>
1034 this->adjust(1,
false);
1035 auto new_idx = innerIdxOffset(this->last_block, this->last_, 1);
1036 this->last_block = new_idx.first();
1037 this->last_ = new_idx.second();
1038 this->setElem(this->last_block, this->last_, e);
1042 template <
typename TYPE,
typename ALLOC>
1047 TYPE res = this->getElem(this->last_block, this->last_);
1048 auto new_idx = innerIdxOffset(this->last_block, this->last_, -1);
1049 this->last_block = new_idx.first();
1050 this->last_ = new_idx.second();
1055 template <
typename TYPE,
typename ALLOC>
1057 return "blocksList";
1060 template <
typename TYPE,
typename ALLOC>
1062 this->blocksListDestruct();
Provides a base class for variable-size serial containers.
Default memory allocator using allocators utilities.
Definition allocator.h:154
A fixed-size array container with random access.
Definition array.h:41
u_integer size() const override
Returns the size of the array.
Definition array.h:382
A base class for basic iterators.
Definition iterator.h:259
Base class for variable-size serial containers.
Definition baseList.h:43
Iterator for blocksList, supports forward and backward iteration.
Definition blocksList.h:192
Iterator * getNext() const override
Gets the next iterator.
Definition blocksList.h:746
Iterator * clone() const override
Clones the iterator.
Definition blocksList.h:674
void operator-=(integer steps) const override
Moves the iterator backward by the specified number of steps.
Definition blocksList.h:712
Iterator & operator=(const Iterator &other)
Assignment operator for the Iterator.
Definition blocksList.h:661
void prev() const override
Moves the iterator to the previous element.
Definition blocksList.h:698
bool hasNext() const override
Checks if there is a next element.
Definition blocksList.h:680
Iterator * getPrev() const override
Gets the previous iterator.
Definition blocksList.h:737
void next() const override
Moves the iterator to the next element.
Definition blocksList.h:692
bool hasPrev() const override
Checks if there is a previous element.
Definition blocksList.h:686
void operator+=(integer steps) const override
Advances the iterator by the specified number of steps.
Definition blocksList.h:704
void set(const TYPE &data) override
Sets the value of the element pointed to by the iterator.
Definition blocksList.h:769
TYPE & get() override
Gets the element pointed to by the iterator.
Definition blocksList.h:755
bool isValid() const override
Checks if the iterator is valid.
Definition blocksList.h:776
bool atPrev(const iterator< TYPE > *other) const override
Checks if the iterator is at the previous element relative to another iterator.
Definition blocksList.h:783
bool atNext(const iterator< TYPE > *other) const override
Checks if the iterator is at the next element relative to another iterator.
Definition blocksList.h:792
std::string className() const override
Gets the class name of the iterator.
Definition blocksList.h:801
integer operator-(const iterator< TYPE > &other) const override
Computes the distance between two iterators.
Definition blocksList.h:720
A block-based list implementation.
Definition blocksList.h:30
std::string className() const override
Gets the class name of the blocksList.
Definition blocksList.h:1056
u_integer indexOf(const TYPE &e) const override
Finds the index of the first occurrence of the specified element.
Definition blocksList.h:935
void pushEnd(const TYPE &e) override
Pushes an element to the end of the blocksList.
Definition blocksList.h:1032
TYPE get(integer index) const override
Gets the element at the specified index.
Definition blocksList.h:895
blocksList(blocksList &&other) noexcept
Move constructor.
Definition blocksList.h:868
void pushBegin(const TYPE &e) override
Pushes an element to the beginning of the blocksList.
Definition blocksList.h:1008
TYPE popEnd() override
Pops the element from the end of the blocksList.
Definition blocksList.h:1043
blocksList(ALLOC alloc=ALLOC{})
Constructs an empty blocksList.
Definition blocksList.h:806
u_integer size() const override
Gets the size of the blocksList.
Definition blocksList.h:903
Iterator * begins() const override
Gets an iterator to the beginning of the blocksList.
Definition blocksList.h:909
void set(integer index, const TYPE &e) override
Sets the element at the specified index.
Definition blocksList.h:927
blocksList(const array< TYPE > &arr)
Constructs a blocksList from an array.
Definition blocksList.h:825
TYPE popBegin() override
Pops the element from the beginning of the blocksList.
Definition blocksList.h:1019
void push(integer index, const TYPE &e) override
Pushes an element to the specified index in the blocksList.
Definition blocksList.h:945
blocksList & operator=(blocksList &&other) noexcept
Move assignment operator.
Definition blocksList.h:874
blocksList(const std::initializer_list< TYPE > &lst)
Constructs a blocksList from an initializer list.
Definition blocksList.h:813
TYPE pop(integer index) override
Pops the element at the specified index in the blocksList.
Definition blocksList.h:979
blocksList(const blocksList &other)
Copy constructor.
Definition blocksList.h:837
Iterator * ends() const override
Gets an iterator to the end of the blocksList.
Definition blocksList.h:914
blocksList & operator=(const blocksList &other)
Copy assignment operator.
Definition blocksList.h:842
~blocksList() override
Destructor for the blocksList.
Definition blocksList.h:1061
TYPE & operator[](integer index) override
Gets a reference to the element at the specified index.
Definition blocksList.h:919
Abstract base class for containers.
Definition container.h:28
ALLOC allocator
The allocator instance used for memory management.
Definition container.h:34
bool empty() const
Checks if the container is empty.
Definition container.h:155
Container for two heterogeneous elements.
Definition couple.h:34
A stream class that allows iteration, comparison, and printing.
Definition iterationStream.h:33
Base iterator interface that supports common operations for iteration.
Definition iterator.h:35
Exception for missing element requests.
Definition error.h:136
Exception for container index out-of-range errors.
Definition error.h:84
bool indexOutOfBound(integer index) const
Checks if the provided index is out of bounds.
Definition serial.h:133
integer parseNegIndex(integer index) const
Converts negative indices into valid positive indices.
Definition serial.h:140
Dynamic array container with amortized constant time operations.
Definition vector.h:42
u_integer size() const override
Gets the size of the vector.
Definition vector.h:557
Generic pair container implementation.
Main namespace for the project Original.
Definition algorithms.h:21
std::uint32_t u_integer
32-bit unsigned integer type for sizes/indexes
Definition config.h:17
auto operator-(const iterator< T > &it, integer steps) -> iterator< T > *
Subtracts a number of steps from the iterator's current position and returns a new iterator.
std::int64_t integer
64-bit signed integer type for arithmetic operations
Definition config.h:15
Dynamic array container with automatic resizing.