Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * rbtree.c
4 : : * implementation for PostgreSQL generic Red-Black binary tree package
5 : : * Adopted from http://algolist.manual.ru/ds/rbtree.php
6 : : *
7 : : * This code comes from Thomas Niemann's "Sorting and Searching Algorithms:
8 : : * a Cookbook".
9 : : *
10 : : * See http://www.cs.auckland.ac.nz/software/AlgAnim/niemann/s_man.htm for
11 : : * license terms: "Source code, when part of a software project, may be used
12 : : * freely without reference to the author."
13 : : *
14 : : * Red-black trees are a type of balanced binary tree wherein (1) any child of
15 : : * a red node is always black, and (2) every path from root to leaf traverses
16 : : * an equal number of black nodes. From these properties, it follows that the
17 : : * longest path from root to leaf is only about twice as long as the shortest,
18 : : * so lookups are guaranteed to run in O(lg n) time.
19 : : *
20 : : * Copyright (c) 2009-2024, PostgreSQL Global Development Group
21 : : *
22 : : * IDENTIFICATION
23 : : * src/backend/lib/rbtree.c
24 : : *
25 : : *-------------------------------------------------------------------------
26 : : */
27 : : #include "postgres.h"
28 : :
29 : : #include "lib/rbtree.h"
30 : :
31 : :
32 : : /*
33 : : * Colors of nodes (values of RBTNode.color)
34 : : */
35 : : #define RBTBLACK (0)
36 : : #define RBTRED (1)
37 : :
38 : : /*
39 : : * RBTree control structure
40 : : */
41 : : struct RBTree
42 : : {
43 : : RBTNode *root; /* root node, or RBTNIL if tree is empty */
44 : :
45 : : /* Remaining fields are constant after rbt_create */
46 : :
47 : : Size node_size; /* actual size of tree nodes */
48 : : /* The caller-supplied manipulation functions */
49 : : rbt_comparator comparator;
50 : : rbt_combiner combiner;
51 : : rbt_allocfunc allocfunc;
52 : : rbt_freefunc freefunc;
53 : : /* Passthrough arg passed to all manipulation functions */
54 : : void *arg;
55 : : };
56 : :
57 : : /*
58 : : * all leafs are sentinels, use customized NIL name to prevent
59 : : * collision with system-wide constant NIL which is actually NULL
60 : : */
61 : : #define RBTNIL (&sentinel)
62 : :
63 : : static RBTNode sentinel =
64 : : {
65 : : .color = RBTBLACK,.left = RBTNIL,.right = RBTNIL,.parent = NULL
66 : : };
67 : :
68 : :
69 : : /*
70 : : * rbt_create: create an empty RBTree
71 : : *
72 : : * Arguments are:
73 : : * node_size: actual size of tree nodes (> sizeof(RBTNode))
74 : : * The manipulation functions:
75 : : * comparator: compare two RBTNodes for less/equal/greater
76 : : * combiner: merge an existing tree entry with a new one
77 : : * allocfunc: allocate a new RBTNode
78 : : * freefunc: free an old RBTNode
79 : : * arg: passthrough pointer that will be passed to the manipulation functions
80 : : *
81 : : * Note that the combiner's righthand argument will be a "proposed" tree node,
82 : : * ie the input to rbt_insert, in which the RBTNode fields themselves aren't
83 : : * valid. Similarly, either input to the comparator may be a "proposed" node.
84 : : * This shouldn't matter since the functions aren't supposed to look at the
85 : : * RBTNode fields, only the extra fields of the struct the RBTNode is embedded
86 : : * in.
87 : : *
88 : : * The freefunc should just be pfree or equivalent; it should NOT attempt
89 : : * to free any subsidiary data, because the node passed to it may not contain
90 : : * valid data! freefunc can be NULL if caller doesn't require retail
91 : : * space reclamation.
92 : : *
93 : : * The RBTree node is palloc'd in the caller's memory context. Note that
94 : : * all contents of the tree are actually allocated by the caller, not here.
95 : : *
96 : : * Since tree contents are managed by the caller, there is currently not
97 : : * an explicit "destroy" operation; typically a tree would be freed by
98 : : * resetting or deleting the memory context it's stored in. You can pfree
99 : : * the RBTree node if you feel the urge.
100 : : */
101 : : RBTree *
1986 tgl@sss.pgh.pa.us 102 :CBC 181 : rbt_create(Size node_size,
103 : : rbt_comparator comparator,
104 : : rbt_combiner combiner,
105 : : rbt_allocfunc allocfunc,
106 : : rbt_freefunc freefunc,
107 : : void *arg)
108 : : {
5005 109 : 181 : RBTree *tree = (RBTree *) palloc(sizeof(RBTree));
110 : :
1986 111 [ - + ]: 181 : Assert(node_size > sizeof(RBTNode));
112 : :
113 : 181 : tree->root = RBTNIL;
5005 114 : 181 : tree->node_size = node_size;
5176 teodor@sigaev.ru 115 : 181 : tree->comparator = comparator;
5005 tgl@sss.pgh.pa.us 116 : 181 : tree->combiner = combiner;
117 : 181 : tree->allocfunc = allocfunc;
5176 teodor@sigaev.ru 118 : 181 : tree->freefunc = freefunc;
119 : :
120 : 181 : tree->arg = arg;
121 : :
122 : 181 : return tree;
123 : : }
124 : :
125 : : /* Copy the additional data fields from one RBTNode to another */
126 : : static inline void
1986 tgl@sss.pgh.pa.us 127 : 320020 : rbt_copy_data(RBTree *rbt, RBTNode *dest, const RBTNode *src)
128 : : {
129 : 320020 : memcpy(dest + 1, src + 1, rbt->node_size - sizeof(RBTNode));
5005 130 : 320020 : }
131 : :
132 : : /**********************************************************************
133 : : * Search *
134 : : **********************************************************************/
135 : :
136 : : /*
137 : : * rbt_find: search for a value in an RBTree
138 : : *
139 : : * data represents the value to try to find. Its RBTNode fields need not
140 : : * be valid, it's the extra data in the larger struct that is of interest.
141 : : *
142 : : * Returns the matching tree entry, or NULL if no match is found.
143 : : */
144 : : RBTNode *
1986 145 : 40001 : rbt_find(RBTree *rbt, const RBTNode *data)
146 : : {
147 : 40001 : RBTNode *node = rbt->root;
148 : :
149 [ + + ]: 490598 : while (node != RBTNIL)
150 : : {
151 : 479597 : int cmp = rbt->comparator(data, node, rbt->arg);
152 : :
5176 teodor@sigaev.ru 153 [ + + ]: 479597 : if (cmp == 0)
5005 tgl@sss.pgh.pa.us 154 : 29000 : return node;
5176 teodor@sigaev.ru 155 [ + + ]: 450597 : else if (cmp < 0)
156 : 260759 : node = node->left;
157 : : else
158 : 189838 : node = node->right;
159 : : }
160 : :
161 : 11001 : return NULL;
162 : : }
163 : :
164 : : /*
165 : : * rbt_find_great: search for a greater value in an RBTree
166 : : *
167 : : * If equal_match is true, this will be a great or equal search.
168 : : *
169 : : * Returns the matching tree entry, or NULL if no match is found.
170 : : */
171 : : RBTNode *
646 akorotkov@postgresql 172 : 3 : rbt_find_great(RBTree *rbt, const RBTNode *data, bool equal_match)
173 : : {
174 : 3 : RBTNode *node = rbt->root;
175 : 3 : RBTNode *greater = NULL;
176 : :
177 [ + + ]: 33 : while (node != RBTNIL)
178 : : {
179 : 31 : int cmp = rbt->comparator(data, node, rbt->arg);
180 : :
181 [ + + + + ]: 31 : if (equal_match && cmp == 0)
182 : 1 : return node;
183 [ - + ]: 30 : else if (cmp < 0)
184 : : {
646 akorotkov@postgresql 185 :LBC (24459) : greater = node;
186 : (24459) : node = node->left;
187 : : }
188 : : else
646 akorotkov@postgresql 189 :CBC 30 : node = node->right;
190 : : }
191 : :
192 : 2 : return greater;
193 : : }
194 : :
195 : : /*
196 : : * rbt_find_less: search for a lesser value in an RBTree
197 : : *
198 : : * If equal_match is true, this will be a less or equal search.
199 : : *
200 : : * Returns the matching tree entry, or NULL if no match is found.
201 : : */
202 : : RBTNode *
203 : 10002 : rbt_find_less(RBTree *rbt, const RBTNode *data, bool equal_match)
204 : : {
205 : 10002 : RBTNode *node = rbt->root;
206 : 10002 : RBTNode *lesser = NULL;
207 : :
208 [ + + ]: 140879 : while (node != RBTNIL)
209 : : {
210 : 130878 : int cmp = rbt->comparator(data, node, rbt->arg);
211 : :
212 [ + + + + ]: 130878 : if (equal_match && cmp == 0)
213 : 1 : return node;
214 [ + + ]: 130877 : else if (cmp > 0)
215 : : {
216 : 67697 : lesser = node;
217 : 67697 : node = node->right;
218 : : }
219 : : else
220 : 63180 : node = node->left;
221 : : }
222 : :
223 : 10001 : return lesser;
224 : : }
225 : :
226 : : /*
227 : : * rbt_leftmost: fetch the leftmost (smallest-valued) tree node.
228 : : * Returns NULL if tree is empty.
229 : : *
230 : : * Note: in the original implementation this included an unlink step, but
231 : : * that's a bit awkward. Just call rbt_delete on the result if that's what
232 : : * you want.
233 : : */
234 : : RBTNode *
1986 tgl@sss.pgh.pa.us 235 : 3 : rbt_leftmost(RBTree *rbt)
236 : : {
237 : 3 : RBTNode *node = rbt->root;
238 : 3 : RBTNode *leftmost = rbt->root;
239 : :
240 [ + + ]: 15 : while (node != RBTNIL)
241 : : {
5005 242 : 12 : leftmost = node;
243 : 12 : node = node->left;
244 : : }
245 : :
1986 246 [ + + ]: 3 : if (leftmost != RBTNIL)
5005 247 : 1 : return leftmost;
248 : :
249 : 2 : return NULL;
250 : : }
251 : :
252 : : /**********************************************************************
253 : : * Insertion *
254 : : **********************************************************************/
255 : :
256 : : /*
257 : : * Rotate node x to left.
258 : : *
259 : : * x's right child takes its place in the tree, and x becomes the left
260 : : * child of that node.
261 : : */
262 : : static void
1986 263 : 268583 : rbt_rotate_left(RBTree *rbt, RBTNode *x)
264 : : {
265 : 268583 : RBTNode *y = x->right;
266 : :
267 : : /* establish x->right link */
5176 teodor@sigaev.ru 268 : 268583 : x->right = y->left;
1986 tgl@sss.pgh.pa.us 269 [ + + ]: 268583 : if (y->left != RBTNIL)
5176 teodor@sigaev.ru 270 : 129724 : y->left->parent = x;
271 : :
272 : : /* establish y->parent link */
1986 tgl@sss.pgh.pa.us 273 [ + - ]: 268583 : if (y != RBTNIL)
5176 teodor@sigaev.ru 274 : 268583 : y->parent = x->parent;
275 [ + + ]: 268583 : if (x->parent)
276 : : {
277 [ + + ]: 268130 : if (x == x->parent->left)
278 : 82296 : x->parent->left = y;
279 : : else
280 : 185834 : x->parent->right = y;
281 : : }
282 : : else
283 : : {
1986 tgl@sss.pgh.pa.us 284 : 453 : rbt->root = y;
285 : : }
286 : :
287 : : /* link x and y */
5176 teodor@sigaev.ru 288 : 268583 : y->left = x;
1986 tgl@sss.pgh.pa.us 289 [ + - ]: 268583 : if (x != RBTNIL)
5176 teodor@sigaev.ru 290 : 268583 : x->parent = y;
291 : 268583 : }
292 : :
293 : : /*
294 : : * Rotate node x to right.
295 : : *
296 : : * x's left right child takes its place in the tree, and x becomes the right
297 : : * child of that node.
298 : : */
299 : : static void
1986 tgl@sss.pgh.pa.us 300 : 70915 : rbt_rotate_right(RBTree *rbt, RBTNode *x)
301 : : {
302 : 70915 : RBTNode *y = x->left;
303 : :
304 : : /* establish x->left link */
5176 teodor@sigaev.ru 305 : 70915 : x->left = y->right;
1986 tgl@sss.pgh.pa.us 306 [ + + ]: 70915 : if (y->right != RBTNIL)
5176 teodor@sigaev.ru 307 : 22722 : y->right->parent = x;
308 : :
309 : : /* establish y->parent link */
1986 tgl@sss.pgh.pa.us 310 [ + - ]: 70915 : if (y != RBTNIL)
5176 teodor@sigaev.ru 311 : 70915 : y->parent = x->parent;
312 [ + + ]: 70915 : if (x->parent)
313 : : {
314 [ + + ]: 70864 : if (x == x->parent->right)
315 : 62604 : x->parent->right = y;
316 : : else
317 : 8260 : x->parent->left = y;
318 : : }
319 : : else
320 : : {
1986 tgl@sss.pgh.pa.us 321 : 51 : rbt->root = y;
322 : : }
323 : :
324 : : /* link x and y */
5176 teodor@sigaev.ru 325 : 70915 : y->right = x;
1986 tgl@sss.pgh.pa.us 326 [ + - ]: 70915 : if (x != RBTNIL)
5176 teodor@sigaev.ru 327 : 70915 : x->parent = y;
328 : 70915 : }
329 : :
330 : : /*
331 : : * Maintain Red-Black tree balance after inserting node x.
332 : : *
333 : : * The newly inserted node is always initially marked red. That may lead to
334 : : * a situation where a red node has a red child, which is prohibited. We can
335 : : * always fix the problem by a series of color changes and/or "rotations",
336 : : * which move the problem progressively higher up in the tree. If one of the
337 : : * two red nodes is the root, we can always fix the problem by changing the
338 : : * root from red to black.
339 : : *
340 : : * (This does not work lower down in the tree because we must also maintain
341 : : * the invariant that every leaf has equal black-height.)
342 : : */
343 : : static void
1986 tgl@sss.pgh.pa.us 344 : 317625 : rbt_insert_fixup(RBTree *rbt, RBTNode *x)
345 : : {
346 : : /*
347 : : * x is always a red node. Initially, it is the newly inserted node. Each
348 : : * iteration of this loop moves it higher up in the tree.
349 : : */
350 [ + + + + ]: 866480 : while (x != rbt->root && x->parent->color == RBTRED)
351 : : {
352 : : /*
353 : : * x and x->parent are both red. Fix depends on whether x->parent is
354 : : * a left or right child. In either case, we define y to be the
355 : : * "uncle" of x, that is, the other child of x's grandparent.
356 : : *
357 : : * If the uncle is red, we flip the grandparent to red and its two
358 : : * children to black. Then we loop around again to check whether the
359 : : * grandparent still has a problem.
360 : : *
361 : : * If the uncle is black, we will perform one or two "rotations" to
362 : : * balance the tree. Either x or x->parent will take the
363 : : * grandparent's position in the tree and recolored black, and the
364 : : * original grandparent will be recolored red and become a child of
365 : : * that node. This always leaves us with a valid red-black tree, so
366 : : * the loop will terminate.
367 : : */
5176 teodor@sigaev.ru 368 [ + + ]: 548855 : if (x->parent == x->parent->parent->left)
369 : : {
1986 tgl@sss.pgh.pa.us 370 : 80485 : RBTNode *y = x->parent->parent->right;
371 : :
372 [ + + ]: 80485 : if (y->color == RBTRED)
373 : : {
374 : : /* uncle is RBTRED */
375 : 19402 : x->parent->color = RBTBLACK;
376 : 19402 : y->color = RBTBLACK;
377 : 19402 : x->parent->parent->color = RBTRED;
378 : :
5176 teodor@sigaev.ru 379 : 19402 : x = x->parent->parent;
380 : : }
381 : : else
382 : : {
383 : : /* uncle is RBTBLACK */
384 [ + + ]: 61083 : if (x == x->parent->right)
385 : : {
386 : : /* make x a left child */
387 : 53853 : x = x->parent;
1986 tgl@sss.pgh.pa.us 388 : 53853 : rbt_rotate_left(rbt, x);
389 : : }
390 : :
391 : : /* recolor and rotate */
392 : 61083 : x->parent->color = RBTBLACK;
393 : 61083 : x->parent->parent->color = RBTRED;
394 : :
395 : 61083 : rbt_rotate_right(rbt, x->parent->parent);
396 : : }
397 : : }
398 : : else
399 : : {
400 : : /* mirror image of above code */
401 : 468370 : RBTNode *y = x->parent->parent->left;
402 : :
403 [ + + ]: 468370 : if (y->color == RBTRED)
404 : : {
405 : : /* uncle is RBTRED */
406 : 259630 : x->parent->color = RBTBLACK;
407 : 259630 : y->color = RBTBLACK;
408 : 259630 : x->parent->parent->color = RBTRED;
409 : :
5176 teodor@sigaev.ru 410 : 259630 : x = x->parent->parent;
411 : : }
412 : : else
413 : : {
414 : : /* uncle is RBTBLACK */
415 [ + + ]: 208740 : if (x == x->parent->left)
416 : : {
417 : 7620 : x = x->parent;
1986 tgl@sss.pgh.pa.us 418 : 7620 : rbt_rotate_right(rbt, x);
419 : : }
420 : 208740 : x->parent->color = RBTBLACK;
421 : 208740 : x->parent->parent->color = RBTRED;
422 : :
423 : 208740 : rbt_rotate_left(rbt, x->parent->parent);
424 : : }
425 : : }
426 : : }
427 : :
428 : : /*
429 : : * The root may already have been black; if not, the black-height of every
430 : : * node in the tree increases by one.
431 : : */
432 : 317625 : rbt->root->color = RBTBLACK;
5176 teodor@sigaev.ru 433 : 317625 : }
434 : :
435 : : /*
436 : : * rbt_insert: insert a new value into the tree.
437 : : *
438 : : * data represents the value to insert. Its RBTNode fields need not
439 : : * be valid, it's the extra data in the larger struct that is of interest.
440 : : *
441 : : * If the value represented by "data" is not present in the tree, then
442 : : * we copy "data" into a new tree entry and return that node, setting *isNew
443 : : * to true.
444 : : *
445 : : * If the value represented by "data" is already present, then we call the
446 : : * combiner function to merge data into the existing node, and return the
447 : : * existing node, setting *isNew to false.
448 : : *
449 : : * "data" is unmodified in either case; it's typically just a local
450 : : * variable in the caller.
451 : : */
452 : : RBTNode *
1986 tgl@sss.pgh.pa.us 453 : 1321013 : rbt_insert(RBTree *rbt, const RBTNode *data, bool *isNew)
454 : : {
455 : : RBTNode *current,
456 : : *parent,
457 : : *x;
458 : : int cmp;
459 : :
460 : : /* find where node belongs */
461 : 1321013 : current = rbt->root;
5176 teodor@sigaev.ru 462 : 1321013 : parent = NULL;
5005 tgl@sss.pgh.pa.us 463 : 1321013 : cmp = 0; /* just to prevent compiler warning */
464 : :
1986 465 [ + + ]: 13766395 : while (current != RBTNIL)
466 : : {
467 : 13448770 : cmp = rbt->comparator(data, current, rbt->arg);
5176 teodor@sigaev.ru 468 [ + + ]: 13448770 : if (cmp == 0)
469 : : {
470 : : /*
471 : : * Found node with given key. Apply combiner.
472 : : */
1986 tgl@sss.pgh.pa.us 473 : 1003388 : rbt->combiner(current, data, rbt->arg);
5005 474 : 1003388 : *isNew = false;
475 : 1003388 : return current;
476 : : }
5176 teodor@sigaev.ru 477 : 12445382 : parent = current;
478 [ + + ]: 12445382 : current = (cmp < 0) ? current->left : current->right;
479 : : }
480 : :
481 : : /*
482 : : * Value is not present, so create a new node containing data.
483 : : */
5005 tgl@sss.pgh.pa.us 484 : 317625 : *isNew = true;
485 : :
1986 486 : 317625 : x = rbt->allocfunc(rbt->arg);
487 : :
488 : 317625 : x->color = RBTRED;
489 : :
490 : 317625 : x->left = RBTNIL;
491 : 317625 : x->right = RBTNIL;
5005 492 : 317625 : x->parent = parent;
1986 493 : 317625 : rbt_copy_data(rbt, x, data);
494 : :
495 : : /* insert node in tree */
5176 teodor@sigaev.ru 496 [ + + ]: 317625 : if (parent)
497 : : {
498 [ + + ]: 317467 : if (cmp < 0)
499 : 68590 : parent->left = x;
500 : : else
501 : 248877 : parent->right = x;
502 : : }
503 : : else
504 : : {
1986 tgl@sss.pgh.pa.us 505 : 158 : rbt->root = x;
506 : : }
507 : :
508 : 317625 : rbt_insert_fixup(rbt, x);
509 : :
5005 510 : 317625 : return x;
511 : : }
512 : :
513 : : /**********************************************************************
514 : : * Deletion *
515 : : **********************************************************************/
516 : :
517 : : /*
518 : : * Maintain Red-Black tree balance after deleting a black node.
519 : : */
520 : : static void
1986 521 : 12765 : rbt_delete_fixup(RBTree *rbt, RBTNode *x)
522 : : {
523 : : /*
524 : : * x is always a black node. Initially, it is the former child of the
525 : : * deleted node. Each iteration of this loop moves it higher up in the
526 : : * tree.
527 : : */
528 [ + + + + ]: 23783 : while (x != rbt->root && x->color == RBTBLACK)
529 : : {
530 : : /*
531 : : * Left and right cases are symmetric. Any nodes that are children of
532 : : * x have a black-height one less than the remainder of the nodes in
533 : : * the tree. We rotate and recolor nodes to move the problem up the
534 : : * tree: at some stage we'll either fix the problem, or reach the root
535 : : * (where the black-height is allowed to decrease).
536 : : */
5176 teodor@sigaev.ru 537 [ + + ]: 11018 : if (x == x->parent->left)
538 : : {
1986 tgl@sss.pgh.pa.us 539 : 9359 : RBTNode *w = x->parent->right;
540 : :
541 [ + + ]: 9359 : if (w->color == RBTRED)
542 : : {
543 : 2245 : w->color = RBTBLACK;
544 : 2245 : x->parent->color = RBTRED;
545 : :
546 : 2245 : rbt_rotate_left(rbt, x->parent);
5176 teodor@sigaev.ru 547 : 2245 : w = x->parent->right;
548 : : }
549 : :
1986 tgl@sss.pgh.pa.us 550 [ + + + + ]: 9359 : if (w->left->color == RBTBLACK && w->right->color == RBTBLACK)
551 : : {
552 : 5918 : w->color = RBTRED;
553 : :
5176 teodor@sigaev.ru 554 : 5918 : x = x->parent;
555 : : }
556 : : else
557 : : {
1986 tgl@sss.pgh.pa.us 558 [ + + ]: 3441 : if (w->right->color == RBTBLACK)
559 : : {
560 : 1149 : w->left->color = RBTBLACK;
561 : 1149 : w->color = RBTRED;
562 : :
563 : 1149 : rbt_rotate_right(rbt, w);
5176 teodor@sigaev.ru 564 : 1149 : w = x->parent->right;
565 : : }
566 : 3441 : w->color = x->parent->color;
1986 tgl@sss.pgh.pa.us 567 : 3441 : x->parent->color = RBTBLACK;
568 : 3441 : w->right->color = RBTBLACK;
569 : :
570 : 3441 : rbt_rotate_left(rbt, x->parent);
571 : 3441 : x = rbt->root; /* Arrange for loop to terminate. */
572 : : }
573 : : }
574 : : else
575 : : {
576 : 1659 : RBTNode *w = x->parent->left;
577 : :
578 [ + + ]: 1659 : if (w->color == RBTRED)
579 : : {
580 : 176 : w->color = RBTBLACK;
581 : 176 : x->parent->color = RBTRED;
582 : :
583 : 176 : rbt_rotate_right(rbt, x->parent);
5176 teodor@sigaev.ru 584 : 176 : w = x->parent->left;
585 : : }
586 : :
1986 tgl@sss.pgh.pa.us 587 [ + + + + ]: 1659 : if (w->right->color == RBTBLACK && w->left->color == RBTBLACK)
588 : : {
589 : 772 : w->color = RBTRED;
590 : :
5176 teodor@sigaev.ru 591 : 772 : x = x->parent;
592 : : }
593 : : else
594 : : {
1986 tgl@sss.pgh.pa.us 595 [ + + ]: 887 : if (w->left->color == RBTBLACK)
596 : : {
597 : 304 : w->right->color = RBTBLACK;
598 : 304 : w->color = RBTRED;
599 : :
600 : 304 : rbt_rotate_left(rbt, w);
5176 teodor@sigaev.ru 601 : 304 : w = x->parent->left;
602 : : }
603 : 887 : w->color = x->parent->color;
1986 tgl@sss.pgh.pa.us 604 : 887 : x->parent->color = RBTBLACK;
605 : 887 : w->left->color = RBTBLACK;
606 : :
607 : 887 : rbt_rotate_right(rbt, x->parent);
608 : 887 : x = rbt->root; /* Arrange for loop to terminate. */
609 : : }
610 : : }
611 : : }
612 : 12765 : x->color = RBTBLACK;
5176 teodor@sigaev.ru 613 : 12765 : }
614 : :
615 : : /*
616 : : * Delete node z from tree.
617 : : */
618 : : static void
1986 tgl@sss.pgh.pa.us 619 : 15016 : rbt_delete_node(RBTree *rbt, RBTNode *z)
620 : : {
621 : : RBTNode *x,
622 : : *y;
623 : :
624 : : /* This is just paranoia: we should only get called on a valid node */
625 [ + - - + ]: 15016 : if (!z || z == RBTNIL)
5176 teodor@sigaev.ru 626 :UBC 0 : return;
627 : :
628 : : /*
629 : : * y is the node that will actually be removed from the tree. This will
630 : : * be z if z has fewer than two children, or the tree successor of z
631 : : * otherwise.
632 : : */
1986 tgl@sss.pgh.pa.us 633 [ + + + + ]:CBC 15016 : if (z->left == RBTNIL || z->right == RBTNIL)
634 : : {
635 : : /* y has a RBTNIL node as a child */
5176 teodor@sigaev.ru 636 : 12621 : y = z;
637 : : }
638 : : else
639 : : {
640 : : /* find tree successor */
641 : 2395 : y = z->right;
1986 tgl@sss.pgh.pa.us 642 [ + + ]: 4726 : while (y->left != RBTNIL)
5176 teodor@sigaev.ru 643 : 2331 : y = y->left;
644 : : }
645 : :
646 : : /* x is y's only child */
1986 tgl@sss.pgh.pa.us 647 [ + + ]: 15016 : if (y->left != RBTNIL)
5176 teodor@sigaev.ru 648 : 678 : x = y->left;
649 : : else
650 : 14338 : x = y->right;
651 : :
652 : : /* Remove y from the tree. */
653 : 15016 : x->parent = y->parent;
654 [ + + ]: 15016 : if (y->parent)
655 : : {
656 [ + + ]: 15014 : if (y == y->parent->left)
657 : 11970 : y->parent->left = x;
658 : : else
659 : 3044 : y->parent->right = x;
660 : : }
661 : : else
662 : : {
1986 tgl@sss.pgh.pa.us 663 : 2 : rbt->root = x;
664 : : }
665 : :
666 : : /*
667 : : * If we removed the tree successor of z rather than z itself, then move
668 : : * the data for the removed node to the one we were supposed to remove.
669 : : */
5176 teodor@sigaev.ru 670 [ + + ]: 15016 : if (y != z)
1986 tgl@sss.pgh.pa.us 671 : 2395 : rbt_copy_data(rbt, z, y);
672 : :
673 : : /*
674 : : * Removing a black node might make some paths from root to leaf contain
675 : : * fewer black nodes than others, or it might make two red nodes adjacent.
676 : : */
677 [ + + ]: 15016 : if (y->color == RBTBLACK)
678 : 12765 : rbt_delete_fixup(rbt, x);
679 : :
680 : : /* Now we can recycle the y node */
681 [ + - ]: 15016 : if (rbt->freefunc)
682 : 15016 : rbt->freefunc(y, rbt->arg);
683 : : }
684 : :
685 : : /*
686 : : * rbt_delete: remove the given tree entry
687 : : *
688 : : * "node" must have previously been found via rbt_find or rbt_leftmost.
689 : : * It is caller's responsibility to free any subsidiary data attached
690 : : * to the node before calling rbt_delete. (Do *not* try to push that
691 : : * responsibility off to the freefunc, as some other physical node
692 : : * may be the one actually freed!)
693 : : */
694 : : void
695 : 15016 : rbt_delete(RBTree *rbt, RBTNode *node)
696 : : {
697 : 15016 : rbt_delete_node(rbt, node);
5176 teodor@sigaev.ru 698 : 15016 : }
699 : :
700 : : /**********************************************************************
701 : : * Traverse *
702 : : **********************************************************************/
703 : :
704 : : static RBTNode *
1986 tgl@sss.pgh.pa.us 705 : 267778 : rbt_left_right_iterator(RBTreeIterator *iter)
706 : : {
2781 heikki.linnakangas@i 707 [ + + ]: 267778 : if (iter->last_visited == NULL)
708 : : {
1986 tgl@sss.pgh.pa.us 709 : 153 : iter->last_visited = iter->rbt->root;
710 [ + + ]: 889 : while (iter->last_visited->left != RBTNIL)
2781 heikki.linnakangas@i 711 : 736 : iter->last_visited = iter->last_visited->left;
712 : :
713 : 153 : return iter->last_visited;
714 : : }
715 : :
1986 tgl@sss.pgh.pa.us 716 [ + + ]: 267625 : if (iter->last_visited->right != RBTNIL)
717 : : {
2781 heikki.linnakangas@i 718 : 133828 : iter->last_visited = iter->last_visited->right;
1986 tgl@sss.pgh.pa.us 719 [ + + ]: 266736 : while (iter->last_visited->left != RBTNIL)
2781 heikki.linnakangas@i 720 : 132908 : iter->last_visited = iter->last_visited->left;
721 : :
722 : 133828 : return iter->last_visited;
723 : : }
724 : :
725 : : for (;;)
5176 teodor@sigaev.ru 726 : 133828 : {
1986 tgl@sss.pgh.pa.us 727 : 267625 : RBTNode *came_from = iter->last_visited;
728 : :
2781 heikki.linnakangas@i 729 : 267625 : iter->last_visited = iter->last_visited->parent;
730 [ + + ]: 267625 : if (iter->last_visited == NULL)
731 : : {
732 : 153 : iter->is_over = true;
5176 teodor@sigaev.ru 733 : 153 : break;
734 : : }
735 : :
2781 heikki.linnakangas@i 736 [ + + ]: 267472 : if (iter->last_visited->left == came_from)
737 : 133644 : break; /* came from left sub-tree, return current
738 : : * node */
739 : :
740 : : /* else - came from right sub-tree, continue to move up */
741 : : }
742 : :
743 : 133797 : return iter->last_visited;
744 : : }
745 : :
746 : : static RBTNode *
1986 tgl@sss.pgh.pa.us 747 : 10001 : rbt_right_left_iterator(RBTreeIterator *iter)
748 : : {
2781 heikki.linnakangas@i 749 [ + + ]: 10001 : if (iter->last_visited == NULL)
750 : : {
1986 tgl@sss.pgh.pa.us 751 : 1 : iter->last_visited = iter->rbt->root;
752 [ + + ]: 13 : while (iter->last_visited->right != RBTNIL)
2781 heikki.linnakangas@i 753 : 12 : iter->last_visited = iter->last_visited->right;
754 : :
755 : 1 : return iter->last_visited;
756 : : }
757 : :
1986 tgl@sss.pgh.pa.us 758 [ + + ]: 10000 : if (iter->last_visited->left != RBTNIL)
759 : : {
2781 heikki.linnakangas@i 760 : 4991 : iter->last_visited = iter->last_visited->left;
1986 tgl@sss.pgh.pa.us 761 [ + + ]: 9987 : while (iter->last_visited->right != RBTNIL)
2781 heikki.linnakangas@i 762 : 4996 : iter->last_visited = iter->last_visited->right;
763 : :
764 : 4991 : return iter->last_visited;
765 : : }
766 : :
767 : : for (;;)
768 : 4991 : {
1986 tgl@sss.pgh.pa.us 769 : 10000 : RBTNode *came_from = iter->last_visited;
770 : :
2781 heikki.linnakangas@i 771 : 10000 : iter->last_visited = iter->last_visited->parent;
772 [ + + ]: 10000 : if (iter->last_visited == NULL)
773 : : {
774 : 1 : iter->is_over = true;
5176 teodor@sigaev.ru 775 : 1 : break;
776 : : }
777 : :
2781 heikki.linnakangas@i 778 [ + + ]: 9999 : if (iter->last_visited->right == came_from)
779 : 5008 : break; /* came from right sub-tree, return current
780 : : * node */
781 : :
782 : : /* else - came from left sub-tree, continue to move up */
783 : : }
784 : :
785 : 5009 : return iter->last_visited;
786 : : }
787 : :
788 : : /*
789 : : * rbt_begin_iterate: prepare to traverse the tree in any of several orders
790 : : *
791 : : * After calling rbt_begin_iterate, call rbt_iterate repeatedly until it
792 : : * returns NULL or the traversal stops being of interest.
793 : : *
794 : : * If the tree is changed during traversal, results of further calls to
795 : : * rbt_iterate are unspecified. Multiple concurrent iterators on the same
796 : : * tree are allowed.
797 : : *
798 : : * The iterator state is stored in the 'iter' struct. The caller should
799 : : * treat it as an opaque struct.
800 : : */
801 : : void
1986 tgl@sss.pgh.pa.us 802 : 179 : rbt_begin_iterate(RBTree *rbt, RBTOrderControl ctrl, RBTreeIterator *iter)
803 : : {
804 : : /* Common initialization for all traversal orders */
805 : 179 : iter->rbt = rbt;
2781 heikki.linnakangas@i 806 : 179 : iter->last_visited = NULL;
1986 tgl@sss.pgh.pa.us 807 : 179 : iter->is_over = (rbt->root == RBTNIL);
808 : :
5176 teodor@sigaev.ru 809 [ + + - ]: 179 : switch (ctrl)
810 : : {
5161 bruce@momjian.us 811 : 177 : case LeftRightWalk: /* visit left, then self, then right */
1986 tgl@sss.pgh.pa.us 812 : 177 : iter->iterate = rbt_left_right_iterator;
5176 teodor@sigaev.ru 813 : 177 : break;
5161 bruce@momjian.us 814 : 2 : case RightLeftWalk: /* visit right, then self, then left */
1986 tgl@sss.pgh.pa.us 815 : 2 : iter->iterate = rbt_right_left_iterator;
5176 teodor@sigaev.ru 816 : 2 : break;
5176 teodor@sigaev.ru 817 :UBC 0 : default:
5005 tgl@sss.pgh.pa.us 818 [ # # ]: 0 : elog(ERROR, "unrecognized rbtree iteration order: %d", ctrl);
819 : : }
5176 teodor@sigaev.ru 820 :CBC 179 : }
821 : :
822 : : /*
823 : : * rbt_iterate: return the next node in traversal order, or NULL if no more
824 : : */
825 : : RBTNode *
1986 tgl@sss.pgh.pa.us 826 : 277804 : rbt_iterate(RBTreeIterator *iter)
827 : : {
2781 heikki.linnakangas@i 828 [ + + ]: 277804 : if (iter->is_over)
5176 teodor@sigaev.ru 829 : 25 : return NULL;
830 : :
2781 heikki.linnakangas@i 831 : 277779 : return iter->iterate(iter);
832 : : }
|