Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
dlink.H
Go to the documentation of this file.
1
2/*
3 Aleph_w
4
5 Data structures & Algorithms
6 version 2.0.0b
7 https://github.com/lrleon/Aleph-w
8
9 This file is part of Aleph-w library
10
11 Copyright (c) 2002-2026 Leandro Rabindranath Leon
12
13 Permission is hereby granted, free of charge, to any person obtaining a copy
14 of this software and associated documentation files (the "Software"), to deal
15 in the Software without restriction, including without limitation the rights
16 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 copies of the Software, and to permit persons to whom the Software is
18 furnished to do so, subject to the following conditions:
19
20 The above copyright notice and this permission notice shall be included in all
21 copies or substantial portions of the Software.
22
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 SOFTWARE.
30*/
31
32
33# ifndef DLINK_H
34# define DLINK_H
35
51# include <aleph.H>
52# include <ah-errors.H>
53
54namespace Aleph {
55
56 template <typename T> class Dnode; // Forward declaration of derived class
57
99 class Dlink
100 {
101 protected:
102
103 mutable Dlink * prev;
104 mutable Dlink * next;
105
106 public:
107
108 template <typename T>
113 T& to_data() noexcept;
116
119
123 : prev(l.prev), next(l.next)
124 {
125 if (l.is_empty())
126 reset();
127 }
128
137 void swap(Dlink * link) noexcept
138 {
139 if (is_empty() and link->is_empty())
140 return;
141
142 if (is_empty())
143 {
144 link->next->prev = this;
145 link->prev->next = this;
146 next = link->next;
147 prev = link->prev;
148 link->reset();
149 return;
150 }
151
152 if (link->is_empty())
153 {
154 next->prev = link;
155 prev->next = link;
156 link->next = next;
157 link->prev = prev;
158 reset();
159 return;
160 }
161
162 std::swap(prev->next, link->prev->next);
163 std::swap(next->prev, link->next->prev);
164 std::swap(prev, link->prev);
165 std::swap(next, link->next);
166 }
167
176 void swap(Dlink & l) noexcept
177 {
178 swap(&l);
179 }
180
189 {
190 swap(l);
191 }
192
200 Dlink & operator = (const Dlink & l) noexcept
201 {
202 if (l.is_empty())
203 return *this;
204
205 assert(is_empty());
206 prev = l.prev;
207 next = l.next;
208 return *this;
209 }
210
222 Dlink & operator = (Dlink && l) noexcept
223 {
224 swap(l);
225 return *this;
226 }
227
235 {
236 next = prev = this;
237 }
238
241 {
242 reset();
243 }
244
246 [[nodiscard]] constexpr bool is_empty() const noexcept { return this == next and this == prev; }
247
249 [[nodiscard]] constexpr bool is_unitarian() const noexcept { return this != next and next == prev; }
250
252 [[nodiscard]] constexpr bool is_unitarian_or_empty() const noexcept { return next == prev; }
253
259 void insert(Dlink * node) noexcept
260 {
261 assert(next != nullptr and prev != nullptr);
262 assert(node != nullptr);
263 assert(node->is_empty());
264
265 node->prev = this;
266 node->next = next;
267 next->prev = node;
268 next = node;
269 }
270
272 void push(Dlink * node) noexcept
273 {
274 insert(node);
275 }
276
282 void append(Dlink * node) noexcept
283 {
284 assert(next != nullptr and prev != nullptr);
285 assert(node != nullptr);
286 assert(node->is_empty());
287
288 node->next = this;
289 node->prev = prev;
290 prev->next = node;
291 prev = node;
292 }
293
296 {
297 assert(next != nullptr and prev != nullptr);
298 return next;
299 }
300
303 {
304 assert(next != nullptr and prev != nullptr);
305 return prev;
306 }
307
309 [[nodiscard]] constexpr Dlink *& get_first_ne() const noexcept { return next; }
310
312 [[nodiscard]] constexpr Dlink *& get_last_ne() const noexcept { return prev; }
313
315 [[nodiscard]] constexpr Dlink *& get_first() const noexcept { return next; }
316
318 [[nodiscard]] constexpr Dlink *& get_last() const noexcept { return prev; }
319
345 void wrap_header(Dlink * l) noexcept
346 {
347 assert(is_empty());
348 l->append(this);
349 }
350
361 void insert_list(Dlink * head) noexcept
362 {
363 if (head->is_empty())
364 return;
365
366 head->prev->next = next;
367 head->next->prev = this;
368 next->prev = head->prev;
369 next = head->next;
370 head->reset();
371 }
372
383 void append_list(Dlink * head) noexcept
384 {
385 if (head->is_empty())
386 return;
387
388 head->next->prev = prev;
389 head->prev->next = this;
390 prev->next = head->next;
391 prev = head->prev;
392 head->reset();
393 }
394
399 void splice(Dlink * l) noexcept
400 {
401 Dlink head;
402 head.wrap_header(l);
403 insert_list(&head);
404 assert(head.is_empty());
405 }
406
416 void concat_list(Dlink * head) noexcept
417 {
418 assert(head != nullptr);
419
420 if (head->is_empty())
421 return;
422
423 if (this->is_empty())
424 {
425 swap(head);
426 return;
427 }
428
429 prev->next = head->next;
430 head->next->prev = prev;
431 prev = head->prev;
432 head->prev->next = this;
433 head->reset();
434 }
435
437 void concat_list(Dlink & head) noexcept
438 {
439 concat_list(&head);
440 }
441
444 {
445 assert(next != nullptr and prev != nullptr);
446
447 prev->next = next;
448 next->prev = prev;
449 reset();
450 return this;
451 }
452
454 void erase() noexcept { del(); }
455
468 {
470
472 retValue->del();
473
474 return retValue;
475 }
476
489 {
491
493 retValue->del();
494
495 return retValue;
496 }
497
500 {
501 return remove_prev();
502 }
503
506 {
507 return remove_next();
508 }
509
512 {
513 return remove_prev();
514 }
515
518 {
519 return remove_next();
520 }
521
523 Dlink * top() const
524 {
525 ah_underflow_error_if(is_empty()) << "Dlink as stack is empty";
526 return get_next();
527 }
528
531 {
532 ah_underflow_error_if(is_empty()) << "Dlink as stack is empty";
533 return remove_next();
534 }
535
541 {
542 if (is_empty())
543 return 0;
544
545 Dlink tmp;
546 size_t counter = 0;
547 for (; not is_empty(); counter++)
549
550 swap(&tmp);
551
552 return counter;
553 }
554
556 size_t reverse() noexcept { return reverse_list(); }
557
571 size_t split_list_ne(Dlink & l, Dlink & r) noexcept
572 {
573 assert(l.is_empty() and r.is_empty()); // l y r deben estar vacías
574
575 size_t count = 0;
576 while (not is_empty())
577 {
579
580 if (is_empty())
581 break;
582
583 r.insert(remove_prev()); ++count;
584 }
585
586 return count;
587 }
588
589 size_t split_list(Dlink & l, Dlink & r) noexcept
590 {
591 return split_list_ne(l, r);
592 }
593
613 Dlink cut_list(Dlink * link) noexcept
614 {
615 assert(not is_empty() and not link->is_empty() and link != this);
616
617 Dlink list;
618 if (link == this->prev) // is link the last item?
619 {
620 link->del();
621 list.append(link);
622 return list;
623 }
624
625 if (link == this->next) // is link the first item?
626 {
627 list.swap(this);
628 assert(this->is_empty());
629 return list;
630 }
631
632 list.prev = this->prev; // enlazar list a link (punto de corte)
633 list.next = link;
634 this->prev = link->prev; // quitar de this todo a partir de link
635 link->prev->next = this;
636 link->prev = &list; // colocar el corte en list
637 list.prev->next = &list;
638
639 return list;
640 }
641
647 {
648 private:
649
650 mutable Dlink * head = nullptr;
651 mutable Dlink * curr = nullptr;
652
653 public:
654
657
659 using Item_Type = Dlink *;
660
667 : head(head_ptr), curr(head->get_next()) { /* */ }
668
673 Iterator(const Dlink & list) noexcept
674 : head(&const_cast<Dlink&>(list)), curr(head->get_next())
675 {
676 // Empty
677 }
678
686 void set(Dlink * new_curr) noexcept
687 {
688 assert(curr != nullptr and head != nullptr);
689 curr = new_curr;
690 }
691
692 Iterator() noexcept : head(nullptr), curr(nullptr) { /* Empty */ }
693
696 {
697 assert(curr != nullptr and head != nullptr);
698 curr = head->get_next();
699 }
700
703 {
704 assert(curr != nullptr and head != nullptr);
705 curr = head->get_prev();
706 }
707
710 {
711 put_itor_at_the_end(*this);
712 }
713
716 {
717 assert(curr != nullptr and head != nullptr);
718 return curr != head;
719 }
720
722 {
723 return head->is_empty() ? false : curr == head->prev;
724 }
725
728 {
729 assert(curr != nullptr and head != nullptr);
730 return curr;
731 }
732
739 {
740 ah_overflow_error_if(not has_curr()) << "Not element in list";
741
742 return get_curr_ne();
743 }
744
746 [[nodiscard]] constexpr bool is_in_first() const noexcept
747 {
748 return head->is_empty() ? false : curr == head->next;
749 }
750
752 [[nodiscard]] bool is_in_last() const noexcept { return is_last(); }
753
757
762 void prev()
763 {
764 ah_underflow_error_if(not has_curr()) << "Not previous element in list";
765 prev_ne();
766 }
767
771
776 void next()
777 {
778 ah_overflow_error_if(not has_curr()) << "Not next element in list";
779 next_ne();
780 }
781
783 [[nodiscard]] constexpr bool operator == (const Iterator & it) const noexcept
784 { return curr == it.curr; }
785
787 [[nodiscard]] constexpr bool operator != (const Iterator & it) const noexcept
788 { return curr != it.curr; }
789
796 {
797 assert(curr != nullptr and head != nullptr);
798 assert(has_curr());
799
800 Dlink * current = get_curr(); // obtener nodo actual
801 next(); // avanzar al siguiente nodo
802 current->del(); // eliminar de la lista antiguo nodo actual
803 return current;
804 }
805
807 {
808 assert(curr != nullptr and head != nullptr);
809 assert(has_curr());
810
811 Dlink * current = get_curr(); // obtener nodo actual
812 next_ne(); // avanzar al siguiente nodo
813 current->del(); // eliminar de la lista antiguo nodo actual
814 return current;
815 }
816
818 [[nodiscard]] constexpr bool verify(Dlink * l) const noexcept { return head == l; }
819
821 [[nodiscard]] constexpr bool verify(const Iterator & it) const noexcept { return head == it.head; }
822 };
823
836 {
837 while (not is_empty())
838 delete remove_next();
839 }
840
855 void rotate_left(size_t n)
856 {
857 if (is_empty())
858 {
859 if (n == 0)
860 return;
861 ah_domain_error() << "List is empty";
862 }
863
864 for (size_t i = 0; i < n; ++i)
866 }
867
869 void rotate_right(size_t n)
870 {
871 if (is_empty())
872 {
873 if (n == 0)
874 return;
875 ah_domain_error() << "List is empty";
876 }
877
878 for (size_t i = 0; i < n; ++i)
880 }
881
883 bool check()
884 {
885 Iterator itor(this);
886 Dlink* node;
887
888 for (/* nothing */; itor.has_curr(); itor.next_ne())
889 {
890 node = itor.get_curr();
891
892 if (not (node->get_next()->get_prev() == node))
893 return false;
894
895 if (not (node->get_prev()->get_next() == node))
896 return false;
897 }
898
899 for (itor.reset_last(); itor.has_curr(); itor.prev())
900 {
901 node = itor.get_curr();
902
903 if (not (node->get_next()->get_prev() == node))
904 return false;
905
906 if (not (node->get_prev()->get_next() == node))
907 return false;
908 }
909
910 return true;
911 }
912 };
913
943# define DLINK_TO_TYPE(type_name, link_name) \
944 inline static type_name * dlink_to_##type_name(Dlink * link) noexcept \
945 { \
946 type_name * ptr_zero = 0; \
947 size_t offset_link = reinterpret_cast<size_t>(&(ptr_zero->link_name)); \
948 char * address_type = reinterpret_cast<char*>(link) - offset_link; \
949 return reinterpret_cast<type_name *>(address_type); \
950 }
951
993# define LINKNAME_TO_TYPE(type_name, link_name) \
994 inline static type_name * link_name##_to_##type_name(Dlink * link) noexcept \
995 { \
996 type_name * ptr_zero = 0; \
997 size_t offset_link = reinterpret_cast<size_t>(&(ptr_zero->link_name)); \
998 char * address_type = reinterpret_cast<char*>(link) - offset_link; \
999 return reinterpret_cast<type_name *>(address_type); \
1000 }
1001
1002
1029# define DLINK_TO_BASE(type_name, link_name) \
1030 inline static type_name * dlink_to_base(Dlink * link) noexcept \
1031 { \
1032 type_name * ptr_zero = 0; \
1033 size_t offset_link = reinterpret_cast<size_t>(&(ptr_zero->link_name)); \
1034 char * address_type = reinterpret_cast<char*>(link) - offset_link; \
1035 return reinterpret_cast<type_name *>(address_type); \
1036 }
1037
1038}
1039
1040# endif /* DLINK_H */
1041
Exception handling system with formatted messages for Aleph-w.
#define ah_domain_error()
Throws std::domain_error unconditionally.
Definition ah-errors.H:554
#define ah_underflow_error_if(C)
Throws std::underflow_error if condition holds.
Definition ah-errors.H:368
#define ah_overflow_error_if(C)
Throws std::overflow_error if condition holds.
Definition ah-errors.H:463
Core header for the Aleph-w library.
void put_itor_at_the_end(Itor &it) noexcept
Definition aleph.H:54
Node belonging to a double circular linked list with header node.
Definition tpl_dnode.H:106
T & insert(const T &item)
Insert a new item by copy.
Definition htlist.H:1502
T & append(const T &item)
Append a new item by copy.
Definition htlist.H:1562
constexpr bool is_empty() const noexcept
Return true if list is empty.
Definition htlist.H:523
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
std::decay_t< typename HeadC::Item_Type > T
Definition ah-zip.H:107
DynList< T > maps(const C &c, Op op)
Classic map operation.
Itor::difference_type count(const Itor &beg, const Itor &end, const T &value)
Count elements equal to a value.
Definition ahAlgo.H:127
DynList< int > l