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>
594 original::chain<TYPE, ALLOC>::chain(ALLOC alloc) : baseList<TYPE, ALLOC>(std::move(alloc)), size_(0), rebind_alloc(std::move(rebind_alloc_node{}))
595 {
596 chainInit();
597 }
598
599 template <typename TYPE, typename ALLOC>
601 this->operator=(other);
602 }
603
604 template <typename TYPE, typename ALLOC>
605 original::chain<TYPE, ALLOC>::chain(const std::initializer_list<TYPE>& list)
606 : chain() {
607 for (const auto& e : list) {
608 auto cur_node = this->createNode(e);
609 if (this->size() == 0)
610 {
611 this->firstAdd(cur_node);
612 }else
613 {
614 chainNode::connect(this->end_, cur_node);
615 this->end_ = cur_node;
616 size_ += 1;
617 }
618 }
619 }
620
621 template <typename TYPE, typename ALLOC>
623 : chain() {
624 for (u_integer i = 0; i < arr.size(); i++) {
625 auto cur_node = this->createNode(arr.get(i));
626 if (this->size() == 0)
627 {
628 this->firstAdd(cur_node);
629 }else
630 {
631 chainNode::connect(this->end_, cur_node);
632 this->end_ = cur_node;
633 size_ += 1;
634 }
635 }
636 }
637
638 template <typename TYPE, typename ALLOC>
640 if (this == &other) return *this;
641 this->chainDestroy();
642 this->size_ = other.size_;
643 if (this->size() != 0){
644 auto other_ = other.begin_->getPPrev();
645 auto pivot = this->createNode(other_->getVal());
646 other_ = other_->getPNext();
647 chainNode::connect(pivot, this->createNode(other_->getVal()));
648 this->begin_ = pivot->getPNext();
649 auto this_ = this->begin_;
650 while (other_ != other.end_){
651 other_ = other_->getPNext();
652 chainNode::connect(this_, this->createNode(other_->getVal()));
653 this_ = this_->getPNext();
654 }
655 this->end_ = this_;
656 } else{
657 this->chainInit();
658 }
659 if constexpr (ALLOC::propagate_on_container_copy_assignment::value){
660 this->allocator = other.allocator;
661 this->rebind_alloc = other.rebind_alloc;
662 }
663 return *this;
664 }
665
666 template <typename TYPE, typename ALLOC>
668 {
669 this->operator=(std::move(other));
670 }
671
672 template <typename TYPE, typename ALLOC>
674 {
675 if (this == &other)
676 return *this;
677
678 this->chainDestroy();
679 this->begin_ = other.begin_;
680 this->end_ = other.end_;
681 this->size_ = other.size_;
682 if constexpr (ALLOC::propagate_on_container_move_assignment::value){
683 this->allocator = std::move(other.allocator);
684 this->rebind_alloc = std::move(other.rebind_alloc);
685 }
686 other.chainInit();
687 return *this;
688 }
689
690 template <typename TYPE, typename ALLOC>
692 {
693 if (this == &other)
694 return;
695
696 std::swap(this->size_, other.size_);
697 std::swap(this->begin_, other.begin_);
698 std::swap(this->end_, other.end_);
699 if constexpr (ALLOC::propagate_on_container_swap::value) {
700 std::swap(this->allocator, other.allocator);
701 std::swap(this->rebind_alloc, other.rebind_alloc);
702 }
703 }
704
705 template <typename TYPE, typename ALLOC>
707 {
708 if (this == &other || other.empty()) return *this;
709
710 this->size_ += other.size_;
711 other.destroyNode(other.begin_->getPPrev());
712 chainNode::connect(this->end_, other.begin_);
713 this->end_ = other.end_;
714 if constexpr (ALLOC::propagate_on_container_merge::value) {
715 this->allocator += other.allocator;
716 this->rebind_alloc += other.rebind_alloc;
717 }
718 other.chainInit();
719 return *this;
720 }
721
722 template <typename TYPE, typename ALLOC>
724 {
725 return this->size_;
726 }
727
728 template <typename TYPE, typename ALLOC>
730 {
731 return "chain";
732 }
733
734 template <typename TYPE, typename ALLOC>
736 {
737 if (this->indexOutOfBound(index)){
738 throw outOfBoundError("chain::get: Index " + printable::formatString(index) +
739 " out of bounds for chain of size " + printable::formatString(this->size()));
740 }
741 chainNode* cur = this->findNode(this->parseNegIndex(index));
742 return cur->getVal();
743 }
744
745 template <typename TYPE, typename ALLOC>
747 {
748 if (this->indexOutOfBound(index)){
749 throw outOfBoundError("chain::operator[]: Index " + printable::formatString(index) +
750 " out of bounds for chain of size " + printable::formatString(this->size()));
751 }
752 chainNode* cur = this->findNode(this->parseNegIndex(index));
753 return cur->getVal();
754 }
755
756 template <typename TYPE, typename ALLOC>
758 {
759 if (this->indexOutOfBound(index)){
760 throw outOfBoundError("chain::set: Index " + printable::formatString(index) +
761 " out of bounds for chain of size " + printable::formatString(this->size()));
762 }
763 auto cur = this->findNode(this->parseNegIndex(index));
764 cur->setVal(e);
765 }
766
767 template <typename TYPE, typename ALLOC>
769 u_integer i = 0;
770 for (chainNode* current = this->begin_; current != nullptr; current = current->getPNext()) {
771 if (current->getVal() == e) {
772 return i;
773 }
774 i += 1;
775 }
776 return this->size();
777 }
778
779 template <typename TYPE, typename ALLOC>
781 {
782 auto new_node = this->createNode(e);
783 if (this->size() == 0){
784 this->firstAdd(new_node);
785 } else{
786 auto pivot = this->begin_->getPPrev();
787 chainNode::connect(new_node, this->begin_);
788 chainNode::connect(pivot, new_node);
789 this->begin_ = new_node;
790 this->size_ += 1;
791 }
792 }
793
794 template <typename TYPE, typename ALLOC>
796 {
797 index = this->parseNegIndex(index);
798 if (index == 0){
799 this->pushBegin(e);
800 } else if (index == this->size()){
801 this->pushEnd(e);
802 } else{
803 if (this->indexOutOfBound(index)){
804 throw outOfBoundError("chain::push: Index " + printable::formatString(index) +
805 " out of bounds for chain of size " + printable::formatString(this->size()));
806 }
807 auto new_node = this->createNode(e);
808 auto cur = this->findNode(index);
809 auto prev = cur->getPPrev();
810 chainNode::connect(prev, new_node);
811 chainNode::connect(new_node, cur);
812 this->size_ += 1;
813 }
814 }
815
816 template <typename TYPE, typename ALLOC>
818 {
819 auto new_node = this->createNode(e);
820 if (this->size() == 0){
821 this->firstAdd(new_node);
822 } else{
823 chainNode::connect(this->end_, new_node);
824 this->end_ = new_node;
825 this->size_ += 1;
826 }
827 }
828
829 template <typename TYPE, typename ALLOC>
831 {
832 TYPE res;
833 if (this->size() == 0){
834 throw noElementError("chain::popBegin: Cannot pop from empty chain");
835 }
836 if (this->size() == 1){
837 auto del = this->lastDelete();
838 res = del->getVal();
839 this->destroyNode(del);
840 } else{
841 res = this->begin_->getVal();
842 auto new_begin = this->begin_->getPNext();
843 auto pivot = this->begin_->getPPrev();
844 this->destroyNode(this->begin_);
845 this->begin_ = new_begin;
846 chainNode::connect(pivot, this->begin_);
847 this->size_ -= 1;
848 }
849 return res;
850 }
851
852 template <typename TYPE, typename ALLOC>
854 {
855 index = this->parseNegIndex(index);
856 if (index == 0){
857 return this->popBegin();
858 }
859 if (index == this->size() - 1){
860 return this->popEnd();
861 }
862 if (this->indexOutOfBound(index)){
863 throw outOfBoundError("chain::pop: Index " + printable::formatString(index) +
864 " out of bounds for chain of size " + printable::formatString(this->size()));
865 }
866 TYPE res;
867 chainNode* cur = this->findNode(index);
868 res = cur->getVal();
869 auto prev = cur->getPPrev();
870 auto next = cur->getPNext();
871 chainNode::connect(prev, next);
872 this->destroyNode(cur);
873 this->size_ -= 1;
874 return res;
875 }
876
877 template <typename TYPE, typename ALLOC>
879 {
880 TYPE res;
881 if (this->size() == 0){
882 throw noElementError("chain::popEnd: Cannot pop from empty chain");
883 }
884 if (this->size() == 1){
885 auto del = this->lastDelete();
886 res = del->getVal();
887 this->destroyNode(del);
888 } else{
889 res = this->end_->getVal();
890 auto new_end = this->end_->getPPrev();
891 this->destroyNode(this->end_);
892 this->end_ = new_end;
893 chainNode::connect(this->end_, nullptr);
894 this->size_ -= 1;
895 }
896 return res;
897 }
898
899 template <typename TYPE, typename ALLOC>
901 return new Iterator(this->begin_);
902 }
903
904 template <typename TYPE, typename ALLOC>
906 return new Iterator(this->end_);
907 }
908
909 template <typename TYPE, typename ALLOC>
911 this->chainDestroy();
912 }
913
914 template <typename TYPE, typename ALLOC>
916 {
917 lhs.swap(rhs);
918 }
919
920#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:768
TYPE popEnd() override
Pops an element from the end of the chain.
Definition chain.h:878
TYPE pop(integer index) override
Pops an element at the specified index in the chain.
Definition chain.h:853
chain(chain &&other) noexcept
Move constructs a chain with optional allocator.
Definition chain.h:667
Iterator * ends() const override
Gets an iterator to the end of the chain.
Definition chain.h:905
u_integer size() const override
Gets the size of the chain.
Definition chain.h:723
Iterator * begins() const override
Gets an iterator to the beginning of the chain.
Definition chain.h:900
chain & operator=(chain &&other) noexcept
Move assignment operator with allocator propagation.
Definition chain.h:673
TYPE popBegin() override
Pops an element from the beginning of the chain.
Definition chain.h:830
std::string className() const override
Gets the class name of the chain.
Definition chain.h:729
chain(const array< TYPE > &arr)
Constructs a chain from an array.
Definition chain.h:622
TYPE get(integer index) const override
Gets the element at the specified index.
Definition chain.h:735
~chain() override
Destructor for the chain.
Definition chain.h:910
TYPE & operator[](integer index) override
Gets a reference to the element at the specified index.
Definition chain.h:746
void push(integer index, const TYPE &e) override
Pushes an element at the specified index in the chain.
Definition chain.h:795
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:600
void pushEnd(const TYPE &e) override
Pushes an element to the end of the chain.
Definition chain.h:817
void pushBegin(const TYPE &e) override
Pushes an element to the beginning of the chain.
Definition chain.h:780
chain & operator=(const chain &other)
Copy assignment operator with allocator propagation.
Definition chain.h:639
void swap(chain &other) noexcept
Swaps the contents of this chain with another.
Definition chain.h:691
chain(const std::initializer_list< TYPE > &list)
Constructs a chain from an initializer list.
Definition chain.h:605
void set(integer index, const TYPE &e) override
Sets the element at the specified index.
Definition chain.h:757
chain & operator+=(chain &other)
Concatenates another chain to this one.
Definition chain.h:706
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.
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 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.
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