Control Surface  1.1.0
MIDI Control Surface library for Arduino
LinkedList.hpp
Go to the documentation of this file.
1 /* ✔ */
2 
3 #pragma once
4 
6 
7 AH_DIAGNOSTIC_WERROR() // Enable errors on warnings
8 
9 #include <AH/Debug/Debug.hpp>
10 #include <AH/Math/MinMaxFix.hpp>
11 #include <stdlib.h>
12 
13 #ifndef __AVR__
14 #include <iterator>
15 #endif
16 
17 /// @addtogroup AH_Containers
18 /// @{
19 
20 /**
21  * @brief A class for doubly linked lists.
22  *
23  * @tparam Node
24  * The type of the nodes of the list.
25  */
26 template <class Node>
28  public:
29  /// Base class for doubly linked list iterators
30  template <class INode>
32  public:
34 
35  bool operator!=(const node_iterator_base &rhs) const {
36  return node != rhs.node;
37  }
38 
39  INode &operator*() const {
40  // TODO: check node != nullptr
41  return *node;
42  }
43 
44  protected:
45  INode *node;
46  };
47 
48  /// Forward bidirectional doubly linked list iterator
49  template <class INode>
50  class node_iterator : public node_iterator_base<INode> {
51  public:
53 
54 #ifndef __AVR__
55  using difference_type = void;
56  using value_type = INode;
57  using pointer = INode *;
58  using reference = INode &;
59  using iterator_category = std::bidirectional_iterator_tag;
60 #endif
61 
62  /// Prefix increment operator
64  // TODO: check node != nullptr
65  this->node = this->node->next;
66  return *this;
67  }
68 
69  /// Prefix decrement operator
71  // TODO: check node != nullptr
72  this->node = this->node->previous;
73  return *this;
74  }
75  };
76 
77  /// Reverse bidirectional doubly linked list iterator
78  template <class INode>
79  class reverse_node_iterator : public node_iterator_base<INode> {
80  public:
82 
83 #ifndef __AVR__
84  using difference_type = void;
85  using value_type = INode;
86  using pointer = INode *;
87  using reference = INode &;
88  using iterator_category = std::bidirectional_iterator_tag;
89 #endif
90 
91  /// Prefix increment operator
93  // TODO: check node != nullptr
94  this->node = this->node->previous;
95  return *this;
96  }
97 
98  /// Prefix decrement operator
100  // TODO: check node != nullptr
101  this->node = this->node->next;
102  return *this;
103  }
104  };
105 
106  using iterator = node_iterator<Node>;
107  using const_iterator = node_iterator<const Node>;
108  using reverse_iterator = reverse_node_iterator<Node>;
109  using const_reverse_iterator = reverse_node_iterator<const Node>;
110 
111  /**
112  * @brief Append a node to a linked list.
113  *
114  * @param node
115  * A pointer to the node to be appended.
116  */
117  void append(Node *node) {
118  if (first == nullptr)
119  first = node;
120  node->previous = last;
121  if (node->previous != nullptr)
122  node->previous->next = node;
123  last = node;
124  node->next = nullptr;
125  }
126 
127  /**
128  * @brief Append a node to a linked list.
129  *
130  * @param node
131  * A reference to the node to be appended.
132  */
133  void append(Node &node) { append(&node); }
134 
135  /**
136  * @brief Insert a node before another node.
137  *
138  * @param toBeInserted
139  * The new node to be inserted.
140  * @param before
141  * The node to insert the new node before. It must be in the list
142  * already.
143  */
144  void insertBefore(Node *toBeInserted, Node *before) {
145  if (before == first)
146  first = toBeInserted;
147  else
148  before->previous->next = toBeInserted;
149  toBeInserted->previous = before->previous;
150  toBeInserted->next = before;
151  before->previous = toBeInserted;
152  }
153 
154  /// @see insertBefore(Node *, Node *)
155  void insertBefore(Node &toBeInserted, Node &before) {
156  insertBefore(&toBeInserted, &before);
157  }
158 
159  /**
160  * @brief Insert a new node at the correct location into a sorted list.
161  *
162  * @param node
163  * The new node to be inserted.
164  * @param cmp
165  * The function to order the nodes.
166  * @tparam Compare
167  * A functor that compares two Nodes and returns a boolean.
168  */
169  template <class Compare>
170  void insertSorted(Node *node, Compare cmp) {
171  iterator it = this->begin();
172  iterator end = this->end();
173  while (it != end) {
174  if (cmp(*node, *it)) {
175  insertBefore(*node, *it);
176  return;
177  }
178  ++it;
179  }
180  append(node);
181  }
182 
183  /**
184  * @brief Insert a new node at the correct location into a sorted list,
185  * using `operator<`.
186  *
187  * @param node
188  * The new node to be inserted.
189  */
190  void insertSorted(Node *node) {
191  insertSorted(node, [](Node &lhs, Node &rhs) { return lhs < rhs; });
192  }
193 
194  /**
195  * @brief Remove a node from the linked list.
196  *
197  * @param node
198  * A pointer to the node to be removed.
199  */
200  void remove(Node *node) {
201  if (node->previous != nullptr)
202  node->previous->next = node->next;
203  if (node == last)
204  last = node->previous;
205  if (node->next != nullptr)
206  node->next->previous = node->previous;
207  if (node == first)
208  first = node->next;
209  node->previous = nullptr;
210  node->next = nullptr;
211  }
212 
213  /**
214  * @brief Remove a node from the linked list.
215  *
216  * @param node
217  * A reference to the node to be removed.
218  */
219  void remove(Node &node) { remove(&node); }
220 
221  /**
222  * @brief Move down the given node in the linked list.
223  *
224  * For example: moving down node `C`:
225  * ```
226  * Before: ... → A → B → C → D → ...
227  * After: ... → A → C → B → D → ...
228  * ```
229  * @param node
230  * A pointer to the node to be moved down.
231  */
232  void moveDown(Node *node) {
233  Node *nodeB = node->previous;
234  if (nodeB == nullptr) // Can't move first node further down
235  return;
236  Node *nodeA = nodeB->previous;
237  Node *nodeD = node->next;
238 
239  if (nodeA != nullptr)
240  nodeA->next = node;
241  else
242  first = node;
243  nodeB->next = nodeD;
244  nodeB->previous = node;
245  node->next = nodeB;
246  node->previous = nodeA;
247  if (nodeD != nullptr)
248  nodeD->previous = nodeB;
249  else
250  last = nodeB;
251  }
252 
253  /**
254  * @brief Check if the linked list could contain the given node.
255  *
256  * @retval true
257  * The given node is part of some linked list or it is the first
258  * node of the given linked list.
259  * It could be that the node is part of a different linked list
260  * if it was ever added to a different list.
261  * However, **if this function returns true and the node was never
262  * added to another linked list, it means that this linked list
263  * contains the given node**.
264  * @retval false
265  * The given node is not part of any linked list, or it is the
266  * only element of a different linked list.
267  */
268  bool couldContain(Node *node) {
269  return node && (node == first || node->next != nullptr ||
270  node->previous != nullptr);
271  }
272 
273  iterator begin() { return {first}; }
274  iterator end() { return {nullptr}; }
275 
276  const_iterator begin() const { return {first}; }
277  const_iterator end() const { return {nullptr}; }
278 
279  reverse_iterator rbegin() { return {last}; }
280  reverse_iterator rend() { return {nullptr}; }
281 
282  const_reverse_iterator rbegin() const { return {last}; }
283  const_reverse_iterator rend() const { return {nullptr}; }
284 
285  /// Get a pointer to the first node.
286  Node *getFirst() const { return first; }
287  /// Get a pointer to the last node.
288  Node *getLast() const { return last; }
289 
290  private:
291  Node *first = nullptr;
292  Node *last = nullptr;
293 };
294 
295 /**
296  * @brief A class that can be inherited from to allow inserting into a
297  * DoublyLinkedList.
298  * @tparam Node
299  * The type of the nodes of the list.
300  */
301 template <class Node>
303  protected:
304  friend class DoublyLinkedList<Node>;
305  Node *next = nullptr;
306  Node *previous = nullptr;
307  virtual ~DoublyLinkable() = default;
308 };
309 
310 /// @}
311 
DoublyLinkedList::last
Node * last
Definition: LinkedList.hpp:292
DoublyLinkedList::reverse_node_iterator::difference_type
void difference_type
Definition: LinkedList.hpp:84
DoublyLinkedList::reverse_node_iterator
Reverse bidirectional doubly linked list iterator.
Definition: LinkedList.hpp:79
DoublyLinkedList::node_iterator::pointer
INode * pointer
Definition: LinkedList.hpp:57
DoublyLinkedList::rend
const_reverse_iterator rend() const
Definition: LinkedList.hpp:283
Warnings.hpp
DoublyLinkable::~DoublyLinkable
virtual ~DoublyLinkable()=default
DoublyLinkedList::rbegin
const_reverse_iterator rbegin() const
Definition: LinkedList.hpp:282
DoublyLinkedList::reverse_node_iterator::operator--
reverse_node_iterator & operator--()
Prefix decrement operator.
Definition: LinkedList.hpp:99
DoublyLinkedList::insertSorted
void insertSorted(Node *node, Compare cmp)
Insert a new node at the correct location into a sorted list.
Definition: LinkedList.hpp:170
DoublyLinkedList< AH::Updatable< NormalUpdatable > >::const_reverse_iterator
reverse_node_iterator< const AH::Updatable< NormalUpdatable > > const_reverse_iterator
Definition: LinkedList.hpp:109
DoublyLinkedList::append
void append(Node *node)
Append a node to a linked list.
Definition: LinkedList.hpp:117
DoublyLinkable::next
Node * next
Definition: LinkedList.hpp:305
DoublyLinkedList::node_iterator_base::operator!=
bool operator!=(const node_iterator_base &rhs) const
Definition: LinkedList.hpp:35
DoublyLinkedList::node_iterator::iterator_category
std::bidirectional_iterator_tag iterator_category
Definition: LinkedList.hpp:59
DoublyLinkedList::first
Node * first
Definition: LinkedList.hpp:291
DoublyLinkedList< AH::Updatable< NormalUpdatable > >::const_iterator
node_iterator< const AH::Updatable< NormalUpdatable > > const_iterator
Definition: LinkedList.hpp:107
AH_DIAGNOSTIC_POP
#define AH_DIAGNOSTIC_POP()
Definition: Warnings.hpp:17
DoublyLinkedList::end
const_iterator end() const
Definition: LinkedList.hpp:277
DoublyLinkedList::insertBefore
void insertBefore(Node *toBeInserted, Node *before)
Insert a node before another node.
Definition: LinkedList.hpp:144
DoublyLinkedList::node_iterator::operator--
node_iterator & operator--()
Prefix decrement operator.
Definition: LinkedList.hpp:70
DoublyLinkedList::node_iterator_base::operator*
INode & operator*() const
Definition: LinkedList.hpp:39
DoublyLinkable::previous
Node * previous
Definition: LinkedList.hpp:306
DoublyLinkedList::remove
void remove(Node *node)
Remove a node from the linked list.
Definition: LinkedList.hpp:200
DoublyLinkedList< AH::Updatable< NormalUpdatable > >::iterator
node_iterator< AH::Updatable< NormalUpdatable > > iterator
Definition: LinkedList.hpp:106
DoublyLinkedList::append
void append(Node &node)
Append a node to a linked list.
Definition: LinkedList.hpp:133
DoublyLinkedList::node_iterator::node_iterator
node_iterator(INode *node)
Definition: LinkedList.hpp:52
DoublyLinkedList< AH::Updatable< NormalUpdatable > >::reverse_iterator
reverse_node_iterator< AH::Updatable< NormalUpdatable > > reverse_iterator
Definition: LinkedList.hpp:108
DoublyLinkedList::begin
iterator begin()
Definition: LinkedList.hpp:273
DoublyLinkedList::node_iterator_base::node
INode * node
Definition: LinkedList.hpp:45
DoublyLinkedList::couldContain
bool couldContain(Node *node)
Check if the linked list could contain the given node.
Definition: LinkedList.hpp:268
DoublyLinkedList::node_iterator_base
Base class for doubly linked list iterators.
Definition: LinkedList.hpp:31
DoublyLinkedList::node_iterator::operator++
node_iterator & operator++()
Prefix increment operator.
Definition: LinkedList.hpp:63
DoublyLinkedList::node_iterator
Forward bidirectional doubly linked list iterator.
Definition: LinkedList.hpp:50
DoublyLinkedList::node_iterator::value_type
INode value_type
Definition: LinkedList.hpp:56
DoublyLinkedList::insertBefore
void insertBefore(Node &toBeInserted, Node &before)
Definition: LinkedList.hpp:155
DoublyLinkedList::rbegin
reverse_iterator rbegin()
Definition: LinkedList.hpp:279
DoublyLinkedList::getLast
Node * getLast() const
Get a pointer to the last node.
Definition: LinkedList.hpp:288
DoublyLinkedList::reverse_node_iterator::reverse_node_iterator
reverse_node_iterator(INode *node)
Definition: LinkedList.hpp:81
DoublyLinkedList::reverse_node_iterator::iterator_category
std::bidirectional_iterator_tag iterator_category
Definition: LinkedList.hpp:88
DoublyLinkedList::node_iterator::difference_type
void difference_type
Definition: LinkedList.hpp:55
DoublyLinkedList::insertSorted
void insertSorted(Node *node)
Insert a new node at the correct location into a sorted list, using operator<.
Definition: LinkedList.hpp:190
DoublyLinkedList::begin
const_iterator begin() const
Definition: LinkedList.hpp:276
DoublyLinkedList
A class for doubly linked lists.
Definition: LinkedList.hpp:27
DoublyLinkedList::rend
reverse_iterator rend()
Definition: LinkedList.hpp:280
DoublyLinkable
A class that can be inherited from to allow inserting into a DoublyLinkedList.
Definition: LinkedList.hpp:302
DoublyLinkedList::node_iterator::reference
INode & reference
Definition: LinkedList.hpp:58
AH_DIAGNOSTIC_WERROR
#define AH_DIAGNOSTIC_WERROR()
Definition: Warnings.hpp:16
DoublyLinkedList::reverse_node_iterator::operator++
reverse_node_iterator & operator++()
Prefix increment operator.
Definition: LinkedList.hpp:92
DoublyLinkedList::end
iterator end()
Definition: LinkedList.hpp:274
DoublyLinkedList::remove
void remove(Node &node)
Remove a node from the linked list.
Definition: LinkedList.hpp:219
DoublyLinkedList::moveDown
void moveDown(Node *node)
Move down the given node in the linked list.
Definition: LinkedList.hpp:232
MinMaxFix.hpp
DoublyLinkedList::node_iterator_base::node_iterator_base
node_iterator_base(INode *node)
Definition: LinkedList.hpp:33
DoublyLinkedList::reverse_node_iterator::pointer
INode * pointer
Definition: LinkedList.hpp:86
DoublyLinkedList::reverse_node_iterator::value_type
INode value_type
Definition: LinkedList.hpp:85
DoublyLinkedList::getFirst
Node * getFirst() const
Get a pointer to the first node.
Definition: LinkedList.hpp:286
DoublyLinkedList::reverse_node_iterator::reference
INode & reference
Definition: LinkedList.hpp:87