GCC Code Coverage Report


Directory: ./
File: Fw/DataStructures/RedBlackTreeSetOrMapImpl.hpp
Date: 2026-09-03 21:13:48
Exec Total Coverage
Lines: 359 361 99.4%
Functions: 169 237 71.3%
Branches: 171 184 92.9%

Line Branch Exec Source
1 //
2 // ======================================================================
3 // \title RedBlackTreeSetOrMapImpl
4 // \author bocchino
5 // \brief An implementation of a set or map based on a red-black tree
6 // ======================================================================
7
8 #ifndef Fw_RedBlackTreeSetOrMapImpl_HPP
9 #define Fw_RedBlackTreeSetOrMapImpl_HPP
10
11 #include <limits>
12
13 #include "Fw/DataStructures/ExternalArray.hpp"
14 #include "Fw/DataStructures/ExternalStack.hpp"
15 #include "Fw/DataStructures/SetOrMapImplConstIterator.hpp"
16 #include "Fw/DataStructures/SetOrMapImplEntry.hpp"
17 #include "Fw/Types/Assert.hpp"
18 #include "Fw/Types/SuccessEnumAc.hpp"
19
20 namespace Fw {
21
22 //! This class template implements a red-black tree that can be used as a
23 //! set or map. A red-black tree is a binary search tree (BST) such that
24 //! each node is colored red or black. A red-black tree is valid if
25 //!
26 //! 1. It satisfies the red child invariant: No red node has a red child.
27 //!
28 //! 2. It satisfies the black height invariant (described below).
29 //!
30 //! The black height invariant of a red-black tree T is checked with respect to the
31 //! leaf-augmented tree T'. T' is constructed from T by replacing every "missing"
32 //! node in T (i.e., every place where there could be a child but is not) with
33 //! a new black node. The black height invariant says that for every node N in T',
34 //! every path from N to a leaf in T' goes through the same number of black nodes.
35 //!
36 //! A valid red-black tree is balanced, in the sense that the find operation
37 //! takes O(log n) steps.
38 template <typename KE, typename VN>
39 class RedBlackTreeSetOrMapImpl final {
40 // ----------------------------------------------------------------------
41 // Friend class for testing
42 // ----------------------------------------------------------------------
43
44 template <typename KK, typename VV>
45 friend class RedBlackTreeSetOrMapImplTester;
46
47 public:
48 // ----------------------------------------------------------------------
49 // The Node type
50 // ----------------------------------------------------------------------
51
52 //! Node
53 class Node {
54 public:
55 //! Color
56 enum class Color : U8 { BLACK, RED };
57
58 //! Direction
59 enum class Direction : U8 { LEFT, RIGHT };
60
61 //! The type of a node index
62 using Index = FwSizeType;
63
64 //! The type of an entry in the set or map
65 using Entry = SetOrMapImplEntry<KE, VN>;
66
67 public:
68 //! Constant value representing no node
69 static constexpr Index NONE = std::numeric_limits<Index>::max();
70
71 public:
72 //! The index of the parent of this node
73 Index m_parent = NONE;
74
75 //! The index of the left child of this node
76 Index m_left = NONE;
77
78 //! The index of the right child of this node
79 Index m_right = NONE;
80
81 //! The color of this node
82 Color m_color = Color::BLACK;
83
84 //! The set or map entry stored in this node
85 Entry m_entry = {};
86
87 public:
88 //! Get the child of this node in the specified direction
89 //! \return The child
90 9838971 Index getChild(Direction direction //!< The direction
91 ) const {
92
2/2
✓ Branch 0 taken 6228373 times.
✓ Branch 1 taken 3610598 times.
9838971 return (direction == Direction::LEFT) ? this->m_left : this->m_right;
93 }
94
95 //! Set the child of this node in the specified direction
96 391958 void setChild(Direction direction, //!< The direction
97 Index node //!< The node index
98 ) {
99
2/2
✓ Branch 0 taken 222081 times.
✓ Branch 1 taken 169877 times.
391958 if (direction == Direction::LEFT) {
100 222081 this->m_left = node;
101 } else {
102 169877 this->m_right = node;
103 }
104 391958 }
105
106 public:
107 // Get the opposite direction
108 215573 static Direction getOppositeDirection(Direction direction //!< The direction
109 ) {
110
2/2
✓ Branch 0 taken 137529 times.
✓ Branch 1 taken 78044 times.
215573 return (direction == Direction::LEFT) ? Direction::RIGHT : Direction::LEFT;
111 }
112 };
113
114 public:
115 // ----------------------------------------------------------------------
116 // Type aliases
117 // ----------------------------------------------------------------------
118
119 //! The color type
120 using Color = typename Node::Color;
121
122 //! The direction type
123 using Direction = typename Node::Direction;
124
125 //! The entry type
126 using Entry = typename Node::Entry;
127
128 //! The node index type
129 using Index = typename Node::Index;
130
131 //! The type of the array for storing the tree nodes
132 using Nodes = ExternalArray<Node>;
133
134 //! The type of the stack of indices of free nodes
135 using FreeNodes = ExternalStack<Index>;
136
137 public:
138 // ----------------------------------------------------------------------
139 // The ConstIterator type
140 // ----------------------------------------------------------------------
141
142 //! Const iterator
143 class ConstIterator final : public SetOrMapImplConstIterator<KE, VN> {
144 public:
145 using ImplKind = typename SetOrMapImplConstIterator<KE, VN>::ImplKind;
146
147 public:
148 //! Default constructor
149 2 ConstIterator() {}
150
151 //! Constructor providing the implementation
152 129820 ConstIterator(const RedBlackTreeSetOrMapImpl<KE, VN>& impl)
153 129820 : SetOrMapImplConstIterator<KE, VN>(), m_impl(&impl) {
154
1/1
✓ Branch 14 taken 129820 times.
129820 this->m_node = this->m_impl->getOuterNodeUnder(this->m_impl->m_root, Direction::LEFT);
155 129820 }
156
157 //! Copy constructor
158 130077 ConstIterator(const ConstIterator& it)
159 130077 : SetOrMapImplConstIterator<KE, VN>(), m_impl(it.m_impl), m_node(it.m_node) {}
160
161 //! Destructor
162 259644 ~ConstIterator() override = default;
163
164 public:
165 //! Copy assignment operator
166 ConstIterator& operator=(const ConstIterator& it) {
167 this->m_impl = it.m_impl;
168 this->m_node = it.m_node;
169 return *this;
170 }
171
172 //! Equality comparison operator
173 63087 bool compareEqual(const ConstIterator& it) const {
174 63087 bool result = false;
175
3/4
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 63086 times.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
63087 if ((this->m_impl == nullptr) && (it.m_impl == nullptr)) {
176 1 result = true;
177
1/2
✓ Branch 8 taken 63086 times.
✗ Branch 9 not taken.
63086 } else if (this->m_impl == it.m_impl) {
178 63086 result |= (this->m_node == it.m_node);
179
3/4
✓ Branch 4 taken 356 times.
✓ Branch 5 taken 62730 times.
✓ Branch 10 taken 356 times.
✗ Branch 11 not taken.
63086 result |= (!this->isInRange() and !it.isInRange());
180 }
181 63087 return result;
182 }
183
184 //! Return the impl kind
185 //! \return The impl kind
186 130490 ImplKind implKind() const override { return ImplKind::RED_BLACK_TREE; }
187
188 //! Get the set or map impl entry pointed to by this iterator
189 //! \return The set or map impl entry
190 2191785 const Entry& getEntry() const override { return this->m_impl->m_nodes[this->m_node].m_entry; }
191
192 //! Increment operator
193 1068247 void increment() override {
194 1068247 FW_ASSERT(this->m_impl != nullptr);
195 1068247 const auto& nodes = this->m_impl->m_nodes;
196
1/2
✓ Branch 4 taken 1068247 times.
✗ Branch 5 not taken.
1068247 if (this->m_node != Node::NONE) {
197 1068247 const auto rightChild = nodes[this->m_node].getChild(Direction::RIGHT);
198
2/2
✓ Branch 0 taken 532563 times.
✓ Branch 1 taken 535684 times.
1068247 if (rightChild != Node::NONE) {
199 // There is a right child. Go to the leftmost node under that child.
200 532563 this->m_node = this->m_impl->getOuterNodeUnder(rightChild, Direction::LEFT);
201 } else {
202 // There is no right child. Go upwards until we pass through a left child
203 // or we hit the root.
204 535684 const auto capacity = this->m_impl->getCapacity();
205 535684 bool done = (capacity == 0);
206
1/2
✓ Branch 0 taken 1068067 times.
✗ Branch 1 not taken.
1068067 for (FwSizeType i = 0; i < capacity; i++) {
207 1068067 const auto previousNode = this->m_node;
208 1068067 this->m_node = nodes[this->m_node].m_parent;
209
6/6
✓ Branch 4 taken 1064399 times.
✓ Branch 5 taken 3668 times.
✓ Branch 6 taken 532016 times.
✓ Branch 7 taken 532383 times.
✓ Branch 8 taken 535684 times.
✓ Branch 9 taken 532383 times.
2132466 if ((this->m_node == Node::NONE) or
210 1064399 (nodes[this->m_node].getChild(Direction::LEFT) == previousNode)) {
211 535684 done = true;
212 535684 break;
213 }
214 }
215 535684 FW_ASSERT(done == true);
216 }
217 }
218 1068247 }
219
220 //! Check whether the iterator is in range
221 2191014 bool isInRange() const override {
222 2191014 FW_ASSERT(this->m_impl != nullptr);
223 2191014 return this->m_node < this->m_impl->getCapacity();
224 }
225
226 //! Set the iterator to the end value
227 62541 void setToEnd() { this->m_node = Node::NONE; }
228
229 private:
230 //! The implementation over which to iterate
231 const RedBlackTreeSetOrMapImpl<KE, VN>* m_impl = nullptr;
232
233 //! The current node
234 Index m_node = Node::NONE;
235 };
236
237 public:
238 // ----------------------------------------------------------------------
239 // Public constructors and destructors
240 // ----------------------------------------------------------------------
241
242 //! Zero-argument constructor
243
1/1
✓ Branch 15 taken 635 times.
635 RedBlackTreeSetOrMapImpl() = default;
244
245 //! Constructor providing typed backing storage.
246 //! nodes must point to at least capacity elements of type Node.
247 //! freeNodes must point to at least capacity elements of type FwSizeType.
248 20 RedBlackTreeSetOrMapImpl(Node* nodes, //!< The nodes
249 Index* freeNodes, //!< The free nodes
250 FwSizeType capacity //!< The capacity
251
1/1
✓ Branch 15 taken 20 times.
20 ) {
252
1/1
✓ Branch 2 taken 20 times.
20 this->setStorage(nodes, freeNodes, capacity);
253 20 }
254
255 //! Constructor providing untyped backing storage.
256 //! data must be aligned according to getByteArrayAlignment().
257 //! data must contain at least getByteArraySize(capacity) bytes.
258 1 RedBlackTreeSetOrMapImpl(ByteArray data, //!< The data
259 FwSizeType capacity //!< The capacity
260
1/1
✓ Branch 15 taken 1 times.
1 ) {
261
1/1
✓ Branch 2 taken 1 times.
1 this->setStorage(data, capacity);
262 1 }
263
264 //! Copy constructor
265
2/2
✓ Branch 15 taken 1 times.
✓ Branch 21 taken 1 times.
1 RedBlackTreeSetOrMapImpl(const RedBlackTreeSetOrMapImpl<KE, VN>& impl) { *this = impl; }
266
267 //! Destructor
268 657 ~RedBlackTreeSetOrMapImpl() = default;
269
270 public:
271 // ----------------------------------------------------------------------
272 // Public member functions
273 // ----------------------------------------------------------------------
274
275 //! operator=
276 6 RedBlackTreeSetOrMapImpl<KE, VN>& operator=(const RedBlackTreeSetOrMapImpl<KE, VN>& impl) {
277
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (&impl != this) {
278 6 this->m_nodes = impl.m_nodes;
279 6 this->m_freeNodes = impl.m_freeNodes;
280 6 this->m_root = impl.m_root;
281 }
282 6 return *this;
283 }
284
285 //! Get the begin iterator
286 129819 ConstIterator begin() const { return ConstIterator(*this); }
287
288 //! Clear the set or map
289 2362 void clear() {
290 // Set the root to NONE
291 2362 this->m_root = Node::NONE;
292 // Clear the free node stack
293 2362 this->m_freeNodes.clear();
294 // Push all the nodes on the free node stack
295 2362 const auto capacity = this->getCapacity();
296
2/2
✓ Branch 3 taken 780203 times.
✓ Branch 4 taken 2362 times.
1562768 for (FwSizeType i = 0; i < capacity; i++) {
297
1/1
✓ Branch 6 taken 780203 times.
780203 const auto status = this->m_freeNodes.push(capacity - i - 1);
298 780203 FW_ASSERT(status == Success::SUCCESS, static_cast<FwAssertArgType>(status));
299 }
300 2362 }
301
302 //! Get the end iterator
303 62541 ConstIterator end() const {
304 62541 auto it = begin();
305 62541 it.setToEnd();
306 62541 return it;
307 }
308
309 //! Find a value associated with a key in the map or an element in a set
310 //! \return SUCCESS if the item was found
311 12408 Success find(const KE& keyOrElement, //!< The key or element
312 VN& valueOrNil //!< The value or Nil
313 ) const {
314 12408 auto node = Node::NONE;
315 12408 auto direction = Direction::LEFT;
316
1/1
✓ Branch 2 taken 12408 times.
12408 const auto status = this->findNode(keyOrElement, node, direction);
317
2/2
✓ Branch 3 taken 4943 times.
✓ Branch 4 taken 7465 times.
12408 if (status == Success::SUCCESS) {
318
1/1
✓ Branch 4 taken 4943 times.
4943 valueOrNil = this->m_nodes[node].m_entry.getValueOrNil();
319 }
320 24816 return status;
321 }
322
323 //! Get the capacity of the set or map (max number of entries)
324 //! \return The capacity
325 4310251 FwSizeType getCapacity() const { return this->m_nodes.getSize(); }
326
327 //! Get the size (number of entries)
328 //! \return The size
329 99934 FwSizeType getSize() const {
330 99934 const auto capacity = this->getCapacity();
331 99934 const auto freeNodesSize = this->m_freeNodes.getSize();
332 99934 FW_ASSERT(freeNodesSize <= capacity, static_cast<FwAssertArgType>(freeNodesSize),
333 static_cast<FwAssertArgType>(capacity));
334 99934 return capacity - freeNodesSize;
335 }
336
337 //! Insert an element in the set or a (key, value) pair in the map
338 //! \return SUCCESS if there is room in the set or map
339 83282 Success insert(const KE& keyOrElement, //!< The key or element
340 const VN& valueOrNil //!< The value or Nil
341 ) {
342 83282 auto node = Node::NONE;
343 83282 auto direction = Direction::LEFT;
344 83282 auto status = Success::FAILURE;
345
1/1
✓ Branch 2 taken 83282 times.
83282 const auto findStatus = this->findNode(keyOrElement, node, direction);
346
2/2
✓ Branch 2 taken 5057 times.
✓ Branch 3 taken 78225 times.
83282 if (findStatus == Success::SUCCESS) {
347
1/1
✓ Branch 3 taken 5057 times.
5057 this->m_nodes[node].m_entry.setValueOrNil(valueOrNil);
348 5057 status = Success::SUCCESS;
349 } else {
350 78225 const auto parent = node;
351
1/1
✓ Branch 4 taken 78225 times.
78225 status = this->m_freeNodes.pop(node);
352
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 78225 times.
✓ Branch 2 taken 78220 times.
✓ Branch 3 taken 5 times.
78225 if (status == Success::SUCCESS) {
353
5/5
✓ Branch 2 taken 78070 times.
✓ Branch 6 taken 150 times.
✓ Branch 8 taken 78070 times.
✓ Branch 10 taken 150 times.
✓ Branch 12 taken 78070 times.
78220 this->m_nodes[node] = Node();
354
2/2
✓ Branch 3 taken 78220 times.
✓ Branch 11 taken 62316 times.
78220 this->m_nodes[node].m_entry.setKeyOrElement(keyOrElement);
355
1/1
✓ Branch 3 taken 78220 times.
78220 this->m_nodes[node].m_entry.setValueOrNil(valueOrNil);
356
1/1
✓ Branch 2 taken 78220 times.
78220 this->insertNode(node, parent, direction);
357 }
358 }
359
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 83282 times.
✓ Branch 3 taken 83282 times.
166564 return status;
360 83282 }
361
362 //! Remove an element from the set or a (key, value) pair from the map
363 //! \return SUCCESS if the key or element was there
364 63780 Success remove(const KE& keyOrElement, //!< The key or element
365 VN& valueOrNil //!< The value or Nil
366 ) {
367 63780 auto node = Node::NONE;
368 63780 auto direction = Direction::LEFT;
369
1/1
✓ Branch 2 taken 63780 times.
63780 const auto status = findNode(keyOrElement, node, direction);
370
2/2
✓ Branch 3 taken 62668 times.
✓ Branch 4 taken 1112 times.
63780 if (status == Success::SUCCESS) {
371
1/1
✓ Branch 3 taken 62668 times.
62668 valueOrNil = this->m_nodes[node].m_entry.getValue();
372 62668 auto removedNode = Node::NONE;
373
1/1
✓ Branch 2 taken 62668 times.
62668 this->removeNode(node, removedNode);
374
1/1
✓ Branch 4 taken 62668 times.
62668 const auto pushStatus = this->m_freeNodes.push(removedNode);
375 62668 FW_ASSERT(pushStatus == Success::SUCCESS, static_cast<FwAssertArgType>(pushStatus));
376 62668 }
377 127560 return status;
378 }
379
380 //! Set the backing storage (typed data)
381 //! nodes must point to at least capacity elements of type Node.
382 //! freeNodes must point to at least capacity elements of type FwSizeType.
383 644 void setStorage(Node* nodes, //!< The nodes
384 Index* freeNodes, //!< The free nodes
385 FwSizeType capacity //!< The capacity
386 ) {
387 644 this->m_nodes.setStorage(nodes, capacity);
388 644 this->m_freeNodes.setStorage(freeNodes, capacity);
389 644 this->clear();
390 644 }
391
392 //! Set the backing storage (untyped data)
393 //! data must be aligned according to getByteArrayAlignment().
394 //! data must contain at least getByteArraySize(capacity) bytes.
395 3 void setStorage(ByteArray data, //!< The data
396 FwSizeType capacity //!< The capacity
397 ) {
398
1/1
✓ Branch 3 taken 3 times.
3 this->m_nodes.setStorage(data, capacity);
399 3 const auto nodesSize = Nodes::getByteArraySize(capacity);
400 // Compute the nearest offset at or after nodesSize that is aligned for FreeNodes
401 3 const auto freeNodesAlignment = FreeNodes::getByteArrayAlignment();
402 3 const U8 modulus = nodesSize % freeNodesAlignment;
403
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 const FwSizeType freeNodesOffset = nodesSize + ((modulus == 0) ? 0 : freeNodesAlignment - modulus);
404 3 FW_ASSERT(freeNodesOffset % freeNodesAlignment == 0, static_cast<FwAssertArgType>(freeNodesOffset),
405 static_cast<FwAssertArgType>(freeNodesAlignment));
406
1/1
✓ Branch 1 taken 3 times.
3 const auto freeNodesSize = FreeNodes::getByteArraySize(capacity);
407 // Make sure that data has enough room
408 3 FW_ASSERT(freeNodesOffset + freeNodesSize <= data.size, static_cast<FwAssertArgType>(freeNodesOffset),
409 static_cast<FwAssertArgType>(freeNodesSize), static_cast<FwAssertArgType>(data.size));
410 3 ByteArray freeNodesData(&data.bytes[freeNodesOffset], freeNodesSize);
411 // Set the storage and clear freeNodes
412
1/1
✓ Branch 6 taken 3 times.
3 this->m_freeNodes.setStorage(freeNodesData, capacity);
413
1/1
✓ Branch 2 taken 3 times.
3 this->clear();
414 3 }
415
416 public:
417 // ----------------------------------------------------------------------
418 // Public static functions
419 // ----------------------------------------------------------------------
420
421 //! Get the alignment of the storage for a RedBlackTreeSetOrMapImpl
422 //! \return The alignment
423 static constexpr U8 getByteArrayAlignment() { return ExternalArray<Entry>::getByteArrayAlignment(); }
424
425 //! Get the size of the storage for an ExternalArray of the specified capacity,
426 //! as a byte array
427 //! \return The byte array size
428 static constexpr FwSizeType getByteArraySize(FwSizeType capacity //!< The capacity
429 ) {
430 return Nodes::getByteArraySize(capacity) + FreeNodes::getByteArrayAlignment() +
431 FreeNodes::getByteArraySize(capacity);
432 }
433
434 private:
435 // ----------------------------------------------------------------------
436 // Private helper functions
437 // ----------------------------------------------------------------------
438
439 //! This function tries to find a node whose key or element ke matches keyOrElement.
440 //! On return from the function:
441 //! 1. If such a node exists, then the return value is SUCCESS,
442 //! and node stores the index of N.
443 //! 2. Otherwise
444 //! a. The return value is FAILURE.
445 //! b. If the tree is empty, then node holds NONE.
446 //! c. Otherwise node stores the index of the node N containing the NONE
447 //! child where ke should be inserted, and direction stores the direction
448 //! of the child in N (left or right).
449 159470 Success findNode(const KE& keyOrElement, //!< The key or element (input)
450 Index& node, //!< The node index (output)
451 Direction& direction //!< The direction (output)
452 ) const {
453 159470 auto result = Success::FAILURE;
454 159470 auto parent = Node::NONE;
455 159470 auto child = this->m_root;
456
1/1
✓ Branch 2 taken 135811 times.
159470 const auto capacity = this->getCapacity();
457 159470 bool done = (capacity == 0);
458
1/2
✓ Branch 0 taken 994382 times.
✗ Branch 1 not taken.
994382 for (FwSizeType i = 0; i < capacity; i++) {
459
2/2
✓ Branch 0 taken 86802 times.
✓ Branch 1 taken 907580 times.
994382 if (child == Node::NONE) {
460 86802 node = parent;
461 86802 done = true;
462 86802 break;
463 }
464
1/1
✓ Branch 4 taken 907580 times.
907580 const auto& entryKey = this->m_nodes[child].m_entry.getKeyOrElement();
465
4/4
✓ Branch 2 taken 668087 times.
✓ Branch 3 taken 239493 times.
✓ Branch 4 taken 66826 times.
✓ Branch 5 taken 595419 times.
907580 if (keyOrElement == entryKey) {
466 72668 result = Success::SUCCESS;
467 72668 node = child;
468 72668 done = true;
469 72668 break;
470
4/4
✓ Branch 2 taken 610436 times.
✓ Branch 3 taken 224476 times.
✓ Branch 4 taken 401831 times.
✓ Branch 5 taken 193588 times.
834912 } else if (keyOrElement < entryKey) {
471 416848 direction = Direction::LEFT;
472 416848 parent = child;
473
1/1
✓ Branch 4 taken 416848 times.
416848 child = this->m_nodes[parent].m_left;
474 } else {
475 418064 direction = Direction::RIGHT;
476 418064 parent = child;
477
1/1
✓ Branch 4 taken 418064 times.
418064 child = this->m_nodes[parent].m_right;
478 }
479 }
480 159470 FW_ASSERT(done);
481
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 159470 times.
✓ Branch 3 taken 159470 times.
318940 return result;
482 }
483
484 //! Get the direction from the parent, i.e., the direction (left or
485 //! right) to follow from the parent of node to get to node.
486 //! node must not be NONE. The parent of node must not be NONE.
487 238122 Direction getDirectionFromParent(Index node //!< The node index
488 ) const {
489 238122 const auto parent = this->m_nodes[node].m_parent;
490 238122 const auto parentRight = m_nodes[parent].m_right;
491
2/2
✓ Branch 0 taken 92065 times.
✓ Branch 1 taken 146057 times.
238122 return (node == parentRight) ? Direction::RIGHT : Direction::LEFT;
492 }
493
494 //! Get the color of a node
495 //! \return The color
496 2538006 Color getNodeColor(Index index //!< The node index
497 ) const {
498
2/2
✓ Branch 0 taken 2453638 times.
✓ Branch 1 taken 84368 times.
2538006 return (index == Node::NONE) ? Color::BLACK : this->m_nodes[index].m_color;
499 }
500
501 //! Get the outer node under node in the specified direction. If node has
502 //! no child in that direction, then the result is node.
503 1196463 Index getOuterNodeUnder(Index node, //!< The node index
504 Direction direction //!< The direction
505 ) const {
506
2/2
✓ Branch 0 taken 1195554 times.
✓ Branch 1 taken 909 times.
1196463 auto child = (node != Node::NONE) ? this->m_nodes[node].getChild(direction) : Node::NONE;
507 1196463 const auto capacity = this->getCapacity();
508 1196463 bool done = (capacity == 0);
509
2/2
✓ Branch 0 taken 2672159 times.
✓ Branch 1 taken 1 times.
2672160 for (FwSizeType i = 0; i < capacity; i++) {
510
2/2
✓ Branch 0 taken 1196462 times.
✓ Branch 1 taken 1475697 times.
2672159 if (child == Node::NONE) {
511 1196462 done = true;
512 1196462 break;
513 }
514 1475697 node = child;
515 1475697 child = this->m_nodes[child].getChild(direction);
516 }
517 1196463 FW_ASSERT(done == true);
518 1196463 return node;
519 }
520
521 //! This function inserts node into the tree as a left or right child of parent,
522 //! according to direction. It rebalances the tree as needed to maintain the
523 //! red-black invariant.
524 //!
525 //! It is permissible for parent to be NONE. In this case we are inserting
526 //! at the root of the tree, and direction is ignored.
527 //!
528 //! It is not permissible for node to be NONE.
529 78220 void insertNode(Index node, //!< The node to insert
530 Index parent, //!< The new parent
531 Direction direction //!< The direction under the new parent
532 ) {
533 // We assume (1) that the tree is a red-black tree, (2) that parent is NONE or
534 // the child of parent in the direction `direction` is NONE, and (3) that
535 // both children of node are NONE.
536 78220 FW_ASSERT(this->m_nodes[node].getChild(Direction::LEFT) == Node::NONE);
537 78220 FW_ASSERT(this->m_nodes[node].getChild(Direction::RIGHT) == Node::NONE);
538 78220 this->m_nodes[node].m_color = Color::RED;
539 78220 this->m_nodes[node].m_parent = parent;
540
2/2
✓ Branch 0 taken 1411 times.
✓ Branch 1 taken 76809 times.
78220 if (parent == Node::NONE) {
541 1411 this->m_root = node;
542 // The tree was empty, and now it consists of a single red node.
543 } else {
544 76809 FW_ASSERT(this->m_nodes[parent].getChild(direction) == Node::NONE,
545 static_cast<FwAssertArgType>(this->m_nodes[parent].getChild(direction)));
546 // Set the parent
547 76809 this->m_nodes[parent].setChild(direction, node);
548 76809 const auto capacity = this->getCapacity();
549 76809 bool done = (capacity == 0);
550
1/2
✓ Branch 0 taken 117798 times.
✗ Branch 1 not taken.
117798 for (FwSizeType i = 0; i < capacity; i++) {
551 // The following invariants hold: (1) node is colored red; (2)
552 // there may be a red child violation from parent to node; and
553 // (3) there are no other violations at any nodes.
554
2/2
✓ Branch 2 taken 34378 times.
✓ Branch 3 taken 83420 times.
117798 if (this->getNodeColor(parent) == Color::BLACK) {
555 // There is no red child violation at parent, because parent is black.
556 34378 done = true;
557 34378 break;
558 }
559 83420 const auto grandparent = this->m_nodes[parent].m_parent;
560
2/2
✓ Branch 0 taken 2712 times.
✓ Branch 1 taken 80708 times.
83420 if (grandparent == Node::NONE) {
561 2712 this->m_nodes[parent].m_color = Color::BLACK;
562 // This step removes the red child violation at parent.
563 // It preserves all other invariants.
564 2712 done = true;
565 2712 break;
566 }
567 80708 const auto parentDirection = this->getDirectionFromParent(parent);
568 80708 const auto parentOppositeDirection = Node::getOppositeDirection(parentDirection);
569 80708 const auto uncle = this->m_nodes[grandparent].getChild(parentOppositeDirection);
570
2/2
✓ Branch 2 taken 37532 times.
✓ Branch 3 taken 43176 times.
80708 if (this->getNodeColor(uncle) == Color::BLACK) {
571
2/2
✓ Branch 5 taken 11554 times.
✓ Branch 6 taken 25978 times.
37532 if (this->m_nodes[parent].getChild(parentOppositeDirection) == node) {
572 // The subtree rooted at grandparent has the following
573 // shape, assuming that parentDirection is RIGHT.
574 // There is a red child violation from parent to node.
575 // There are no other violations at any nodes.
576 // K1, K2, K3, and K4 are arbitrary keys with K1 < K2 < K3 < K4.
577 /*
578 // BBBBBBBBBBBBBBBBBBBB
579 // B B
580 // B K2 (grandparent) B
581 // B B
582 // BBBBBBBBBBBBBBBBBBBB
583 // / \
584 // / \
585 // V V
586 // BBBBBBBBBBBBBB RRRRRRRRRRRRRRR
587 // B B R R
588 // B K1 (uncle) B R K4 (parent) R
589 // B B R R
590 // BBBBBBBBBBBBBB RRRRRRRRRRRRRRR
591 // | | / \
592 // | | / \
593 // V V V \
594 // ------------------ RRRRRRRRRRRRR |
595 // | | R R |
596 // | black height n | R K3 (node) R |
597 // | | R R |
598 // ------------------ RRRRRRRRRRRRR /
599 // | | /
600 // | | /
601 // V V V
602 // ----------------------
603 // | |
604 // | black height n + 1 |
605 // | |
606 // ----------------------
607 */
608 11554 this->rotateSubtree(parent, parentDirection);
609 11554 parent = this->m_nodes[grandparent].getChild(parentDirection);
610 }
611 // The subtree rooted at grandparent has the following
612 // shape, assuming that parentDirection is RIGHT.
613 // There is a red child violation from parent to K4.
614 // There are no other violations at any nodes.
615 /*
616 // BBBBBBBBBBBBBBBBBBBB
617 // B B
618 // B K2 (grandparent) B
619 // B B
620 // BBBBBBBBBBBBBBBBBBBB
621 // / \
622 // / \
623 // V V
624 // BBBBBBBBBBBBBB RRRRRRRRRRRRRRR
625 // B B R R
626 // B K1 (uncle) B R K3 (parent) R
627 // B B R R
628 // BBBBBBBBBBBBBB RRRRRRRRRRRRRRR
629 // | | / \
630 // | | / \
631 // V V | V
632 // ------------------ | RRRRRRRRRRRRRR
633 // | | | R R
634 // | black height n | | R K4 R
635 // | | | R R
636 // ------------------ | RRRRRRRRRRRRRR
637 // \ | |
638 // \ | |
639 // V V V
640 // ----------------------
641 // | |
642 // | black height n + 1 |
643 // | |
644 // ----------------------
645 */
646 37532 this->rotateSubtree(grandparent, parentOppositeDirection);
647 37532 this->m_nodes[parent].m_color = Color::BLACK;
648 37532 this->m_nodes[grandparent].m_color = Color::RED;
649 // The subtree has the following shape.
650 /*
651 // BBBBBBBBBBBBBBBBBBB
652 // B B
653 // B K3 (parent) B
654 // B B
655 // BBBBBBBBBBBBBBBBBBB
656 // / \
657 // / \
658 // V V
659 // RRRRRRRRRRRRRRRRRRRR RRRRRRRRRRRRRRRR
660 // R R R R
661 // R K2 (grandparent) R R K4 R
662 // R R R R
663 // RRRRRRRRRRRRRRRRRRRR RRRRRRRRRRRRRRRR
664 // / \ | |
665 // / \ | |
666 // V V V V
667 // BBBBBBBBBBBBBBBBBB ----------------------------
668 // B B | |
669 // B K1 (uncle) B | black height n + 1 |
670 // B B | |
671 // BBBBBBBBBBBBBBBBBB ----------------------------
672 // | |
673 // | |
674 // V V
675 // ------------------
676 // | |
677 // | black height n |
678 // | |
679 // ------------------
680 */
681 37532 done = true;
682 37532 break;
683 } else {
684 // The subtree rooted at grandparent has one of four
685 // shapes, one of which is shown below. Each of the arrows
686 // to red nodes may point the other way.
687 // There is a red child violation from parent to K4.
688 // There are no other violations at any nodes.
689 /*
690 // BBBBBBBBBBBBBBBBBBBB
691 // B B
692 // B K2 (grandparent) B
693 // B B
694 // BBBBBBBBBBBBBBBBBBBB
695 // / \
696 // / \
697 // V V
698 // RRRRRRRRRRRRRR RRRRRRRRRRRRRRR
699 // R R R R
700 // R K1 (uncle) R R K3 (parent) R
701 // R R R R
702 // RRRRRRRRRRRRRR RRRRRRRRRRRRRRR
703 // \ \ / \
704 // \ \ / \
705 // \ \ / V
706 // \ \ / RRRRRRRRRRRRRR
707 // \ \ / R R
708 // \ \ / R K4 R
709 // \ \ | R R
710 // \ \ | RRRRRRRRRRRRRR
711 // \ \ | / /
712 // \ \ | / /
713 // V V V V V
714 // ----------------------------------
715 // | |
716 // | black height n |
717 // | |
718 // ----------------------------------
719 */
720 43176 this->m_nodes[parent].m_color = Color::BLACK;
721 43176 this->m_nodes[uncle].m_color = Color::BLACK;
722 43176 this->m_nodes[grandparent].m_color = Color::RED;
723 43176 node = grandparent;
724 43176 parent = this->m_nodes[node].m_parent;
725 // The tree shown above now has the following shape.
726 /*
727 // ???????????????????
728 // ? ?
729 // ? parent ?
730 // ? ?
731 // ???????????????????
732 // ^
733 // |
734 // |
735 // RRRRRRRRRRRRRRRRRRR
736 // R R
737 // R K2 (node) R
738 // R R
739 // RRRRRRRRRRRRRRRRRRR
740 // / \
741 // / \
742 // V V
743 // BBBBBBBBBBBBBB BBBBBBBBBBBBBBB
744 // B B B B
745 // B K1 (uncle) B B K3 B
746 // B B B B
747 // BBBBBBBBBBBBBB BBBBBBBBBBBBBBB
748 // \ \ / \
749 // \ \ / \
750 // \ \ / V
751 // \ \ / RRRRRRRRRRRRRR
752 // \ \ / R R
753 // \ \ / R K4 R
754 // \ \ | R R
755 // \ \ | RRRRRRRRRRRRRR
756 // \ \ | / /
757 // \ \ | / /
758 // V V V V V
759 // ----------------------------------
760 // | |
761 // | black height n |
762 // | |
763 // ----------------------------------
764 */
765
2/2
✓ Branch 0 taken 2187 times.
✓ Branch 1 taken 40989 times.
43176 if (parent == Node::NONE) {
766 // We have reached the root of the tree.
767 // Break out of the loop.
768 2187 done = true;
769 2187 break;
770 }
771 // The invariants at the top of the loop are satisfied.
772 // Continue to the next iteration.
773 }
774 }
775 76809 FW_ASSERT(done);
776 }
777 // The tree is a red-black tree.
778 78220 }
779
780 //! This function removes a node that is colored black and is a leaf node
781 //! (i.e., it has no children) and is not the root. node stores the node to
782 //! remove. It must not be NONE.
783 34335 void removeBlackLeafNode(Index node //!< The node to remove
784 ) {
785 // We assume that the tree is a red-black tree, that node is colored
786 // black, that node is a leaf node, and that node is not the root.
787 34335 auto parent = m_nodes[node].m_parent;
788 // Since node is not the root, parent is not NONE.
789 34335 auto direction = this->getDirectionFromParent(node);
790 34335 auto oppositeDirection = Node::getOppositeDirection(direction);
791 // The leaf-augmented subtree rooted at parent has this shape, assuming
792 // direction == RIGHT. We use ? to represent the unknown color (red or
793 // black) of parent.
794 /*
795 // ????????????????
796 // ? ?
797 // ? parent ?
798 // ? ?
799 // ????????????????
800 // / \
801 // / \
802 // V V
803 // ------------------ BBBBBBBBBBBB
804 // | | B B
805 // | black height 2 | B node B
806 // | | B B
807 // ------------------ BBBBBBBBBBBB
808 // / \
809 // / \
810 // V V
811 // BBBBBBBBBB BBBBBBBBBB
812 // B B B B
813 // B B B B
814 // B B B B
815 // BBBBBBBBBB BBBBBBBBBB
816 */
817 34335 this->m_nodes[parent].setChild(direction, Node::NONE);
818 // The previous step performs the deletion.
819 // The remaining steps are for rebalancing.
820 /*
821 // The leaf-augmented subtree rooted at parent looks like this,
822 // assuming direction == RIGHT:
823 //
824 // ????????????????
825 // ? ?
826 // ? parent ?
827 // ? ?
828 // ????????????????
829 // / \
830 // / \
831 // V V
832 // ------------------ BBBBBBBBBBBB
833 // | | B B
834 // | black height 2 | B B
835 // | | B B
836 // ------------------ BBBBBBBBBBBB
837 //
838 // The black height invariant is violated, because the left subtree of
839 // parent has black height 2, and the right subtree has black height 1.
840 // Therefore there is a black height violation at parent and at every
841 // node in the path from the root to parent. To restore the black
842 // height invariant, we must perform rebalancing.
843 */
844 34335 bool done = false;
845 34335 const auto capacity = this->getCapacity();
846
1/2
✓ Branch 0 taken 48733 times.
✗ Branch 1 not taken.
48733 for (FwSizeType i = 0; i < capacity; i++) {
847 // The red child constraint is satisfied. The black height
848 // constraint is violated because the leaf-augmented subtree rooted
849 // at parent has this shape, assuming direction == RIGHT. i is the
850 // loop index. Note that this diagram agrees with the previous one
851 // when i = 0.
852 /*
853 // ????????????????
854 // ? ?
855 // ? parent ?
856 // ? ?
857 // ????????????????
858 // / \
859 // / \
860 // V V
861 // ---------------------- ----------------------
862 // | | | |
863 // | black height i + 2 | | black height i + 1 |
864 // | | | |
865 // ---------------------- ----------------------
866 //
867 // The black height constraint would be satisfied if the child of
868 // parent in the direction `direction` were replaced with a red-black
869 // tree of black height i + 2.
870 */
871
1/1
✓ Branch 4 taken 48733 times.
48733 auto sibling = this->m_nodes[parent].getChild(oppositeDirection);
872
1/1
✓ Branch 3 taken 48733 times.
48733 auto closeNephew = this->m_nodes[sibling].getChild(direction);
873
1/1
✓ Branch 4 taken 48733 times.
48733 auto distantNephew = this->m_nodes[sibling].getChild(oppositeDirection);
874 // The leaf-augmented subtree rooted at parent has this shape
875 // (direction == RIGHT). If distantNephew or closeNephew are leaves
876 // in the leaf-augmented tree, then K1 and K4 are names for the
877 // nodes; they are not keys in the original tree.
878 // There is a black height violation at parent.
879 /*
880 // ???????????????????
881 // ? ?
882 // ? K6 (parent) ?
883 // ? ?
884 // ???????????????????
885 // / \
886 // / \
887 // V V
888 // ????????????????? ----------------------
889 // ? ? | |
890 // ? K2 (sibling) ? | black height i + 1 |
891 // ? ? | |
892 // ????????????????? ----------------------
893 // / \
894 // / \
895 // V V
896 // ???????????????????? ????????????????????
897 // ? ? ? ?
898 // ? K1 (distantNephew) ? ? K4 (closeNephew) ?
899 // ? ? ? ?
900 // ???????????????????? ????????????????????
901 // | | | |
902 // | | | |
903 // V V V V
904 // ------------------------- -------------------------
905 // | | | |
906 // | black height i + 2 - | | black height i + 2 - |
907 // | number of black nodes | | number of black nodes |
908 // | in { K1, K2 } | | in { K2, K4 } |
909 // | | | |
910 // ------------------------- -------------------------
911 */
912
3/3
✓ Branch 2 taken 48733 times.
✓ Branch 4 taken 11486 times.
✓ Branch 5 taken 37247 times.
48733 if (this->getNodeColor(sibling) == Color::RED) {
913 // The leaf-augmented subtree rooted at parent has this shape.
914 // There is a black height violation at parent.
915 /*
916 // BBBBBBBBBBBBBBBBBBB
917 // B B
918 // B K6 (parent) B
919 // B B
920 // BBBBBBBBBBBBBBBBBBB
921 // / \
922 // / \
923 // V V
924 // RRRRRRRRRRRRRRRRR ----------------------
925 // R R | |
926 // R K2 (sibling) R | black height i + 1 |
927 // R R | |
928 // RRRRRRRRRRRRRRRRR ----------------------
929 // / \
930 // / \
931 // V V
932 // BBBBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBBBBBB
933 // B B B B
934 // B K1 (distantNephew) B B K4 (closeNephew) B
935 // B B B B
936 // BBBBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBBBBBB
937 // | | | |
938 // | | | |
939 // V V V V
940 // ------------------------ ------------------------
941 // | | | |
942 // | black height i + 1 | | black height i + 1 |
943 // | | | |
944 // ------------------------ ------------------------
945 */
946
1/1
✓ Branch 2 taken 11486 times.
11486 this->rotateSubtree(parent, direction);
947
1/1
✓ Branch 3 taken 11486 times.
11486 this->m_nodes[parent].m_color = Color::RED;
948
1/1
✓ Branch 3 taken 11486 times.
11486 this->m_nodes[sibling].m_color = Color::BLACK;
949 11486 sibling = closeNephew;
950
1/1
✓ Branch 3 taken 11486 times.
11486 closeNephew = this->m_nodes[sibling].getChild(direction);
951
1/1
✓ Branch 3 taken 11486 times.
11486 distantNephew = this->m_nodes[sibling].getChild(oppositeDirection);
952 // The subtree has this shape:
953 /*
954 // BBBBBBBBBBBBBBBB
955 // B B
956 // B K2 B
957 // B B
958 // BBBBBBBBBBBBBBBB
959 // / \
960 // / \
961 // / \
962 // V V
963 // BBBBBBBBBBBBBB RRRRRRRRRRRRRRRRRRR
964 // B B R R
965 // B K1 B R K6 (parent) R
966 // B B R R
967 // BBBBBBBBBBBBBB RRRRRRRRRRRRRRRRRRR
968 // | | / \
969 // | | / \
970 // V V V V
971 // ------------------------ BBBBBBBBBBBBBBBBBB ------------------------
972 // | | B B | |
973 // | black height i + 1 | B K4 (sibling) B | black height i + 1 |
974 // | | B B | |
975 // ------------------------ BBBBBBBBBBBBBBBBBB ------------------------
976 // / \
977 // / \
978 // V V
979 // -------------------------------- --------------------------------
980 // | | | |
981 // | black height i + 1 | | black height i + 1 |
982 // | with root K3 (distantNephew) | | with root K5 (closeNephew) |
983 // | | | |
984 // -------------------------------- --------------------------------
985 */
986
3/3
✓ Branch 2 taken 11486 times.
✓ Branch 4 taken 5352 times.
✓ Branch 5 taken 6134 times.
11486 if (this->getNodeColor(distantNephew) == Color::RED) {
987 // The subtree has this shape:
988 /*
989 // BBBBBBBBBBBBBBBB
990 // B B
991 // B K2 B
992 // B B
993 // BBBBBBBBBBBBBBBB
994 // / \
995 // / \
996 // / \
997 // V V
998 // BBBBBBBBBBBBBB RRRRRRRRRRRRRRRRRRR
999 // B B R R
1000 // B K1 B R K6 (parent) R
1001 // B B R R
1002 // BBBBBBBBBBBBBB RRRRRRRRRRRRRRRRRRR
1003 // | | / \
1004 // | | / \
1005 // V V V V
1006 // ------------------------ BBBBBBBBBBBBBBBBBB ------------------------
1007 // | | B B | |
1008 // | black height i + 1 | B K4 (sibling) B | black height i + 1 |
1009 // | | B B | |
1010 // ------------------------ BBBBBBBBBBBBBBBBBB ------------------------
1011 // / \
1012 // / \
1013 // V V
1014 // RRRRRRRRRRRRRRRRRRRRRRRRRR ------------------------
1015 // R R | |
1016 // R K3 (distantNephew) R | black height i + 1 |
1017 // R R | |
1018 // RRRRRRRRRRRRRRRRRRRRRRRRRR ------------------------
1019 // | |
1020 // | |
1021 // V V
1022 // ------------------------
1023 // | |
1024 // | black height i + 1 |
1025 // | |
1026 // ------------------------
1027 */
1028
1/1
✓ Branch 2 taken 5352 times.
5352 this->removeBlackLeafNodeHelper2(parent, sibling, distantNephew, direction);
1029 // The subtree has this shape. The entire tree is a valid red-black tree.
1030 /*
1031 // BBBBBBBBBBBBBBBB
1032 // B B
1033 // B K2 B
1034 // B B
1035 // BBBBBBBBBBBBBBBB
1036 // / \
1037 // / \
1038 // / \
1039 // V V
1040 // BBBBBBBBBBBBBB RRRRRRRRRRRRRRRRRRR
1041 // B B R R
1042 // B K1 B R K4 (sibling) R
1043 // B B R R
1044 // BBBBBBBBBBBBBB RRRRRRRRRRRRRRRRRRR
1045 // | | / \
1046 // | | / \
1047 // V V V V
1048 // ------------------------ BBBBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBB
1049 // | | B B B B
1050 // | black height i + 1 | B K3 (distantNephew) B B K6 (parent) B
1051 // | | B B B B
1052 // ------------------------ BBBBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBB
1053 // | | | |
1054 // | | | |
1055 // V V V V
1056 // ------------------------ ------------------------
1057 // | | | |
1058 // | black height i + 1 | | black height i + 1 |
1059 // | | | |
1060 // ------------------------ ------------------------
1061 */
1062 5352 done = true;
1063 5352 break;
1064
3/3
✓ Branch 2 taken 6134 times.
✓ Branch 4 taken 2306 times.
✓ Branch 5 taken 3828 times.
6134 } else if (this->getNodeColor(closeNephew) == Color::RED) {
1065 // The subtree has this shape:
1066 /*
1067 // BBBBBBBBBBBBBBBB
1068 // B B
1069 // B K2 B
1070 // B B
1071 // BBBBBBBBBBBBBBBB
1072 // / \
1073 // / \
1074 // / \
1075 // V V
1076 // BBBBBBBBBBBBBB RRRRRRRRRRRRRRRRRRR
1077 // B B R R
1078 // B K1 B R K6 (parent) R
1079 // B B R R
1080 // BBBBBBBBBBBBBB RRRRRRRRRRRRRRRRRRR
1081 // | | / \
1082 // | | / \
1083 // V V V V
1084 // ------------------------ BBBBBBBBBBBBBBBBBB ------------------------
1085 // | | B B | |
1086 // | black height i + 1 | B K4 (sibling) B | black height i + 1 |
1087 // | | B B | |
1088 // ------------------------ BBBBBBBBBBBBBBBBBB ------------------------
1089 // / \
1090 // / \
1091 // V V
1092 // ------------------------ RRRRRRRRRRRRRRRRRRRRRRRRRR
1093 // | | R R
1094 // | black height i + 1 | R K5 (closeNephew) R
1095 // | | R R
1096 // ------------------------ RRRRRRRRRRRRRRRRRRRRRRRRRR
1097 // | |
1098 // | |
1099 // V V
1100 // ------------------------
1101 // | |
1102 // | black height i + 1 |
1103 // | |
1104 // ------------------------
1105 */
1106
1/1
✓ Branch 2 taken 2306 times.
2306 this->removeBlackLeafNodeHelper1(closeNephew, oppositeDirection, sibling, distantNephew);
1107 // The subtree has this shape:
1108 /*
1109 // BBBBBBBBBBBBBBBB
1110 // B B
1111 // B K2 B
1112 // B B
1113 // BBBBBBBBBBBBBBBB
1114 // / \
1115 // / \
1116 // / \
1117 // V V
1118 // BBBBBBBBBBBBBB RRRRRRRRRRRRRRRRRRR
1119 // B B R R
1120 // B K1 B R K6 (parent) R
1121 // B B R R
1122 // BBBBBBBBBBBBBB RRRRRRRRRRRRRRRRRRR
1123 // | | / \
1124 // | | / \
1125 // V V V V
1126 // ------------------------ BBBBBBBBBBBBBBBBBB ------------------------
1127 // | | B B | |
1128 // | black height i + 1 | B K5 (sibling) B | black height i + 1 |
1129 // | | B B | |
1130 // ------------------------ BBBBBBBBBBBBBBBBBB ------------------------
1131 // / \
1132 // / \
1133 // V V
1134 // RRRRRRRRRRRRRRRRRRRRRRRRRR ------------------------
1135 // R R | |
1136 // R K4 (distantNephew) R | black height i + 1 |
1137 // R R | |
1138 // RRRRRRRRRRRRRRRRRRRRRRRRRR ------------------------
1139 // | |
1140 // | |
1141 // V V
1142 // ------------------------
1143 // | |
1144 // | black height i + 1 |
1145 // | |
1146 // -----------------------
1147 */
1148
1/1
✓ Branch 2 taken 2306 times.
2306 this->removeBlackLeafNodeHelper2(parent, sibling, distantNephew, direction);
1149 // The subtree has this shape. The entire tree is a valid red-black tree.
1150 /*
1151 // BBBBBBBBBBBBBBBB
1152 // B B
1153 // B K2 B
1154 // B B
1155 // BBBBBBBBBBBBBBBB
1156 // / \
1157 // / \
1158 // / \
1159 // V V
1160 // BBBBBBBBBBBBBB RRRRRRRRRRRRRRRRRRRR
1161 // B B R R
1162 // B K1 B R K5 (sibling) R
1163 // B B R R
1164 // BBBBBBBBBBBBBB RRRRRRRRRRRRRRRRRRRR
1165 // | | / \
1166 // | | / \
1167 // V V V V
1168 // ------------------------ BBBBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBB
1169 // | | B B B B
1170 // | black height i + 1 | B K4 (distantNephew) B B K6 (parent) B
1171 // | | B B B B
1172 // ------------------------ BBBBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBB
1173 // | | | |
1174 // | | | |
1175 // V V V V
1176 // ------------------------ ------------------------
1177 // | | | |
1178 // | black height i + 1 | | black height i + 1 |
1179 // | | | |
1180 // ------------------------ ------------------------
1181 */
1182 2306 done = true;
1183 2306 break;
1184 } else {
1185
1/1
✓ Branch 3 taken 3828 times.
3828 this->m_nodes[sibling].m_color = Color::RED;
1186
1/1
✓ Branch 3 taken 3828 times.
3828 this->m_nodes[parent].m_color = Color::BLACK;
1187 // The subtree has this shape. The entire tree is a valid red-black tree.
1188 /*
1189 // BBBBBBBBBBBBBBBB
1190 // B B
1191 // B K2 B
1192 // B B
1193 // BBBBBBBBBBBBBBBB
1194 // / \
1195 // / \
1196 // / \
1197 // V V
1198 // BBBBBBBBBBBBBB BBBBBBBBBBBBBBBBBBB
1199 // B B B B
1200 // B K1 B B K6 (parent) B
1201 // B B B B
1202 // BBBBBBBBBBBBBB BBBBBBBBBBBBBBBBBBB
1203 // | | / \
1204 // | | / \
1205 // V V V V
1206 // ------------------------ RRRRRRRRRRRRRRRRRR ------------------------
1207 // | | R R | |
1208 // | black height i + 1 | R K4 (sibling) R | black height i + 1 |
1209 // | | R R | |
1210 // ------------------------ RRRRRRRRRRRRRRRRRR ------------------------
1211 // / \
1212 // / \
1213 // V V
1214 // BBBBBBBBBBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBBBBBBBBBB
1215 // B B B B
1216 // B K3 (distantNephew) B B K5 (closeNephew) B
1217 // B B B B
1218 // BBBBBBBBBBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBBBBBBBBBB
1219 // | | | |
1220 // | | | |
1221 // V V V V
1222 // ------------------------ ------------------------
1223 // | | | |
1224 // | black height i | | black height i |
1225 // | | | |
1226 // ------------------------ ------------------------
1227 */
1228 3828 done = true;
1229 3828 break;
1230 }
1231
3/3
✓ Branch 2 taken 37247 times.
✓ Branch 4 taken 8704 times.
✓ Branch 5 taken 28543 times.
37247 } else if (this->getNodeColor(distantNephew) == Color::RED) {
1232 // The leaf-augmented subtree rooted at parent has this shape.
1233 // There is a black height violation at parent.
1234 /*
1235 // ???????????????????
1236 // ? ?
1237 // ? K6 (parent) ?
1238 // ? ?
1239 // ???????????????????
1240 // / \
1241 // / \
1242 // V V
1243 // BBBBBBBBBBBBBBBBB ----------------------
1244 // B B | |
1245 // B K2 (sibling) B | black height i + 1 |
1246 // B B | |
1247 // BBBBBBBBBBBBBBBBB ----------------------
1248 // / \
1249 // / \
1250 // V V
1251 // RRRRRRRRRRRRRRRRRRRR ------------------------
1252 // R R | |
1253 // R K1 (distantNephew) R | black height i + 1 |
1254 // R R | |
1255 // RRRRRRRRRRRRRRRRRRRR ------------------------
1256 // | |
1257 // | |
1258 // V V
1259 // ------------------------
1260 // | |
1261 // | black height i + 1 |
1262 // | |
1263 // ------------------------
1264 */
1265
1/1
✓ Branch 2 taken 8704 times.
8704 this->removeBlackLeafNodeHelper2(parent, sibling, distantNephew, direction);
1266 // The subtree has this shape. The entire tree is a valid red-black tree.
1267 /*
1268 // BBBBBBBBBBBBBBBBB
1269 // B B
1270 // B K2 (sibling) B
1271 // B B
1272 // BBBBBBBBBBBBBBBBB
1273 // / \
1274 // / \
1275 // V V
1276 // BBBBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBBB
1277 // B B B B
1278 // B K1 (distantNephew) B B K6 (parent) B
1279 // B B B B
1280 // RRRRRRRRRRRRRRRRRRRR BBBBBBBBBBBBBBBBB
1281 // | | | |
1282 // | | | |
1283 // V V V V
1284 // ------------------------ ------------------------
1285 // | | | |
1286 // | black height i + 1 | | black height i + 1 |
1287 // | | | |
1288 // ------------------------ ------------------------
1289 */
1290 8704 done = true;
1291 8704 break;
1292
3/3
✓ Branch 2 taken 28543 times.
✓ Branch 4 taken 3446 times.
✓ Branch 5 taken 25097 times.
28543 } else if (this->getNodeColor(closeNephew) == Color::RED) {
1293 // The leaf-augmented subtree rooted at parent has this shape.
1294 // There is a black height violation at parent.
1295 /*
1296 // ???????????????????
1297 // ? ?
1298 // ? K6 (parent) ?
1299 // ? ?
1300 // ???????????????????
1301 // / \
1302 // / \
1303 // V V
1304 // BBBBBBBBBBBBBBBBB ----------------------
1305 // B B | |
1306 // B K2 (sibling) B | black height i + 1 |
1307 // B B | |
1308 // BBBBBBBBBBBBBBBBB ----------------------
1309 // / \
1310 // / \
1311 // V V
1312 // ------------------------ RRRRRRRRRRRRRRRRRRRR
1313 // | | R R
1314 // | black height i + 1 | R K4 (closeNephew) R
1315 // | | R R
1316 // ------------------------ RRRRRRRRRRRRRRRRRRRR
1317 // | |
1318 // | |
1319 // V V
1320 // ------------------------
1321 // | |
1322 // | black height i + 1 |
1323 // | |
1324 // ------------------------
1325 */
1326
1/1
✓ Branch 2 taken 3446 times.
3446 this->removeBlackLeafNodeHelper1(closeNephew, oppositeDirection, sibling, distantNephew);
1327 // The subtree has this shape:
1328 /*
1329 // ???????????????????
1330 // ? ?
1331 // ? K6 (parent) ?
1332 // ? ?
1333 // ???????????????????
1334 // / \
1335 // / \
1336 // V V
1337 // BBBBBBBBBBBBBBBBB ----------------------
1338 // B B | |
1339 // B K4 (sibling) B | black height i + 1 |
1340 // B B | |
1341 // BBBBBBBBBBBBBBBBB ----------------------
1342 // / \
1343 // / \
1344 // V V
1345 // RRRRRRRRRRRRRRRRRRRR ------------------------
1346 // R R | |
1347 // R K2 (distantNephew) R | black height i + 1 |
1348 // R R | |
1349 // RRRRRRRRRRRRRRRRRRRR ------------------------
1350 // | |
1351 // | |
1352 // V V
1353 // ------------------------
1354 // | |
1355 // | black height i + 1 |
1356 // | |
1357 // ------------------------
1358 */
1359
1/1
✓ Branch 2 taken 3446 times.
3446 this->removeBlackLeafNodeHelper2(parent, sibling, distantNephew, direction);
1360 // The subtree has this shape. The entire tree is a valid red-black tree.
1361 /*
1362 // BBBBBBBBBBBBBBBBB
1363 // B B
1364 // B K4 (sibling) B
1365 // B B
1366 // BBBBBBBBBBBBBBBBB
1367 // / \
1368 // / \
1369 // V V
1370 // BBBBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBBB
1371 // B B B B
1372 // B K2 (distantNephew) B B K6 (parent) B
1373 // B B B B
1374 // RRRRRRRRRRRRRRRRRRRR BBBBBBBBBBBBBBBBB
1375 // | | | |
1376 // | | | |
1377 // V V V V
1378 // ------------------------ ------------------------
1379 // | | | |
1380 // | black height i + 1 | | black height i + 1 |
1381 // | | | |
1382 // ------------------------ ------------------------
1383 */
1384 3446 done = true;
1385 3446 break;
1386
3/3
✓ Branch 2 taken 25097 times.
✓ Branch 4 taken 9035 times.
✓ Branch 5 taken 16062 times.
25097 } else if (this->getNodeColor(parent) == Color::RED) {
1387
1/1
✓ Branch 3 taken 9035 times.
9035 this->m_nodes[sibling].m_color = Color::RED;
1388
1/1
✓ Branch 3 taken 9035 times.
9035 this->m_nodes[parent].m_color = Color::BLACK;
1389 // The leaf-augmented tree rooted at parent has this shape.
1390 // The entire tree is a valid red-black tree.
1391 /*
1392 // BBBBBBBBBBBBBBBBBBB
1393 // B B
1394 // B K6 (parent) B
1395 // B B
1396 // BBBBBBBBBBBBBBBBBBB
1397 // / \
1398 // / \
1399 // V V
1400 // RRRRRRRRRRRRRRRRR ----------------------
1401 // R R | |
1402 // R K2 (sibling) R | black height i + 1 |
1403 // R R | |
1404 // RRRRRRRRRRRRRRRRR ----------------------
1405 // / \
1406 // / \
1407 // V V
1408 // BBBBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBBBBBB
1409 // B B B B
1410 // B K1 (distantNephew) B B K4 (closeNephew) B
1411 // B B B B
1412 // BBBBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBBBBBB
1413 // | | | |
1414 // | | | |
1415 // V V V V
1416 // ------------------------ ------------------------
1417 // | | | |
1418 // | black height i | | black height i |
1419 // | | | |
1420 // ------------------------ ------------------------
1421 */
1422 9035 done = true;
1423 9035 break;
1424 } else {
1425 // The leaf-augmented subtree rooted at parent has this shape.
1426 /*
1427 // BBBBBBBBBBBBBBBBBBB
1428 // B B
1429 // B K6 (parent) B
1430 // B B
1431 // BBBBBBBBBBBBBBBBBBB
1432 // / \
1433 // / \
1434 // V V
1435 // BBBBBBBBBBBBBBBBB ----------------------
1436 // B B | |
1437 // B K2 (sibling) B | black height i + 1 |
1438 // B B | |
1439 // BBBBBBBBBBBBBBBBB ----------------------
1440 // / \
1441 // / \
1442 // V V
1443 // BBBBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBBBBBB
1444 // B B B B
1445 // B K1 (distantNephew) B B K4 (closeNephew) B
1446 // B B B B
1447 // BBBBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBBBBBB
1448 // | | | |
1449 // | | | |
1450 // V V V V
1451 // ------------------------ ------------------------
1452 // | | | |
1453 // | black height i | | black height i |
1454 // | | | |
1455 // ------------------------ ------------------------
1456 */
1457
1/1
✓ Branch 3 taken 16062 times.
16062 this->m_nodes[sibling].m_color = Color::RED;
1458 16062 node = parent;
1459
1/1
✓ Branch 3 taken 16062 times.
16062 parent = this->m_nodes[node].m_parent;
1460
2/2
✓ Branch 0 taken 1664 times.
✓ Branch 1 taken 14398 times.
16062 if (parent == Node::NONE) {
1461 // The entire leaf-augmented tree has this shape.
1462 // The entire tree is a valid red-black tree.
1463 /*
1464 // BBBBBBBBBBBBBBBBBBB
1465 // B B
1466 // B K6 (node) B
1467 // B B
1468 // BBBBBBBBBBBBBBBBBBB
1469 // / \
1470 // / \
1471 // V V
1472 // RRRRRRRRRRRRRRRRR ----------------------
1473 // R R | |
1474 // R K2 (sibling) R | black height i + 1 |
1475 // R R | |
1476 // RRRRRRRRRRRRRRRRR ----------------------
1477 // / \
1478 // / \
1479 // V V
1480 // BBBBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBBBBBB
1481 // B B B B
1482 // B K1 (distantNephew) B B K4 (closeNephew) B
1483 // B B B B
1484 // BBBBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBBBBBB
1485 // | | | |
1486 // | | | |
1487 // V V V V
1488 // ------------------------ ------------------------
1489 // | | | |
1490 // | black height i | | black height i |
1491 // | | | |
1492 // ------------------------ ------------------------
1493 */
1494 1664 done = true;
1495 1664 break;
1496 } else {
1497
1/1
✓ Branch 2 taken 14398 times.
14398 direction = getDirectionFromParent(node);
1498 14398 oppositeDirection = Node::getOppositeDirection(direction);
1499 // The leaf-augmented subtree rooted at parent has this
1500 // shape, assuming that direction == RIGHT:
1501 /*
1502 // ??????????????
1503 // ? ?
1504 // ? parent ?
1505 // ? ?
1506 // ??????????????
1507 // / \
1508 // / \
1509 // V V
1510 // ------------------------ BBBBBBBBBBBBBBBBBBB
1511 // | | B B
1512 // | black height i + 3 | B K6 (node) B
1513 // | | B B
1514 // ------------------------ BBBBBBBBBBBBBBBBBBB
1515 // / \
1516 // / \
1517 // V V
1518 // RRRRRRRRRRRRRRRRR ----------------------
1519 // R R | |
1520 // R K2 (sibling) R | black height i + 1 |
1521 // R R | |
1522 // RRRRRRRRRRRRRRRRR ----------------------
1523 // / \
1524 // / \
1525 // V V
1526 // BBBBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBBBBBB
1527 // B B B B
1528 // B K1 (distantNephew) B B K4 (closeNephew) B
1529 // B B B B
1530 // BBBBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBBBBBB
1531 // | | | |
1532 // | | | |
1533 // V V V V
1534 // ------------------------ ------------------------
1535 // | | | |
1536 // | black height i | | black height i |
1537 // | | | |
1538 // ------------------------ ------------------------
1539 //
1540 // There is a black height violation at parent because the
1541 // left subtree of parent has black height i + 3, and the
1542 // right subtree has black height i + 2. So we need at
1543 // least one more loop iteration. After incrementing i, the
1544 // invariant at the top of the loop is satisfied.
1545 */
1546 }
1547 }
1548 }
1549 34335 FW_ASSERT(done);
1550 // The tree is a valid red-black tree.
1551 34335 }
1552
1553 //! This is a helper function for removeBlackLeafNode. sibling and
1554 //! distantNephew are in-out parameters (they are both read and written).
1555 5752 void removeBlackLeafNodeHelper1(Index closeNephew, //!< The close nephew (input)
1556 Direction oppositeDirection, //!< The opposite direction (input)
1557 Index& sibling, //!< The sibling (input and output)
1558 Index& distantNephew //!< The distant nephew (input and output)
1559 ) {
1560 5752 FW_ASSERT(sibling != Node::NONE);
1561 5752 FW_ASSERT(closeNephew != Node::NONE);
1562 5752 this->rotateSubtree(sibling, oppositeDirection);
1563 5752 this->m_nodes[sibling].m_color = Color::RED;
1564 5752 this->m_nodes[closeNephew].m_color = Color::BLACK;
1565 5752 distantNephew = sibling;
1566 5752 sibling = closeNephew;
1567 5752 }
1568
1569 //! This is a helper function for removeBlackLeafNode.
1570 19808 void removeBlackLeafNodeHelper2(Index parent, //!< The parent
1571 Index sibling, //!< The sibling
1572 Index distantNephew, //!< The distant nephew
1573 Direction direction //!< The direction
1574 ) {
1575 19808 this->rotateSubtree(parent, direction);
1576 19808 this->m_nodes[sibling].m_color = this->m_nodes[parent].m_color;
1577 19808 this->m_nodes[parent].m_color = Color::BLACK;
1578 19808 this->m_nodes[distantNephew].m_color = Color::BLACK;
1579 19808 }
1580
1581 //! This function removes a node of the tree. On entry, node stores the key
1582 //! and value to be removed. It must not be NONE. On return, removedNode
1583 //! stores the node that was actually removed.
1584 62668 void removeNode(Index node, //!< The node to remove (input)
1585 Index& removedNode //!< The node actually removed (output)
1586 ) {
1587
6/6
✓ Branch 5 taken 684 times.
✓ Branch 6 taken 61984 times.
✓ Branch 12 taken 344 times.
✓ Branch 13 taken 340 times.
✓ Branch 14 taken 344 times.
✓ Branch 15 taken 62324 times.
62668 if ((this->m_nodes[node].m_left) != Node::NONE && (this->m_nodes[node].m_right != Node::NONE)) {
1588 344 this->removeNodeWithTwoChildren(node, removedNode);
1589 } else {
1590 62324 this->removeNodeWithAtMostOneChild(node);
1591 62324 removedNode = node;
1592 }
1593 62668 }
1594
1595 //! This function removes a node of the tree with at most one child. On
1596 //! entry, node stores the node to be removed. It must not be NONE.
1597 62668 void removeNodeWithAtMostOneChild(Index node //!< The node to remove
1598 ) {
1599 62668 FW_ASSERT(node != Node::NONE);
1600
2/2
✓ Branch 5 taken 340 times.
✓ Branch 6 taken 62328 times.
62668 if (this->m_nodes[node].m_left != Node::NONE) {
1601 340 this->removeNodeWithOneChild(node, Direction::LEFT);
1602
2/2
✓ Branch 5 taken 26118 times.
✓ Branch 6 taken 36210 times.
62328 } else if (this->m_nodes[node].m_right != Node::NONE) {
1603 26118 this->removeNodeWithOneChild(node, Direction::RIGHT);
1604
2/2
✓ Branch 2 taken 871 times.
✓ Branch 3 taken 35339 times.
36210 } else if (node == this->m_root) {
1605 871 this->m_root = Node::NONE;
1606
2/2
✓ Branch 5 taken 1004 times.
✓ Branch 6 taken 34335 times.
35339 } else if (this->m_nodes[node].m_color == Color::RED) {
1607 1004 this->removeRedLeafNode(node);
1608 } else {
1609 34335 this->removeBlackLeafNode(node);
1610 }
1611 62668 }
1612
1613 //! This function removes a node of the tree with exactly one child. node
1614 //! stores the node to remove. It must not be NONE. direction stores the
1615 //! direction of the child.
1616 26458 void removeNodeWithOneChild(Index node, //!< The node
1617 Direction direction //!< The direction of the child
1618 ) {
1619 // Since the tree is a valid red-black tree, a node with exactly one
1620 // child must be black, and the child must be red.
1621 26458 FW_ASSERT(this->m_nodes[node].m_color == Color::BLACK,
1622 static_cast<FwAssertArgType>(this->m_nodes[node].m_color));
1623 26458 const auto parent = this->m_nodes[node].m_parent;
1624 26458 const auto child = this->m_nodes[node].getChild(direction);
1625 26458 FW_ASSERT(this->m_nodes[child].m_color == Color::RED,
1626 static_cast<FwAssertArgType>(this->m_nodes[node].m_color));
1627
2/2
✓ Branch 0 taken 697 times.
✓ Branch 1 taken 25761 times.
26458 if (parent == Node::NONE) {
1628 697 this->m_root = child;
1629 } else {
1630 25761 const auto parentDirection = this->getDirectionFromParent(node);
1631 25761 this->m_nodes[parent].setChild(parentDirection, child);
1632 }
1633 26458 this->m_nodes[child].m_parent = parent;
1634 26458 this->m_nodes[child].m_color = Color::BLACK;
1635 26458 }
1636
1637 //! This function removes a node of the tree that has two children. On
1638 //! entry, node stores the key and value to be removed. It must not be NONE,
1639 //! and it must have two children. On return, removedNode stores the node
1640 //! that was actually removed.
1641 344 void removeNodeWithTwoChildren(Index node, //!< The node to remove (input)
1642 Index& removedNode //!< The node actually removed (output)
1643 ) {
1644 344 const auto rightChild = this->m_nodes[node].m_right;
1645 344 removedNode = this->getOuterNodeUnder(rightChild, Direction::LEFT);
1646 344 this->m_nodes[node].m_entry = this->m_nodes[removedNode].m_entry;
1647 344 this->removeNodeWithAtMostOneChild(removedNode);
1648 344 }
1649
1650 //! This function removes a node that is colored red and is a leaf node
1651 //! (i.e., it has no children) and is not the root. node stores the node to
1652 //! remove. It must not be NONE.
1653 1004 void removeRedLeafNode(Index node //!< The node to remove
1654 ) {
1655 1004 FW_ASSERT(node != this->m_root);
1656 1004 const auto& nodeObj = this->m_nodes[node];
1657 1004 FW_ASSERT(nodeObj.m_color == Color::RED);
1658 1004 FW_ASSERT(nodeObj.m_left == Node::NONE);
1659 1004 FW_ASSERT(nodeObj.m_right == Node::NONE);
1660 1004 const auto parent = nodeObj.m_parent;
1661 1004 const auto direction = this->getDirectionFromParent(node);
1662 1004 this->m_nodes[parent].setChild(direction, Node::NONE);
1663 1004 }
1664
1665 //! This function performs a left or right rotation on the subtree whose
1666 //! root is node. The following invariants must hold on entry to this
1667 //! function, or an assertion failure will occur:
1668 //!
1669 //! 1. node must not be NONE.
1670 //!
1671 //! 2. The child of node in the direction opposite direction must not be
1672 //! NONE.
1673 86132 void rotateSubtree(Index node, //!< The node index
1674 Direction direction //!< The direction
1675 ) {
1676 // We assume that the tree is a binary search tree (BST).
1677 86132 FW_ASSERT(node != Node::NONE);
1678 86132 const auto parent = this->m_nodes[node].m_parent;
1679 86132 const auto oppositeDirection = Node::getOppositeDirection(direction);
1680 86132 const auto newRoot = this->m_nodes[node].getChild(oppositeDirection);
1681 86132 FW_ASSERT(newRoot != Node::NONE);
1682 86132 const auto newChild = this->m_nodes[newRoot].getChild(direction);
1683 86132 this->m_nodes[node].setChild(oppositeDirection, newChild);
1684
2/2
✓ Branch 0 taken 39761 times.
✓ Branch 1 taken 46371 times.
86132 if (newChild != Node::NONE) {
1685 39761 this->m_nodes[newChild].m_parent = node;
1686 }
1687 86132 this->m_nodes[newRoot].setChild(direction, node);
1688 86132 this->m_nodes[newRoot].m_parent = parent;
1689
2/2
✓ Branch 0 taken 81785 times.
✓ Branch 1 taken 4347 times.
86132 if (parent != Node::NONE) {
1690 81785 const auto parentDirection = getDirectionFromParent(node);
1691 81785 this->m_nodes[parent].setChild(parentDirection, newRoot);
1692 } else {
1693 4347 this->m_root = newRoot;
1694 }
1695 86132 this->m_nodes[node].m_parent = newRoot;
1696 // The tree is a BST.
1697 86132 }
1698
1699 private:
1700 // ----------------------------------------------------------------------
1701 // Private member variables
1702 // ----------------------------------------------------------------------
1703
1704 //! The array for storing the tree nodes
1705 Nodes m_nodes = {};
1706
1707 //! The stack of indices of free nodes. The indices point into m_nodes.
1708 FreeNodes m_freeNodes = {};
1709
1710 //! The index of the root node
1711 Index m_root = Node::NONE;
1712 };
1713
1714 } // namespace Fw
1715
1716 #endif
1717