CCF
Loading...
Searching...
No Matches
dl_list.h
Go to the documentation of this file.
1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the Apache 2.0 License.
3#pragma once
4
5#include <cassert>
6#include <type_traits>
7
8namespace ds
9{
10 // Adapted from snmalloc 0.5.3.
11 // Intrusive doubly-linked list. Elements added via `insert()` and
12 // `insert_back()` become owned by the list (i.e. deleted on `clear()`).
13 template <class T>
14 class DLList final
15 {
16 private:
17 static_assert(
18 std::is_same<decltype(T::prev), T*>::value, "T->prev must be a T*");
19 static_assert(
20 std::is_same<decltype(T::next), T*>::value, "T->next must be a T*");
21
22 T* head = nullptr;
23 T* tail = nullptr;
24
25 public:
26 DLList() = default;
27
28 DLList(DLList&& o) noexcept
29 {
30 head = o.head;
31 tail = o.tail;
32
33 o.head = nullptr;
34 o.tail = nullptr;
35 }
36
38 {
39 clear();
40 }
41
42 DLList& operator=(DLList&& o) noexcept
43 {
44 head = o.head;
45 tail = o.tail;
46
47 o.head = nullptr;
48 o.tail = nullptr;
49 return *this;
50 }
51
52 bool is_empty()
53 {
54 return head == nullptr;
55 }
56
58 {
59 return head;
60 }
61
63 {
64 return tail;
65 }
66
67 T* pop()
68 {
69 T* item = head;
70
71 if (item != nullptr)
72 remove(item);
73
74 return item;
75 }
76
78 {
79 T* item = tail;
80
81 if (item != nullptr)
82 remove(item);
83
84 return item;
85 }
86
87 void insert(T* item)
88 {
89#ifndef NDEBUG
91#endif
92
93 item->next = head;
94 item->prev = nullptr;
95
96 if (head != nullptr)
97 head->prev = item;
98 else
99 tail = item;
100
101 head = item;
102#ifndef NDEBUG
103 debug_check();
104#endif
105 }
106
107 void insert_back(T* item)
108 {
109#ifndef NDEBUG
111#endif
112
113 item->prev = tail;
114 item->next = nullptr;
115
116 if (tail != nullptr)
117 tail->next = item;
118 else
119 head = item;
120
121 tail = item;
122#ifndef NDEBUG
123 debug_check();
124#endif
125 }
126
127 void remove(T* item)
128 {
129#ifndef NDEBUG
131#endif
132
133 if (item->next != nullptr)
134 item->next->prev = item->prev;
135 else
136 tail = item->prev;
137
138 if (item->prev != nullptr)
139 item->prev->next = item->next;
140 else
141 head = item->next;
142
143#ifndef NDEBUG
144 debug_check();
145#endif
146 }
147
148 void clear()
149 {
150 while (head != nullptr)
151 {
152 auto c = head;
153 // The analysis does not seem to take into account that the
154 // penultimate remove will result in head->next == nullptr
155 // and head == nullptr on the next iteration
156 // This is perhaps related to
157 // https://github.com/llvm/llvm-project/issues/43395
158 remove(c); // NOLINT(clang-analyzer-cplusplus.NewDelete)
159 delete c;
160 }
161 }
162
164 {
165#ifndef NDEBUG
166 debug_check();
167 T* curr = head;
168
169 while (curr != item)
170 {
171 assert(curr != nullptr);
172 curr = curr->next;
173 }
174#else
175 (void)(item);
176#endif
177 }
178
180 {
181#ifndef NDEBUG
182 debug_check();
183 T* curr = head;
184
185 while (curr != nullptr)
186 {
187 assert(curr != item);
188 curr = curr->next;
189 }
190#else
191 (void)(item);
192#endif
193 }
194
196 {
197#ifndef NDEBUG
198 T* item = head;
199 T* prev = nullptr;
200
201 while (item != nullptr)
202 {
203 assert(item->prev == prev);
204 prev = item;
205 item = item->next;
206 }
207#endif
208 }
209 };
210}
Definition dl_list.h:15
void insert(T *item)
Definition dl_list.h:87
void debug_check_contains(T *item)
Definition dl_list.h:163
void debug_check_not_contains(T *item)
Definition dl_list.h:179
T * pop()
Definition dl_list.h:67
void remove(T *item)
Definition dl_list.h:127
void insert_back(T *item)
Definition dl_list.h:107
T * get_tail()
Definition dl_list.h:62
void clear()
Definition dl_list.h:148
DLList()=default
T * get_head()
Definition dl_list.h:57
void debug_check()
Definition dl_list.h:195
~DLList()
Definition dl_list.h:37
DLList & operator=(DLList &&o) noexcept
Definition dl_list.h:42
DLList(DLList &&o) noexcept
Definition dl_list.h:28
bool is_empty()
Definition dl_list.h:52
T * pop_tail()
Definition dl_list.h:77
Definition dl_list.h:9