Zth (libzth)
Loading...
Searching...
No Matches
list.h
Go to the documentation of this file.
1#ifndef ZTH_LIST_H
2#define ZTH_LIST_H
3/*
4 * SPDX-FileCopyrightText: 2019-2026 Jochem Rutgers
5 *
6 * SPDX-License-Identifier: MPL-2.0
7 */
8
9#include <libzth/macros.h>
10
11#ifdef __cplusplus
12
13# include <libzth/allocator.h>
14# include <libzth/config.h>
15# include <libzth/util.h>
16
17# include <functional>
18
19namespace zth {
20
21class Listable;
22
23template <typename T>
24class List;
25
26template <typename T = Listable, typename Compare = std::less<T> >
27class SortedList;
28
29class Listable {
30public:
31 typedef void* user_type;
32
33 constexpr Listable() noexcept
34 : prev()
35 , next()
36 , user()
37 {}
38
39 constexpr Listable(Listable const& UNUSED_PAR(e)) noexcept
40 : prev()
41 , next()
42 , user()
43 {}
44
45 // cppcheck-suppress operatorEqVarError
46 Listable& operator=(Listable const& UNUSED_PAR(rhs)) noexcept
47 {
49 prev = next = nullptr;
50 return *this;
51 }
52
53# if __cplusplus >= 201103L
54 Listable(Listable&& l) noexcept
55 {
56 *this = std::move(l);
57 }
58
59 // cppcheck-suppress operatorEqVarError
61 {
62 // Cannot move while in a list.
64 zth_assert(!l.prev);
66 zth_assert(!l.next);
67 return *this;
68 }
69# endif // C++11
70
71private:
72 union {
73 Listable* prev; // for List
74 Listable* left; // for SortedList
75 };
76 union {
77 Listable* next; // for List
78 Listable* right; // for SortedList
79 };
80 union {
81 user_type user; // For List
82 uint_fast8_t level; // for SortedList
83 };
84
85 template <typename T>
86 friend class List;
87 template <typename T, typename Compare>
88 friend class SortedList;
89};
90
91template <typename T = Listable>
92class List {
95public:
96 typedef T type;
99
100 template <bool cyclic>
101 class Iterator {
102 public:
103 constexpr explicit Iterator(elem_type* start, elem_type* current = nullptr) noexcept
104 : m_start(start)
105 , m_current(current)
106 {}
107
108 bool atBegin() const noexcept
109 {
110 return !m_current && m_start;
111 }
112
113 bool atEnd() const noexcept
114 {
115 return m_current == m_start;
116 }
117
118 elem_type* get() const noexcept
119 {
120 zth_assert(cyclic || !atEnd());
121 return unlikely(atBegin()) ? m_start : m_current;
122 }
123
124 template <bool C>
125 bool operator==(Iterator<C> const& rhs) const noexcept
126 {
127 if(atEnd())
128 return rhs.atEnd();
129 if(rhs.atEnd())
130 return false;
131 return get() == rhs.get();
132 }
133
134 template <bool C>
135 bool operator!=(Iterator<C> const& rhs) const noexcept
136 {
137 return !(*this == rhs);
138 }
139
140 void next() noexcept
141 {
142 zth_assert((cyclic || !atEnd()) && m_start);
143 // NOLINTNEXTLINE(clang-analyzer-core.NullDereference)
144 m_current = unlikely(atBegin()) ? m_start->next : m_current->next;
145 }
146
147 void prev() noexcept
148 {
149 zth_assert((cyclic || !atEnd()) && m_start);
150 m_current =
151 unlikely(m_current->prev == m_start) ? nullptr : m_current->prev;
152 }
153
155 {
156 next();
157 return *this;
158 }
159
160 Iterator operator++(int) noexcept
161 {
162 Iterator i = *this;
163 next();
164 return i;
165 }
166
168 {
169 prev();
170 return *this;
171 }
172
173 Iterator operator--(int) noexcept
174 {
175 Iterator i = *this;
176 prev();
177 return i;
178 }
179
180 type& operator*() const noexcept
181 {
182 elem_type* elem = get();
183 zth_assert(elem);
184 // cppcheck-suppress nullPointerRedundantCheck
185 return *static_cast<type*>(elem);
186 }
187
188 type* operator->() const noexcept
189 {
190 return &this->operator*();
191 }
192
193 user_type const& user() const noexcept
194 {
195 elem_type const* elem = get();
196 zth_assert(elem);
197 // cppcheck-suppress nullPointerRedundantCheck
198 return elem->user;
199 }
200
201 user_type& user() noexcept
202 {
203 elem_type* elem = get();
204 zth_assert(elem);
205 // cppcheck-suppress nullPointerRedundantCheck
206 return elem->user;
207 }
208
209 private:
210 elem_type* m_start;
211 elem_type* m_current;
212 };
213
216
217 constexpr List() noexcept
218 : m_head()
219 , m_tail()
220 {}
221
222 ~List() noexcept
223 {
225 clear();
226 }
227
228 type& back() const noexcept
229 {
230 zth_assert(!empty());
231 return *static_cast<type*>(m_tail);
232 }
233
234 user_type const& user_back() const noexcept
235 {
236 zth_assert(!empty());
237 return m_tail->user;
238 }
239
241 {
242 zth_assert(!empty());
243 return m_tail->user;
244 }
245
247 {
248 zth_assert(elem.prev == nullptr);
249 zth_assert(elem.next == nullptr);
250
251 elem.user = user_type();
252
253 if(m_tail == nullptr) {
254 zth_assert(m_head == nullptr);
255 m_tail = m_head = elem.prev = elem.next = &elem;
256 return begin();
257 } else {
258 elem.next = m_tail->next;
259 elem.prev = m_tail;
260 m_tail = elem.next->prev = elem.prev->next = &elem;
261 return iterator(m_head, &elem);
262 }
263 }
264
266 {
267 zth_assert(!empty());
268
269 elem_type* elem = m_tail;
270
271 if(m_tail == m_head) {
272 m_tail = m_head = nullptr;
273 zth_assert(elem->prev == elem->next);
274 zth_assert(elem->prev == elem);
275 } else {
276 m_tail = m_tail->prev;
277 elem->prev->next = elem->next;
278 elem->next->prev = elem->prev;
279 }
280
282 elem->prev = elem->next = nullptr;
283
284 return elem->user;
285 }
286
287 type& front() const noexcept
288 {
289 zth_assert(!empty());
290 return *static_cast<type*>(m_head);
291 }
292
293 user_type const& user_front() const noexcept
294 {
295 zth_assert(!empty());
296 return m_head->user;
297 }
298
300 {
301 zth_assert(!empty());
302 return m_head->user;
303 }
304
306 {
307 zth_assert(elem.prev == nullptr);
308 zth_assert(elem.next == nullptr);
309
310 if(m_head == nullptr) {
311 zth_assert(m_tail == nullptr);
312 m_tail = m_head = elem.prev = elem.next = &elem;
313 } else {
314 elem.next = m_head;
315 elem.prev = m_head->prev;
316 elem.prev->next = elem.next->prev = m_head = &elem;
317 }
318 elem.user = user_type();
319 return iterator(m_head, &elem);
320 }
321
323 {
324 zth_assert(!empty());
325
326 elem_type* elem = m_head;
327
328 if(m_tail == m_head) {
329 m_tail = m_head = nullptr;
330 zth_assert(elem->prev == elem->next);
331 zth_assert(elem->prev == elem);
332 } else {
333 m_head = m_head->next;
334 elem->prev->next = elem->next;
335 elem->next->prev = elem->prev;
336 }
337
339 elem->prev = elem->next = nullptr;
340
341 return elem->user;
342 }
343
344 bool empty() const noexcept
345 {
346 zth_assert(m_head != nullptr || m_tail == nullptr);
347 return m_head == nullptr;
348 }
349
350 void clear() noexcept
351 {
353 while(!empty())
354 pop_front();
355 else
356 m_head = m_tail = nullptr;
357 }
358
359 iterator begin() const noexcept
360 {
361 return iterator(m_head);
362 }
363
364 cyclic_iterator cyclic(elem_type& start) const noexcept
365 {
366 zth_assert(contains(start));
367 return cyclic_iterator(&start);
368 }
369
370 iterator end() const noexcept
371 {
372 return iterator(m_head, m_head);
373 }
374
375 bool contains(elem_type const& elem) const noexcept
376 {
377 for(iterator it = begin(); it != end(); ++it)
378 if(it.get() == &elem)
379 return true;
380 return false;
381 }
382
383 size_t size() const noexcept
384 {
385 size_t res = 0;
386 for(iterator it = begin(); it != end(); ++it)
387 res++;
388 return res;
389 }
390
391 iterator insert(iterator const& pos, elem_type& elem) noexcept
392 {
393 if(pos.atEnd()) {
394 push_back(elem);
395 return iterator(m_head, &elem);
396 } else if(pos.atBegin()) {
397 push_front(elem);
398 return begin();
399 } else {
400 elem_type* before = pos.get();
401 elem.next = before;
402 elem.prev = before->prev;
403 before->prev = elem.prev->next = &elem;
404 elem.user = user_type();
405 return iterator(m_head, &elem);
406 }
407 }
408
409 iterator erase(iterator const& pos) noexcept
410 {
411 zth_assert(!pos.atEnd());
412 if(pos.atBegin()) {
413 erase(*pos.get());
414 return begin();
415 } else if(pos.get() == m_tail) {
416 erase(*pos.get());
417 return end();
418 } else {
419 elem_type* next = pos.get()->next;
420 erase(*pos.get());
421 return iterator(m_head, next);
422 }
423 }
424
425 user_type erase(elem_type& elem) noexcept
426 {
427 zth_assert(contains(elem));
428 if(m_head == &elem) {
429 return pop_front();
430 } else if(m_tail == &elem) {
431 return pop_back();
432 } else {
433 elem.prev->next = elem.next;
434 elem.next->prev = elem.prev;
436 elem.next = elem.prev = nullptr;
437 return elem.user;
438 }
439 }
440
441 void rotate(elem_type& elem) noexcept
442 {
443 zth_assert(contains(elem));
444 m_head = &elem;
445 m_tail = elem.prev;
446 }
447
448private:
449 elem_type* m_head;
450 elem_type* m_tail;
451};
452
453template <typename T, typename Compare>
457public:
458 typedef T type;
460
461 constexpr SortedList() noexcept
462 : m_comp()
463 , m_t()
464 , m_head()
465 , m_size()
466 {}
467
468 ~SortedList() noexcept
469 {
470 clear();
471 }
472
473 void insert(elem_type& x) noexcept
474 {
475 zth_assert(!x.left);
476 zth_assert(!x.right);
477 zth_assert(x.level == 0);
478 zth_assert(!contains(x));
479 if(!m_t)
480 m_head = &x;
481 m_t = insert_(x, m_t);
482 m_size++;
483 check();
484 }
485
486 void erase(elem_type& x) noexcept
487 {
489 m_t = delete_(x, m_t);
490 if(m_head == &x)
491 m_head = lowest(m_t);
493 x.level = 0;
494 x.left = x.right = nullptr;
495 }
496 m_size--;
497 check();
498 }
499
500 void clear() noexcept
501 {
503 while(!empty())
504 erase(*m_t);
505 } else {
506 m_t = m_head = nullptr;
507 m_size = 0;
508 }
509 }
510
511 size_t size() const noexcept
512 {
513 zth_assert(m_size > 0 || !m_t);
514 return m_size;
515 }
516
517 bool empty() const noexcept
518 {
519 zth_assert(m_size > 0 || !m_t);
520 return !m_t;
521 }
522
523 bool contains(elem_type& x) const noexcept
524 {
525 elem_type* t = m_t;
526 while(t) {
527 if(t == &x)
528 return true;
529 else if(m_comp(static_cast<type&>(x), static_cast<type&>(*t)))
530 t = t->left;
531 else if(m_comp(static_cast<type&>(*t), static_cast<type&>(x)))
532 t = t->right;
533 else if((uintptr_t)&x < (uintptr_t)t)
534 t = t->left;
535 else
536 t = t->right;
537 }
538 return false;
539 }
540
541 type& front() const noexcept
542 {
543 zth_assert(m_head && m_t);
544 return static_cast<type&>(*m_head);
545 }
546
547protected:
548 static elem_type* skew(elem_type* t) noexcept
549 {
550 if(!t)
551 return nullptr;
552 else if(!t->left)
553 return t;
554 else if(t->left->level == t->level) {
555 elem_type* l = t->left;
556 t->left = l->right;
557 l->right = t;
558 return l;
559 } else
560 return t;
561 }
562
563 static elem_type* split(elem_type* t) noexcept
564 {
565 if(!t)
566 return nullptr;
567 else if(!t->right || !t->right->right)
568 return t;
569 else if(t->level == t->right->right->level) {
570 elem_type* r = t->right;
571 t->right = r->left;
572 r->left = t;
573 zth_assert(r->level < std::numeric_limits<decltype(r->level)>::max());
574 r->level++;
575 return r;
576 } else
577 return t;
578 }
579
581 {
582 if(!t) {
583 x.level = 1;
584 x.left = x.right = nullptr;
585 return &x;
586 } else if(m_comp(static_cast<type&>(x), static_cast<type&>(*t)))
587 t->left = insert_(x, t->left);
588 else if(m_comp(static_cast<type&>(*t), static_cast<type&>(x)))
589 t->right = insert_(x, t->right);
590 else if((uintptr_t)&x < (uintptr_t)t)
591 t->left = insert_(x, t->left);
592 else
593 t->right = insert_(x, t->right);
594
595 if(t == m_head && t->left)
596 m_head = t->left;
597
598 return split(skew(t));
599 }
600
602 {
603 if(!t)
604 return nullptr;
605 else if(&x == t) {
606 if(!t->left && !t->right) {
607 return nullptr;
608 } else if(!t->left) {
609 elem_type* l = successor(t);
610 l->right = delete_(*l, t->right);
611 l->left = t->left;
612 l->level = t->level;
613 t = l;
614 } else {
615 elem_type* l = predecessor(t);
616 l->left = delete_(*l, t->left);
617 l->right = t->right;
618 l->level = t->level;
619 t = l;
620 }
621 } else if(m_comp(static_cast<type&>(x), static_cast<type&>(*t)))
622 t->left = delete_(x, t->left);
623 else if(m_comp(static_cast<type&>(*t), static_cast<type&>(x)))
624 t->right = delete_(x, t->right);
625 else if((uintptr_t)&x < (uintptr_t)t)
626 t->left = delete_(x, t->left);
627 else
628 t->right = delete_(x, t->right);
629
631 t = skew(t);
632 t->right = skew(t->right);
633 if(t->right)
634 t->right->right = skew(t->right->right);
635 t = split(t);
636 t->right = split(t->right);
637 return t;
638 }
639
640 static elem_type* lowest(elem_type* t) noexcept
641 {
642 if(!t)
643 return nullptr;
644 else if(!t->left)
645 return t;
646 else
647 return lowest(t->left);
648 }
649
650 static elem_type* highest(elem_type* t) noexcept
651 {
652 if(!t)
653 return nullptr;
654 else if(!t->right)
655 return t;
656 else
657 return highest(t->right);
658 }
659
660 static elem_type* successor(elem_type* t) noexcept
661 {
662 return t ? lowest(t->right) : nullptr;
663 }
664
665 static elem_type* predecessor(elem_type* t) noexcept
666 {
667 return t ? highest(t->left) : nullptr;
668 }
669
670 // cppcheck-suppress constParameterPointer
671 static void decrease_level(elem_type* t) noexcept
672 {
673# ifndef CPPCHECK // Internal error, somehow.
674 decltype(t->level) ll = t->left ? t->left->level : 0;
675 decltype(t->level) lr = t->right ? t->right->level : 0;
676 decltype(t->level) should_be = (decltype(t->level))((ll < lr ? ll : lr) + 1U);
677 if(should_be < t->level) {
678 t->level = should_be;
679 if(t->right && should_be < t->right->level)
680 t->right->level = should_be;
681 }
682# endif
683 }
684
685 void check() const noexcept
686 {
687 zth_dbg(list, "SortedList %p (head %p):", this, m_head);
688 print(m_t, 2);
689 zth_assert(m_size == check(m_t));
690 zth_assert((!m_t && !m_head) || (m_t && m_head && lowest(m_t) == m_head));
691 }
692
693 size_t check(elem_type* t) const noexcept
694 {
696 return 0;
697 if(!t)
698 return 0;
699
701 !t->left || m_comp(static_cast<type&>(*t->left), static_cast<type&>(*t))
702 || (!m_comp(static_cast<type&>(*t), static_cast<type&>(*t->left))
703 && ((uintptr_t)t > (uintptr_t)t->left)));
705 !t->right || m_comp(static_cast<type&>(*t), static_cast<type&>(*t->right))
706 || (!m_comp(static_cast<type&>(*t->right), static_cast<type&>(*t))
707 || ((uintptr_t)t < (uintptr_t)t->right)));
708
709 zth_assert(t->left || t->right || t->level == 1);
710 zth_assert(!t->left || t->left->level == t->level - 1);
712 !t->right || t->right->level == t->level - 1
713 || t->right->level == t->level);
714 zth_assert(!t->right || !t->right->right || t->right->right->level < t->level);
715 zth_assert(t->level < 2 || (t->left && t->right));
716 return 1 + check(t->left) + check(t->right);
717 }
718
719 static void print(elem_type* t, int indent = 0) noexcept
720 {
722 return;
723
724 if(!t)
725 zth_dbg(list, "%*s (null)", indent, "");
726 else {
727 zth_dbg(list, "%*s node %p level=%d: %s", indent, "", static_cast<type*>(t),
728 t->level, static_cast<type*>(t)->str().c_str());
729 if(t->left || t->right) {
730 print(t->left, indent + 2);
731 print(t->right, indent + 2);
732 }
733 }
734 }
735
736private:
737 Compare m_comp;
738 elem_type* m_t;
739 elem_type* m_head;
740 size_t m_size;
741};
742
743template <typename T>
744class Hookable {
746public:
747 typedef T type;
748 typedef void* arg_type;
749 typedef void (*function_type)(type, arg_type)
750# if defined(__cpp_noexcept_function_type) && __cpp_noexcept_function_type >= 201510
751 noexcept
752# endif
753 ;
754
755 explicit Hookable(function_type f, arg_type a = arg_type(), Hookable* n = nullptr) noexcept
756 : func(f)
757 , arg(a)
758 , next(n)
759 {}
760
761 Hookable* operator()(type x) const noexcept
762 {
763 func(x, arg);
764 return next;
765 }
766
770};
771
772template <typename T>
773class Hook {
776public:
777 typedef T type;
781
782 Hook() noexcept
783 : m_head()
784 {}
785
786 ~Hook() noexcept
787 {
788 clear();
789 }
790
791 void add(function_type f, arg_type a = arg_type()) noexcept
792 {
793 m_head = new hookable_type(f, a, m_head);
794 }
795
796 void remove(arg_type a) noexcept
797 {
798 zth_assert(a);
799
800 if(!m_head) {
801 // Empty.
802 } else if(m_head->arg == a) {
803 // Drop head.
804 hookable_type* h = m_head;
805 m_head = h->next;
806 delete h;
807 } else {
808 // Drop from middle or end.
809 hookable_type* prev = m_head;
810 hookable_type* h = prev->next;
811 while(h) {
812 if(h->arg == a) {
813 // Got it.
814 prev->next = h->next;
815 delete h;
816 break;
817 }
818
819 prev = h;
820 h = h->next;
821 }
822 }
823 }
824
825 void operator()(type x) const noexcept
826 {
827 hookable_type const* h = m_head;
828 while(h)
829 h = (*h)(x);
830 }
831
832 void once(type x) noexcept
833 {
834 hookable_type* h = m_head;
835
836 while(h) {
837 hookable_type* next = (*h)(x);
838 delete h;
839 h = next;
840 }
841 m_head = nullptr;
842 }
843
844 void clear() noexcept
845 {
846 hookable_type* h = m_head;
847
848 while(h) {
849 hookable_type* next = h->next;
850 delete h;
851 h = next;
852 }
853 m_head = nullptr;
854 }
855
856private:
857 hookable_type* m_head;
858};
859
860} // namespace zth
861#endif // __cplusplus
862#endif // ZTH_LIST_H
void clear() noexcept
Definition list.h:844
void add(function_type f, arg_type a=arg_type()) noexcept
Definition list.h:791
Hookable< type > hookable_type
Definition list.h:778
void operator()(type x) const noexcept
Definition list.h:825
hookable_type::function_type function_type
Definition list.h:779
~Hook() noexcept
Definition list.h:786
Hook() noexcept
Definition list.h:782
hookable_type::arg_type arg_type
Definition list.h:780
void remove(arg_type a) noexcept
Definition list.h:796
T type
Definition list.h:777
void once(type x) noexcept
Definition list.h:832
void(* function_type)(type, arg_type)
Definition list.h:749
Hookable(function_type f, arg_type a=arg_type(), Hookable *n=nullptr) noexcept
Definition list.h:755
function_type func
Definition list.h:767
Hookable * next
Definition list.h:769
Hookable * operator()(type x) const noexcept
Definition list.h:761
arg_type arg
Definition list.h:768
void * arg_type
Definition list.h:748
Iterator operator--(int) noexcept
Definition list.h:173
bool operator==(Iterator< C > const &rhs) const noexcept
Definition list.h:125
bool operator!=(Iterator< C > const &rhs) const noexcept
Definition list.h:135
void next() noexcept
Definition list.h:140
void prev() noexcept
Definition list.h:147
user_type & user() noexcept
Definition list.h:201
bool atEnd() const noexcept
Definition list.h:113
constexpr Iterator(elem_type *start, elem_type *current=nullptr) noexcept
Definition list.h:103
Iterator & operator++() noexcept
Definition list.h:154
bool atBegin() const noexcept
Definition list.h:108
Iterator & operator--() noexcept
Definition list.h:167
user_type const & user() const noexcept
Definition list.h:193
Iterator operator++(int) noexcept
Definition list.h:160
elem_type * get() const noexcept
Definition list.h:118
type & operator*() const noexcept
Definition list.h:180
type * operator->() const noexcept
Definition list.h:188
T type
Definition list.h:96
user_type const & user_back() const noexcept
Definition list.h:234
Iterator< false > iterator
Definition list.h:214
iterator begin() const noexcept
Definition list.h:359
elem_type::user_type user_type
Definition list.h:98
size_t size() const noexcept
Definition list.h:383
bool empty() const noexcept
Definition list.h:344
user_type const & user_front() const noexcept
Definition list.h:293
iterator erase(iterator const &pos) noexcept
Definition list.h:409
iterator push_back(elem_type &elem) noexcept
Definition list.h:246
user_type erase(elem_type &elem) noexcept
Definition list.h:425
constexpr List() noexcept
Definition list.h:217
iterator insert(iterator const &pos, elem_type &elem) noexcept
Definition list.h:391
Listable elem_type
Definition list.h:97
user_type pop_front() noexcept
Definition list.h:322
iterator push_front(elem_type &elem) noexcept
Definition list.h:305
user_type pop_back() noexcept
Definition list.h:265
type & back() const noexcept
Definition list.h:228
iterator end() const noexcept
Definition list.h:370
void clear() noexcept
Definition list.h:350
~List() noexcept
Definition list.h:222
bool contains(elem_type const &elem) const noexcept
Definition list.h:375
cyclic_iterator cyclic(elem_type &start) const noexcept
Definition list.h:364
user_type & user_front() noexcept
Definition list.h:299
user_type & user_back() noexcept
Definition list.h:240
type & front() const noexcept
Definition list.h:287
Iterator< true > cyclic_iterator
Definition list.h:215
void rotate(elem_type &elem) noexcept
Definition list.h:441
Listable(Listable &&l) noexcept
Definition list.h:54
Listable & operator=(Listable &&l) noexcept
Definition list.h:60
constexpr Listable(Listable const &e) noexcept
Definition list.h:39
user_type user
Definition list.h:81
uint_fast8_t level
Definition list.h:82
void * user_type
Definition list.h:31
Listable * prev
Definition list.h:73
Listable * right
Definition list.h:78
Listable * next
Definition list.h:77
constexpr Listable() noexcept
Definition list.h:33
Listable * left
Definition list.h:74
Listable & operator=(Listable const &rhs) noexcept
Definition list.h:46
void erase(elem_type &x) noexcept
Definition list.h:486
void check() const noexcept
Definition list.h:685
void clear() noexcept
Definition list.h:500
void insert(elem_type &x) noexcept
Definition list.h:473
bool contains(elem_type &x) const noexcept
Definition list.h:523
elem_type * insert_(elem_type &x, elem_type *t) noexcept
Definition list.h:580
static void decrease_level(elem_type *t) noexcept
Definition list.h:671
static elem_type * lowest(elem_type *t) noexcept
Definition list.h:640
type & front() const noexcept
Definition list.h:541
static elem_type * successor(elem_type *t) noexcept
Definition list.h:660
static elem_type * skew(elem_type *t) noexcept
Definition list.h:548
size_t size() const noexcept
Definition list.h:511
static void print(elem_type *t, int indent=0) noexcept
Definition list.h:719
~SortedList() noexcept
Definition list.h:468
size_t check(elem_type *t) const noexcept
Definition list.h:693
elem_type * delete_(elem_type &x, elem_type *t) noexcept
Definition list.h:601
static elem_type * split(elem_type *t) noexcept
Definition list.h:563
constexpr SortedList() noexcept
Definition list.h:461
static elem_type * highest(elem_type *t) noexcept
Definition list.h:650
static elem_type * predecessor(elem_type *t) noexcept
Definition list.h:665
bool empty() const noexcept
Definition list.h:517
Listable elem_type
Definition list.h:459
#define zth_dbg(group, fmt, a...)
Debug printf()-like function.
Definition util.h:194
#define ZTH_CLASS_NEW_DELETE(T)
Define new/delete operators for a class, which are allocator-aware.
Definition allocator.h:160
#define UNUSED_PAR(name)
Definition macros.h:79
static bool const EnableAssert
When true, enable zth_assert().
Definition config.h:70
static int const Print_list
Definition config.h:162
static bool const SupportDebugPrint
Add support to enable debug output prints.
Definition config.h:131
#define zth_assert(expr)
assert(), but better integrated in Zth.
Definition util.h:217
#define ZTH_CLASS_NOCOPY(Class)
Definition util.h:234
#define unlikely(expr)
Marks the given expression to likely be evaluated to true.
Definition util.h:60