File Coverage

rbtree.c
Criterion Covered Total %
statement 367 455 80.6
branch 224 316 70.8
condition n/a
subroutine n/a
pod n/a
total 591 771 76.6


line stmt bran cond sub pod time code
1             /* Auto-Generated by RBGen version 0.1 on 2026-02-17T05:30:14Z */
2              
3             /*
4             Credits:
5              
6             Intrest in red/black trees was inspired by Dr. John Franco, and his animated
7             red/black tree java applet.
8             http://www.ececs.uc.edu/~franco/C321/html/RedBlack/redblack.html
9              
10             The node insertion code was written in a joint effort with Anthony Deeter,
11             as a class project.
12              
13             The red/black deletion algorithm was derived from the deletion patterns in
14             "Fundamentals of Sequential and Parallel Algorithms",
15             by Dr. Kenneth A. Berman and Dr. Jerome L. Paul
16              
17             I also got the sentinel node idea from this book.
18              
19             */
20              
21             #include "/root/.cpan/build/Tree-RB-XS-0.20-0/rbtree.h"
22             #include
23              
24             #define IS_BLACK(node) (!(node)->color)
25             #define IS_RED(node) ((node)->color)
26             #define NODE_IS_IN_TREE(node) ((node)->count != 0)
27             #define SET_COLOR_BLACK(node) ((node)->color= 0)
28             #define SET_COLOR_RED(node) ((node)->color= 1)
29             #define COPY_COLOR(dest,src) ((dest)->color= (src)->color)
30             #define GET_COUNT(node) ((node)->count)
31             #define SET_COUNT(node,val) ((node)->count= (val))
32             #define ADD_COUNT(node,val) ((node)->count+= (val))
33             #define IS_SENTINEL(node) (!(bool) (node)->count)
34             #define IS_ROOTSENTINEL(node) (!(bool) (node)->parent)
35             #define NOT_SENTINEL(node) ((bool) (node)->count)
36             #define NOT_ROOTSENTINEL(node) ((bool) (node)->parent)
37             #define PTR_OFS(node,ofs) ((void*)(((char*)(void*)(node))+ofs))
38              
39             static void Balance( rbtree_node_t *current );
40             static void RotateRight( rbtree_node_t *node );
41             static void RotateLeft( rbtree_node_t *node );
42             static void PruneLeaf( rbtree_node_t *node );
43             static void InsertAtLeaf( rbtree_node_t *leaf, rbtree_node_t *new_node, bool on_left);
44              
45 111           void rbtree_init_tree( rbtree_node_t *root_sentinel, rbtree_node_t *leaf_sentinel ) {
46 111           SET_COUNT(root_sentinel, 0);
47 111           SET_COLOR_BLACK(leaf_sentinel);
48 111           root_sentinel->parent= NULL;
49 111           root_sentinel->left= leaf_sentinel;
50 111           root_sentinel->right= leaf_sentinel;
51 111           SET_COUNT(leaf_sentinel, 0);
52 111           SET_COLOR_BLACK(leaf_sentinel);
53 111           leaf_sentinel->left= leaf_sentinel;
54 111           leaf_sentinel->right= leaf_sentinel;
55 111           leaf_sentinel->parent= leaf_sentinel;
56 111           }
57              
58 275           rbtree_node_t *rbtree_node_left_leaf( rbtree_node_t *node ) {
59 275 100         if (IS_SENTINEL(node)) return NULL;
60 826 100         while (NOT_SENTINEL(node->left))
61 554           node= node->left;
62 272           return node;
63             }
64              
65 140           rbtree_node_t *rbtree_node_right_leaf( rbtree_node_t *node ) {
66 140 100         if (IS_SENTINEL(node)) return NULL;
67 587 100         while (NOT_SENTINEL(node->right))
68 448           node= node->right;
69 139           return node;
70             }
71              
72 0           rbtree_node_t *rbtree_node_prev_leaf( rbtree_node_t *node ) {
73 0           node= node->left;
74 0 0         while (NOT_SENTINEL(node->right))
75 0           node= node->right;
76 0 0         return IS_SENTINEL(node)? NULL : node;
77             }
78              
79 0           rbtree_node_t *rbtree_node_next_leaf( rbtree_node_t *node ) {
80 0           node= node->right;
81 0 0         while (NOT_SENTINEL(node->left))
82 0           node= node->left;
83 0 0         return IS_SENTINEL(node)? NULL : node;
84             }
85              
86 177           rbtree_node_t *rbtree_node_rootsentinel( rbtree_node_t *node ) {
87 596 50         while (node && node->parent)
    100          
88 419           node= node->parent;
89             // The node might not have been part of the tree, so make extra checks that
90             // this is really a sentinel
91 177 50         return node && node->right && node->right->right == node->right? node : NULL;
    100          
    50          
92             }
93              
94 518           rbtree_node_t *rbtree_node_prev( rbtree_node_t *node ) {
95 518 100         if (IS_SENTINEL(node)) return NULL;
96             // If we are not at a leaf, move to the right-most node
97             // in the tree to the left of this node.
98 513 100         if (NOT_SENTINEL(node->left)) {
99 184           node= node->left;
100 225 100         while (NOT_SENTINEL(node->right))
101 41           node= node->right;
102 184           return node;
103             }
104             // Else walk up the tree until we see a parent node to the left
105             else {
106 329           rbtree_node_t *parent= node->parent;
107 547 100         while (parent->left == node) {
108 279           node= parent;
109 279           parent= parent->parent;
110             // Check for root_sentinel
111 279 100         if (!parent) return NULL;
112             }
113 268           return parent;
114             }
115             }
116              
117 1001854           rbtree_node_t *rbtree_node_next( rbtree_node_t *node ) {
118 1001854 100         if (IS_SENTINEL(node)) return NULL;
119             // If we are not at a leaf, move to the left-most node
120             // in the tree to the right of this node.
121 1001850 100         if (NOT_SENTINEL(node->right)) {
122 287974           node= node->right;
123 538066 100         while (NOT_SENTINEL(node->left))
124 250092           node= node->left;
125 287974           return node;
126             }
127             // Else walk up the tree until we see a parent node to the right
128             else {
129 713876           rbtree_node_t *parent= node->parent;
130 713876 50         assert(parent);
131 10234086 100         while (parent->right == node) {
132 9520210 50         assert(parent != parent->parent);
133 9520210           node= parent;
134 9520210           parent= node->parent;
135             }
136             // Check for the root_sentinel
137 713876 100         if (!parent->parent) return NULL;
138 362889           return parent;
139             }
140             }
141              
142             /** Simple find algorithm.
143             * This function looks for the nearest node to the requested key, returning the node and
144             * the final value of the compare function which indicates whether this is the node equal to,
145             * before, or after the requested key.
146             */
147 15743           rbtree_node_t * rbtree_find_nearest(rbtree_node_t *node, void *goal,
148             int(*compare)(void *ctx, void *a,void *b), void *ctx, int cmp_ptr_ofs,
149             int *last_cmp_out
150             ) {
151 15743           rbtree_node_t *nearest= NULL, *test;
152 15743           int count, cmp= 0;
153            
154 15743 50         if (IS_ROOTSENTINEL(node))
155 15743           node= node->left;
156              
157 335627 100         while (NOT_SENTINEL(node)) {
158 320265           nearest= node;
159 320265           cmp= compare( ctx, goal, PTR_OFS(node,cmp_ptr_ofs) );
160 320265 100         if (cmp<0) node= node->left;
161 239261 100         else if (cmp>0) node= node->right;
162 381           else break;
163             }
164 15743 100         if (nearest && last_cmp_out)
    50          
165 15642           *last_cmp_out= cmp;
166 15743           return nearest;
167             }
168              
169             /** Find-all algorithm.
170             * This function not only finds a node, but can find the nearest node to the one requested, finds the number of
171             * matching nodes, and gets the first and last node so the matches can be iterated.
172             */
173 79           bool rbtree_find_all(rbtree_node_t *node, void* goal,
174             int(*compare)(void *ctx, void *a,void *b), void *ctx, int cmp_ptr_ofs,
175             rbtree_node_t **result_first, rbtree_node_t **result_last, size_t *result_count
176             ) {
177 79           rbtree_node_t *nearest= NULL, *first, *last, *test;
178             size_t count;
179             int cmp;
180            
181 79 100         if (IS_ROOTSENTINEL(node))
182 76           node= node->left;
183              
184 198 100         while (NOT_SENTINEL(node)) {
185 185           nearest= node;
186 185           cmp= compare( ctx, goal, PTR_OFS(node,cmp_ptr_ofs) );
187 185 100         if (cmp<0) node= node->left;
188 129 100         else if (cmp>0) node= node->right;
189 66           else break;
190             }
191 79 100         if (IS_SENTINEL(node)) {
192             /* no matches. Look up neighbor node if requested. */
193 13 50         if (result_first)
194 13 50         *result_first= nearest && cmp < 0? rbtree_node_prev(nearest) : nearest;
    100          
195 13 50         if (result_last)
196 13 50         *result_last= nearest && cmp > 0? rbtree_node_next(nearest) : nearest;
    100          
197 13 100         if (result_count) *result_count= 0;
198 13           return false;
199             }
200             // we've found the head of the tree the matches will be found in
201 66           count= 1;
202 66 100         if (result_first || result_count) {
    50          
203             // Search the left tree for the first match
204 66           first= node;
205 66           test= first->left;
206 111 100         while (NOT_SENTINEL(test)) {
207 45           cmp= compare( ctx, goal, PTR_OFS(test,cmp_ptr_ofs) );
208 45 100         if (cmp == 0) {
209 4           first= test;
210 4           count+= 1 + GET_COUNT(test->right);
211 4           test= test->left;
212             }
213             else /* cmp > 0 */
214 41           test= test->right;
215             }
216 66 100         if (result_first) *result_first= first;
217             }
218 66 100         if (result_last || result_count) {
    50          
219             // Search the right tree for the last match
220 66           last= node;
221 66           test= last->right;
222 117 100         while (NOT_SENTINEL(test)) {
223 51           cmp= compare( ctx, goal, PTR_OFS(test,cmp_ptr_ofs) );
224 51 100         if (cmp == 0) {
225 6           last= test;
226 6           count+= 1 + GET_COUNT(test->left);
227 6           test= test->right;
228             }
229             else /* cmp < 0 */
230 45           test= test->left;
231             }
232 66 100         if (result_last) *result_last= last;
233 66 100         if (result_count) *result_count= count;
234             }
235 66           return true;
236             }
237              
238 2           rbtree_node_t * rbtree_find_leftmost_samekey(rbtree_node_t *node, int(*compare)(void *ctx, void *a, void *b), void *ctx, int cmp_ptr_ofs) {
239             // Search the left tree for the first match
240 2           rbtree_node_t *first= node, *test= node->left;
241 4 100         while (NOT_SENTINEL(test)) {
242 2 50         if (0 == compare(ctx, PTR_OFS(test,cmp_ptr_ofs), PTR_OFS(node,cmp_ptr_ofs) )) {
243 2           first= test;
244 2           test= test->left;
245             }
246             else
247 0           test= test->right;
248             }
249 2           return first;
250             }
251              
252 22           rbtree_node_t * rbtree_find_rightmost_samekey(rbtree_node_t *node, int(*compare)(void *ctx, void *a, void *b), void *ctx, int cmp_ptr_ofs) {
253             // Search the left tree for the first match
254 22           rbtree_node_t *last= node, *test= node->right;
255 38 100         while (NOT_SENTINEL(test)) {
256 16 100         if (0 == compare(ctx, PTR_OFS(test,cmp_ptr_ofs), PTR_OFS(node,cmp_ptr_ofs) )) {
257 7           last= test;
258 7           test= test->right;
259             }
260             else
261 9           test= test->left;
262             }
263 22           return last;
264             }
265              
266             /* Insert a new object into the tree. The initial node is called 'hint' because if the new node
267             * isn't a child of hint, this will backtrack up the tree to find the actual insertion point.
268             */
269 0           bool rbtree_node_insert( rbtree_node_t *hint, rbtree_node_t *node, int(*compare)(void *ctx, void *a, void *b), void *ctx, int cmp_ptr_ofs) {
270             // Can't insert node if it is already in the tree
271 0 0         if (NODE_IS_IN_TREE(node))
272 0           return false;
273             // check for first node scenario
274 0 0         if (IS_ROOTSENTINEL(hint)) {
275 0 0         if (IS_SENTINEL(hint->left)) {
276 0           hint->left= node;
277 0           node->parent= hint;
278 0           node->left= hint->right; // tree's leaf sentinel
279 0           node->right= hint->right;
280 0           SET_COUNT(node, 1);
281 0           SET_COLOR_BLACK(node);
282 0           return true;
283             }
284             else
285 0           hint= hint->left;
286             }
287             // else traverse hint until leaf
288             int cmp;
289 0           bool leftmost= true, rightmost= true;
290 0           rbtree_node_t *pos= hint, *next, *parent;
291             while (1) {
292 0           cmp= compare(ctx, PTR_OFS(node,cmp_ptr_ofs), PTR_OFS(pos,cmp_ptr_ofs) );
293 0 0         if (cmp < 0) {
294 0           rightmost= false;
295 0           next= pos->left;
296             } else {
297 0           leftmost= false;
298 0           next= pos->right;
299             }
300 0 0         if (IS_SENTINEL(next))
301 0           break;
302 0           pos= next;
303             }
304             // If the original hint was not the root of the tree, and cmp indicate the same direction
305             // as leftmost or rightmost, then backtrack and see if we're completely in the wrong spot.
306 0 0         if (NOT_ROOTSENTINEL(hint->parent) && (cmp < 0? leftmost : rightmost)) {
    0          
    0          
307             // we are the leftmost child of hint, so if there is a parent to the left,
308             // key needs to not compare less else we have to start over.
309 0           parent= hint->parent;
310             while (1) {
311 0 0         if ((cmp < 0? parent->right : parent->left) == hint) {
    0          
312 0 0         if ((cmp < 0) == (compare(ctx, PTR_OFS(node,cmp_ptr_ofs), PTR_OFS(parent,cmp_ptr_ofs)) < 0)) {
313             // Whoops. Hint was wrong. Should start over from root.
314 0 0         while (NOT_ROOTSENTINEL(parent->parent))
315 0           parent= parent->parent;
316 0           return rbtree_node_insert(parent, node, compare, ctx, cmp_ptr_ofs);
317             }
318 0           else break; // we're fine afterall
319             }
320 0 0         else if (IS_ROOTSENTINEL(parent->parent))
321 0           break; // we're fine afterall
322 0           parent= parent->parent;
323             }
324             }
325 0 0         if (cmp < 0)
326 0           pos->left= node;
327             else
328 0           pos->right= node;
329 0           node->parent= pos;
330             // next is pointing to the leaf-sentinel for this tree after exiting loop above
331 0           node->left= next;
332 0           node->right= next;
333 0           SET_COUNT(node, 1);
334 0           SET_COLOR_RED(node);
335 0 0         for (parent= pos; NOT_ROOTSENTINEL(parent); parent= parent->parent)
336 0           ADD_COUNT(parent, 1);
337 0           Balance(pos);
338             // We've iterated to the root sentinel- so node->left is the head of the tree.
339             // Set the tree's root to black
340 0           SET_COLOR_BLACK(parent->left);
341 0           return true;
342             }
343              
344             /* Insert a new node into the tree immediately before a given node.
345             * This does not perform any comparisons, and will break the tree if given bad parameters.
346             */
347 7670           void rbtree_node_insert_before( rbtree_node_t *parent, rbtree_node_t *node) {
348             rbtree_node_t *sentinel, *tmp;
349 7670 100         if (IS_SENTINEL(parent->left)) {
350 7667           sentinel= parent->left;
351 7667           parent->left= node;
352             }
353             else {
354 3           parent= parent->left;
355 3 50         while (!IS_SENTINEL(parent->right))
356 0           parent= parent->right;
357 3           sentinel= parent->right;
358 3           parent->right= node;
359             }
360 7670           node->parent= parent;
361 7670           node->left= sentinel;
362 7670           node->right= sentinel;
363 7670           SET_COUNT(node, 1);
364 7670           SET_COLOR_RED(node);
365 159305 100         for (tmp= parent; NOT_ROOTSENTINEL(tmp); tmp= tmp->parent)
366 151635           ADD_COUNT(tmp, 1);
367 7670           Balance(parent);
368             // We've iterated to the root sentinel- so node->left is the head of the tree.
369             // Set the tree's root to black
370 7670           SET_COLOR_BLACK(tmp->left);
371 7670           }
372              
373             /* Insert a new node into the tree immediately after a given node.
374             * This does not perform any comparisons, and will break the tree if given bad parameters.
375             */
376 493358           void rbtree_node_insert_after( rbtree_node_t *parent, rbtree_node_t *node) {
377             rbtree_node_t *sentinel, *tmp;
378 493358 100         if (IS_SENTINEL(parent->right)) {
379 463378           sentinel= parent->right;
380 463378           parent->right= node;
381             }
382             else {
383 29980           parent= parent->right;
384 29982 100         while (!IS_SENTINEL(parent->left))
385 2           parent= parent->left;
386 29980           sentinel= parent->left;
387 29980           parent->left= node;
388             }
389 493358           node->parent= parent;
390 493358           node->left= sentinel;
391 493358           node->right= sentinel;
392 493358           SET_COUNT(node, 1);
393 493358           SET_COLOR_RED(node);
394 13023210 100         for (tmp= parent; NOT_ROOTSENTINEL(tmp); tmp= tmp->parent)
395 12529852           ADD_COUNT(tmp, 1);
396 493358           Balance(parent);
397             // We've iterated to the root sentinel- so node->left is the head of the tree.
398             // Set the tree's root to black
399 493358           SET_COLOR_BLACK(tmp->left);
400 493358           }
401              
402 66686           void RotateRight( rbtree_node_t *node ) {
403 66686           rbtree_node_t *new_head= node->left;
404 66686           rbtree_node_t *parent= node->parent;
405              
406 66686 100         if (parent->right == node) parent->right= new_head;
407 19198           else parent->left= new_head;
408 66686           new_head->parent= parent;
409              
410 66686           ADD_COUNT(node, -1 - GET_COUNT(new_head->left));
411 66686           ADD_COUNT(new_head, 1 + GET_COUNT(node->right));
412 66686           node->left= new_head->right;
413 66686           new_head->right->parent= node;
414              
415 66686           new_head->right= node;
416 66686           node->parent= new_head;
417 66686           }
418              
419 480554           void RotateLeft( rbtree_node_t *node ) {
420 480554           rbtree_node_t *new_head= node->right;
421 480554           rbtree_node_t *parent= node->parent;
422              
423 480554 100         if (parent->right == node) parent->right= new_head;
424 81954           else parent->left= new_head;
425 480554           new_head->parent= parent;
426              
427 480554           ADD_COUNT(node, -1 - GET_COUNT(new_head->right));
428 480554           ADD_COUNT(new_head, 1 + GET_COUNT(node->left));
429 480554           node->right= new_head->left;
430 480554           new_head->left->parent= node;
431              
432 480554           new_head->left= node;
433 480554           node->parent= new_head;
434 480554           }
435              
436             /** Re-balance a tree which has just had one element added.
437             * current is the parent node of the node just added. The child is red.
438             *
439             * node counts are *not* updated by this method.
440             */
441 501028           void Balance( rbtree_node_t *current ) {
442             // if current is a black node, no rotations needed
443 975669 100         while (IS_RED(current)) {
444             // current is red, the imbalanced child is red, and parent is black.
445              
446 955598           rbtree_node_t *parent= current->parent;
447              
448             // if the current is on the right of the parent, the parent is to the left
449 955598 100         if (parent->right == current) {
450             // if the sibling is also red, we can pull down the color black from the parent
451 887325 100         if (IS_RED(parent->left)) {
452 472612           SET_COLOR_BLACK(parent->left);
453 472612           SET_COLOR_BLACK(current);
454 472612           SET_COLOR_RED(parent);
455             // jump twice up the tree. if current reaches the HeadSentinel (black node), the loop will stop
456 472612           current= parent->parent;
457 472612           continue;
458             }
459             // if the imbalance (red node) is on the left, and the parent is on the left,
460             // a "prep-slide" is needed. (see diagram)
461 414713 100         if (IS_RED(current->left))
462 439           RotateRight( current );
463              
464             // Now we can do our left rotation to balance the tree.
465 414713           RotateLeft( parent );
466 414713           SET_COLOR_RED(parent);
467 414713           SET_COLOR_BLACK(parent->parent);
468 414713           return;
469             }
470             // else the parent is to the right
471             else {
472             // if the sibling is also red, we can pull down the color black from the parent
473 68273 100         if (IS_RED(parent->right)) {
474 2029           SET_COLOR_BLACK(parent->right);
475 2029           SET_COLOR_BLACK(current);
476 2029           SET_COLOR_RED(parent);
477             // jump twice up the tree. if current reaches the HeadSentinel (black node), the loop will stop
478 2029           current= parent->parent;
479 2029           continue;
480             }
481             // if the imbalance (red node) is on the right, and the parent is on the right,
482             // a "prep-slide" is needed. (see diagram)
483 66244 100         if (IS_RED(current->right))
484 65815           RotateLeft( current );
485              
486             // Now we can do our right rotation to balance the tree.
487 66244           RotateRight( parent );
488 66244           SET_COLOR_RED(parent);
489 66244           SET_COLOR_BLACK(parent->parent);
490 66244           return;
491             }
492             }
493             // note that we should now set the root node to be black.
494             // but the caller does this anyway.
495 20071           return;
496             }
497              
498              
499 100916           size_t rbtree_node_index( rbtree_node_t *node ) {
500 100916           int left_count= GET_COUNT(node->left);
501 100916           rbtree_node_t *prev= node;
502 100916           node= node->parent;
503 1969661 100         while (NOT_SENTINEL(node)) {
504 1868745 100         if (node->right == prev)
505 1663758           left_count += GET_COUNT(node->left)+1;
506 1868745           prev= node;
507 1868745           node= node->parent;
508             }
509 100916           return left_count;
510             }
511              
512             /** Find the Nth node in the tree, indexed from 0, from the left to right.
513             * This operates by looking at the count of the left subtree, to descend down to the Nth element.
514             */
515 794           rbtree_node_t *rbtree_node_child_at_index( rbtree_node_t *node, size_t index ) {
516 794 100         if (index >= GET_COUNT(node))
517 150           return NULL;
518 2092 100         while (index != GET_COUNT(node->left)) {
519 1448 100         if (index < GET_COUNT(node->left))
520 450           node= node->left;
521             else {
522 998           index -= GET_COUNT(node->left)+1;
523 998           node= node->right;
524             }
525             }
526 644           return node;
527             }
528              
529             /** Prune a node from anywhere in the tree.
530             * If the node is a leaf, it can be removed easily. Otherwise we must swap the node for a leaf node
531             * with an adjacent key value, and then remove from the position of that leaf.
532             *
533             * This function *does* update node counts.
534             */
535 141           void rbtree_node_prune( rbtree_node_t *current ) {
536             rbtree_node_t *temp, *successor;
537 141 50         if (GET_COUNT(current) == 0)
538 0           return;
539              
540             // If this is a leaf node (or almost a leaf) we can just prune it
541 141 100         if (IS_SENTINEL(current->left) || IS_SENTINEL(current->right))
    100          
542 116           PruneLeaf(current);
543              
544             // Otherwise we need a successor. We are guaranteed to have one because
545             // the current node has 2 children.
546             else {
547             // pick from the largest subtree
548 50           successor= (GET_COUNT(current->left) > GET_COUNT(current->right))?
549 3           rbtree_node_prev( current )
550 25 100         : rbtree_node_next( current );
551 25           PruneLeaf( successor );
552              
553             // now exchange the successor for the current node
554 25           temp= current->right;
555 25           successor->right= temp;
556 25           temp->parent= successor;
557              
558 25           temp= current->left;
559 25           successor->left= temp;
560 25           temp->parent= successor;
561              
562 25           temp= current->parent;
563 25           successor->parent= temp;
564 25 100         if (temp->left == current) temp->left= successor; else temp->right= successor;
565 25           COPY_COLOR(successor, current);
566 25           SET_COUNT(successor, GET_COUNT(current));
567             }
568 141           current->left= current->right= current->parent= NULL;
569 141           SET_COLOR_BLACK(current);
570 141           SET_COUNT(current, 0);
571             }
572              
573             /** PruneLeaf performs pruning of nodes with at most one child node.
574             * This is the real heart of node deletion.
575             * The first operation is to decrease the node count from node to root_sentinel.
576             */
577 141           void PruneLeaf( rbtree_node_t *node ) {
578 141           rbtree_node_t *parent= node->parent, *current, *sibling, *sentinel;
579 141           bool leftside= (parent->left == node);
580 141 100         sentinel= IS_SENTINEL(node->left)? node->left : node->right;
581            
582             // first, decrement the count from here to root_sentinel
583 523 100         for (current= node; NOT_ROOTSENTINEL(current); current= current->parent)
584 382           ADD_COUNT(current, -1);
585              
586             // if the node is red and has at most one child, then it has no child.
587             // Prune it.
588 141 100         if (IS_RED(node)) {
589 48 100         if (leftside) parent->left= sentinel;
590 28           else parent->right= sentinel;
591 48           return;
592             }
593              
594             // node is black here. If it has a child, the child will be red.
595 93 100         if (node->left != sentinel) {
596             // swap with child
597 22           SET_COLOR_BLACK(node->left);
598 22           node->left->parent= parent;
599 22 50         if (leftside) parent->left= node->left;
600 0           else parent->right= node->left;
601 22           return;
602             }
603 71 100         if (node->right != sentinel) {
604             // swap with child
605 24           SET_COLOR_BLACK(node->right);
606 24           node->right->parent= parent;
607 24 100         if (leftside) parent->left= node->right;
608 8           else parent->right= node->right;
609 24           return;
610             }
611              
612             // Now, we have determined that node is a black leaf node with no children.
613             // The tree must have the same number of black nodes along any path from root
614             // to leaf. We want to remove a black node, disrupting the number of black
615             // nodes along the path from the root to the current leaf. To correct this,
616             // we must either shorten all other paths, or add a black node to the current
617             // path. Then we can freely remove our black leaf.
618             //
619             // While we are pointing to it, we will go ahead and delete the leaf and
620             // replace it with the sentinel (which is also black, so it won't affect
621             // the algorithm).
622              
623 47 100         if (leftside) parent->left= sentinel; else parent->right= sentinel;
624              
625 47 100         sibling= (leftside)? parent->right : parent->left;
626 47           current= node;
627              
628             // Loop until the current node is red, or until we get to the root node.
629             // (The root node's parent is the root_sentinel, which will have a NULL parent.)
630 105 100         while (IS_BLACK(current) && NOT_ROOTSENTINEL(parent)) {
    100          
631             // If the sibling is red, we are unable to reduce the number of black
632             // nodes in the sibling tree, and we can't increase the number of black
633             // nodes in our tree.. Thus we must do a rotation from the sibling
634             // tree to our tree to give us some extra (red) nodes to play with.
635             // This is Case 1 from the text
636 68 100         if (IS_RED(sibling)) {
637 16           SET_COLOR_RED(parent);
638 16           SET_COLOR_BLACK(sibling);
639 16 50         if (leftside) {
640 16           RotateLeft(parent);
641 16           sibling= parent->right;
642             }
643             else {
644 0           RotateRight(parent);
645 0           sibling= parent->left;
646             }
647 16           continue;
648             }
649             // sibling will be black here
650              
651             // If the sibling is black and both children are black, we have to
652             // reduce the black node count in the sibling's tree to match ours.
653             // This is Case 2a from the text.
654 52 100         if (IS_BLACK(sibling->right) && IS_BLACK(sibling->left)) {
    100          
655 42 50         assert(NOT_SENTINEL(sibling));
656 42           SET_COLOR_RED(sibling);
657             // Now we move one level up the tree to continue fixing the
658             // other branches.
659 42           current= parent;
660 42           parent= current->parent;
661 42           leftside= (parent->left == current);
662 42 100         sibling= (leftside)? parent->right : parent->left;
663 42           continue;
664             }
665             // sibling will be black with 1 or 2 red children here
666              
667             // << Case 2b is handled by the while loop. >>
668              
669             // If one of the sibling's children are red, we again can't make the
670             // sibling red to balance the tree at the parent, so we have to do a
671             // rotation. If the "near" nephew is red and the "far" nephew is
672             // black, we need to rotate that tree rightward before rotating the
673             // parent leftward.
674             // After doing a rotation and rearranging a few colors, the effect is
675             // that we maintain the same number of black nodes per path on the far
676             // side of the parent, and we gain a black node on the current side,
677             // so we are done.
678             // This is Case 4 from the text. (Case 3 is the double rotation)
679 10 50         if (leftside) {
680 10 100         if (IS_BLACK(sibling->right)) { // Case 3 from the text
681 3           RotateRight( sibling );
682 3           sibling= parent->right;
683             }
684             // now Case 4 from the text
685 10           SET_COLOR_BLACK(sibling->right);
686 10 50         assert(NOT_SENTINEL(sibling));
687 10           COPY_COLOR(sibling, parent);
688 10           SET_COLOR_BLACK(parent);
689              
690 10           current= parent;
691 10           parent= current->parent;
692 10           RotateLeft( current );
693 10           return;
694             }
695             else {
696 0 0         if (IS_BLACK(sibling->left)) { // Case 3 from the text
697 0           RotateLeft( sibling );
698 0           sibling= parent->left;
699             }
700             // now Case 4 from the text
701 0           SET_COLOR_BLACK(sibling->left);
702 0 0         assert(NOT_SENTINEL(sibling));
703 0           COPY_COLOR(sibling, parent);
704 0           SET_COLOR_BLACK(parent);
705              
706 0           current= parent;
707 0           parent= current->parent;
708 0           RotateRight( current );
709 0           return;
710             }
711             }
712              
713             // Now, make the current node black (to fulfill Case 2b)
714             // Case 4 will have exited directly out of the function.
715             // If we stopped because we reached the top of the tree,
716             // the head is black anyway so don't worry about it.
717 37           SET_COLOR_BLACK(current);
718             }
719              
720             /** Mark all nodes as being not-in-tree, and possibly delete the objects that contain them.
721             * DeleteProc is optional. If given, it will be called on the 'Object' which contains the rbtree_node_t.
722             * obj_ofs is a negative (or zero) number of bytes offset from the rbtree_node_t pointer to the containing
723             * object pointer. `ctx` is a user-defined context pointer to pass to the destructor.
724             */
725 114           void rbtree_clear( rbtree_node_t *root_sentinel, void (*destructor)(void *obj, void *ctx), int obj_ofs, void *ctx ) {
726             rbtree_node_t *current, *next;
727             int from_left;
728             // Delete in a depth-first post-traversal, because the node might not exist after
729             // calling the destructor.
730 114 50         if (!IS_ROOTSENTINEL(root_sentinel))
731 0           return; /* this is API usage bug, but no way to report it */
732 114 100         if (IS_SENTINEL(root_sentinel->left))
733 19           return; /* tree already empty */
734 95           current= root_sentinel->left;
735             while (1) {
736 500792           check_left: // came from above, go down-left
737 500887 100         if (NOT_SENTINEL(current->left)) {
738 250388           current= current->left;
739 250388           goto check_left;
740             }
741 250499           check_right: // came up from the left, go down-right
742 500887 100         if (NOT_SENTINEL(current->right)) {
743 250404           current= current->right;
744 250404           goto check_left;
745             }
746 250483           zap_current: // came up from the right, kill the current node and proceed up
747 500887           next= current->parent;
748 500887           from_left= (next->left == current)? 1 : 0;
749 500887           SET_COUNT(current, 0);
750 500887           current->left= current->right= current->parent= NULL;
751 500887 50         if (destructor) destructor(PTR_OFS(current,obj_ofs), ctx);
752 500887           current= next;
753 500887 100         if (current == root_sentinel)
754 95           break;
755 500792 100         else if (from_left)
756 250388           goto check_right;
757             else
758 250404           goto zap_current;
759             }
760 95           root_sentinel->left= root_sentinel->right;
761 95           SET_COLOR_BLACK(root_sentinel);
762 95           SET_COUNT(root_sentinel, 0);
763             }
764              
765              
766             static int CheckSubtree(rbtree_node_t *node, rbtree_compare_fn, void *ctx, int, int *);
767              
768 19           int rbtree_check_structure(rbtree_node_t *node, rbtree_compare_fn compare, void *ctx, int cmp_pointer_ofs) {
769             // If at root, check for root sentinel details
770 19 50         if (node && !node->parent) {
    50          
771 19 50         if (IS_RED(node) || IS_RED(node->left) || GET_COUNT(node) || GET_COUNT(node->right))
    50          
    50          
    50          
772 0           return RBTREE_INVALID_ROOT;
773 19 50         if (GET_COUNT(node->right) || IS_RED(node->right) || node->right->left != node->right
    50          
    50          
774 19 50         || node->right->right != node->right)
775 0           return RBTREE_INVALID_SENTINEL;
776 19 50         if (node->left == node->right) return 0; /* empty tree, nothing more to check */
777 19 50         if (node->left->parent != node)
778 0           return RBTREE_INVALID_ROOT;
779 19           node= node->left; /* else start checking at first real node */
780             }
781             int black_count;
782 19           return CheckSubtree(node, compare, ctx, cmp_pointer_ofs, &black_count);
783             }
784              
785 500010           int CheckSubtree(rbtree_node_t *node, rbtree_compare_fn compare, void *ctx, int cmp_pointer_ofs, int *black_count) {
786             // This node should be fully attached to the tree
787 500010 50         if (!node || !node->parent || !node->left || !node->right || !GET_COUNT(node))
    50          
    50          
    50          
    50          
788 0           return RBTREE_INVALID_NODE;
789             // Check counts. This is an easy way to validate the relation to sentinels too
790 500010 50         if (GET_COUNT(node) != GET_COUNT(node->left) + GET_COUNT(node->right) + 1)
791 0           return RBTREE_INVALID_COUNT;
792             // Check node key order
793 500010           int left_black_count= 0, right_black_count= 0;
794 500010 100         if (NOT_SENTINEL(node->left)) {
795 249992 50         if (node->left->parent != node)
796 0           return RBTREE_INVALID_NODE;
797 249992 100         if (IS_RED(node) && IS_RED(node->left))
    50          
798 0           return RBTREE_INVALID_COLOR;
799 249992 50         if (compare(ctx, PTR_OFS(node->left, cmp_pointer_ofs), PTR_OFS(node, cmp_pointer_ofs)) > 0)
800 0           return RBTREE_INVALID_ORDER;
801 249992           int err= CheckSubtree(node->left, compare, ctx, cmp_pointer_ofs, &left_black_count);
802 249992 50         if (err) return err;
803             }
804 500010 100         if (NOT_SENTINEL(node->right)) {
805 249999 50         if (node->right->parent != node)
806 0           return RBTREE_INVALID_NODE;
807 249999 100         if (IS_RED(node) && IS_RED(node->right))
    50          
808 0           return RBTREE_INVALID_COLOR;
809 249999 50         if (compare(ctx, PTR_OFS(node->right, cmp_pointer_ofs), PTR_OFS(node, cmp_pointer_ofs)) < 0)
810 0           return RBTREE_INVALID_ORDER;
811 249999           int err= CheckSubtree(node->right, compare, ctx, cmp_pointer_ofs, &right_black_count);
812 249999 50         if (err) return err;
813             }
814 500010 50         if (left_black_count != right_black_count)
815 0           return RBTREE_INVALID_COLOR;
816 500010           *black_count= left_black_count + (IS_BLACK(node)? 1 : 0);
817 500010           return 0;
818             }