Sane C++ Libraries
C++ Platform Abstraction Libraries
IntrusiveDoubleLinkedList.h
1// Copyright (c) Stefano Cristiano
2// SPDX-License-Identifier: MIT
3#pragma once
4#include "../Foundation/Assert.h"
5
6namespace SC
7{
8template <typename T>
9struct IntrusiveDoubleLinkedList;
10} // namespace SC
11
14
20template <typename T>
22{
23 T* back = nullptr; // has no next
24 T* front = nullptr; // has no prev
25
26 [[nodiscard]] T* peekFront() const { return front; }
27
28 [[nodiscard]] bool isEmpty() const { return peekFront() == nullptr; }
29
30 void clear()
31 {
32 for (T* current = front; current != nullptr;)
33 {
34 T* next = static_cast<T*>(current->next);
35 current->next = nullptr;
36 current->prev = nullptr;
37 current = next;
38 }
39 back = nullptr;
40 front = nullptr;
41 }
42
43 void appendBack(IntrusiveDoubleLinkedList& other)
44 {
45 if (&other == this)
46 return;
47 if (other.front)
48 {
49 SC_ASSERT_DEBUG(other.front->prev == nullptr);
50 queueBackUnchecked(*other.front, *other.back);
51 }
52 other.clear();
53 }
54
55 void queueBack(T& item)
56 {
57 SC_ASSERT_DEBUG(item.next == nullptr and item.prev == nullptr);
58 queueBackUnchecked(item, item);
59 }
60
61 private:
62 void queueBackUnchecked(T& item, T& newBack)
63 {
64 if (back)
65 {
66 back->next = &item;
67 item.prev = back;
68 }
69 else
70 {
71 SC_ASSERT_DEBUG(front == nullptr);
72 front = &item;
73 }
74 back = &newBack;
75 SC_ASSERT_DEBUG(back->next == nullptr);
76 SC_ASSERT_DEBUG(front->prev == nullptr);
77 }
78
79 public:
80 [[nodiscard]] T* dequeueFront()
81 {
82 if (not front)
83 {
84 return nullptr;
85 }
86 T* item = front;
87 front = static_cast<T*>(item->next);
88 if (front)
89 {
90 front->prev = nullptr;
91 }
92 item->next = nullptr;
93 item->prev = nullptr;
94 if (back == item)
95 {
96 back = nullptr;
97 }
98 return item;
99 }
100
101 void remove(T& item)
102 {
103#if SC_CONFIGURATION_DEBUG
104 bool found = false;
105 auto it = front;
106 while (it)
107 {
108 if (it == &item)
109 {
110 found = true;
111 break;
112 }
113 it = static_cast<T*>(it->next);
114 }
115 SC_ASSERT_DEBUG(found);
116#endif
117 if (&item == front)
118 {
119 front = static_cast<T*>(front->next);
120 }
121 if (&item == back)
122 {
123 back = static_cast<T*>(back->prev);
124 }
125
126 T* next = static_cast<T*>(item.next);
127 T* prev = static_cast<T*>(item.prev);
128
129 if (prev)
130 {
131 prev->next = next;
132 }
133
134 if (next)
135 {
136 next->prev = prev;
137 }
138
139 item.next = nullptr;
140 item.prev = nullptr;
141 }
142};
#define SC_ASSERT_DEBUG(e)
Assert expression e to be true.
Definition: Assert.h:82
An Intrusive Double Linked List.
Definition: IntrusiveDoubleLinkedList.h:22