Arduino DLNA Server
Loading...
Searching...
No Matches
List.h
Go to the documentation of this file.
1#pragma once
2#include "dlna_config.h"
3#include "Allocator.h"
4#include <assert.h>
5#include <utility>
6#include <stddef.h>
7#include <memory>
8
9namespace tiny_dlna {
10
18template <class T, class Alloc = DLNA_ALLOCATOR<T>>
19class List {
20 public:
22 struct Node {
23 Node* next = nullptr;
24 Node* prior = nullptr;
26 };
27
29 class Iterator {
30 public:
31 Iterator(Node* node) { this->node = node; }
33 if (node->next != nullptr) {
34 node = node->next;
35 is_eof = false;
36 } else
37 is_eof = true;
38 return *this;
39 }
40 inline Iterator operator++(int) { return ++*this; }
42 if (node->prior != nullptr) {
43 node = node->prior;
44 is_eof = false;
45 } else
46 is_eof = true;
47 return *this;
48 }
49 inline Iterator operator--(int) { return --*this; }
50 inline Iterator operator+(int offset) {
51 return getIteratorAtOffset(offset);
52 }
53 inline Iterator operator-(int offset) {
54 return getIteratorAtOffset(-offset);
55 }
56 inline bool operator==(Iterator it) { return node == it.get_node(); }
57 inline bool operator!=(Iterator it) { return node != it.get_node(); }
58 inline T& operator*() {
59 assert(node != nullptr);
60 return node->data;
61 }
62 inline T* operator->() {
63 assert(node != nullptr);
64 return &(node->data);
65 }
66 inline Node* get_node() { return node; }
67 inline operator bool() { return is_eof; }
68
69 protected:
70 Node* node = nullptr;
71 bool is_eof = false;
72
74 Node* tmp = node;
75 if (offset > 0) {
76 for (int j = 0; j < offset; j++) {
77 if (tmp->next == nullptr) {
78 return Iterator(tmp);
79 }
80 tmp = tmp->next;
81 }
82 } else if (offset < 0) {
83 for (int j = 0; j < -offset; j++) {
84 if (tmp->prior == nullptr) {
85 return Iterator(tmp);
86 }
87 tmp = tmp->prior;
88 }
89 }
90 Iterator it(tmp);
91 return it;
92 }
93 };
94
96 List() { link(); };
97 explicit List(const Alloc& alloc) : node_alloc_(alloc) { link(); }
99 List(List& ref) = default;
100
102 template <size_t N>
103 List(const T (&a)[N]) {
104 link();
105 for (int i = 0; i < N; ++i) push_back(a[i]);
106 }
107
108 ~List() { clear(); }
109
110 bool swap(List<T>& ref) {
111 List<T> tmp(*this);
112 validate();
113
114 first = ref.first;
115 last = ref.last;
117
118 ref.first = tmp.first;
119 ref.last = tmp.last;
120 ref.record_count = tmp.record_count;
121
122 validate();
123 return true;
124 }
125
126 // lvalue overload - copy into node (non-const reference allowing types
127 // with non-const copy/assignment semantics)
128 bool push_back(T& data) {
129 Node* node = createNode();
130 if (node == nullptr) return false;
131 node->data = data;
132
133 // update links
134 Node* old_last_prior = last.prior;
135 node->next = &last;
136 node->prior = old_last_prior;
137 old_last_prior->next = node;
138 last.prior = node;
139
140 record_count++;
141 validate();
142 return true;
143 }
144
145 // rvalue overload - move into node to avoid expensive copies
146 bool push_back(T&& data) {
147 Node* node = createNode();
148 if (node == nullptr) return false;
149 node->data = std::move(data);
150 // update links
151 Node* old_last_prior = last.prior;
152 node->next = &last;
153 node->prior = old_last_prior;
154 old_last_prior->next = node;
155 last.prior = node;
156
157 record_count++;
158 validate();
159 return true;
160 }
161
162 // lvalue overload - copy into node (non-const reference)
163 bool push_front(T& data) {
164 Node* node = createNode();
165 if (node == nullptr) return false;
166 node->data = data;
167
168 // update links
169 Node* old_begin_next = first.next;
170 node->prior = &first;
171 node->next = old_begin_next;
172 old_begin_next->prior = node;
173 first.next = node;
174
175 record_count++;
176 validate();
177 return true;
178 }
179
180 // rvalue overload - move into node
181 bool push_front(T&& data) {
182 Node* node = createNode();
183 if (node == nullptr) return false;
184 node->data = std::move(data);
185
186 // update links
187 Node* old_begin_next = first.next;
188 node->prior = &first;
189 node->next = old_begin_next;
190 old_begin_next->prior = node;
191 first.next = node;
192
193 record_count++;
194 validate();
195 return true;
196 }
197
198 bool insert(Iterator it, T& data) {
199 Node* node = createNode();
200 if (node == nullptr) return false;
201 node->data = data;
202
203 // update links
204 Node* current_node = it.get_node();
205 Node* prior = current_node->prior;
206
207 prior->next = node;
208 current_node->prior = node;
209 node->prior = prior;
210 node->next = current_node;
211
212 record_count++;
213 validate();
214 return true;
215 }
216
217 // rvalue overload - move into node
218 bool insert(Iterator it, T&& data) {
219 Node* node = createNode();
220 if (node == nullptr) return false;
221 node->data = std::move(data);
222
223 // update links
224 Node* current_node = it.get_node();
225 Node* prior = current_node->prior;
226
227 prior->next = node;
228 current_node->prior = node;
229 node->prior = prior;
230 node->next = current_node;
231
232 record_count++;
233 validate();
234 return true;
235 }
236
237 bool pop_front() {
238 T tmp;
239 return pop_front(tmp);
240 }
241
242 bool pop_back() {
243 T tmp;
244 return pop_back(tmp);
245 }
246
247 bool pop_front(T& data) {
248 if (record_count == 0) return false;
249 // get data
250 Node* p_delete = firstDataNode();
251 Node* p_prior = p_delete->prior;
252 Node* p_next = p_delete->next;
253
254 data = p_delete->data;
255
256 // remove last node
257 p_prior->next = p_next;
258 p_next->prior = p_prior;
259
260 deleteNode(p_delete);
261
262 record_count--;
263
264 validate();
265 return true;
266 }
267
268 bool pop_back(T& data) {
269 if (record_count == 0) return false;
270 Node* p_delete = lastDataNode();
271 if (p_delete == nullptr) return false;
272 Node* p_prior = p_delete->prior;
273 Node* p_next = p_delete->next;
274
275 // get data
276 data = p_delete->data;
277
278 // remove last node
279 p_prior->next = p_next;
280 p_next->prior = p_prior;
281
282 deleteNode(p_delete);
283
284 record_count--;
285
286 validate();
287 return true;
288 }
289
291 Node* p_delete = it.get_node();
292 // check for valid iterator
293 if (empty() || p_delete == &first || p_delete == &last) {
294 return end();
295 }
296 Node* p_prior = p_delete->prior;
297 Node* p_next = p_delete->next;
298
299 // remove last node
300 p_prior->next = p_next;
301 p_next->prior = p_prior;
302
303 deleteNode(p_delete);
304
305 record_count--;
306 return Iterator(p_next);
307 }
308
311 return it;
312 }
313
315 Iterator it(&last);
316 return it;
317 }
318
321 return it;
322 }
323
325 Iterator it(&first);
326 return it;
327 }
328
329 size_t size() { return record_count; }
330
331 bool empty() { return size() == 0; }
332
333 bool clear() {
334 while (pop_front());
335 validate();
336 return true;
337 }
338
339 inline T& operator[](int index) {
340 Node* n = firstDataNode();
341 for (int j = 0; j < index; j++) {
342 if (n == &last || n == nullptr) {
343 assert(false && "List index out of bounds");
344 return last.data; // fallback, but will assert
345 }
346 n = n->next;
347 }
348 if (n == &last || n == nullptr) {
349 assert(false && "List index out of bounds");
350 return last.data; // fallback, but will assert
351 }
352 return n->data;
353 }
354
355 // Allocator: nodes are allocated via std::allocator (or compatible Alloc).
356
358 T& back() { return *rbegin(); }
359
360 protected:
361 Node first; // empty dummy first node which which is always before the first
362 // data node
363 Node last; // empty dummy last node which which is always after the last data
364 // node
365 size_t record_count = 0;
366 using NodeAlloc = typename std::allocator_traits<Alloc>::template rebind_alloc<Node>;
368
370 Node* raw = node_alloc_.allocate(1);
371 new (raw) Node();
372 return raw;
373 }
374
375 void deleteNode(Node* p_delete) {
376 if (!p_delete) return;
377 p_delete->~Node();
378 node_alloc_.deallocate(p_delete, 1);
379 }
380
381 void link() {
382 first.next = &last;
383 last.prior = &first;
384 }
385
388
389 void validate() {
390 assert(first.next != nullptr);
391 assert(last.prior != nullptr);
392 if (empty()) {
393 assert(first.next == &last);
394 assert(last.prior == &first);
395 }
396 }
397};
398
399} // namespace tiny_dlna
List Iterator.
Definition: List.h:29
Iterator operator-(int offset)
Definition: List.h:53
Node * node
Definition: List.h:70
Node * get_node()
Definition: List.h:66
T & operator*()
Definition: List.h:58
T * operator->()
Definition: List.h:62
Iterator operator++(int)
Definition: List.h:40
Iterator(Node *node)
Definition: List.h:31
Iterator operator--()
Definition: List.h:41
Iterator operator++()
Definition: List.h:32
bool operator==(Iterator it)
Definition: List.h:56
Iterator operator+(int offset)
Definition: List.h:50
bool operator!=(Iterator it)
Definition: List.h:57
bool is_eof
Definition: List.h:71
Iterator operator--(int)
Definition: List.h:49
Iterator getIteratorAtOffset(int offset)
Definition: List.h:73
Double linked list.
Definition: List.h:19
size_t record_count
Definition: List.h:365
bool pop_front(T &data)
Definition: List.h:247
bool swap(List< T > &ref)
Definition: List.h:110
void deleteNode(Node *p_delete)
Definition: List.h:375
Iterator begin()
Definition: List.h:309
List(const T(&a)[N])
Constructor using array.
Definition: List.h:103
~List()
Definition: List.h:108
bool pop_back(T &data)
Definition: List.h:268
bool push_front(T &data)
Definition: List.h:163
Node first
Definition: List.h:361
T & back()
Provides the last element.
Definition: List.h:358
bool empty()
Definition: List.h:331
bool push_back(T &data)
Definition: List.h:128
bool push_front(T &&data)
Definition: List.h:181
List(List &ref)=default
copy constructor
Node * lastDataNode()
Definition: List.h:386
Node last
Definition: List.h:363
bool insert(Iterator it, T &data)
Definition: List.h:198
void link()
Definition: List.h:381
Iterator end()
Definition: List.h:314
List(const Alloc &alloc)
Definition: List.h:97
List()
Default constructor.
Definition: List.h:96
bool insert(Iterator it, T &&data)
Definition: List.h:218
NodeAlloc node_alloc_
Definition: List.h:367
bool pop_front()
Definition: List.h:237
size_t size()
Definition: List.h:329
bool push_back(T &&data)
Definition: List.h:146
Iterator erase(Iterator it)
Definition: List.h:290
typename std::allocator_traits< Alloc >::template rebind_alloc< Node > NodeAlloc
Definition: List.h:366
Node * createNode()
Definition: List.h:369
Iterator rend()
Definition: List.h:324
Node * firstDataNode()
Definition: List.h:387
Iterator rbegin()
Definition: List.h:319
bool pop_back()
Definition: List.h:242
T & operator[](int index)
Definition: List.h:339
void validate()
Definition: List.h:389
bool clear()
Definition: List.h:333
Definition: Allocator.h:13
List Node.
Definition: List.h:22
Node * next
Definition: List.h:23
T data
Definition: List.h:25
Node * prior
Definition: List.h:24