Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qrbtree_p.h
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5#ifndef QRBTREE_P_H
6#define QRBTREE_P_H
7
8//
9// W A R N I N G
10// -------------
11//
12// This file is not part of the Qt API. It exists purely as an
13// implementation detail. This header file may change from version to
14// version without notice, or even be removed.
15//
16// We mean it.
17//
18
19#include <QtGui/private/qtguiglobal_p.h>
20
21QT_BEGIN_NAMESPACE
22
23template <class T>
24struct QRBTree
25{
26 struct Node
27 {
28 inline Node() : parent(nullptr), left(nullptr), right(nullptr), red(true) { }
29 inline ~Node() {if (left) delete left; if (right) delete right;}
30 T data;
31 Node *parent;
32 Node *left;
33 Node *right;
34 bool red;
35 };
36
37 inline QRBTree() : root(nullptr), freeList(nullptr) { }
38 inline ~QRBTree();
39
40 inline void clear();
41
42 void attachBefore(Node *parent, Node *child);
43 void attachAfter(Node *parent, Node *child);
44
45 inline Node *front(Node *node) const;
46 inline Node *back(Node *node) const;
47 Node *next(Node *node) const;
48 Node *previous(Node *node) const;
49
50 inline void deleteNode(Node *&node);
51 inline Node *newNode();
52
53 // Return 1 if 'left' comes after 'right', 0 if equal, and -1 otherwise.
54 // 'left' and 'right' cannot be null.
55 int order(Node *left, Node *right);
56 inline bool validate() const;
57
58private:
59 void rotateLeft(Node *node);
60 void rotateRight(Node *node);
61 void update(Node *node);
62
63 inline void attachLeft(Node *parent, Node *child);
64 inline void attachRight(Node *parent, Node *child);
65
66 int blackDepth(Node *top) const;
67 bool checkRedBlackProperty(Node *top) const;
68
69 void swapNodes(Node *n1, Node *n2);
70 void detach(Node *node);
71
72 // 'node' must be black. rebalance will reduce the depth of black nodes by one in the sibling tree.
73 void rebalance(Node *node);
74
75public:
76 Node *root;
77private:
78 Node *freeList;
79};
80
81template <class T>
82inline QRBTree<T>::~QRBTree()
83{
84 clear();
85 while (freeList) {
86 // Avoid recursively calling the destructor, as this list may become large.
87 Node *next = freeList->right;
88 freeList->right = nullptr;
89 delete freeList;
90 freeList = next;
91 }
92}
93
94template <class T>
95inline void QRBTree<T>::clear()
96{
97 if (root)
98 delete root;
99 root = nullptr;
100}
101
102template <class T>
103void QRBTree<T>::rotateLeft(Node *node)
104{
105 // | | //
106 // N B //
107 // / \ / \ //
108 // A B ---> N D //
109 // / \ / \ //
110 // C D A C //
111
112 Node *&ref = (node->parent ? (node == node->parent->left ? node->parent->left : node->parent->right) : root);
113 ref = node->right;
114 node->right->parent = node->parent;
115
116 // : //
117 // N //
118 // / :| //
119 // A B //
120 // / \ //
121 // C D //
122
123 node->right = ref->left;
124 if (ref->left)
125 ref->left->parent = node;
126
127 // : | //
128 // N B //
129 // / \ : \ //
130 // A C D //
131
132 ref->left = node;
133 node->parent = ref;
134
135 // | //
136 // B //
137 // / \ //
138 // N D //
139 // / \ //
140 // A C //
141}
142
143template <class T>
144void QRBTree<T>::rotateRight(Node *node)
145{
146 // | | //
147 // N A //
148 // / \ / \ //
149 // A B ---> C N //
150 // / \ / \ //
151 // C D D B //
152
153 Node *&ref = (node->parent ? (node == node->parent->left ? node->parent->left : node->parent->right) : root);
154 ref = node->left;
155 node->left->parent = node->parent;
156
157 node->left = ref->right;
158 if (ref->right)
159 ref->right->parent = node;
160
161 ref->right = node;
162 node->parent = ref;
163}
164
165template <class T>
166void QRBTree<T>::update(Node *node) // call this after inserting a node
167{
168 for (;;) {
169 Node *parent = node->parent;
170
171 // if the node is the root, color it black
172 if (!parent) {
173 node->red = false;
174 return;
175 }
176
177 // if the parent is black, the node can be left red
178 if (!parent->red)
179 return;
180
181 // at this point, the parent is red and cannot be the root
182 Node *grandpa = parent->parent;
183 Q_ASSERT(grandpa);
184
185 Node *uncle = (parent == grandpa->left ? grandpa->right : grandpa->left);
186 if (uncle && uncle->red) {
187 // grandpa's black, parent and uncle are red.
188 // let parent and uncle be black, grandpa red and recursively update grandpa.
189 Q_ASSERT(!grandpa->red);
190 parent->red = false;
191 uncle->red = false;
192 grandpa->red = true;
193 node = grandpa;
194 continue;
195 }
196
197 // at this point, uncle is black
198 if (node == parent->right && parent == grandpa->left)
199 rotateLeft(node = parent);
200 else if (node == parent->left && parent == grandpa->right)
201 rotateRight(node = parent);
202 parent = node->parent;
203
204 if (parent == grandpa->left) {
205 rotateRight(grandpa);
206 parent->red = false;
207 grandpa->red = true;
208 } else {
209 rotateLeft(grandpa);
210 parent->red = false;
211 grandpa->red = true;
212 }
213 return;
214 }
215}
216
217template <class T>
218inline void QRBTree<T>::attachLeft(Node *parent, Node *child)
219{
220 Q_ASSERT(!parent->left);
221 parent->left = child;
222 child->parent = parent;
223 update(child);
224}
225
226template <class T>
227inline void QRBTree<T>::attachRight(Node *parent, Node *child)
228{
229 Q_ASSERT(!parent->right);
230 parent->right = child;
231 child->parent = parent;
232 update(child);
233}
234
235template <class T>
236void QRBTree<T>::attachBefore(Node *parent, Node *child)
237{
238 if (!root)
239 update(root = child);
240 else if (!parent)
241 attachRight(back(root), child);
242 else if (parent->left)
243 attachRight(back(parent->left), child);
244 else
245 attachLeft(parent, child);
246}
247
248template <class T>
249void QRBTree<T>::attachAfter(Node *parent, Node *child)
250{
251 if (!root)
252 update(root = child);
253 else if (!parent)
254 attachLeft(front(root), child);
255 else if (parent->right)
256 attachLeft(front(parent->right), child);
257 else
258 attachRight(parent, child);
259}
260
261template <class T>
262void QRBTree<T>::swapNodes(Node *n1, Node *n2)
263{
264 // Since iterators must not be invalidated, it is not sufficient to only swap the data.
265 if (n1->parent == n2) {
266 n1->parent = n2->parent;
267 n2->parent = n1;
268 } else if (n2->parent == n1) {
269 n2->parent = n1->parent;
270 n1->parent = n2;
271 } else {
272 qSwap(n1->parent, n2->parent);
273 }
274
275 qSwap(n1->left, n2->left);
276 qSwap(n1->right, n2->right);
277 qSwap(n1->red, n2->red);
278
279 if (n1->parent) {
280 if (n1->parent->left == n2)
281 n1->parent->left = n1;
282 else
283 n1->parent->right = n1;
284 } else {
285 root = n1;
286 }
287
288 if (n2->parent) {
289 if (n2->parent->left == n1)
290 n2->parent->left = n2;
291 else
292 n2->parent->right = n2;
293 } else {
294 root = n2;
295 }
296
297 if (n1->left)
298 n1->left->parent = n1;
299 if (n1->right)
300 n1->right->parent = n1;
301
302 if (n2->left)
303 n2->left->parent = n2;
304 if (n2->right)
305 n2->right->parent = n2;
306}
307
308template <class T>
309void QRBTree<T>::detach(Node *node) // call this before removing a node.
310{
311 if (node->right)
312 swapNodes(node, front(node->right));
313
314 Node *child = (node->left ? node->left : node->right);
315
316 if (!node->red) {
317 if (child && child->red)
318 child->red = false;
319 else
320 rebalance(node);
321 }
322
323 Node *&ref = (node->parent ? (node == node->parent->left ? node->parent->left : node->parent->right) : root);
324 ref = child;
325 if (child)
326 child->parent = node->parent;
327 node->left = node->right = node->parent = nullptr;
328}
329
330// 'node' must be black. rebalance will reduce the depth of black nodes by one in the sibling tree.
331template <class T>
332void QRBTree<T>::rebalance(Node *node)
333{
334 Q_ASSERT(!node->red);
335 for (;;) {
336 if (!node->parent)
337 return;
338
339 // at this point, node is not a parent, it is black, thus it must have a sibling.
340 Node *sibling = (node == node->parent->left ? node->parent->right : node->parent->left);
341 Q_ASSERT(sibling);
342
343 if (sibling->red) {
344 sibling->red = false;
345 node->parent->red = true;
346 if (node == node->parent->left)
347 rotateLeft(node->parent);
348 else
349 rotateRight(node->parent);
350 sibling = (node == node->parent->left ? node->parent->right : node->parent->left);
351 Q_ASSERT(sibling);
352 }
353
354 // at this point, the sibling is black.
355 Q_ASSERT(!sibling->red);
356
357 if ((!sibling->left || !sibling->left->red) && (!sibling->right || !sibling->right->red)) {
358 bool parentWasRed = node->parent->red;
359 sibling->red = true;
360 node->parent->red = false;
361 if (parentWasRed)
362 return;
363 node = node->parent;
364 continue;
365 }
366
367 // at this point, at least one of the sibling's children is red.
368
369 if (node == node->parent->left) {
370 if (!sibling->right || !sibling->right->red) {
371 Q_ASSERT(sibling->left);
372 sibling->red = true;
373 sibling->left->red = false;
374 rotateRight(sibling);
375
376 sibling = sibling->parent;
377 Q_ASSERT(sibling);
378 }
379 sibling->red = node->parent->red;
380 node->parent->red = false;
381
382 Q_ASSERT(sibling->right->red);
383 sibling->right->red = false;
384 rotateLeft(node->parent);
385 } else {
386 if (!sibling->left || !sibling->left->red) {
387 Q_ASSERT(sibling->right);
388 sibling->red = true;
389 sibling->right->red = false;
390 rotateLeft(sibling);
391
392 sibling = sibling->parent;
393 Q_ASSERT(sibling);
394 }
395 sibling->red = node->parent->red;
396 node->parent->red = false;
397
398 Q_ASSERT(sibling->left->red);
399 sibling->left->red = false;
400 rotateRight(node->parent);
401 }
402 return;
403 }
404}
405
406template <class T>
407inline typename QRBTree<T>::Node *QRBTree<T>::front(Node *node) const
408{
409 while (node->left)
410 node = node->left;
411 return node;
412}
413
414template <class T>
415inline typename QRBTree<T>::Node *QRBTree<T>::back(Node *node) const
416{
417 while (node->right)
418 node = node->right;
419 return node;
420}
421
422template <class T>
423typename QRBTree<T>::Node *QRBTree<T>::next(Node *node) const
424{
425 if (node->right)
426 return front(node->right);
427 while (node->parent && node == node->parent->right)
428 node = node->parent;
429 return node->parent;
430}
431
432template <class T>
433typename QRBTree<T>::Node *QRBTree<T>::previous(Node *node) const
434{
435 if (node->left)
436 return back(node->left);
437 while (node->parent && node == node->parent->left)
438 node = node->parent;
439 return node->parent;
440}
441
442template <class T>
443int QRBTree<T>::blackDepth(Node *top) const
444{
445 if (!top)
446 return 0;
447 int leftDepth = blackDepth(top->left);
448 int rightDepth = blackDepth(top->right);
449 if (leftDepth != rightDepth)
450 return -1;
451 if (!top->red)
452 ++leftDepth;
453 return leftDepth;
454}
455
456template <class T>
457bool QRBTree<T>::checkRedBlackProperty(Node *top) const
458{
459 if (!top)
460 return true;
461 if (top->left && !checkRedBlackProperty(top->left))
462 return false;
463 if (top->right && !checkRedBlackProperty(top->right))
464 return false;
465 return !(top->red && ((top->left && top->left->red) || (top->right && top->right->red)));
466}
467
468template <class T>
469inline bool QRBTree<T>::validate() const
470{
471 return checkRedBlackProperty(root) && blackDepth(root) != -1;
472}
473
474template <class T>
475inline void QRBTree<T>::deleteNode(Node *&node)
476{
477 Q_ASSERT(node);
478 detach(node);
479 node->right = freeList;
480 freeList = node;
481 node = nullptr;
482}
483
484template <class T>
485inline typename QRBTree<T>::Node *QRBTree<T>::newNode()
486{
487 if (freeList) {
488 Node *node = freeList;
489 freeList = freeList->right;
490 node->parent = node->left = node->right = nullptr;
491 node->red = true;
492 return node;
493 }
494 return new Node;
495}
496
497// Return 1 if 'left' comes after 'right', 0 if equal, and -1 otherwise.
498// 'left' and 'right' cannot be null.
499template <class T>
500int QRBTree<T>::order(Node *left, Node *right)
501{
502 Q_ASSERT(left && right);
503 if (left == right)
504 return 0;
505
506 QList<Node *> leftAncestors;
507 QList<Node *> rightAncestors;
508 while (left) {
509 leftAncestors.push_back(left);
510 left = left->parent;
511 }
512 while (right) {
513 rightAncestors.push_back(right);
514 right = right->parent;
515 }
516 Q_ASSERT(leftAncestors.back() == root && rightAncestors.back() == root);
517
518 while (!leftAncestors.empty() && !rightAncestors.empty() && leftAncestors.back() == rightAncestors.back()) {
519 leftAncestors.pop_back();
520 rightAncestors.pop_back();
521 }
522
523 if (!leftAncestors.empty())
524 return (leftAncestors.back() == leftAncestors.back()->parent->left ? -1 : 1);
525
526 if (!rightAncestors.empty())
527 return (rightAncestors.back() == rightAncestors.back()->parent->right ? -1 : 1);
528
529 // The code should never reach this point.
530 Q_ASSERT(!leftAncestors.empty() || !rightAncestors.empty());
531 return 0;
532}
533
534QT_END_NAMESPACE
535
536#endif