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-2019, 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 | RBTBLACK, RBTNIL, RBTNIL, 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 * |
102 | 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 | { |
109 | RBTree *tree = (RBTree *) palloc(sizeof(RBTree)); |
110 | |
111 | Assert(node_size > sizeof(RBTNode)); |
112 | |
113 | tree->root = RBTNIL; |
114 | tree->node_size = node_size; |
115 | tree->comparator = comparator; |
116 | tree->combiner = combiner; |
117 | tree->allocfunc = allocfunc; |
118 | tree->freefunc = freefunc; |
119 | |
120 | tree->arg = arg; |
121 | |
122 | return tree; |
123 | } |
124 | |
125 | /* Copy the additional data fields from one RBTNode to another */ |
126 | static inline void |
127 | rbt_copy_data(RBTree *rbt, RBTNode *dest, const RBTNode *src) |
128 | { |
129 | memcpy(dest + 1, src + 1, rbt->node_size - sizeof(RBTNode)); |
130 | } |
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 * |
145 | rbt_find(RBTree *rbt, const RBTNode *data) |
146 | { |
147 | RBTNode *node = rbt->root; |
148 | |
149 | while (node != RBTNIL) |
150 | { |
151 | int cmp = rbt->comparator(data, node, rbt->arg); |
152 | |
153 | if (cmp == 0) |
154 | return node; |
155 | else if (cmp < 0) |
156 | node = node->left; |
157 | else |
158 | node = node->right; |
159 | } |
160 | |
161 | return NULL; |
162 | } |
163 | |
164 | /* |
165 | * rbt_leftmost: fetch the leftmost (smallest-valued) tree node. |
166 | * Returns NULL if tree is empty. |
167 | * |
168 | * Note: in the original implementation this included an unlink step, but |
169 | * that's a bit awkward. Just call rbt_delete on the result if that's what |
170 | * you want. |
171 | */ |
172 | RBTNode * |
173 | rbt_leftmost(RBTree *rbt) |
174 | { |
175 | RBTNode *node = rbt->root; |
176 | RBTNode *leftmost = rbt->root; |
177 | |
178 | while (node != RBTNIL) |
179 | { |
180 | leftmost = node; |
181 | node = node->left; |
182 | } |
183 | |
184 | if (leftmost != RBTNIL) |
185 | return leftmost; |
186 | |
187 | return NULL; |
188 | } |
189 | |
190 | /********************************************************************** |
191 | * Insertion * |
192 | **********************************************************************/ |
193 | |
194 | /* |
195 | * Rotate node x to left. |
196 | * |
197 | * x's right child takes its place in the tree, and x becomes the left |
198 | * child of that node. |
199 | */ |
200 | static void |
201 | rbt_rotate_left(RBTree *rbt, RBTNode *x) |
202 | { |
203 | RBTNode *y = x->right; |
204 | |
205 | /* establish x->right link */ |
206 | x->right = y->left; |
207 | if (y->left != RBTNIL) |
208 | y->left->parent = x; |
209 | |
210 | /* establish y->parent link */ |
211 | if (y != RBTNIL) |
212 | y->parent = x->parent; |
213 | if (x->parent) |
214 | { |
215 | if (x == x->parent->left) |
216 | x->parent->left = y; |
217 | else |
218 | x->parent->right = y; |
219 | } |
220 | else |
221 | { |
222 | rbt->root = y; |
223 | } |
224 | |
225 | /* link x and y */ |
226 | y->left = x; |
227 | if (x != RBTNIL) |
228 | x->parent = y; |
229 | } |
230 | |
231 | /* |
232 | * Rotate node x to right. |
233 | * |
234 | * x's left right child takes its place in the tree, and x becomes the right |
235 | * child of that node. |
236 | */ |
237 | static void |
238 | rbt_rotate_right(RBTree *rbt, RBTNode *x) |
239 | { |
240 | RBTNode *y = x->left; |
241 | |
242 | /* establish x->left link */ |
243 | x->left = y->right; |
244 | if (y->right != RBTNIL) |
245 | y->right->parent = x; |
246 | |
247 | /* establish y->parent link */ |
248 | if (y != RBTNIL) |
249 | y->parent = x->parent; |
250 | if (x->parent) |
251 | { |
252 | if (x == x->parent->right) |
253 | x->parent->right = y; |
254 | else |
255 | x->parent->left = y; |
256 | } |
257 | else |
258 | { |
259 | rbt->root = y; |
260 | } |
261 | |
262 | /* link x and y */ |
263 | y->right = x; |
264 | if (x != RBTNIL) |
265 | x->parent = y; |
266 | } |
267 | |
268 | /* |
269 | * Maintain Red-Black tree balance after inserting node x. |
270 | * |
271 | * The newly inserted node is always initially marked red. That may lead to |
272 | * a situation where a red node has a red child, which is prohibited. We can |
273 | * always fix the problem by a series of color changes and/or "rotations", |
274 | * which move the problem progressively higher up in the tree. If one of the |
275 | * two red nodes is the root, we can always fix the problem by changing the |
276 | * root from red to black. |
277 | * |
278 | * (This does not work lower down in the tree because we must also maintain |
279 | * the invariant that every leaf has equal black-height.) |
280 | */ |
281 | static void |
282 | rbt_insert_fixup(RBTree *rbt, RBTNode *x) |
283 | { |
284 | /* |
285 | * x is always a red node. Initially, it is the newly inserted node. Each |
286 | * iteration of this loop moves it higher up in the tree. |
287 | */ |
288 | while (x != rbt->root && x->parent->color == RBTRED) |
289 | { |
290 | /* |
291 | * x and x->parent are both red. Fix depends on whether x->parent is |
292 | * a left or right child. In either case, we define y to be the |
293 | * "uncle" of x, that is, the other child of x's grandparent. |
294 | * |
295 | * If the uncle is red, we flip the grandparent to red and its two |
296 | * children to black. Then we loop around again to check whether the |
297 | * grandparent still has a problem. |
298 | * |
299 | * If the uncle is black, we will perform one or two "rotations" to |
300 | * balance the tree. Either x or x->parent will take the |
301 | * grandparent's position in the tree and recolored black, and the |
302 | * original grandparent will be recolored red and become a child of |
303 | * that node. This always leaves us with a valid red-black tree, so |
304 | * the loop will terminate. |
305 | */ |
306 | if (x->parent == x->parent->parent->left) |
307 | { |
308 | RBTNode *y = x->parent->parent->right; |
309 | |
310 | if (y->color == RBTRED) |
311 | { |
312 | /* uncle is RBTRED */ |
313 | x->parent->color = RBTBLACK; |
314 | y->color = RBTBLACK; |
315 | x->parent->parent->color = RBTRED; |
316 | |
317 | x = x->parent->parent; |
318 | } |
319 | else |
320 | { |
321 | /* uncle is RBTBLACK */ |
322 | if (x == x->parent->right) |
323 | { |
324 | /* make x a left child */ |
325 | x = x->parent; |
326 | rbt_rotate_left(rbt, x); |
327 | } |
328 | |
329 | /* recolor and rotate */ |
330 | x->parent->color = RBTBLACK; |
331 | x->parent->parent->color = RBTRED; |
332 | |
333 | rbt_rotate_right(rbt, x->parent->parent); |
334 | } |
335 | } |
336 | else |
337 | { |
338 | /* mirror image of above code */ |
339 | RBTNode *y = x->parent->parent->left; |
340 | |
341 | if (y->color == RBTRED) |
342 | { |
343 | /* uncle is RBTRED */ |
344 | x->parent->color = RBTBLACK; |
345 | y->color = RBTBLACK; |
346 | x->parent->parent->color = RBTRED; |
347 | |
348 | x = x->parent->parent; |
349 | } |
350 | else |
351 | { |
352 | /* uncle is RBTBLACK */ |
353 | if (x == x->parent->left) |
354 | { |
355 | x = x->parent; |
356 | rbt_rotate_right(rbt, x); |
357 | } |
358 | x->parent->color = RBTBLACK; |
359 | x->parent->parent->color = RBTRED; |
360 | |
361 | rbt_rotate_left(rbt, x->parent->parent); |
362 | } |
363 | } |
364 | } |
365 | |
366 | /* |
367 | * The root may already have been black; if not, the black-height of every |
368 | * node in the tree increases by one. |
369 | */ |
370 | rbt->root->color = RBTBLACK; |
371 | } |
372 | |
373 | /* |
374 | * rbt_insert: insert a new value into the tree. |
375 | * |
376 | * data represents the value to insert. Its RBTNode fields need not |
377 | * be valid, it's the extra data in the larger struct that is of interest. |
378 | * |
379 | * If the value represented by "data" is not present in the tree, then |
380 | * we copy "data" into a new tree entry and return that node, setting *isNew |
381 | * to true. |
382 | * |
383 | * If the value represented by "data" is already present, then we call the |
384 | * combiner function to merge data into the existing node, and return the |
385 | * existing node, setting *isNew to false. |
386 | * |
387 | * "data" is unmodified in either case; it's typically just a local |
388 | * variable in the caller. |
389 | */ |
390 | RBTNode * |
391 | rbt_insert(RBTree *rbt, const RBTNode *data, bool *isNew) |
392 | { |
393 | RBTNode *current, |
394 | *parent, |
395 | *x; |
396 | int cmp; |
397 | |
398 | /* find where node belongs */ |
399 | current = rbt->root; |
400 | parent = NULL; |
401 | cmp = 0; /* just to prevent compiler warning */ |
402 | |
403 | while (current != RBTNIL) |
404 | { |
405 | cmp = rbt->comparator(data, current, rbt->arg); |
406 | if (cmp == 0) |
407 | { |
408 | /* |
409 | * Found node with given key. Apply combiner. |
410 | */ |
411 | rbt->combiner(current, data, rbt->arg); |
412 | *isNew = false; |
413 | return current; |
414 | } |
415 | parent = current; |
416 | current = (cmp < 0) ? current->left : current->right; |
417 | } |
418 | |
419 | /* |
420 | * Value is not present, so create a new node containing data. |
421 | */ |
422 | *isNew = true; |
423 | |
424 | x = rbt->allocfunc(rbt->arg); |
425 | |
426 | x->color = RBTRED; |
427 | |
428 | x->left = RBTNIL; |
429 | x->right = RBTNIL; |
430 | x->parent = parent; |
431 | rbt_copy_data(rbt, x, data); |
432 | |
433 | /* insert node in tree */ |
434 | if (parent) |
435 | { |
436 | if (cmp < 0) |
437 | parent->left = x; |
438 | else |
439 | parent->right = x; |
440 | } |
441 | else |
442 | { |
443 | rbt->root = x; |
444 | } |
445 | |
446 | rbt_insert_fixup(rbt, x); |
447 | |
448 | return x; |
449 | } |
450 | |
451 | /********************************************************************** |
452 | * Deletion * |
453 | **********************************************************************/ |
454 | |
455 | /* |
456 | * Maintain Red-Black tree balance after deleting a black node. |
457 | */ |
458 | static void |
459 | rbt_delete_fixup(RBTree *rbt, RBTNode *x) |
460 | { |
461 | /* |
462 | * x is always a black node. Initially, it is the former child of the |
463 | * deleted node. Each iteration of this loop moves it higher up in the |
464 | * tree. |
465 | */ |
466 | while (x != rbt->root && x->color == RBTBLACK) |
467 | { |
468 | /* |
469 | * Left and right cases are symmetric. Any nodes that are children of |
470 | * x have a black-height one less than the remainder of the nodes in |
471 | * the tree. We rotate and recolor nodes to move the problem up the |
472 | * tree: at some stage we'll either fix the problem, or reach the root |
473 | * (where the black-height is allowed to decrease). |
474 | */ |
475 | if (x == x->parent->left) |
476 | { |
477 | RBTNode *w = x->parent->right; |
478 | |
479 | if (w->color == RBTRED) |
480 | { |
481 | w->color = RBTBLACK; |
482 | x->parent->color = RBTRED; |
483 | |
484 | rbt_rotate_left(rbt, x->parent); |
485 | w = x->parent->right; |
486 | } |
487 | |
488 | if (w->left->color == RBTBLACK && w->right->color == RBTBLACK) |
489 | { |
490 | w->color = RBTRED; |
491 | |
492 | x = x->parent; |
493 | } |
494 | else |
495 | { |
496 | if (w->right->color == RBTBLACK) |
497 | { |
498 | w->left->color = RBTBLACK; |
499 | w->color = RBTRED; |
500 | |
501 | rbt_rotate_right(rbt, w); |
502 | w = x->parent->right; |
503 | } |
504 | w->color = x->parent->color; |
505 | x->parent->color = RBTBLACK; |
506 | w->right->color = RBTBLACK; |
507 | |
508 | rbt_rotate_left(rbt, x->parent); |
509 | x = rbt->root; /* Arrange for loop to terminate. */ |
510 | } |
511 | } |
512 | else |
513 | { |
514 | RBTNode *w = x->parent->left; |
515 | |
516 | if (w->color == RBTRED) |
517 | { |
518 | w->color = RBTBLACK; |
519 | x->parent->color = RBTRED; |
520 | |
521 | rbt_rotate_right(rbt, x->parent); |
522 | w = x->parent->left; |
523 | } |
524 | |
525 | if (w->right->color == RBTBLACK && w->left->color == RBTBLACK) |
526 | { |
527 | w->color = RBTRED; |
528 | |
529 | x = x->parent; |
530 | } |
531 | else |
532 | { |
533 | if (w->left->color == RBTBLACK) |
534 | { |
535 | w->right->color = RBTBLACK; |
536 | w->color = RBTRED; |
537 | |
538 | rbt_rotate_left(rbt, w); |
539 | w = x->parent->left; |
540 | } |
541 | w->color = x->parent->color; |
542 | x->parent->color = RBTBLACK; |
543 | w->left->color = RBTBLACK; |
544 | |
545 | rbt_rotate_right(rbt, x->parent); |
546 | x = rbt->root; /* Arrange for loop to terminate. */ |
547 | } |
548 | } |
549 | } |
550 | x->color = RBTBLACK; |
551 | } |
552 | |
553 | /* |
554 | * Delete node z from tree. |
555 | */ |
556 | static void |
557 | rbt_delete_node(RBTree *rbt, RBTNode *z) |
558 | { |
559 | RBTNode *x, |
560 | *y; |
561 | |
562 | /* This is just paranoia: we should only get called on a valid node */ |
563 | if (!z || z == RBTNIL) |
564 | return; |
565 | |
566 | /* |
567 | * y is the node that will actually be removed from the tree. This will |
568 | * be z if z has fewer than two children, or the tree successor of z |
569 | * otherwise. |
570 | */ |
571 | if (z->left == RBTNIL || z->right == RBTNIL) |
572 | { |
573 | /* y has a RBTNIL node as a child */ |
574 | y = z; |
575 | } |
576 | else |
577 | { |
578 | /* find tree successor */ |
579 | y = z->right; |
580 | while (y->left != RBTNIL) |
581 | y = y->left; |
582 | } |
583 | |
584 | /* x is y's only child */ |
585 | if (y->left != RBTNIL) |
586 | x = y->left; |
587 | else |
588 | x = y->right; |
589 | |
590 | /* Remove y from the tree. */ |
591 | x->parent = y->parent; |
592 | if (y->parent) |
593 | { |
594 | if (y == y->parent->left) |
595 | y->parent->left = x; |
596 | else |
597 | y->parent->right = x; |
598 | } |
599 | else |
600 | { |
601 | rbt->root = x; |
602 | } |
603 | |
604 | /* |
605 | * If we removed the tree successor of z rather than z itself, then move |
606 | * the data for the removed node to the one we were supposed to remove. |
607 | */ |
608 | if (y != z) |
609 | rbt_copy_data(rbt, z, y); |
610 | |
611 | /* |
612 | * Removing a black node might make some paths from root to leaf contain |
613 | * fewer black nodes than others, or it might make two red nodes adjacent. |
614 | */ |
615 | if (y->color == RBTBLACK) |
616 | rbt_delete_fixup(rbt, x); |
617 | |
618 | /* Now we can recycle the y node */ |
619 | if (rbt->freefunc) |
620 | rbt->freefunc(y, rbt->arg); |
621 | } |
622 | |
623 | /* |
624 | * rbt_delete: remove the given tree entry |
625 | * |
626 | * "node" must have previously been found via rbt_find or rbt_leftmost. |
627 | * It is caller's responsibility to free any subsidiary data attached |
628 | * to the node before calling rbt_delete. (Do *not* try to push that |
629 | * responsibility off to the freefunc, as some other physical node |
630 | * may be the one actually freed!) |
631 | */ |
632 | void |
633 | rbt_delete(RBTree *rbt, RBTNode *node) |
634 | { |
635 | rbt_delete_node(rbt, node); |
636 | } |
637 | |
638 | /********************************************************************** |
639 | * Traverse * |
640 | **********************************************************************/ |
641 | |
642 | static RBTNode * |
643 | rbt_left_right_iterator(RBTreeIterator *iter) |
644 | { |
645 | if (iter->last_visited == NULL) |
646 | { |
647 | iter->last_visited = iter->rbt->root; |
648 | while (iter->last_visited->left != RBTNIL) |
649 | iter->last_visited = iter->last_visited->left; |
650 | |
651 | return iter->last_visited; |
652 | } |
653 | |
654 | if (iter->last_visited->right != RBTNIL) |
655 | { |
656 | iter->last_visited = iter->last_visited->right; |
657 | while (iter->last_visited->left != RBTNIL) |
658 | iter->last_visited = iter->last_visited->left; |
659 | |
660 | return iter->last_visited; |
661 | } |
662 | |
663 | for (;;) |
664 | { |
665 | RBTNode *came_from = iter->last_visited; |
666 | |
667 | iter->last_visited = iter->last_visited->parent; |
668 | if (iter->last_visited == NULL) |
669 | { |
670 | iter->is_over = true; |
671 | break; |
672 | } |
673 | |
674 | if (iter->last_visited->left == came_from) |
675 | break; /* came from left sub-tree, return current |
676 | * node */ |
677 | |
678 | /* else - came from right sub-tree, continue to move up */ |
679 | } |
680 | |
681 | return iter->last_visited; |
682 | } |
683 | |
684 | static RBTNode * |
685 | rbt_right_left_iterator(RBTreeIterator *iter) |
686 | { |
687 | if (iter->last_visited == NULL) |
688 | { |
689 | iter->last_visited = iter->rbt->root; |
690 | while (iter->last_visited->right != RBTNIL) |
691 | iter->last_visited = iter->last_visited->right; |
692 | |
693 | return iter->last_visited; |
694 | } |
695 | |
696 | if (iter->last_visited->left != RBTNIL) |
697 | { |
698 | iter->last_visited = iter->last_visited->left; |
699 | while (iter->last_visited->right != RBTNIL) |
700 | iter->last_visited = iter->last_visited->right; |
701 | |
702 | return iter->last_visited; |
703 | } |
704 | |
705 | for (;;) |
706 | { |
707 | RBTNode *came_from = iter->last_visited; |
708 | |
709 | iter->last_visited = iter->last_visited->parent; |
710 | if (iter->last_visited == NULL) |
711 | { |
712 | iter->is_over = true; |
713 | break; |
714 | } |
715 | |
716 | if (iter->last_visited->right == came_from) |
717 | break; /* came from right sub-tree, return current |
718 | * node */ |
719 | |
720 | /* else - came from left sub-tree, continue to move up */ |
721 | } |
722 | |
723 | return iter->last_visited; |
724 | } |
725 | |
726 | /* |
727 | * rbt_begin_iterate: prepare to traverse the tree in any of several orders |
728 | * |
729 | * After calling rbt_begin_iterate, call rbt_iterate repeatedly until it |
730 | * returns NULL or the traversal stops being of interest. |
731 | * |
732 | * If the tree is changed during traversal, results of further calls to |
733 | * rbt_iterate are unspecified. Multiple concurrent iterators on the same |
734 | * tree are allowed. |
735 | * |
736 | * The iterator state is stored in the 'iter' struct. The caller should |
737 | * treat it as an opaque struct. |
738 | */ |
739 | void |
740 | rbt_begin_iterate(RBTree *rbt, RBTOrderControl ctrl, RBTreeIterator *iter) |
741 | { |
742 | /* Common initialization for all traversal orders */ |
743 | iter->rbt = rbt; |
744 | iter->last_visited = NULL; |
745 | iter->is_over = (rbt->root == RBTNIL); |
746 | |
747 | switch (ctrl) |
748 | { |
749 | case LeftRightWalk: /* visit left, then self, then right */ |
750 | iter->iterate = rbt_left_right_iterator; |
751 | break; |
752 | case RightLeftWalk: /* visit right, then self, then left */ |
753 | iter->iterate = rbt_right_left_iterator; |
754 | break; |
755 | default: |
756 | elog(ERROR, "unrecognized rbtree iteration order: %d" , ctrl); |
757 | } |
758 | } |
759 | |
760 | /* |
761 | * rbt_iterate: return the next node in traversal order, or NULL if no more |
762 | */ |
763 | RBTNode * |
764 | rbt_iterate(RBTreeIterator *iter) |
765 | { |
766 | if (iter->is_over) |
767 | return NULL; |
768 | |
769 | return iter->iterate(iter); |
770 | } |
771 | |