| 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
|
|
|
|
|
|
|
} |