avl_tree.hpp
Go to the documentation of this file.
1 /*
2  * AVL Tree implementation.
3  * Copyright (C) 2019 Theodoros Ntakouris <zarkopafilis@gmail.com>
4  */
5 
6 #ifndef UAVCAN_UTIL_AVL_TREE_HPP_INCLUDED
7 #define UAVCAN_UTIL_AVL_TREE_HPP_INCLUDED
8 
9 #include <cstdlib>
10 #include <cassert>
11 #include <cmath>
12 #include <algorithm>
13 #include <functional>
14 #include <uavcan/build_config.hpp>
17 #include <uavcan/debug.hpp>
18 
19 namespace uavcan
20 {
21 template <typename T>
23 {
24 protected:
25  struct Node {
26  T* data = UAVCAN_NULLPTR;
27  int16_t h = 1; // initially added as leaf
29  Node* right = UAVCAN_NULLPTR;
30  Node* equal_keys = UAVCAN_NULLPTR;
31  };
32 
34 
35 private:
36  size_t len_ = 0;
37 
38  static int16_t heightOf(const Node* n) {
39  if (n == UAVCAN_NULLPTR) {
40  return 0;
41  }
42 
43  return n->h;
44  }
45 
46  void postOrderTraverseRecursively(Node* n, std::function<void(T*&)> forEach) {
47  if (n == UAVCAN_NULLPTR) {
48  return;
49  }
50 
51  postOrderTraverseRecursively(n->left, forEach);
52  postOrderTraverseRecursively(n->right, forEach);
53  forEach(n->data);
54  }
55 
56  Node* makeNode(T* payload) {
57  void* praw = this->allocator_.allocate(sizeof(Node));
58 
59  if (praw == UAVCAN_NULLPTR) {
60  UAVCAN_TRACE("AvlTree", " OOM -- Can't allocate Node");
61  return UAVCAN_NULLPTR; // Push rejected
62  }
63 
64  Node* node = new (praw) Node();
66 
67  node->data = payload;
68  return node;
69  }
70 
71  void deleteNode(Node*& n) {
72  if (n != UAVCAN_NULLPTR) {
73  n->~Node();
74  allocator_.deallocate(n);
75  n = UAVCAN_NULLPTR;
76  }
77  }
78 
79  static int16_t balanceOf(Node* n) {
80  if (n == UAVCAN_NULLPTR) {
81  return 0;
82  }
83 
84  return static_cast<int16_t>(heightOf(n->left) - heightOf(n->right));
85  }
86 
87  static int16_t maxOf(int16_t a, int16_t b) {
88  return a > b ? a : b;
89  }
90 
91  static Node* rotateRight(Node* y) {
92  Node* x = y->left;
93  Node* T2 = x->right;
94 
95  x->right = y;
96  y->left = T2;
97 
98  y->h = static_cast<int16_t>(maxOf(heightOf(y->left), heightOf(y->right)) + 1);
99  x->h = static_cast<int16_t>(maxOf(heightOf(x->left), heightOf(x->right)) + 1);
100 
101  return x;
102  }
103 
104  static Node* rotateLeft(Node* x) {
105  Node* y = x->right;
106  Node* T2 = y->left;
107 
108  y->left = x;
109  x->right = T2;
110 
111  x->h = static_cast<int16_t>(maxOf(heightOf(x->left), heightOf(x->right)) + 1);
112  y->h = static_cast<int16_t>(maxOf(heightOf(y->left), heightOf(y->right)) + 1);
113 
114  return y;
115  }
116 
117  // If UAVCAN_NULLPTR is returned, OOM happened.
118  Node* insertNode(Node* node, Node* newNode) {
119  if (node == UAVCAN_NULLPTR) {
120  len_++;
121  return newNode;
122  }
123 
124  if (*newNode->data < *node->data) {
125  node->left = insertNode(node->left, newNode);
126  } else if (*newNode->data > *node->data) {
127  node->right = insertNode(node->right, newNode);
128  } else {
129  len_++;
130  appendToEndOf(node, newNode);
131  return node;
132  }
133 
134  node->h = static_cast<int16_t>(maxOf(heightOf(node->left), heightOf(node->right)) + 1);
135 
136  int16_t balance = balanceOf(node);
137 
138  if (balance > 1 && (*newNode->data < *node->left->data)) {
139  return rotateRight(node);
140  }
141 
142  if (balance < -1 && (*newNode->data > *node->right->data)) {
143  return rotateLeft(node);
144  }
145 
146  if (balance > 1 && (*newNode->data > *node->left->data)) {
147  node->left = rotateLeft(node->left);
148  return rotateRight(node);
149  }
150 
151  if (balance < -1 && (*newNode->data < *node->right->data)) {
152  node->right = rotateRight(node->right);
153  return rotateLeft(node);
154  }
155 
156  return node;
157  }
158 
159  static void appendToEndOf(Node* head, Node* newNode) {
160  Node* target = head;
161  while(target->equal_keys != UAVCAN_NULLPTR) {
162  target = target->equal_keys;
163  }
164 
165  target->equal_keys = newNode;
166  }
167 
168  /* Delete the element of the linked list (memory address comparison)
169  * and return the new head
170  */
171  Node* deleteFromList(Node* root, T* data) {
172  Node* current = root;
173  Node* prev = UAVCAN_NULLPTR;
174 
175  while(current != UAVCAN_NULLPTR) {
176  if (current->data == data) {
177  if (current == root) {
178  Node* ret = current->equal_keys; // From the remove method, this should never be null
179 
180  /* Inherit subtrees */
181  ret->h = current->h;
182  ret->left = current->left;
183  ret->right = current->right;
184 
185  len_--;
186  deleteNode(current);
187 
188  return ret; /* Return one element forward */
189  } else {
190  Node* next = current->equal_keys;
191  prev->equal_keys = next;
192  len_--;
193  deleteNode(current);
194  return root; /* Unchanged root, non-head element was changed */
195  }
196  }
197 
198  prev = current;
199  current = current->equal_keys;
200  }
201 
202  return root;
203  }
204 
206  if (n == UAVCAN_NULLPTR) {
207  return;
208  }
209 
210  postOrderTraverseNodeCleanup(n->left);
211  postOrderTraverseNodeCleanup(n->right);
212  this->deleteNode(n);
213  }
214 
215 protected:
216  /*
217  * Use this only to allocate the Node struct.
218  * `T data` should be already allocated and
219  * provided ready for usage from the outside world
220  */
222 
223  void postOrderNodeTraverseRecursively(Node* n, std::function<void(Node*&)> forEach) {
224  if (n == UAVCAN_NULLPTR) {
225  return;
226  }
227 
228  postOrderNodeTraverseRecursively(n->left, forEach);
229  postOrderNodeTraverseRecursively(n->right, forEach);
230  forEach(n);
231  }
232 
233  Node* removeNode(Node* node, T* data) {
234  if (node == UAVCAN_NULLPTR) {
235  return node;
236  }
237 
238  if (*data < *node->data) {
239  node->left = removeNode(node->left, data);
240  } else if (*data > *node->data) {
241  node->right = removeNode(node->right, data);
242  } else {
243  if (node->equal_keys == UAVCAN_NULLPTR) {
244  if (node->left == UAVCAN_NULLPTR || node->right == UAVCAN_NULLPTR) {
245  Node *temp = node->left ? node->left : node->right;
246 
247  if (temp == UAVCAN_NULLPTR) {
248  temp = node;
250  } else {
251  *node = *temp;
252  }
253 
254  len_--;
255  deleteNode(temp);
256  } else {
257  Node *minOfRight = node->right;
258 
259  while (minOfRight->left != UAVCAN_NULLPTR) {
260  minOfRight = minOfRight->left;
261  }
262 
263  node->data = minOfRight->data;
264  node->right = removeNode(node->right, minOfRight->data);
265  }
266  } else {
267  Node* newHead = deleteFromList(node, data);
268  return newHead;
269  }
270  }
271 
272  if (node == UAVCAN_NULLPTR) {
273  return node;
274  }
275 
276  node->h = static_cast<int16_t>(maxOf(heightOf(node->left), heightOf(node->right)) + 1);
277 
278  int16_t balance = balanceOf(node);
279 
280  if (balance > 1 && balanceOf(node->left) >= 0) {
281  return rotateRight(node);
282  }
283 
284  if (balance > 1 && balanceOf(node->left) < 0) {
285  node->left = rotateLeft(node->left);
286  return rotateRight(node);
287  }
288 
289  if (balance < -1 && balanceOf(node->right) <= 0) {
290  return rotateLeft(node);
291  }
292 
293  if (balance < -1 && balanceOf(node->right) > 0) {
294  node->right = rotateRight(node->right);
295  return rotateLeft(node);
296  }
297 
298  return node;
299  }
300 
301  static bool linkedListContains(Node* head, const T* data) {
302  Node* next = head;
303  while(next != UAVCAN_NULLPTR) {
304  if (next->data == data) { /* Memory address comparison */
305  return true;
306  }
307  next = next->equal_keys;
308  }
309  return false;
310  }
311 
312 public:
313  AvlTree(IPoolAllocator &allocator, std::size_t allocator_quota)
314  : root_(UAVCAN_NULLPTR)
315  , len_(0)
316  , allocator_(allocator, allocator_quota)
317  {}
318 
319  virtual ~AvlTree() {
320  // Delete leafs first.
321  postOrderTraverseNodeCleanup(this->root_);
322  }
323 
324  void removeEntry(T* data) {
325  root_ = removeNode(root_, data);
326  }
327 
328  bool insert(T* data) {
329  Node* newNode = makeNode(data);
330  if (newNode == UAVCAN_NULLPTR) {
331  return false;
332  }
333 
334  root_ = insertNode(root_, newNode);
335 
336  return true;
337  }
338 
339  size_t getSize() const {
340  return len_;
341  }
342 
343  void walkPostOrder(std::function<void(T*&)> forEach) {
344  postOrderTraverseRecursively(root_, forEach);
345  }
346 
347 
348  bool isEmpty() const {
349  return getSize() == 0;
350  }
351 
352  T* max() const {
353  Node* n = root_;
354 
355  if (n == UAVCAN_NULLPTR) {
356  return UAVCAN_NULLPTR;
357  }
358 
359  while (n->right != UAVCAN_NULLPTR) {
360  n = n->right;
361  }
362 
363  return n->data;
364  }
365 
366  bool contains(const T* data) const {
367  Node* n = root_;
368  while (n != UAVCAN_NULLPTR) {
369  if (*n->data < *data) {
370  n = n->right;
371  continue;
372  }
373 
374  if (*n->data > *data) {
375  n = n->left;
376  continue;
377  }
378 
379  return linkedListContains(n, data);
380  }
381  return false;
382  }
383 
384 };
385 }
386 
387 #endif // UAVCAN_UTIL_AVL_TREE_HPP_INCLUDED
UAVCAN_NULLPTR
#define UAVCAN_NULLPTR
Definition: libuavcan/libuavcan/include/uavcan/build_config.hpp:51
uavcan::Noncopyable
Definition: templates.hpp:46
templates.hpp
uavcan::AvlTree::Node
Definition: avl_tree.hpp:25
std::size_t
unsigned long size_t
Definition: coverity_scan_model.cpp:19
uavcan::AvlTree::postOrderTraverseRecursively
void postOrderTraverseRecursively(Node *n, std::function< void(T *&)> forEach)
Definition: avl_tree.hpp:46
debug.hpp
uavcan::AvlTree::rotateRight
static Node * rotateRight(Node *y)
Definition: avl_tree.hpp:91
uavcan::AvlTree::maxOf
static int16_t maxOf(int16_t a, int16_t b)
Definition: avl_tree.hpp:87
uavcan::LimitedPoolAllocator
Definition: dynamic_memory.hpp:112
uavcan::AvlTree::AvlTree
AvlTree(IPoolAllocator &allocator, std::size_t allocator_quota)
Definition: avl_tree.hpp:313
dynamic_memory.hpp
uavcan::AvlTree::heightOf
static int16_t heightOf(const Node *n)
Definition: avl_tree.hpp:38
uavcan::AvlTree::isEmpty
bool isEmpty() const
Definition: avl_tree.hpp:348
uavcan::AvlTree::removeEntry
void removeEntry(T *data)
Definition: avl_tree.hpp:324
UAVCAN_TRACE
#define UAVCAN_TRACE(...)
Definition: libuavcan/libuavcan/include/uavcan/debug.hpp:31
uavcan::AvlTree::insertNode
Node * insertNode(Node *node, Node *newNode)
Definition: avl_tree.hpp:118
uavcan::AvlTree::walkPostOrder
void walkPostOrder(std::function< void(T *&)> forEach)
Definition: avl_tree.hpp:343
uavcan::int16_t
std::int16_t int16_t
Definition: std.hpp:30
uavcan::AvlTree::root_
Node * root_
Definition: avl_tree.hpp:33
uavcan::AvlTree::allocator_
LimitedPoolAllocator allocator_
Definition: avl_tree.hpp:221
uavcan::IPoolAllocator
Definition: dynamic_memory.hpp:21
uavcan::AvlTree::postOrderTraverseNodeCleanup
void postOrderTraverseNodeCleanup(Node *n)
Definition: avl_tree.hpp:205
uavcan::AvlTree::max
T * max() const
Definition: avl_tree.hpp:352
uavcan::AvlTree::removeNode
Node * removeNode(Node *node, T *data)
Definition: avl_tree.hpp:233
uavcan::AvlTree::appendToEndOf
static void appendToEndOf(Node *head, Node *newNode)
Definition: avl_tree.hpp:159
UAVCAN_EXPORT
#define UAVCAN_EXPORT
Definition: libuavcan/libuavcan/include/uavcan/build_config.hpp:108
len_
std::uint8_t len_
Definition: can.cpp:85
build_config.hpp
uavcan::AvlTree::postOrderNodeTraverseRecursively
void postOrderNodeTraverseRecursively(Node *n, std::function< void(Node *&)> forEach)
Definition: avl_tree.hpp:223
uavcan::AvlTree::insert
bool insert(T *data)
Definition: avl_tree.hpp:328
uavcan::AvlTree::contains
bool contains(const T *data) const
Definition: avl_tree.hpp:366
uavcan::AvlTree::getSize
size_t getSize() const
Definition: avl_tree.hpp:339
uavcan::AvlTree::~AvlTree
virtual ~AvlTree()
Definition: avl_tree.hpp:319
uavcan::AvlTree
Definition: avl_tree.hpp:22
uavcan::AvlTree::deleteNode
void deleteNode(Node *&n)
Definition: avl_tree.hpp:71
uavcan::AvlTree::balanceOf
static int16_t balanceOf(Node *n)
Definition: avl_tree.hpp:79
pyuavcan_v0.introspect.node
node
Definition: introspect.py:398
uavcan::AvlTree::rotateLeft
static Node * rotateLeft(Node *x)
Definition: avl_tree.hpp:104
uavcan
Definition: libuavcan/libuavcan/include/uavcan/build_config.hpp:204
uavcan::AvlTree::linkedListContains
static bool linkedListContains(Node *head, const T *data)
Definition: avl_tree.hpp:301
uavcan_linux::makeNode
static NodePtr makeNode(const std::vector< std::string > &iface_names, ClockAdjustmentMode clock_adjustment_mode=SystemClock::detectPreferredClockAdjustmentMode())
Definition: platform_specific_components/linux/libuavcan/include/uavcan_linux/helpers.hpp:363
uavcan::AvlTree::deleteFromList
Node * deleteFromList(Node *root, T *data)
Definition: avl_tree.hpp:171
uavcan::AvlTree::makeNode
Node * makeNode(T *payload)
Definition: avl_tree.hpp:56
pyuavcan_v0.driver.timestamp_estimator.x
x
Definition: timestamp_estimator.py:221
uavcan::Node
Definition: node.hpp:38
UAVCAN_ASSERT
#define UAVCAN_ASSERT(x)
Definition: libuavcan/libuavcan/include/uavcan/build_config.hpp:184


uavcan_communicator
Author(s):
autogenerated on Fri Dec 13 2024 03:10:02