ORIGINAL
Loading...
Searching...
No Matches
chain.h
Go to the documentation of this file.
1#ifndef CHAIN_H
2#define CHAIN_H
3#pragma once
4
6#include "array.h"
7#include "baseList.h"
8#include "iterationStream.h"
9
20namespace original {
35 template <typename TYPE, typename ALLOC = allocator<TYPE>>
36 class chain final : public baseList<TYPE, ALLOC>, public iterationStream<TYPE, chain<TYPE, ALLOC>>{
46 class chainNode final : public wrapper<TYPE>{
47 public:
48 friend class iterator<TYPE>;
49 friend class chain;
50
57 explicit chainNode(const TYPE& data = TYPE{}, chainNode* prev = nullptr, chainNode* next = nullptr);
58 private:
59 TYPE data_;
60 chainNode* prev;
61 chainNode* next;
62 protected:
63
68 chainNode(const chainNode& other);
69
75 chainNode& operator=(const chainNode& other);
76
81 TYPE& getVal() override;
82
87 const TYPE& getVal() const override;
88
93 void setVal(TYPE data) override;
94
99 chainNode* getPPrev() const override;
100
105 chainNode* getPNext() const override;
106
111 void setPPrev(chainNode* new_prev);
112
117 void setPNext(chainNode* new_next);
118
124 static void connect(chainNode* prev, chainNode* next);
125 };
126
131 using rebind_alloc_node = ALLOC::template rebind_alloc<chainNode>;
132
133 u_integer size_;
134 chainNode* begin_;
135 chainNode* end_;
136 rebind_alloc_node rebind_alloc{};
137
138
144 chainNode* findNode(integer index) const;
145
153 chainNode* createNode(const TYPE& value = TYPE{}, chainNode* prev = nullptr, chainNode* next = nullptr);
154
160 void destroyNode(chainNode* node) noexcept;
161
165 void chainInit();
166
171 void firstAdd(chainNode* node);
172
177 chainNode* lastDelete();
178
182 void chainDestroy();
183 public:
184
194 class Iterator final : public doubleDirectionIterator<TYPE>
195 {
196
201 explicit Iterator(chainNode* ptr);
202 public:
203 friend chain;
204
209 Iterator(const Iterator& other);
210
216 Iterator& operator=(const Iterator& other);
217
222 Iterator* clone() const override;
223
229 bool atPrev(const iterator<TYPE> *other) const override;
230
236 bool atNext(const iterator<TYPE> *other) const override;
237
242 [[nodiscard]] std::string className() const override;
243 };
244
249 explicit chain(ALLOC alloc = ALLOC{});
250
256 chain(const chain& other);
257
262 chain(const std::initializer_list<TYPE>& list);
263
268 explicit chain(const array<TYPE>& arr);
269
276 chain& operator=(const chain& other);
277
283 chain(chain&& other) noexcept;
284
291 chain& operator=(chain&& other) noexcept;
292
299
304 [[nodiscard]] u_integer size() const override;
305
311 TYPE get(integer index) const override;
312
318 TYPE& operator[](integer index) override;
319
325 void set(integer index, const TYPE &e) override;
326
332 u_integer indexOf(const TYPE &e) const override;
333
338 void pushBegin(const TYPE &e) override;
339
345 void push(integer index, const TYPE &e) override;
346
351 void pushEnd(const TYPE &e) override;
352
357 TYPE popBegin() override;
358
364 TYPE pop(integer index) override;
365
370 TYPE popEnd() override;
371
376 Iterator* begins() const override;
377
382 Iterator* ends() const override;
383
388 [[nodiscard]] std::string className() const override;
389
393 ~chain() override;
394 };
395}
396
397 template <typename TYPE, typename ALLOC>
398 original::chain<TYPE, ALLOC>::chainNode::chainNode(const TYPE& data, chainNode* prev, chainNode* next)
399 : data_(data), prev(prev), next(next) {}
400
401 template <typename TYPE, typename ALLOC>
403 : data_(other.data_), prev(other.prev), next(other.next) {}
404
405 template <typename TYPE, typename ALLOC>
406 auto original::chain<TYPE, ALLOC>::chainNode::operator=(const chainNode& other) -> chainNode& {
407 if (this != &other) {
408 data_ = other.data_;
409 prev = other.prev;
410 next = other.next;
411 }
412 return *this;
413 }
414
415 template <typename TYPE, typename ALLOC>
417 {
418 return this->data_;
419 }
420
421 template <typename TYPE, typename ALLOC>
422 auto original::chain<TYPE, ALLOC>::chainNode::getVal() const -> const TYPE&
423 {
424 return this->data_;
425 }
426
427 template <typename TYPE, typename ALLOC>
429 {
430 this->data_ = data;
431 }
432
433 template <typename TYPE, typename ALLOC>
434 auto original::chain<TYPE, ALLOC>::chainNode::getPPrev() const -> chainNode* {
435 return this->prev;
436 }
437
438 template <typename TYPE, typename ALLOC>
439 auto original::chain<TYPE, ALLOC>::chainNode::getPNext() const -> chainNode* {
440 return this->next;
441 }
442
443 template <typename TYPE, typename ALLOC>
444 auto original::chain<TYPE, ALLOC>::chainNode::setPPrev(chainNode* new_prev) -> void {
445 this->prev = new_prev;
446 }
447
448 template <typename TYPE, typename ALLOC>
449 auto original::chain<TYPE, ALLOC>::chainNode::setPNext(chainNode* new_next) -> void {
450 this->next = new_next;
451 }
452
453 template <typename TYPE, typename ALLOC>
454 auto original::chain<TYPE, ALLOC>::chainNode::connect(chainNode* prev, chainNode* next) -> void
455 {
456 if (prev != nullptr) prev->setPNext(next);
457 if (next != nullptr) next->setPPrev(prev);
458 }
459
460 template <typename TYPE, typename ALLOC>
461 auto original::chain<TYPE, ALLOC>::findNode(integer index) const -> chainNode* {
462 const bool reverse_visit = index <= this->size() / 2 ? 0 : 1;
463 chainNode* cur;
464 if (!reverse_visit){
465 cur = this->begin_;
466 for(u_integer i = 0; i < index; i++)
467 {
468 cur = cur->getPNext();
469 }
470 } else{
471 cur = this->end_;
472 for(u_integer i = this->size() - 1; i > index; i -= 1)
473 {
474 cur = cur->getPPrev();
475 }
476 }
477 return cur;
478 }
479
480 template<typename TYPE, typename ALLOC>
481 auto original::chain<TYPE, ALLOC>::createNode(const TYPE &value, chainNode* prev, chainNode* next) -> chainNode* {
482 auto node = this->rebind_alloc.allocate(1);
483 this->rebind_alloc.construct(node, value, prev, next);
484 return node;
485 }
486
487 template<typename TYPE, typename ALLOC>
488 void original::chain<TYPE, ALLOC>::destroyNode(chainNode *node) noexcept {
489 this->rebind_alloc.destroy(node);
490 this->rebind_alloc.deallocate(node, 1);
491 }
492
493 template <typename TYPE, typename ALLOC>
495 {
496 auto pivot = this->createNode();
497 this->size_ = 0;
498 this->begin_ = pivot->getPNext();
499 this->end_ = pivot;
500 }
501
502 template <typename TYPE, typename ALLOC>
503 auto original::chain<TYPE, ALLOC>::firstAdd(chainNode* node) -> void
504 {
505 chainNode::connect(this->end_, node);
506 this->begin_ = node;
507 this->end_ = node;
508 this->size_ += 1;
509 }
510
511 template <typename TYPE, typename ALLOC>
513 {
514 auto last = this->end_;
515 this->destroyNode(last->getPPrev());
516 chainNode::connect(nullptr, last);
517 this->chainInit();
518 return last;
519 }
520
521 template <typename TYPE, typename ALLOC>
523 {
524 auto current = this->end_;
525 while (current) {
526 auto prev = current->getPPrev();
527 this->destroyNode(current);
528 current = prev;
529 }
530 }
531
532 template <typename TYPE, typename ALLOC>
534 : doubleDirectionIterator<TYPE>::doubleDirectionIterator(ptr) {}
535
536 template <typename TYPE, typename ALLOC>
541
542 template <typename TYPE, typename ALLOC>
544 if (this == &other) return *this;
546 return *this;
547 }
548
549 template <typename TYPE, typename ALLOC>
551 return new Iterator(*this);
552 }
553
554 template <typename TYPE, typename ALLOC>
556 auto other_it = dynamic_cast<const Iterator*>(other);
557 return other_it != nullptr && this->_ptr->getPNext() == other_it->_ptr;
558 }
559
560 template <typename TYPE, typename ALLOC>
562 auto other_it = dynamic_cast<const Iterator*>(other);
563 return other_it != nullptr && other_it->_ptr->getPNext() == this->_ptr;
564 }
565
566 template <typename TYPE, typename ALLOC>
568 return "chain::Iterator";
569 }
570
571 template <typename TYPE, typename ALLOC>
572 original::chain<TYPE, ALLOC>::chain(ALLOC alloc) : baseList<TYPE, ALLOC>(std::move(alloc)), size_(0), rebind_alloc(std::move(rebind_alloc_node{}))
573 {
574 chainInit();
575 }
576
577 template <typename TYPE, typename ALLOC>
579 this->operator=(other);
580 }
581
582 template <typename TYPE, typename ALLOC>
583 original::chain<TYPE, ALLOC>::chain(const std::initializer_list<TYPE>& list)
584 : chain() {
585 for (const auto& e : list) {
586 auto cur_node = this->createNode(e);
587 if (this->size() == 0)
588 {
589 this->firstAdd(cur_node);
590 }else
591 {
592 chainNode::connect(this->end_, cur_node);
593 this->end_ = cur_node;
594 size_ += 1;
595 }
596 }
597 }
598
599 template <typename TYPE, typename ALLOC>
601 : chain() {
602 for (u_integer i = 0; i < arr.size(); i++) {
603 auto cur_node = this->createNode(arr.get(i));
604 if (this->size() == 0)
605 {
606 this->firstAdd(cur_node);
607 }else
608 {
609 chainNode::connect(this->end_, cur_node);
610 this->end_ = cur_node;
611 size_ += 1;
612 }
613 }
614 }
615
616 template <typename TYPE, typename ALLOC>
618 if (this == &other) return *this;
619 this->chainDestroy();
620 this->size_ = other.size_;
621 if (this->size() != 0){
622 auto other_ = other.begin_->getPPrev();
623 auto pivot = this->createNode(other_->getVal());
624 other_ = other_->getPNext();
625 chainNode::connect(pivot, this->createNode(other_->getVal()));
626 this->begin_ = pivot->getPNext();
627 auto this_ = this->begin_;
628 while (other_ != other.end_){
629 other_ = other_->getPNext();
630 chainNode::connect(this_, this->createNode(other_->getVal()));
631 this_ = this_->getPNext();
632 }
633 this->end_ = this_;
634 } else{
635 this->chainInit();
636 }
637 if constexpr (ALLOC::propagate_on_container_copy_assignment::value){
638 this->allocator = other.allocator;
639 this->rebind_alloc = other.rebind_alloc;
640 }
641 return *this;
642 }
643
644 template <typename TYPE, typename ALLOC>
646 {
647 this->operator=(std::move(other));
648 }
649
650 template <typename TYPE, typename ALLOC>
652 {
653 if (this == &other)
654 return *this;
655
656 this->chainDestroy();
657 this->begin_ = other.begin_;
658 this->end_ = other.end_;
659 this->size_ = other.size_;
660 if constexpr (ALLOC::propagate_on_container_move_assignment::value){
661 this->allocator = std::move(other.allocator);
662 this->rebind_alloc = std::move(other.rebind_alloc);
663 }
664 other.chainInit();
665 return *this;
666 }
667
668 template <typename TYPE, typename ALLOC>
670 {
671 if (this == &other || other.empty()) return *this;
672
673 this->size_ += other.size_;
674 other.destroyNode(other.begin_->getPPrev());
675 chainNode::connect(this->end_, other.begin_);
676 this->end_ = other.end_;
677 if constexpr (ALLOC::propagate_on_container_merge::value) {
678 this->allocator += other.allocator;
679 this->rebind_alloc += other.rebind_alloc;
680 }
681 other.chainInit();
682 return *this;
683 }
684
685 template <typename TYPE, typename ALLOC>
687 {
688 return this->size_;
689 }
690
691 template <typename TYPE, typename ALLOC>
692 auto original::chain<TYPE, ALLOC>::className() const -> std::string
693 {
694 return "chain";
695 }
696
697 template <typename TYPE, typename ALLOC>
699 {
700 if (this->indexOutOfBound(index)){
701 throw outOfBoundError("chain::get: Index " + printable::formatString(index) +
702 " out of bounds for chain of size " + printable::formatString(this->size()));
703 }
704 chainNode* cur = this->findNode(this->parseNegIndex(index));
705 return cur->getVal();
706 }
707
708 template <typename TYPE, typename ALLOC>
710 {
711 if (this->indexOutOfBound(index)){
712 throw outOfBoundError("chain::operator[]: Index " + printable::formatString(index) +
713 " out of bounds for chain of size " + printable::formatString(this->size()));
714 }
715 chainNode* cur = this->findNode(this->parseNegIndex(index));
716 return cur->getVal();
717 }
718
719 template <typename TYPE, typename ALLOC>
720 auto original::chain<TYPE, ALLOC>::set(integer index, const TYPE &e) -> void
721 {
722 if (this->indexOutOfBound(index)){
723 throw outOfBoundError("chain::set: Index " + printable::formatString(index) +
724 " out of bounds for chain of size " + printable::formatString(this->size()));
725 }
726 auto cur = this->findNode(this->parseNegIndex(index));
727 cur->setVal(e);
728 }
729
730 template <typename TYPE, typename ALLOC>
732 u_integer i = 0;
733 for (chainNode* current = this->begin_; current != nullptr; current = current->getPNext()) {
734 if (current->getVal() == e) {
735 return i;
736 }
737 i += 1;
738 }
739 return this->size();
740 }
741
742 template <typename TYPE, typename ALLOC>
743 auto original::chain<TYPE, ALLOC>::pushBegin(const TYPE &e) -> void
744 {
745 auto new_node = this->createNode(e);
746 if (this->size() == 0){
747 this->firstAdd(new_node);
748 } else{
749 auto pivot = this->begin_->getPPrev();
750 chainNode::connect(new_node, this->begin_);
751 chainNode::connect(pivot, new_node);
752 this->begin_ = new_node;
753 this->size_ += 1;
754 }
755 }
756
757 template <typename TYPE, typename ALLOC>
758 auto original::chain<TYPE, ALLOC>::push(integer index, const TYPE &e) -> void
759 {
760 index = this->parseNegIndex(index);
761 if (index == 0){
762 this->pushBegin(e);
763 } else if (index == this->size()){
764 this->pushEnd(e);
765 } else{
766 if (this->indexOutOfBound(index)){
767 throw outOfBoundError("chain::push: Index " + printable::formatString(index) +
768 " out of bounds for chain of size " + printable::formatString(this->size()));
769 }
770 auto new_node = this->createNode(e);
771 auto cur = this->findNode(index);
772 auto prev = cur->getPPrev();
773 chainNode::connect(prev, new_node);
774 chainNode::connect(new_node, cur);
775 this->size_ += 1;
776 }
777 }
778
779 template <typename TYPE, typename ALLOC>
780 auto original::chain<TYPE, ALLOC>::pushEnd(const TYPE &e) -> void
781 {
782 auto new_node = this->createNode(e);
783 if (this->size() == 0){
784 this->firstAdd(new_node);
785 } else{
786 chainNode::connect(this->end_, new_node);
787 this->end_ = new_node;
788 this->size_ += 1;
789 }
790 }
791
792 template <typename TYPE, typename ALLOC>
794 {
795 TYPE res;
796 if (this->size() == 0){
797 throw noElementError("chain::popBegin: Cannot pop from empty chain");
798 }
799 if (this->size() == 1){
800 auto del = this->lastDelete();
801 res = del->getVal();
802 this->destroyNode(del);
803 } else{
804 res = this->begin_->getVal();
805 auto new_begin = this->begin_->getPNext();
806 auto pivot = this->begin_->getPPrev();
807 this->destroyNode(this->begin_);
808 this->begin_ = new_begin;
809 chainNode::connect(pivot, this->begin_);
810 this->size_ -= 1;
811 }
812 return res;
813 }
814
815 template <typename TYPE, typename ALLOC>
817 {
818 index = this->parseNegIndex(index);
819 if (index == 0){
820 return this->popBegin();
821 }
822 if (index == this->size() - 1){
823 return this->popEnd();
824 }
825 if (this->indexOutOfBound(index)){
826 throw outOfBoundError("chain::pop: Index " + printable::formatString(index) +
827 " out of bounds for chain of size " + printable::formatString(this->size()));
828 }
829 TYPE res;
830 chainNode* cur = this->findNode(index);
831 res = cur->getVal();
832 auto prev = cur->getPPrev();
833 auto next = cur->getPNext();
834 chainNode::connect(prev, next);
835 this->destroyNode(cur);
836 this->size_ -= 1;
837 return res;
838 }
839
840 template <typename TYPE, typename ALLOC>
842 {
843 TYPE res;
844 if (this->size() == 0){
845 throw noElementError("chain::popEnd: Cannot pop from empty chain");
846 }
847 if (this->size() == 1){
848 auto del = this->lastDelete();
849 res = del->getVal();
850 this->destroyNode(del);
851 } else{
852 res = this->end_->getVal();
853 auto new_end = this->end_->getPPrev();
854 this->destroyNode(this->end_);
855 this->end_ = new_end;
856 chainNode::connect(this->end_, nullptr);
857 this->size_ -= 1;
858 }
859 return res;
860 }
861
862 template <typename TYPE, typename ALLOC>
864 return new Iterator(this->begin_);
865 }
866
867 template <typename TYPE, typename ALLOC>
869 return new Iterator(this->end_);
870 }
871
872 template <typename TYPE, typename ALLOC>
874 this->chainDestroy();
875 }
876
877#endif //CHAIN_H
Provides the array class for a fixed-size container with random access.
Provides a base class for variable-size serial containers.
DERIVED< O_TYPE > rebind_alloc
Rebinds allocator to different type.
Definition allocator.h:97
Default memory allocator using allocators utilities.
Definition allocator.h:154
A fixed-size array container with random access.
Definition array.h:41
TYPE get(integer index) const override
Retrieves an element at a specified index.
Definition array.h:446
u_integer size() const override
Returns the size of the array.
Definition array.h:435
Base class for variable-size serial containers.
Definition baseList.h:43
Bidirectional iterator implementation for chain.
Definition chain.h:195
Iterator & operator=(const Iterator &other)
Assignment operator for Iterator.
Definition chain.h:543
std::string className() const override
Gets the class name of the iterator.
Definition chain.h:567
bool atNext(const iterator< TYPE > *other) const override
Checks if the iterator is at the next position relative to another iterator.
Definition chain.h:561
Iterator * clone() const override
Clones the iterator.
Definition chain.h:550
bool atPrev(const iterator< TYPE > *other) const override
Checks if the iterator is at the previous position relative to another iterator.
Definition chain.h:555
Non-cyclic doubly linked list container.
Definition chain.h:36
u_integer indexOf(const TYPE &e) const override
Finds the index of the first occurrence of the specified element.
Definition chain.h:731
TYPE popEnd() override
Pops an element from the end of the chain.
Definition chain.h:841
TYPE pop(integer index) override
Pops an element at the specified index in the chain.
Definition chain.h:816
chain(chain &&other) noexcept
Move constructs a chain with optional allocator.
Definition chain.h:645
Iterator * ends() const override
Gets an iterator to the end of the chain.
Definition chain.h:868
u_integer size() const override
Gets the size of the chain.
Definition chain.h:686
Iterator * begins() const override
Gets an iterator to the beginning of the chain.
Definition chain.h:863
chain & operator=(chain &&other) noexcept
Move assignment operator with allocator propagation.
Definition chain.h:651
TYPE popBegin() override
Pops an element from the beginning of the chain.
Definition chain.h:793
std::string className() const override
Gets the class name of the chain.
Definition chain.h:692
chain(const array< TYPE > &arr)
Constructs a chain from an array.
Definition chain.h:600
TYPE get(integer index) const override
Gets the element at the specified index.
Definition chain.h:698
~chain() override
Destructor for the chain.
Definition chain.h:873
TYPE & operator[](integer index) override
Gets a reference to the element at the specified index.
Definition chain.h:709
void push(integer index, const TYPE &e) override
Pushes an element at the specified index in the chain.
Definition chain.h:758
chain(ALLOC alloc=ALLOC{})
Constructs an empty chain with specified allocator.
Definition chain.h:572
chain(const chain &other)
Copy constructs a chain with optional allocator.
Definition chain.h:578
void pushEnd(const TYPE &e) override
Pushes an element to the end of the chain.
Definition chain.h:780
void pushBegin(const TYPE &e) override
Pushes an element to the beginning of the chain.
Definition chain.h:743
chain & operator=(const chain &other)
Copy assignment operator with allocator propagation.
Definition chain.h:617
chain(const std::initializer_list< TYPE > &list)
Constructs a chain from an initializer list.
Definition chain.h:583
void set(integer index, const TYPE &e) override
Sets the element at the specified index.
Definition chain.h:720
chain & operator+=(chain &other)
Concatenates another chain to this one.
Definition chain.h:669
ALLOC allocator
The allocator instance used for memory management.
Definition container.h:32
TYPE * allocate(u_integer size)
Allocates raw memory for elements.
Definition container.h:131
void destroy(O_TYPE *o_ptr)
Destroys an element.
Definition container.h:148
Abstract base class for double-direction iterators.
Definition doubleDirectionIterator.h:24
doubleDirectionIterator & operator=(const doubleDirectionIterator &other)
Copy assignment operator for doubleDirectionIterator.
Definition doubleDirectionIterator.h:77
A stream class that allows iteration, comparison, and printing.
Definition iterationStream.h:32
Base iterator interface that supports common operations for iteration.
Definition iterator.h:37
Exception for missing element requests.
Definition error.h:213
Exception for container index out-of-range errors.
Definition error.h:129
static std::string formatString(const TYPE &t)
Universal value-to-string conversion.
Definition printable.h:263
wrapper< TYPE > * _ptr
Pointer to the current wrapper.
Definition stepIterator.h:40
Base class for linked value containers with formatted output.
Definition wrapper.h:28
Double-direction iterator base class.
std::uint32_t u_integer
32-bit unsigned integer type for sizes and indexes
Definition config.h:263
std::int64_t integer
64-bit signed integer type for arithmetic operations
Definition config.h:254
Provides functionality for an iteration stream.
Main namespace for the project Original.
Definition algorithms.h:21