arduino-audio-tools
List.h
1 #pragma once
2 #ifdef USE_INITIALIZER_LIST
3 # include "InitializerList.h"
4 #endif
5 #include <stddef.h>
6 #include "Allocator.h"
7 
8 namespace audio_tools {
9 
17 template <class T>
18 class List {
19  public:
20  struct Node {
21  Node* next = nullptr;
22  Node* prior = nullptr;
23  T data;
24  };
25 
26  class Iterator {
27  public:
28  Iterator(Node*node){
29  this->node = node;
30  }
31  inline Iterator operator++() {
32  if (node->next!=nullptr){
33  node = node->next;
34  is_eof = false;
35  } else is_eof=true;
36  return *this;
37  }
38  inline Iterator operator++(int) {
39  return ++*this;
40  }
41  inline Iterator operator--() {
42  if (node->prior!=nullptr){
43  node = node->prior;
44  is_eof = false;
45  } else is_eof=true;
46  return *this;
47  }
48  inline Iterator operator--(int) {
49  return --*this;
50  }
51  inline Iterator operator+(int offset) {
52  return getIteratorAtOffset(offset);
53  }
54  inline Iterator operator-(int offset) {
55  return getIteratorAtOffset(-offset);
56  }
57  inline bool operator==(Iterator it) {
58  return node == it.get_node();
59  }
60  inline bool operator!=(Iterator it) {
61  return node != it.get_node();
62  }
63  inline T &operator*() {
64  return node->data;
65  }
66  inline T *operator->() {
67  return &(node->data);
68  }
69  inline Node *get_node() {
70  return node;
71  }
72  inline operator bool() {
73  return is_eof;
74  }
75  protected:
76  Node* node=nullptr;
77  bool is_eof = false;
78 
79  Iterator getIteratorAtOffset(int offset){
80  Node *tmp = node;
81  if (offset>0){
82  for (int j=0;j<offset;j++){
83  if (tmp->next==nullptr){
84  return Iterator(tmp);
85  }
86  tmp = tmp->next;
87  }
88  } else if (offset<0){
89  for (int j=0;j<-offset;j++){
90  if (tmp->prior==nullptr){
91  return Iterator(tmp);
92  }
93  tmp = tmp->prior;
94  }
95  }
96  Iterator it(tmp);
97  return it;
98  }
99 
100  };
101 
103  List(Allocator &allocator=DefaultAllocator) {
104  p_allocator = &allocator;
105  link();
106  };
108  List(List&ref) = default;
109 
111  template<size_t N>
112  List(const T (&a)[N], Allocator &allocator=DefaultAllocator) {
113  p_allocator = &allocator;
114  link();
115  for(int i = 0; i < N; ++i)
116  push_back(a[i]);
117  }
118 
119  ~List(){
120  clear();
121  }
122 
123 #ifdef USE_INITIALIZER_LIST
124 
125  List(std::initializer_list<T> iniList) {
126  link();
127  for(auto &obj : iniList)
128  push_back(obj);
129  }
130 #endif
131  bool swap(List<T>&ref){
132  List<T> tmp(*this);
133  validate();
134 
135  first = ref.first;
136  last = ref.last;
137  record_count = ref.record_count;
138 
139  ref.first = tmp.first;
140  ref.last = tmp.last;
141  ref.record_count = tmp.record_count;
142 
143  validate();
144  return true;
145  }
146 
147  bool push_back(T data){
148  Node *node = createNode();
149  if (node==nullptr) return false;
150  node->data = data;
151 
152  // update links
153  Node *old_last_prior = last.prior;
154  node->next = &last;
155  node->prior = old_last_prior;
156  old_last_prior->next = node;
157  last.prior = node;
158 
159  record_count++;
160  validate();
161  return true;
162  }
163 
164  bool push_front(T data){
165  Node *node = createNode();
166  if (node==nullptr) return false;
167  node->data = data;
168 
169  // update links
170  Node *old_begin_next = first.next;
171  node->prior = &first;
172  node->next = old_begin_next;
173  old_begin_next->prior = node;
174  first.next = node;
175 
176  record_count++;
177  validate();
178  return true;
179  }
180 
181  bool insert(Iterator it, const T& data){
182  Node *node = createNode();
183  if (node==nullptr) return false;
184  node->data = data;
185 
186  // update links
187  Node *current_node = it.get_node();
188  Node *prior = current_node->prior;
189 
190  prior->next = node;
191  current_node->prior = node;
192  node->prior = prior;
193  node->next = current_node;
194 
195  record_count++;
196  validate();
197  return true;
198  }
199 
200 
201  bool pop_front(){
202  T tmp;
203  return pop_front(tmp);
204  }
205 
206  bool pop_back(){
207  T tmp;
208  return pop_back(tmp);
209  }
210 
211  bool pop_front(T &data){
212  if (record_count==0) return false;
213  // get data
214  Node *p_delete = firstDataNode();
215  Node *p_prior = p_delete->prior;
216  Node *p_next = p_delete->next;
217 
218  data = p_delete->data;
219 
220  // remove last node
221  p_prior->next = p_next;
222  p_next->prior = p_prior;
223 
224  deleteNode(p_delete);
225 
226  record_count--;
227 
228  validate();
229  return true;
230  }
231 
232  bool pop_back(T &data){
233  if (record_count==0) return false;
234  Node *p_delete = lastDataNode();
235  Node *p_prior = p_delete->prior;
236  Node *p_next = p_delete->next;
237 
238  // get data
239  data = p_delete->data;
240 
241  // remove last node
242  p_prior->next = p_next;
243  p_next->prior = p_prior;
244 
245  deleteNode(p_delete);
246 
247  record_count--;
248 
249  validate();
250  return true;
251  }
252 
253  bool erase (Iterator it){
254  Node *p_delete = it.get_node();
255  // check for valid iterator
256  if (empty() || p_delete==&first || p_delete==&last){
257  return false;
258  }
259  Node *p_prior = p_delete->prior;
260  Node *p_next = p_delete->next;
261 
262  // remove last node
263  p_prior->next = p_next;
264  p_next->prior = p_prior;
265 
266  deleteNode(p_delete);
267 
268  record_count--;
269  return true;
270  }
271 
272 
273  Iterator begin() {
274  Iterator it(firstDataNode());
275  return it;
276  }
277 
278  Iterator end(){
279  Iterator it(&last);
280  return it;
281  }
282 
283  Iterator rbegin() {
284  Iterator it(lastDataNode());
285  return it;
286  }
287 
288  Iterator rend(){
289  Iterator it(&first);
290  return it;
291  }
292 
293  size_t size() {
294  return record_count;
295  }
296 
297  bool empty() {
298  return size()==0;
299  }
300 
301  bool clear() {
302  while(pop_front())
303  ;
304  validate();
305  return true;
306  }
307 
308  inline T &operator[](int index) {
309  Node *n = firstDataNode();
310  for (int j=0;j<index;j++){
311  n = n->next;
312  if (n==nullptr){
313  return last.data;
314  }
315  }
316  return n->data;
317  }
318 
319  void setAllocator(Allocator &allocator){
320  p_allocator = &allocator;
321  }
322 
324  T& back() {
325  return *rbegin();
326  }
327 
328 
329  protected:
330  Node first; // empty dummy first node which which is always before the first data node
331  Node last; // empty dummy last node which which is always after the last data node
332  size_t record_count=0;
333  Allocator *p_allocator = &DefaultAllocator;
334 
335  Node* createNode() {
336 #if USE_ALLOCATOR
337  Node *node = (Node*) p_allocator->allocate(sizeof(Node));// new Node();
338 #else
339  Node *node = new Node();
340 #endif
341  return node;
342  }
343 
344  void deleteNode(Node* p_delete){
345 #if USE_ALLOCATOR
346  p_allocator->free(p_delete); //delete p_delete;
347 #else
348  delete p_delete;
349 #endif
350 
351  }
352 
353  void link(){
354  first.next = &last;
355  last.prior = &first;
356  }
357 
358  Node* lastDataNode(){
359  return last.prior;
360  }
361  Node* firstDataNode(){
362  return first.next;
363  }
364 
365  void validate() {
366  assert(first.next!=nullptr);
367  assert(last.prior!=nullptr);
368  if (empty()){
369  assert(first.next = &last);
370  assert(last.prior = &first);
371  }
372  }
373 
374 };
375 
376 }
Memory allocateator which uses malloc.
Definition: Allocator.h:22
virtual void * allocate(size_t size)
Allocates memory.
Definition: Allocator.h:62
virtual void free(void *memory)
frees memory
Definition: Allocator.h:74
Definition: List.h:26
Double linked list.
Definition: List.h:18
List(Allocator &allocator=DefaultAllocator)
Default constructor.
Definition: List.h:103
T & back()
Provides the last element.
Definition: List.h:324
List(List &ref)=default
copy constructor
List(const T(&a)[N], Allocator &allocator=DefaultAllocator)
Constructor using array.
Definition: List.h:112
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition: AnalogAudio.h:10
Definition: List.h:20