Coverage Report

Created: 2025-10-10 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/unit/src/nxt_rbtree.c
Line
Count
Source
1
2
/*
3
 * Copyright (C) Igor Sysoev
4
 * Copyright (C) NGINX, Inc.
5
 */
6
7
#include <nxt_main.h>
8
9
10
/*
11
 * The red-black tree code is based on the algorithm described in
12
 * the "Introduction to Algorithms" by Cormen, Leiserson and Rivest.
13
 */
14
15
16
static void nxt_rbtree_insert_fixup(nxt_rbtree_node_t *node);
17
static void nxt_rbtree_delete_fixup(nxt_rbtree_t *tree,
18
    nxt_rbtree_node_t *node);
19
nxt_inline void nxt_rbtree_left_rotate(nxt_rbtree_node_t *node);
20
nxt_inline void nxt_rbtree_right_rotate(nxt_rbtree_node_t *node);
21
nxt_inline void nxt_rbtree_parent_relink(nxt_rbtree_node_t *subst,
22
    nxt_rbtree_node_t *node);
23
24
25
182k
#define NXT_RBTREE_BLACK  0
26
62.4k
#define NXT_RBTREE_RED    1
27
28
29
#define nxt_rbtree_comparison_callback(tree)                                  \
30
0
    ((nxt_rbtree_compare_t) (tree)->sentinel.right)
31
32
33
void
34
nxt_rbtree_init(nxt_rbtree_t *tree, nxt_rbtree_compare_t compare)
35
55.6k
{
36
    /*
37
     * The sentinel is used as a leaf node sentinel and as a tree root
38
     * sentinel: it is a parent of a root node and the root node is
39
     * the left child of the sentinel.  Combining two sentinels in one
40
     * entry and the fact that the sentinel's left child is a root node
41
     * simplifies nxt_rbtree_node_successor() and eliminates explicit
42
     * root node test before or inside nxt_rbtree_min().
43
     */
44
45
    /* The root is empty. */
46
55.6k
    tree->sentinel.left = &tree->sentinel;
47
48
    /*
49
     * The sentinel's right child is never used so
50
     * comparison callback can be safely stored here.
51
     */
52
55.6k
    tree->sentinel.right = (void *) compare;
53
54
    /* The root and leaf sentinel must be black. */
55
55.6k
    tree->sentinel.color = NXT_RBTREE_BLACK;
56
55.6k
}
57
58
59
void
60
nxt_rbtree_insert(nxt_rbtree_t *tree, nxt_rbtree_part_t *part)
61
60.1k
{
62
60.1k
    nxt_rbtree_node_t     *node, *new_node, *sentinel, **child;
63
60.1k
    nxt_rbtree_compare_t  compare;
64
65
60.1k
    new_node = (nxt_rbtree_node_t *) part;
66
67
60.1k
    node = nxt_rbtree_root(tree);
68
60.1k
    sentinel = nxt_rbtree_sentinel(tree);
69
70
60.1k
    new_node->left = sentinel;
71
60.1k
    new_node->right = sentinel;
72
60.1k
    new_node->color = NXT_RBTREE_RED;
73
74
60.1k
    compare = (nxt_rbtree_compare_t) tree->sentinel.right;
75
60.1k
    child = &nxt_rbtree_root(tree);
76
77
74.4k
    while (*child != sentinel) {
78
14.2k
        node = *child;
79
80
14.2k
        nxt_prefetch(node->left);
81
14.2k
        nxt_prefetch(node->right);
82
83
14.2k
        child = (compare(new_node, node) < 0) ? &node->left : &node->right;
84
14.2k
    }
85
86
60.1k
    *child = new_node;
87
60.1k
    new_node->parent = node;
88
89
60.1k
    nxt_rbtree_insert_fixup(new_node);
90
91
60.1k
    node = nxt_rbtree_root(tree);
92
60.1k
    node->color = NXT_RBTREE_BLACK;
93
60.1k
}
94
95
96
static void
97
nxt_rbtree_insert_fixup(nxt_rbtree_node_t *node)
98
60.1k
{
99
60.1k
    nxt_rbtree_node_t  *parent, *grandparent, *uncle;
100
101
    /*
102
     * Prefetching parent nodes does not help here because they are
103
     * already traversed during insertion.
104
     */
105
106
60.9k
    for ( ;; ) {
107
60.9k
        parent = node->parent;
108
109
        /*
110
         * Testing whether a node is a tree root is not required here since
111
         * a root node's parent is the sentinel and it is always black.
112
         */
113
60.9k
        if (parent->color == NXT_RBTREE_BLACK) {
114
58.7k
            return;
115
58.7k
        }
116
117
2.20k
        grandparent = parent->parent;
118
119
2.20k
        if (parent == grandparent->left) {
120
814
            uncle = grandparent->right;
121
122
814
            if (uncle->color == NXT_RBTREE_BLACK) {
123
124
439
                if (node == parent->right) {
125
206
                    node = parent;
126
206
                    nxt_rbtree_left_rotate(node);
127
206
                }
128
129
                /*
130
                 * nxt_rbtree_left_rotate() swaps parent and
131
                 * child whilst keeps grandparent the same.
132
                 */
133
439
                parent = node->parent;
134
135
439
                parent->color = NXT_RBTREE_BLACK;
136
439
                grandparent->color = NXT_RBTREE_RED;
137
138
439
                nxt_rbtree_right_rotate(grandparent);
139
                /*
140
                 * nxt_rbtree_right_rotate() does not change node->parent
141
                 * color which is now black, so testing color is not required
142
                 * to return from function.
143
                 */
144
439
                return;
145
439
            }
146
147
1.39k
        } else {
148
1.39k
            uncle = grandparent->left;
149
150
1.39k
            if (uncle->color == NXT_RBTREE_BLACK) {
151
152
1.01k
                if (node == parent->left) {
153
423
                    node = parent;
154
423
                    nxt_rbtree_right_rotate(node);
155
423
                }
156
157
                /* See the comment in the symmetric branch above. */
158
1.01k
                parent = node->parent;
159
160
1.01k
                parent->color = NXT_RBTREE_BLACK;
161
1.01k
                grandparent->color = NXT_RBTREE_RED;
162
163
1.01k
                nxt_rbtree_left_rotate(grandparent);
164
165
                /* See the comment in the symmetric branch above. */
166
1.01k
                return;
167
1.01k
            }
168
1.39k
        }
169
170
754
        uncle->color = NXT_RBTREE_BLACK;
171
754
        parent->color = NXT_RBTREE_BLACK;
172
754
        grandparent->color = NXT_RBTREE_RED;
173
174
754
        node = grandparent;
175
754
    }
176
60.1k
}
177
178
179
nxt_rbtree_node_t *
180
nxt_rbtree_find(nxt_rbtree_t *tree, nxt_rbtree_part_t *part)
181
0
{
182
0
    intptr_t              n;
183
0
    nxt_rbtree_node_t     *node, *next, *sentinel;
184
0
    nxt_rbtree_compare_t  compare;
185
186
0
    node = (nxt_rbtree_node_t *) part;
187
188
0
    next = nxt_rbtree_root(tree);
189
0
    sentinel = nxt_rbtree_sentinel(tree);
190
0
    compare = nxt_rbtree_comparison_callback(tree);
191
192
0
    while (next != sentinel) {
193
0
        nxt_prefetch(next->left);
194
0
        nxt_prefetch(next->right);
195
196
0
        n = compare(node, next);
197
198
0
        if (n < 0) {
199
0
            next = next->left;
200
201
0
        } else if (n > 0) {
202
0
            next = next->right;
203
204
0
        } else {
205
0
            return next;
206
0
        }
207
0
    }
208
209
0
    return NULL;
210
0
}
211
212
213
nxt_rbtree_node_t *
214
nxt_rbtree_find_less_or_equal(nxt_rbtree_t *tree, nxt_rbtree_part_t *part)
215
0
{
216
0
    intptr_t              n;
217
0
    nxt_rbtree_node_t     *node, *retval, *next, *sentinel;
218
0
    nxt_rbtree_compare_t  compare;
219
220
0
    node = (nxt_rbtree_node_t *) part;
221
222
0
    retval = NULL;
223
0
    next = nxt_rbtree_root(tree);
224
0
    sentinel = nxt_rbtree_sentinel(tree);
225
0
    compare = nxt_rbtree_comparison_callback(tree);
226
227
0
    while (next != sentinel) {
228
0
        nxt_prefetch(next->left);
229
0
        nxt_prefetch(next->right);
230
231
0
        n = compare(node, next);
232
233
0
        if (n < 0) {
234
0
            next = next->left;
235
236
0
        } else if (n > 0) {
237
0
            retval = next;
238
0
            next = next->right;
239
240
0
        } else {
241
            /* Exact match. */
242
0
            return next;
243
0
        }
244
0
    }
245
246
0
    return retval;
247
0
}
248
249
250
nxt_rbtree_node_t *
251
nxt_rbtree_find_greater_or_equal(nxt_rbtree_t *tree, nxt_rbtree_part_t *part)
252
0
{
253
0
    intptr_t              n;
254
0
    nxt_rbtree_node_t     *node, *retval, *next, *sentinel;
255
0
    nxt_rbtree_compare_t  compare;
256
257
0
    node = (nxt_rbtree_node_t *) part;
258
259
0
    retval = NULL;
260
0
    next = nxt_rbtree_root(tree);
261
0
    sentinel = nxt_rbtree_sentinel(tree);
262
0
    compare = nxt_rbtree_comparison_callback(tree);
263
264
0
    while (next != sentinel) {
265
0
        nxt_prefetch(next->left);
266
0
        nxt_prefetch(next->right);
267
268
0
        n = compare(node, next);
269
270
0
        if (n < 0) {
271
0
            retval = next;
272
0
            next = next->left;
273
274
0
        } else if (n > 0) {
275
0
            next = next->right;
276
277
0
        } else {
278
            /* Exact match. */
279
0
            return next;
280
0
        }
281
0
    }
282
283
0
    return retval;
284
0
}
285
286
287
void
288
nxt_rbtree_delete(nxt_rbtree_t *tree, nxt_rbtree_part_t *part)
289
204
{
290
204
    uint8_t            color;
291
204
    nxt_rbtree_node_t  *node, *sentinel, *subst, *child;
292
293
204
    node = (nxt_rbtree_node_t *) part;
294
295
204
    subst = node;
296
204
    sentinel = nxt_rbtree_sentinel(tree);
297
298
204
    if (node->left == sentinel) {
299
132
        child = node->right;
300
301
132
    } else if (node->right == sentinel) {
302
19
        child = node->left;
303
304
53
    } else {
305
53
        subst = nxt_rbtree_branch_min(tree, node->right);
306
53
        child = subst->right;
307
53
    }
308
309
204
    nxt_rbtree_parent_relink(child, subst);
310
311
204
    color = subst->color;
312
313
204
    if (subst != node) {
314
        /* Move the subst node to the deleted node position in the tree. */
315
316
53
        subst->color = node->color;
317
318
53
        subst->left = node->left;
319
53
        subst->left->parent = subst;
320
321
53
        subst->right = node->right;
322
53
        subst->right->parent = subst;
323
324
53
        nxt_rbtree_parent_relink(subst, node);
325
53
    }
326
327
#if (NXT_DEBUG)
328
    node->left = NULL;
329
    node->right = NULL;
330
    node->parent = NULL;
331
#endif
332
333
204
    if (color == NXT_RBTREE_BLACK) {
334
111
        nxt_rbtree_delete_fixup(tree, child);
335
111
    }
336
204
}
337
338
339
static void
340
nxt_rbtree_delete_fixup(nxt_rbtree_t *tree, nxt_rbtree_node_t *node)
341
111
{
342
111
    nxt_rbtree_node_t  *parent, *sibling;
343
344
114
    while (node != nxt_rbtree_root(tree) && node->color == NXT_RBTREE_BLACK) {
345
        /*
346
         * Prefetching parent nodes does not help here according
347
         * to microbenchmarks.
348
         */
349
350
37
        parent = node->parent;
351
352
37
        if (node == parent->left) {
353
22
            sibling = parent->right;
354
355
22
            if (sibling->color != NXT_RBTREE_BLACK) {
356
357
0
                sibling->color = NXT_RBTREE_BLACK;
358
0
                parent->color = NXT_RBTREE_RED;
359
360
0
                nxt_rbtree_left_rotate(parent);
361
362
0
                sibling = parent->right;
363
0
            }
364
365
22
            if (sibling->right->color == NXT_RBTREE_BLACK) {
366
367
12
                sibling->color = NXT_RBTREE_RED;
368
369
12
                if (sibling->left->color == NXT_RBTREE_BLACK) {
370
0
                    node = parent;
371
0
                    continue;
372
0
                }
373
374
12
                sibling->left->color = NXT_RBTREE_BLACK;
375
376
12
                nxt_rbtree_right_rotate(sibling);
377
                /*
378
                 * If the node is the leaf sentinel then the right
379
                 * rotate above changes its parent so a sibling below
380
                 * becames the leaf sentinel as well and this causes
381
                 * segmentation fault.  This is the reason why usual
382
                 * red-black tree implementations with a leaf sentinel
383
                 * which does not require to test leaf nodes at all
384
                 * nevertheless test the leaf sentinel in the left and
385
                 * right rotate procedures.  Since according to the
386
                 * algorithm node->parent must not be changed by both
387
                 * the left and right rotates above, it can be cached
388
                 * in a local variable.  This not only eliminates the
389
                 * sentinel test in nxt_rbtree_parent_relink() but also
390
                 * decreases the code size because C forces to reload
391
                 * non-restrict pointers.
392
                 */
393
12
                sibling = parent->right;
394
12
            }
395
396
22
            sibling->color = parent->color;
397
22
            parent->color = NXT_RBTREE_BLACK;
398
22
            sibling->right->color = NXT_RBTREE_BLACK;
399
400
22
            nxt_rbtree_left_rotate(parent);
401
402
22
            return;
403
404
22
        } else {
405
15
            sibling = parent->left;
406
407
15
            if (sibling->color != NXT_RBTREE_BLACK) {
408
409
2
                sibling->color = NXT_RBTREE_BLACK;
410
2
                parent->color = NXT_RBTREE_RED;
411
412
2
                nxt_rbtree_right_rotate(parent);
413
414
2
                sibling = parent->left;
415
2
            }
416
417
15
            if (sibling->left->color == NXT_RBTREE_BLACK) {
418
419
8
                sibling->color = NXT_RBTREE_RED;
420
421
8
                if (sibling->right->color == NXT_RBTREE_BLACK) {
422
3
                    node = parent;
423
3
                    continue;
424
3
                }
425
426
5
                sibling->right->color = NXT_RBTREE_BLACK;
427
428
5
                nxt_rbtree_left_rotate(sibling);
429
430
                /* See the comment in the symmetric branch above. */
431
5
                sibling = parent->left;
432
5
            }
433
434
12
            sibling->color = parent->color;
435
12
            parent->color = NXT_RBTREE_BLACK;
436
12
            sibling->left->color = NXT_RBTREE_BLACK;
437
438
12
            nxt_rbtree_right_rotate(parent);
439
440
12
            return;
441
15
        }
442
37
    }
443
444
77
    node->color = NXT_RBTREE_BLACK;
445
77
}
446
447
448
nxt_inline void
449
nxt_rbtree_left_rotate(nxt_rbtree_node_t *node)
450
1.24k
{
451
1.24k
    nxt_rbtree_node_t  *child;
452
453
1.24k
    child = node->right;
454
1.24k
    node->right = child->left;
455
1.24k
    child->left->parent = node;
456
1.24k
    child->left = node;
457
458
1.24k
    nxt_rbtree_parent_relink(child, node);
459
460
1.24k
    node->parent = child;
461
1.24k
}
462
463
464
nxt_inline void
465
nxt_rbtree_right_rotate(nxt_rbtree_node_t *node)
466
888
{
467
888
    nxt_rbtree_node_t  *child;
468
469
888
    child = node->left;
470
888
    node->left = child->right;
471
888
    child->right->parent = node;
472
888
    child->right = node;
473
474
888
    nxt_rbtree_parent_relink(child, node);
475
476
888
    node->parent = child;
477
888
}
478
479
480
/* Relink a parent from the node to the subst node. */
481
482
nxt_inline void
483
nxt_rbtree_parent_relink(nxt_rbtree_node_t *subst, nxt_rbtree_node_t *node)
484
2.39k
{
485
2.39k
    nxt_rbtree_node_t  *parent, **link;
486
487
2.39k
    parent = node->parent;
488
    /*
489
     * The leaf sentinel's parent can be safely changed here.
490
     * See the comment in nxt_rbtree_delete_fixup() for details.
491
     */
492
2.39k
    subst->parent = parent;
493
    /*
494
     * If the node's parent is the root sentinel it is safely changed
495
     * because the root sentinel's left child is the tree root.
496
     */
497
2.39k
    link = (node == parent->left) ? &parent->left : &parent->right;
498
2.39k
    *link = subst;
499
2.39k
}
500
501
502
nxt_rbtree_node_t *
503
nxt_rbtree_destroy_next(nxt_rbtree_t *tree, nxt_rbtree_node_t **next)
504
59.9k
{
505
59.9k
    nxt_rbtree_node_t  *node, *subst, *parent, *sentinel;
506
507
59.9k
    sentinel = nxt_rbtree_sentinel(tree);
508
509
    /* Find the leftmost node. */
510
62.2k
    for (node = *next; node->left != sentinel; node = node->left);
511
512
    /* Replace the leftmost node with its right child. */
513
59.9k
    subst = node->right;
514
59.9k
    parent = node->parent;
515
516
59.9k
    parent->left = subst;
517
59.9k
    subst->parent = parent;
518
519
    /*
520
     * The right child is used as the next start node.  If the right child
521
     * is the sentinel then parent of the leftmost node is used as the next
522
     * start node.  The parent of the root node is the sentinel so after
523
     * the single root node will be replaced with the sentinel, the next
524
     * start node will be equal to the sentinel and iteration will stop.
525
     */
526
59.9k
    if (subst == sentinel) {
527
52.1k
        subst = parent;
528
52.1k
    }
529
530
59.9k
    *next = subst;
531
532
59.9k
    return node;
533
59.9k
}