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
19
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 = typename 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 chainDestruction();
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>
402 original::chain<TYPE, ALLOC>::chainNode::chainNode(const chainNode& other)
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>
416 auto original::chain<TYPE, ALLOC>::chainNode::getVal() -> TYPE&
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>
428 auto original::chain<TYPE, ALLOC>::chainNode::setVal(TYPE data) -> void
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>
494 auto original::chain<TYPE, ALLOC>::chainInit() -> void
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>
512 auto original::chain<TYPE, ALLOC>::lastDelete() -> chainNode*
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>
522 auto original::chain<TYPE, ALLOC>::chainDestruction() -> void
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>
533 original::chain<TYPE, ALLOC>::Iterator::Iterator(chainNode* ptr)
535
536 template <typename TYPE, typename ALLOC>
537 original::chain<TYPE, ALLOC>::Iterator::Iterator(const Iterator& other)
539 this->operator=(other);
540 }
541
542 template <typename TYPE, typename ALLOC>
543 auto original::chain<TYPE, ALLOC>::Iterator::operator=(const Iterator& other) -> Iterator& {
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->chainDestruction();
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->chainDestruction();
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();
702 }
703 chainNode* cur = this->findNode(this->parseNegIndex(index));
704 return cur->getVal();
705 }
706
707 template <typename TYPE, typename ALLOC>
709 {
710 if (this->indexOutOfBound(index)){
711 throw outOfBoundError();
712 }
713 chainNode* cur = this->findNode(this->parseNegIndex(index));
714 return cur->getVal();
715 }
716
717 template <typename TYPE, typename ALLOC>
718 auto original::chain<TYPE, ALLOC>::set(integer index, const TYPE &e) -> void
719 {
720 if (this->indexOutOfBound(index)){
721 throw outOfBoundError();
722 }
723 auto cur = this->findNode(this->parseNegIndex(index));
724 cur->setVal(e);
725 }
726
727 template <typename TYPE, typename ALLOC>
729 u_integer i = 0;
730 for (chainNode* current = this->begin_; current != nullptr; current = current->getPNext()) {
731 if (current->getVal() == e) {
732 return i;
733 }
734 i += 1;
735 }
736 return this->size();
737 }
738
739 template <typename TYPE, typename ALLOC>
740 auto original::chain<TYPE, ALLOC>::pushBegin(const TYPE &e) -> void
741 {
742 auto new_node = this->createNode(e);
743 if (this->size() == 0){
744 this->firstAdd(new_node);
745 } else{
746 auto pivot = this->begin_->getPPrev();
747 chainNode::connect(new_node, this->begin_);
748 chainNode::connect(pivot, new_node);
749 this->begin_ = new_node;
750 this->size_ += 1;
751 }
752 }
753
754 template <typename TYPE, typename ALLOC>
755 auto original::chain<TYPE, ALLOC>::push(integer index, const TYPE &e) -> void
756 {
757 index = this->parseNegIndex(index);
758 if (index == 0){
759 this->pushBegin(e);
760 } else if (index == this->size()){
761 this->pushEnd(e);
762 } else{
763 if (this->indexOutOfBound(index)){
764 throw outOfBoundError();
765 }
766 auto new_node = this->createNode(e);
767 auto cur = this->findNode(index);
768 auto prev = cur->getPPrev();
769 chainNode::connect(prev, new_node);
770 chainNode::connect(new_node, cur);
771 this->size_ += 1;
772 }
773 }
774
775 template <typename TYPE, typename ALLOC>
776 auto original::chain<TYPE, ALLOC>::pushEnd(const TYPE &e) -> void
777 {
778 auto new_node = this->createNode(e);
779 if (this->size() == 0){
780 this->firstAdd(new_node);
781 } else{
782 chainNode::connect(this->end_, new_node);
783 this->end_ = new_node;
784 this->size_ += 1;
785 }
786 }
787
788 template <typename TYPE, typename ALLOC>
790 {
791 TYPE res;
792 if (this->size() == 0){
793 throw noElementError();
794 }
795 if (this->size() == 1){
796 auto del = this->lastDelete();
797 res = del->getVal();
798 this->destroyNode(del);
799 } else{
800 res = this->begin_->getVal();
801 auto new_begin = this->begin_->getPNext();
802 auto pivot = this->begin_->getPPrev();
803 this->destroyNode(this->begin_);
804 this->begin_ = new_begin;
805 chainNode::connect(pivot, this->begin_);
806 this->size_ -= 1;
807 }
808 return res;
809 }
810
811 template <typename TYPE, typename ALLOC>
813 {
814 index = this->parseNegIndex(index);
815 if (index == 0){
816 return this->popBegin();
817 }
818 if (index == this->size() - 1){
819 return this->popEnd();
820 }
821 if (this->indexOutOfBound(index)){
822 throw outOfBoundError();
823 }
824 TYPE res;
825 chainNode* cur = this->findNode(index);
826 res = cur->getVal();
827 auto prev = cur->getPPrev();
828 auto next = cur->getPNext();
829 chainNode::connect(prev, next);
830 this->destroyNode(cur);
831 this->size_ -= 1;
832 return res;
833 }
834
835 template <typename TYPE, typename ALLOC>
837 {
838 TYPE res;
839 if (this->size() == 0){
840 throw noElementError();
841 }
842 if (this->size() == 1){
843 auto del = this->lastDelete();
844 res = del->getVal();
845 this->destroyNode(del);
846 } else{
847 res = this->end_->getVal();
848 auto new_end = this->end_->getPPrev();
849 this->destroyNode(this->end_);
850 this->end_ = new_end;
851 chainNode::connect(this->end_, nullptr);
852 this->size_ -= 1;
853 }
854 return res;
855 }
856
857 template <typename TYPE, typename ALLOC>
859 return new Iterator(this->begin_);
860 }
861
862 template <typename TYPE, typename ALLOC>
864 return new Iterator(this->end_);
865 }
866
867 template <typename TYPE, typename ALLOC>
869 this->chainDestruction();
870 }
871
872#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:393
u_integer size() const override
Returns the size of the array.
Definition array.h:382
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:728
TYPE popEnd() override
Pops an element from the end of the chain.
Definition chain.h:836
TYPE pop(integer index) override
Pops an element at the specified index in the chain.
Definition chain.h:812
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:863
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:858
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:789
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:868
TYPE & operator[](integer index) override
Gets a reference to the element at the specified index.
Definition chain.h:708
void push(integer index, const TYPE &e) override
Pushes an element at the specified index in the chain.
Definition chain.h:755
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:776
void pushBegin(const TYPE &e) override
Pushes an element to the beginning of the chain.
Definition chain.h:740
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:718
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:34
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
doubleDirectionIterator(wrapper< TYPE > *ptr)
Protected constructor for doubleDirectionIterator.
Definition doubleDirectionIterator.h:67
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
wrapper< TYPE > * _ptr
Pointer to the current wrapper.
Definition stepIterator.h:39
Base class for linked value containers with formatted output.
Definition wrapper.h:28
Double-direction iterator base class.
Provides functionality for an iteration stream.
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
std::int64_t integer
64-bit signed integer type for arithmetic operations
Definition config.h:15