Coverage Report

Created: 2025-08-12 06:43

/src/postgres/src/backend/lib/rbtree.c
Line
Count
Source (jump to first uncovered line)
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-2025, 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
0
#define RBTBLACK  (0)
36
0
#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
0
#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 *
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
0
{
109
0
  RBTree     *tree = (RBTree *) palloc(sizeof(RBTree));
110
111
0
  Assert(node_size > sizeof(RBTNode));
112
113
0
  tree->root = RBTNIL;
114
0
  tree->node_size = node_size;
115
0
  tree->comparator = comparator;
116
0
  tree->combiner = combiner;
117
0
  tree->allocfunc = allocfunc;
118
0
  tree->freefunc = freefunc;
119
120
0
  tree->arg = arg;
121
122
0
  return tree;
123
0
}
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
0
{
129
0
  memcpy(dest + 1, src + 1, rbt->node_size - sizeof(RBTNode));
130
0
}
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
0
{
147
0
  RBTNode    *node = rbt->root;
148
149
0
  while (node != RBTNIL)
150
0
  {
151
0
    int     cmp = rbt->comparator(data, node, rbt->arg);
152
153
0
    if (cmp == 0)
154
0
      return node;
155
0
    else if (cmp < 0)
156
0
      node = node->left;
157
0
    else
158
0
      node = node->right;
159
0
  }
160
161
0
  return NULL;
162
0
}
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 *
172
rbt_find_great(RBTree *rbt, const RBTNode *data, bool equal_match)
173
0
{
174
0
  RBTNode    *node = rbt->root;
175
0
  RBTNode    *greater = NULL;
176
177
0
  while (node != RBTNIL)
178
0
  {
179
0
    int     cmp = rbt->comparator(data, node, rbt->arg);
180
181
0
    if (equal_match && cmp == 0)
182
0
      return node;
183
0
    else if (cmp < 0)
184
0
    {
185
0
      greater = node;
186
0
      node = node->left;
187
0
    }
188
0
    else
189
0
      node = node->right;
190
0
  }
191
192
0
  return greater;
193
0
}
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
rbt_find_less(RBTree *rbt, const RBTNode *data, bool equal_match)
204
0
{
205
0
  RBTNode    *node = rbt->root;
206
0
  RBTNode    *lesser = NULL;
207
208
0
  while (node != RBTNIL)
209
0
  {
210
0
    int     cmp = rbt->comparator(data, node, rbt->arg);
211
212
0
    if (equal_match && cmp == 0)
213
0
      return node;
214
0
    else if (cmp > 0)
215
0
    {
216
0
      lesser = node;
217
0
      node = node->right;
218
0
    }
219
0
    else
220
0
      node = node->left;
221
0
  }
222
223
0
  return lesser;
224
0
}
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 *
235
rbt_leftmost(RBTree *rbt)
236
0
{
237
0
  RBTNode    *node = rbt->root;
238
0
  RBTNode    *leftmost = rbt->root;
239
240
0
  while (node != RBTNIL)
241
0
  {
242
0
    leftmost = node;
243
0
    node = node->left;
244
0
  }
245
246
0
  if (leftmost != RBTNIL)
247
0
    return leftmost;
248
249
0
  return NULL;
250
0
}
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
263
rbt_rotate_left(RBTree *rbt, RBTNode *x)
264
0
{
265
0
  RBTNode    *y = x->right;
266
267
  /* establish x->right link */
268
0
  x->right = y->left;
269
0
  if (y->left != RBTNIL)
270
0
    y->left->parent = x;
271
272
  /* establish y->parent link */
273
0
  if (y != RBTNIL)
274
0
    y->parent = x->parent;
275
0
  if (x->parent)
276
0
  {
277
0
    if (x == x->parent->left)
278
0
      x->parent->left = y;
279
0
    else
280
0
      x->parent->right = y;
281
0
  }
282
0
  else
283
0
  {
284
0
    rbt->root = y;
285
0
  }
286
287
  /* link x and y */
288
0
  y->left = x;
289
0
  if (x != RBTNIL)
290
0
    x->parent = y;
291
0
}
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
300
rbt_rotate_right(RBTree *rbt, RBTNode *x)
301
0
{
302
0
  RBTNode    *y = x->left;
303
304
  /* establish x->left link */
305
0
  x->left = y->right;
306
0
  if (y->right != RBTNIL)
307
0
    y->right->parent = x;
308
309
  /* establish y->parent link */
310
0
  if (y != RBTNIL)
311
0
    y->parent = x->parent;
312
0
  if (x->parent)
313
0
  {
314
0
    if (x == x->parent->right)
315
0
      x->parent->right = y;
316
0
    else
317
0
      x->parent->left = y;
318
0
  }
319
0
  else
320
0
  {
321
0
    rbt->root = y;
322
0
  }
323
324
  /* link x and y */
325
0
  y->right = x;
326
0
  if (x != RBTNIL)
327
0
    x->parent = y;
328
0
}
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
344
rbt_insert_fixup(RBTree *rbt, RBTNode *x)
345
0
{
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
0
  while (x != rbt->root && x->parent->color == RBTRED)
351
0
  {
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
     */
368
0
    if (x->parent == x->parent->parent->left)
369
0
    {
370
0
      RBTNode    *y = x->parent->parent->right;
371
372
0
      if (y->color == RBTRED)
373
0
      {
374
        /* uncle is RBTRED */
375
0
        x->parent->color = RBTBLACK;
376
0
        y->color = RBTBLACK;
377
0
        x->parent->parent->color = RBTRED;
378
379
0
        x = x->parent->parent;
380
0
      }
381
0
      else
382
0
      {
383
        /* uncle is RBTBLACK */
384
0
        if (x == x->parent->right)
385
0
        {
386
          /* make x a left child */
387
0
          x = x->parent;
388
0
          rbt_rotate_left(rbt, x);
389
0
        }
390
391
        /* recolor and rotate */
392
0
        x->parent->color = RBTBLACK;
393
0
        x->parent->parent->color = RBTRED;
394
395
0
        rbt_rotate_right(rbt, x->parent->parent);
396
0
      }
397
0
    }
398
0
    else
399
0
    {
400
      /* mirror image of above code */
401
0
      RBTNode    *y = x->parent->parent->left;
402
403
0
      if (y->color == RBTRED)
404
0
      {
405
        /* uncle is RBTRED */
406
0
        x->parent->color = RBTBLACK;
407
0
        y->color = RBTBLACK;
408
0
        x->parent->parent->color = RBTRED;
409
410
0
        x = x->parent->parent;
411
0
      }
412
0
      else
413
0
      {
414
        /* uncle is RBTBLACK */
415
0
        if (x == x->parent->left)
416
0
        {
417
0
          x = x->parent;
418
0
          rbt_rotate_right(rbt, x);
419
0
        }
420
0
        x->parent->color = RBTBLACK;
421
0
        x->parent->parent->color = RBTRED;
422
423
0
        rbt_rotate_left(rbt, x->parent->parent);
424
0
      }
425
0
    }
426
0
  }
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
0
  rbt->root->color = RBTBLACK;
433
0
}
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 *
453
rbt_insert(RBTree *rbt, const RBTNode *data, bool *isNew)
454
0
{
455
0
  RBTNode    *current,
456
0
         *parent,
457
0
         *x;
458
0
  int     cmp;
459
460
  /* find where node belongs */
461
0
  current = rbt->root;
462
0
  parent = NULL;
463
0
  cmp = 0;          /* just to prevent compiler warning */
464
465
0
  while (current != RBTNIL)
466
0
  {
467
0
    cmp = rbt->comparator(data, current, rbt->arg);
468
0
    if (cmp == 0)
469
0
    {
470
      /*
471
       * Found node with given key.  Apply combiner.
472
       */
473
0
      rbt->combiner(current, data, rbt->arg);
474
0
      *isNew = false;
475
0
      return current;
476
0
    }
477
0
    parent = current;
478
0
    current = (cmp < 0) ? current->left : current->right;
479
0
  }
480
481
  /*
482
   * Value is not present, so create a new node containing data.
483
   */
484
0
  *isNew = true;
485
486
0
  x = rbt->allocfunc(rbt->arg);
487
488
0
  x->color = RBTRED;
489
490
0
  x->left = RBTNIL;
491
0
  x->right = RBTNIL;
492
0
  x->parent = parent;
493
0
  rbt_copy_data(rbt, x, data);
494
495
  /* insert node in tree */
496
0
  if (parent)
497
0
  {
498
0
    if (cmp < 0)
499
0
      parent->left = x;
500
0
    else
501
0
      parent->right = x;
502
0
  }
503
0
  else
504
0
  {
505
0
    rbt->root = x;
506
0
  }
507
508
0
  rbt_insert_fixup(rbt, x);
509
510
0
  return x;
511
0
}
512
513
/**********************************************************************
514
 *              Deletion                  *
515
 **********************************************************************/
516
517
/*
518
 * Maintain Red-Black tree balance after deleting a black node.
519
 */
520
static void
521
rbt_delete_fixup(RBTree *rbt, RBTNode *x)
522
0
{
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
0
  while (x != rbt->root && x->color == RBTBLACK)
529
0
  {
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
     */
537
0
    if (x == x->parent->left)
538
0
    {
539
0
      RBTNode    *w = x->parent->right;
540
541
0
      if (w->color == RBTRED)
542
0
      {
543
0
        w->color = RBTBLACK;
544
0
        x->parent->color = RBTRED;
545
546
0
        rbt_rotate_left(rbt, x->parent);
547
0
        w = x->parent->right;
548
0
      }
549
550
0
      if (w->left->color == RBTBLACK && w->right->color == RBTBLACK)
551
0
      {
552
0
        w->color = RBTRED;
553
554
0
        x = x->parent;
555
0
      }
556
0
      else
557
0
      {
558
0
        if (w->right->color == RBTBLACK)
559
0
        {
560
0
          w->left->color = RBTBLACK;
561
0
          w->color = RBTRED;
562
563
0
          rbt_rotate_right(rbt, w);
564
0
          w = x->parent->right;
565
0
        }
566
0
        w->color = x->parent->color;
567
0
        x->parent->color = RBTBLACK;
568
0
        w->right->color = RBTBLACK;
569
570
0
        rbt_rotate_left(rbt, x->parent);
571
0
        x = rbt->root;  /* Arrange for loop to terminate. */
572
0
      }
573
0
    }
574
0
    else
575
0
    {
576
0
      RBTNode    *w = x->parent->left;
577
578
0
      if (w->color == RBTRED)
579
0
      {
580
0
        w->color = RBTBLACK;
581
0
        x->parent->color = RBTRED;
582
583
0
        rbt_rotate_right(rbt, x->parent);
584
0
        w = x->parent->left;
585
0
      }
586
587
0
      if (w->right->color == RBTBLACK && w->left->color == RBTBLACK)
588
0
      {
589
0
        w->color = RBTRED;
590
591
0
        x = x->parent;
592
0
      }
593
0
      else
594
0
      {
595
0
        if (w->left->color == RBTBLACK)
596
0
        {
597
0
          w->right->color = RBTBLACK;
598
0
          w->color = RBTRED;
599
600
0
          rbt_rotate_left(rbt, w);
601
0
          w = x->parent->left;
602
0
        }
603
0
        w->color = x->parent->color;
604
0
        x->parent->color = RBTBLACK;
605
0
        w->left->color = RBTBLACK;
606
607
0
        rbt_rotate_right(rbt, x->parent);
608
0
        x = rbt->root;  /* Arrange for loop to terminate. */
609
0
      }
610
0
    }
611
0
  }
612
0
  x->color = RBTBLACK;
613
0
}
614
615
/*
616
 * Delete node z from tree.
617
 */
618
static void
619
rbt_delete_node(RBTree *rbt, RBTNode *z)
620
0
{
621
0
  RBTNode    *x,
622
0
         *y;
623
624
  /* This is just paranoia: we should only get called on a valid node */
625
0
  if (!z || z == RBTNIL)
626
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
   */
633
0
  if (z->left == RBTNIL || z->right == RBTNIL)
634
0
  {
635
    /* y has a RBTNIL node as a child */
636
0
    y = z;
637
0
  }
638
0
  else
639
0
  {
640
    /* find tree successor */
641
0
    y = z->right;
642
0
    while (y->left != RBTNIL)
643
0
      y = y->left;
644
0
  }
645
646
  /* x is y's only child */
647
0
  if (y->left != RBTNIL)
648
0
    x = y->left;
649
0
  else
650
0
    x = y->right;
651
652
  /* Remove y from the tree. */
653
0
  x->parent = y->parent;
654
0
  if (y->parent)
655
0
  {
656
0
    if (y == y->parent->left)
657
0
      y->parent->left = x;
658
0
    else
659
0
      y->parent->right = x;
660
0
  }
661
0
  else
662
0
  {
663
0
    rbt->root = x;
664
0
  }
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
   */
670
0
  if (y != z)
671
0
    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
0
  if (y->color == RBTBLACK)
678
0
    rbt_delete_fixup(rbt, x);
679
680
  /* Now we can recycle the y node */
681
0
  if (rbt->freefunc)
682
0
    rbt->freefunc(y, rbt->arg);
683
0
}
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
rbt_delete(RBTree *rbt, RBTNode *node)
696
0
{
697
0
  rbt_delete_node(rbt, node);
698
0
}
699
700
/**********************************************************************
701
 *              Traverse                    *
702
 **********************************************************************/
703
704
static RBTNode *
705
rbt_left_right_iterator(RBTreeIterator *iter)
706
0
{
707
0
  if (iter->last_visited == NULL)
708
0
  {
709
0
    iter->last_visited = iter->rbt->root;
710
0
    while (iter->last_visited->left != RBTNIL)
711
0
      iter->last_visited = iter->last_visited->left;
712
713
0
    return iter->last_visited;
714
0
  }
715
716
0
  if (iter->last_visited->right != RBTNIL)
717
0
  {
718
0
    iter->last_visited = iter->last_visited->right;
719
0
    while (iter->last_visited->left != RBTNIL)
720
0
      iter->last_visited = iter->last_visited->left;
721
722
0
    return iter->last_visited;
723
0
  }
724
725
0
  for (;;)
726
0
  {
727
0
    RBTNode    *came_from = iter->last_visited;
728
729
0
    iter->last_visited = iter->last_visited->parent;
730
0
    if (iter->last_visited == NULL)
731
0
    {
732
0
      iter->is_over = true;
733
0
      break;
734
0
    }
735
736
0
    if (iter->last_visited->left == came_from)
737
0
      break;       /* came from left sub-tree, return current
738
                 * node */
739
740
    /* else - came from right sub-tree, continue to move up */
741
0
  }
742
743
0
  return iter->last_visited;
744
0
}
745
746
static RBTNode *
747
rbt_right_left_iterator(RBTreeIterator *iter)
748
0
{
749
0
  if (iter->last_visited == NULL)
750
0
  {
751
0
    iter->last_visited = iter->rbt->root;
752
0
    while (iter->last_visited->right != RBTNIL)
753
0
      iter->last_visited = iter->last_visited->right;
754
755
0
    return iter->last_visited;
756
0
  }
757
758
0
  if (iter->last_visited->left != RBTNIL)
759
0
  {
760
0
    iter->last_visited = iter->last_visited->left;
761
0
    while (iter->last_visited->right != RBTNIL)
762
0
      iter->last_visited = iter->last_visited->right;
763
764
0
    return iter->last_visited;
765
0
  }
766
767
0
  for (;;)
768
0
  {
769
0
    RBTNode    *came_from = iter->last_visited;
770
771
0
    iter->last_visited = iter->last_visited->parent;
772
0
    if (iter->last_visited == NULL)
773
0
    {
774
0
      iter->is_over = true;
775
0
      break;
776
0
    }
777
778
0
    if (iter->last_visited->right == came_from)
779
0
      break;       /* came from right sub-tree, return current
780
                 * node */
781
782
    /* else - came from left sub-tree, continue to move up */
783
0
  }
784
785
0
  return iter->last_visited;
786
0
}
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
802
rbt_begin_iterate(RBTree *rbt, RBTOrderControl ctrl, RBTreeIterator *iter)
803
0
{
804
  /* Common initialization for all traversal orders */
805
0
  iter->rbt = rbt;
806
0
  iter->last_visited = NULL;
807
0
  iter->is_over = (rbt->root == RBTNIL);
808
809
0
  switch (ctrl)
810
0
  {
811
0
    case LeftRightWalk:   /* visit left, then self, then right */
812
0
      iter->iterate = rbt_left_right_iterator;
813
0
      break;
814
0
    case RightLeftWalk:   /* visit right, then self, then left */
815
0
      iter->iterate = rbt_right_left_iterator;
816
0
      break;
817
0
    default:
818
0
      elog(ERROR, "unrecognized rbtree iteration order: %d", ctrl);
819
0
  }
820
0
}
821
822
/*
823
 * rbt_iterate: return the next node in traversal order, or NULL if no more
824
 */
825
RBTNode *
826
rbt_iterate(RBTreeIterator *iter)
827
0
{
828
0
  if (iter->is_over)
829
0
    return NULL;
830
831
0
  return iter->iterate(iter);
832
0
}