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
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
257
262 chain(const std::initializer_list<TYPE>& list);
263
268 explicit chain(const array<TYPE>& arr);
269
277
283 chain(chain&& other) noexcept;
284
292
299 void swap(chain& other) noexcept;
300
309
314 [[nodiscard]] u_integer size() const override;
315
321 TYPE get(integer index) const override;
322
328 TYPE& operator[](integer index) override;
329
335 void set(integer index, const TYPE &e) override;
336
342 u_integer indexOf(const TYPE &e) const override;
343
348 void pushBegin(const TYPE &e) override;
349
355 void push(integer index, const TYPE &e) override;
356
361 void pushEnd(const TYPE &e) override;
362
367 TYPE popBegin() override;
368
374 TYPE pop(integer index) override;
375
380 TYPE popEnd() override;
381
386 Iterator* begins() const override;
387
392 Iterator* ends() const override;
393
398 [[nodiscard]] std::string className() const override;
399
403 ~chain() override;
404 };
405}
406
407namespace std {
415 template<typename TYPE, typename ALLOC>
416 void swap(original::chain<TYPE, ALLOC>& lhs, original::chain<TYPE, ALLOC>& rhs) noexcept; // NOLINT
417}
418
419 template <typename TYPE, typename ALLOC>
420 original::chain<TYPE, ALLOC>::chainNode::chainNode(const TYPE& data, chainNode* prev, chainNode* next)
421 : data_(data), prev(prev), next(next) {}
422
423 template <typename TYPE, typename ALLOC>
425 : data_(other.data_), prev(other.prev), next(other.next) {}
426
427 template <typename TYPE, typename ALLOC>
428 auto original::chain<TYPE, ALLOC>::chainNode::operator=(const chainNode& other) -> chainNode& {
429 if (this != &other) {
430 data_ = other.data_;
431 prev = other.prev;
432 next = other.next;
433 }
434 return *this;
435 }
436
437 template <typename TYPE, typename ALLOC>
439 {
440 return this->data_;
441 }
442
443 template <typename TYPE, typename ALLOC>
444 auto original::chain<TYPE, ALLOC>::chainNode::getVal() const -> const TYPE&
445 {
446 return this->data_;
447 }
448
449 template <typename TYPE, typename ALLOC>
451 {
452 this->data_ = data;
453 }
454
455 template <typename TYPE, typename ALLOC>
456 auto original::chain<TYPE, ALLOC>::chainNode::getPPrev() const -> chainNode* {
457 return this->prev;
458 }
459
460 template <typename TYPE, typename ALLOC>
461 auto original::chain<TYPE, ALLOC>::chainNode::getPNext() const -> chainNode* {
462 return this->next;
463 }
464
465 template <typename TYPE, typename ALLOC>
466 auto original::chain<TYPE, ALLOC>::chainNode::setPPrev(chainNode* new_prev) -> void {
467 this->prev = new_prev;
468 }
469
470 template <typename TYPE, typename ALLOC>
471 auto original::chain<TYPE, ALLOC>::chainNode::setPNext(chainNode* new_next) -> void {
472 this->next = new_next;
473 }
474
475 template <typename TYPE, typename ALLOC>
476 auto original::chain<TYPE, ALLOC>::chainNode::connect(chainNode* prev, chainNode* next) -> void
477 {
478 if (prev != nullptr) prev->setPNext(next);
479 if (next != nullptr) next->setPPrev(prev);
480 }
481
482 template <typename TYPE, typename ALLOC>
483 auto original::chain<TYPE, ALLOC>::findNode(integer index) const -> chainNode* {
484 const bool reverse_visit = index <= this->size() / 2 ? 0 : 1;
485 chainNode* cur;
486 if (!reverse_visit){
487 cur = this->begin_;
488 for(u_integer i = 0; i < index; i++)
489 {
490 cur = cur->getPNext();
491 }
492 } else{
493 cur = this->end_;
494 for(u_integer i = this->size() - 1; i > index; i -= 1)
495 {
496 cur = cur->getPPrev();
497 }
498 }
499 return cur;
500 }
501
502 template<typename TYPE, typename ALLOC>
503 auto original::chain<TYPE, ALLOC>::createNode(const TYPE &value, chainNode* prev, chainNode* next) -> chainNode* {
504 auto node = this->rebind_alloc.allocate(1);
505 this->rebind_alloc.construct(node, value, prev, next);
506 return node;
507 }
508
509 template<typename TYPE, typename ALLOC>
510 void original::chain<TYPE, ALLOC>::destroyNode(chainNode *node) noexcept {
511 this->rebind_alloc.destroy(node);
512 this->rebind_alloc.deallocate(node, 1);
513 }
514
515 template <typename TYPE, typename ALLOC>
517 {
518 auto pivot = this->createNode();
519 this->size_ = 0;
520 this->begin_ = pivot->getPNext();
521 this->end_ = pivot;
522 }
523
524 template <typename TYPE, typename ALLOC>
525 auto original::chain<TYPE, ALLOC>::firstAdd(chainNode* node) -> void
526 {
527 chainNode::connect(this->end_, node);
528 this->begin_ = node;
529 this->end_ = node;
530 this->size_ += 1;
531 }
532
533 template <typename TYPE, typename ALLOC>
535 {
536 auto last = this->end_;
537 this->destroyNode(last->getPPrev());
538 chainNode::connect(nullptr, last);
539 this->chainInit();
540 return last;
541 }
542
543 template <typename TYPE, typename ALLOC>
545 {
546 auto current = this->end_;
547 while (current) {
548 auto prev = current->getPPrev();
549 this->destroyNode(current);
550 current = prev;
551 }
552 }
553
554 template <typename TYPE, typename ALLOC>
556 : doubleDirectionIterator<TYPE>::doubleDirectionIterator(ptr) {}
557
558 template <typename TYPE, typename ALLOC>
563
564 template <typename TYPE, typename ALLOC>
566 if (this == &other) return *this;
568 return *this;
569 }
570
571 template <typename TYPE, typename ALLOC>
573 return new Iterator(*this);
574 }
575
576 template <typename TYPE, typename ALLOC>
578 auto other_it = dynamic_cast<const Iterator*>(other);
579 return other_it != nullptr && this->_ptr->getPNext() == other_it->_ptr;
580 }
581
582 template <typename TYPE, typename ALLOC>
584 auto other_it = dynamic_cast<const Iterator*>(other);
585 return other_it != nullptr && other_it->_ptr->getPNext() == this->_ptr;
586 }
587
588 template <typename TYPE, typename ALLOC>
590 return "chain::Iterator";
591 }
592
593 template <typename TYPE, typename ALLOC>
596 size_(0),
597 begin_(nullptr),
598 end_(nullptr),
599 rebind_alloc(std::move(rebind_alloc_node{}))
600 {
601 chainInit();
602 }
603
604 template <typename TYPE, typename ALLOC>
606 this->operator=(other);
607 }
608
609 template <typename TYPE, typename ALLOC>
610 original::chain<TYPE, ALLOC>::chain(const std::initializer_list<TYPE>& list)
611 : chain() {
612 for (const auto& e : list) {
613 auto cur_node = this->createNode(e);
614 if (this->size() == 0)
615 {
616 this->firstAdd(cur_node);
617 }else
618 {
619 chainNode::connect(this->end_, cur_node);
620 this->end_ = cur_node;
621 size_ += 1;
622 }
623 }
624 }
625
626 template <typename TYPE, typename ALLOC>
628 : chain() {
629 for (u_integer i = 0; i < arr.size(); i++) {
630 auto cur_node = this->createNode(arr.get(i));
631 if (this->size() == 0)
632 {
633 this->firstAdd(cur_node);
634 }else
635 {
636 chainNode::connect(this->end_, cur_node);
637 this->end_ = cur_node;
638 size_ += 1;
639 }
640 }
641 }
642
643 template <typename TYPE, typename ALLOC>
645 if (this == &other) return *this;
646 this->chainDestroy();
647 this->size_ = other.size_;
648 if (this->size() != 0){
649 auto other_ = other.begin_->getPPrev();
650 auto pivot = this->createNode(other_->getVal());
651 other_ = other_->getPNext();
652 chainNode::connect(pivot, this->createNode(other_->getVal()));
653 this->begin_ = pivot->getPNext();
654 auto this_ = this->begin_;
655 while (other_ != other.end_){
656 other_ = other_->getPNext();
657 chainNode::connect(this_, this->createNode(other_->getVal()));
658 this_ = this_->getPNext();
659 }
660 this->end_ = this_;
661 } else{
662 this->chainInit();
663 }
664 if constexpr (ALLOC::propagate_on_container_copy_assignment::value){
665 this->allocator = other.allocator;
666 this->rebind_alloc = other.rebind_alloc;
667 }
668 return *this;
669 }
670
671 template <typename TYPE, typename ALLOC>
673 {
674 this->operator=(std::move(other));
675 }
676
677 template <typename TYPE, typename ALLOC>
679 {
680 if (this == &other)
681 return *this;
682
683 this->chainDestroy();
684 this->begin_ = other.begin_;
685 this->end_ = other.end_;
686 this->size_ = other.size_;
687 if constexpr (ALLOC::propagate_on_container_move_assignment::value){
688 this->allocator = std::move(other.allocator);
689 this->rebind_alloc = std::move(other.rebind_alloc);
690 }
691 other.chainInit();
692 return *this;
693 }
694
695 template <typename TYPE, typename ALLOC>
697 {
698 if (this == &other)
699 return;
700
701 std::swap(this->size_, other.size_);
702 std::swap(this->begin_, other.begin_);
703 std::swap(this->end_, other.end_);
704 if constexpr (ALLOC::propagate_on_container_swap::value) {
705 std::swap(this->allocator, other.allocator);
706 std::swap(this->rebind_alloc, other.rebind_alloc);
707 }
708 }
709
710 template <typename TYPE, typename ALLOC>
712 {
713 if (this == &other || other.empty()) return *this;
714
715 this->size_ += other.size_;
716 other.destroyNode(other.begin_->getPPrev());
717 chainNode::connect(this->end_, other.begin_);
718 this->end_ = other.end_;
719 if constexpr (ALLOC::propagate_on_container_merge::value) {
720 this->allocator += other.allocator;
721 this->rebind_alloc += other.rebind_alloc;
722 }
723 other.chainInit();
724 return *this;
725 }
726
727 template <typename TYPE, typename ALLOC>
729 {
730 return this->size_;
731 }
732
733 template <typename TYPE, typename ALLOC>
735 {
736 return "chain";
737 }
738
739 template <typename TYPE, typename ALLOC>
741 {
742 if (this->indexOutOfBound(index)){
743 throw outOfBoundError("chain::get: Index " + printable::formatString(index) +
744 " out of bounds for chain of size " + printable::formatString(this->size()));
745 }
746 chainNode* cur = this->findNode(this->parseNegIndex(index));
747 return cur->getVal();
748 }
749
750 template <typename TYPE, typename ALLOC>
752 {
753 if (this->indexOutOfBound(index)){
754 throw outOfBoundError("chain::operator[]: Index " + printable::formatString(index) +
755 " out of bounds for chain of size " + printable::formatString(this->size()));
756 }
757 chainNode* cur = this->findNode(this->parseNegIndex(index));
758 return cur->getVal();
759 }
760
761 template <typename TYPE, typename ALLOC>
763 {
764 if (this->indexOutOfBound(index)){
765 throw outOfBoundError("chain::set: Index " + printable::formatString(index) +
766 " out of bounds for chain of size " + printable::formatString(this->size()));
767 }
768 auto cur = this->findNode(this->parseNegIndex(index));
769 cur->setVal(e);
770 }
771
772 template <typename TYPE, typename ALLOC>
774 u_integer i = 0;
775 for (chainNode* current = this->begin_; current != nullptr; current = current->getPNext()) {
776 if (current->getVal() == e) {
777 return i;
778 }
779 i += 1;
780 }
781 return this->size();
782 }
783
784 template <typename TYPE, typename ALLOC>
786 {
787 auto new_node = this->createNode(e);
788 if (this->size() == 0){
789 this->firstAdd(new_node);
790 } else{
791 auto pivot = this->begin_->getPPrev();
792 chainNode::connect(new_node, this->begin_);
793 chainNode::connect(pivot, new_node);
794 this->begin_ = new_node;
795 this->size_ += 1;
796 }
797 }
798
799 template <typename TYPE, typename ALLOC>
801 {
802 index = this->parseNegIndex(index);
803 if (index == 0){
804 this->pushBegin(e);
805 } else if (index == this->size()){
806 this->pushEnd(e);
807 } else{
808 if (this->indexOutOfBound(index)){
809 throw outOfBoundError("chain::push: Index " + printable::formatString(index) +
810 " out of bounds for chain of size " + printable::formatString(this->size()));
811 }
812 auto new_node = this->createNode(e);
813 auto cur = this->findNode(index);
814 auto prev = cur->getPPrev();
815 chainNode::connect(prev, new_node);
816 chainNode::connect(new_node, cur);
817 this->size_ += 1;
818 }
819 }
820
821 template <typename TYPE, typename ALLOC>
823 {
824 auto new_node = this->createNode(e);
825 if (this->size() == 0){
826 this->firstAdd(new_node);
827 } else{
828 chainNode::connect(this->end_, new_node);
829 this->end_ = new_node;
830 this->size_ += 1;
831 }
832 }
833
834 template <typename TYPE, typename ALLOC>
836 {
837 TYPE res;
838 if (this->size() == 0){
839 throw noElementError("chain::popBegin: Cannot pop from empty chain");
840 }
841 if (this->size() == 1){
842 auto del = this->lastDelete();
843 res = del->getVal();
844 this->destroyNode(del);
845 } else{
846 res = this->begin_->getVal();
847 auto new_begin = this->begin_->getPNext();
848 auto pivot = this->begin_->getPPrev();
849 this->destroyNode(this->begin_);
850 this->begin_ = new_begin;
851 chainNode::connect(pivot, this->begin_);
852 this->size_ -= 1;
853 }
854 return res;
855 }
856
857 template <typename TYPE, typename ALLOC>
859 {
860 index = this->parseNegIndex(index);
861 if (index == 0){
862 return this->popBegin();
863 }
864 if (index == this->size() - 1){
865 return this->popEnd();
866 }
867 if (this->indexOutOfBound(index)){
868 throw outOfBoundError("chain::pop: Index " + printable::formatString(index) +
869 " out of bounds for chain of size " + printable::formatString(this->size()));
870 }
871 TYPE res;
872 chainNode* cur = this->findNode(index);
873 res = cur->getVal();
874 auto prev = cur->getPPrev();
875 auto next = cur->getPNext();
876 chainNode::connect(prev, next);
877 this->destroyNode(cur);
878 this->size_ -= 1;
879 return res;
880 }
881
882 template <typename TYPE, typename ALLOC>
884 {
885 TYPE res;
886 if (this->size() == 0){
887 throw noElementError("chain::popEnd: Cannot pop from empty chain");
888 }
889 if (this->size() == 1){
890 auto del = this->lastDelete();
891 res = del->getVal();
892 this->destroyNode(del);
893 } else{
894 res = this->end_->getVal();
895 auto new_end = this->end_->getPPrev();
896 this->destroyNode(this->end_);
897 this->end_ = new_end;
898 chainNode::connect(this->end_, nullptr);
899 this->size_ -= 1;
900 }
901 return res;
902 }
903
904 template <typename TYPE, typename ALLOC>
906 return new Iterator(this->begin_);
907 }
908
909 template <typename TYPE, typename ALLOC>
911 return new Iterator(this->end_);
912 }
913
914 template <typename TYPE, typename ALLOC>
916 this->chainDestroy();
917 }
918
919 template <typename TYPE, typename ALLOC>
921 {
922 lhs.swap(rhs);
923 }
924
925#endif //CHAIN_H
Provides the array class for a fixed-size container with random access.
Provides a base class for variable-size serial containers.
Default memory allocator using allocators utilities.
Definition allocator.h:153
void swap(autoPtr &other) noexcept
Swaps the reference counters between two autoPtr instances.
Definition autoPtr.h:703
const TYPE * get() const
Get managed pointer const version.
Definition autoPtr.h:629
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:565
std::string className() const override
Gets the class name of the iterator.
Definition chain.h:589
bool atNext(const iterator< TYPE > *other) const override
Checks if the iterator is at the next position relative to another iterator.
Definition chain.h:583
Iterator * clone() const override
Clones the iterator.
Definition chain.h:572
bool atPrev(const iterator< TYPE > *other) const override
Checks if the iterator is at the previous position relative to another iterator.
Definition chain.h:577
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:773
TYPE popEnd() override
Pops an element from the end of the chain.
Definition chain.h:883
TYPE pop(integer index) override
Pops an element at the specified index in the chain.
Definition chain.h:858
chain(chain &&other) noexcept
Move constructs a chain with optional allocator.
Definition chain.h:672
Iterator * ends() const override
Gets an iterator to the end of the chain.
Definition chain.h:910
u_integer size() const override
Gets the size of the chain.
Definition chain.h:728
Iterator * begins() const override
Gets an iterator to the beginning of the chain.
Definition chain.h:905
chain & operator=(chain &&other) noexcept
Move assignment operator with allocator propagation.
Definition chain.h:678
TYPE popBegin() override
Pops an element from the beginning of the chain.
Definition chain.h:835
std::string className() const override
Gets the class name of the chain.
Definition chain.h:734
chain(const array< TYPE > &arr)
Constructs a chain from an array.
Definition chain.h:627
TYPE get(integer index) const override
Gets the element at the specified index.
Definition chain.h:740
~chain() override
Destructor for the chain.
Definition chain.h:915
TYPE & operator[](integer index) override
Gets a reference to the element at the specified index.
Definition chain.h:751
void push(integer index, const TYPE &e) override
Pushes an element at the specified index in the chain.
Definition chain.h:800
chain(ALLOC alloc=ALLOC{})
Constructs an empty chain with specified allocator.
Definition chain.h:594
chain(const chain &other)
Copy constructs a chain with optional allocator.
Definition chain.h:605
void pushEnd(const TYPE &e) override
Pushes an element to the end of the chain.
Definition chain.h:822
void pushBegin(const TYPE &e) override
Pushes an element to the beginning of the chain.
Definition chain.h:785
chain & operator=(const chain &other)
Copy assignment operator with allocator propagation.
Definition chain.h:644
void swap(chain &other) noexcept
Swaps the contents of this chain with another.
Definition chain.h:696
chain(const std::initializer_list< TYPE > &list)
Constructs a chain from an initializer list.
Definition chain.h:610
void set(integer index, const TYPE &e) override
Sets the element at the specified index.
Definition chain.h:762
chain & operator+=(chain &other)
Concatenates another chain to this one.
Definition chain.h:711
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, hashing and printing.
Definition iterationStream.h:60
Base iterator interface that supports common operations for iteration.
Definition iterator.h:37
Exception for missing element requests.
Definition error.h:298
Exception for container index out-of-range errors.
Definition error.h:192
Unique ownership smart pointer with move semantics.
Definition ownerPtr.h:37
static std::string formatString(const TYPE &t)
Universal value-to-string conversion with type-specific formatting.
Definition printable.h:339
Base class for linked value containers with formatted output.
Definition wrapper.h:28
Double-direction iterator base class.
Provides functionality for an iteration stream with comparison, hashing and printing.
Main namespace for the project Original.
Definition algorithms.h:21
SERIAL< TYPE > list(coroutine::generator< TYPE > gen)
Collects generator elements into a list container.
Definition generators.h:655
Standard namespace extensions for original::alternative.
Definition allocator.h:351
void swap(original::objPoolAllocator< TYPE > &lhs, original::objPoolAllocator< TYPE > &rhs) noexcept
Specialization of std::swap for objPoolAllocator.
Definition allocator.h:635