data-structures-c
Loading...
Searching...
No Matches
rbtree.h
Go to the documentation of this file.
1/* rbtree.h
2 *
3 * Copyright (C) 2023 abxh
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 * See the file LICENSE included with this distribution for more
10 * information. */
11
38// macro definitions: {{{
39
40#ifndef RBTREE_H
41#define RBTREE_H
42
43#include "container_of.h" // container_of
44#include "paste.h" // PASTE, XPASTE, JOIN
45
46#include <assert.h>
47#include <stdbool.h>
48#include <stddef.h>
49#include <stdint.h>
50
62#define rbtree_node_entry(ptr, type, member) container_of(ptr, type, member)
63
64#endif
65
73#ifndef NAME
74#error "Must define NAME."
75#define NAME rbtree
76#else
77#define RBTREE_NAME NAME
78#endif
79
87#ifndef KEY_TYPE
88#error "Must define KEY_TYPE."
89#define KEY_TYPE int
90#endif
91
105#ifndef KEY_IS_STRICTLY_LESS
106#error "Must define KEY_IS_STRICTLY_LESS."
107#define KEY_IS_STRICTLY_LESS(a, b) ((a) < (b))
108#endif
109
122#ifdef ALLOW_DUPLICATES
123#endif
124
129#ifdef KEY_MEMBER_IS_FIRST
130#endif
131
133#define RBTREE_NODE_TYPE struct JOIN(RBTREE_NAME, node)
134#define RBTREE_CONTAINS_KEY JOIN(RBTREE_NAME, contains_key)
135#define RBTREE_NODE_IS_RED JOIN(RBTREE_NAME, node_is_red)
136#define RBTREE_NODE_IS_BLACK JOIN(RBTREE_NAME, node_is_black)
137#define RBTREE_NODE_GET_PARENT_PTR JOIN(RBTREE_NAME, node_get_parent_ptr)
138#define RBTREE_INSERT_FIXUP JOIN(internal, JOIN(RBTREE_NAME, insert_fixup))
139#define RBTREE_DELETE_FIXUP JOIN(internal, JOIN(RBTREE_NAME, delete_fixup))
140
141#define RBTREE_NODE_TRANSPLANT JOIN(internal, JOIN(RBTREE_NAME, node_transplant))
142#define RBTREE_NODE_SET_COLOR_TO_RED JOIN(internal, JOIN(RBTREE_NAME, node_set_color_to_red))
143#define RBTREE_NODE_SET_COLOR_TO_BLACK JOIN(internal, JOIN(RBTREE_NAME, node_set_color_to_black))
144#define RBTREE_NODE_SET_PARENT_PTR JOIN(internal, JOIN(RBTREE_NAME, node_set_parent_ptr))
145#define RBTREE_NODE_SET_COLOR_TO_COLOR_OF_OTHER JOIN(internal, JOIN(RBTREE_NAME, node_set_color_to_color_of_other))
146#define RBTREE_ROTATE_DIR JOIN(internal, JOIN(RBTREE_NAME, rotate_dir))
147
148#define RBTREE_CHILD_DIR(node_ptr) ((node_ptr) == RBTREE_NODE_GET_PARENT_PTR(node_ptr)->left_ptr ? 0 : 1)
150
151// }}}
152
153// type definitions: {{{
154
158struct JOIN(RBTREE_NAME, node) {
159#ifdef KEY_MEMBER_IS_FIRST
160 KEY_TYPE key;
161#endif
164 union {
165 struct {
166 RBTREE_NODE_TYPE *left_ptr;
167 RBTREE_NODE_TYPE *right_ptr;
168 };
169 RBTREE_NODE_TYPE *child_ptrs[2];
170 };
171#ifndef KEY_MEMBER_IS_FIRST
173#endif
174};
175
176// }}}
177
178// function definitions: {{{
179
181
182static inline void JOIN(internal, JOIN(RBTREE_NAME, node_set_color_to_red))(RBTREE_NODE_TYPE *node_ptr)
183{
184 assert(node_ptr != NULL);
185
186 node_ptr->__parent_ptr_with_color_bit &= ~(uintptr_t)1;
187}
188
189static inline void JOIN(internal, JOIN(RBTREE_NAME, node_set_color_to_black))(RBTREE_NODE_TYPE *node_ptr)
190{
191 assert(node_ptr != NULL);
192
193 node_ptr->__parent_ptr_with_color_bit |= 1;
194}
195
196static inline void JOIN(internal,
197 JOIN(RBTREE_NAME, node_set_color_to_color_of_other))(RBTREE_NODE_TYPE *node_ptr,
198 const RBTREE_NODE_TYPE *other_ptr)
199{
200 assert(other_ptr != NULL);
201 assert(node_ptr != NULL);
202
203 const bool is_black = other_ptr->__parent_ptr_with_color_bit & 1;
204
205 node_ptr->__parent_ptr_with_color_bit &= ~(uintptr_t)1;
206 node_ptr->__parent_ptr_with_color_bit += is_black;
207}
208
209static inline void JOIN(internal, JOIN(RBTREE_NAME, node_set_parent_ptr))(RBTREE_NODE_TYPE *node_ptr,
210 RBTREE_NODE_TYPE *parent_ptr)
211{
212 assert(node_ptr != NULL);
213
214 const bool is_black = node_ptr->__parent_ptr_with_color_bit & 1;
215
216 node_ptr->__parent_ptr_with_color_bit = (uintptr_t)parent_ptr;
217 node_ptr->__parent_ptr_with_color_bit += is_black;
218}
219
220// rotate a subtree around a given subtree root node and direction (0: left or
221// 1: right). returns the new subtree root
222static inline RBTREE_NODE_TYPE *JOIN(internal, JOIN(RBTREE_NAME, rotate_dir))(RBTREE_NODE_TYPE **rootptr_ptr,
223 RBTREE_NODE_TYPE *P, const int dir);
224
225// rebalance tree after insert. see explanation in the sources linked above.
226static inline void JOIN(internal, JOIN(RBTREE_NAME, insert_fixup))(RBTREE_NODE_TYPE **rootptr_ptr, RBTREE_NODE_TYPE *N);
227
228// move the parent of a node (src) to another node (dest).
229static inline void JOIN(internal, JOIN(RBTREE_NAME, node_transplant))(RBTREE_NODE_TYPE **rootptr_ptr,
230 RBTREE_NODE_TYPE *src_node,
231 RBTREE_NODE_TYPE *dest_node);
232
233// rebalance tree after delete. see explanation in the sources linked above.
234// for the special case where: (P's child) was not root and was black and had no children.
235static inline void JOIN(internal, JOIN(RBTREE_NAME, delete_fixup))(RBTREE_NODE_TYPE **rootptr_ptr, RBTREE_NODE_TYPE *P,
236 int dir);
237
239
247static inline void JOIN(RBTREE_NAME, init)(RBTREE_NODE_TYPE **rootptr_ptr)
248{
249 assert(rootptr_ptr != NULL);
250
251 *rootptr_ptr = NULL;
252}
253
260static inline void JOIN(RBTREE_NAME, node_init)(RBTREE_NODE_TYPE *node_ptr, KEY_TYPE key)
261{
262 assert(node_ptr != NULL);
263
264 node_ptr->key = key;
265 node_ptr->left_ptr = node_ptr->right_ptr = NULL;
266 RBTREE_NODE_SET_PARENT_PTR(node_ptr, NULL);
267}
268
274static inline RBTREE_NODE_TYPE *JOIN(RBTREE_NAME, node_get_parent_ptr)(RBTREE_NODE_TYPE *node_ptr)
275{
276 assert(node_ptr != NULL);
277
278 return (RBTREE_NODE_TYPE *)(node_ptr->__parent_ptr_with_color_bit & ~(uintptr_t)1);
279}
280
286static inline bool JOIN(RBTREE_NAME, node_is_black)(const RBTREE_NODE_TYPE *node_ptr)
287{
288 assert(node_ptr != NULL);
289
290 return (node_ptr->__parent_ptr_with_color_bit & 1);
291}
292
298static inline bool JOIN(RBTREE_NAME, node_is_red)(const RBTREE_NODE_TYPE *node_ptr)
299{
300 assert(node_ptr != NULL);
301
302 return !RBTREE_NODE_IS_BLACK(node_ptr);
303}
304
312static inline bool JOIN(RBTREE_NAME, is_empty)(RBTREE_NODE_TYPE **rootptr_ptr)
313{
314 assert(rootptr_ptr != NULL);
315
316 return *rootptr_ptr == NULL;
317}
318
327static inline bool JOIN(RBTREE_NAME, contains_key)(RBTREE_NODE_TYPE **rootptr_ptr, const KEY_TYPE key)
328{
329 assert(rootptr_ptr != NULL);
330
331 RBTREE_NODE_TYPE *node_ptr = *rootptr_ptr;
332
333 while (node_ptr != NULL) {
334 const bool is_strictly_less = KEY_IS_STRICTLY_LESS(key, node_ptr->key);
335 const bool is_strictly_greater = KEY_IS_STRICTLY_LESS(node_ptr->key, key);
336 const bool is_equal = !is_strictly_less && !is_strictly_greater;
337
338 if (is_equal) {
339 return true;
340 }
341 else if (is_strictly_less) {
342 node_ptr = node_ptr->left_ptr;
343 }
344 else {
345 node_ptr = node_ptr->right_ptr;
346 }
347 }
348 return false;
349}
350
360static inline RBTREE_NODE_TYPE *JOIN(RBTREE_NAME, search_node)(RBTREE_NODE_TYPE **rootptr_ptr, const KEY_TYPE key)
361{
362 assert(rootptr_ptr != NULL);
363
364 RBTREE_NODE_TYPE *node_ptr = *rootptr_ptr;
365 while (node_ptr != NULL) {
366 const bool is_strictly_less = KEY_IS_STRICTLY_LESS(key, node_ptr->key);
367 const bool is_strictly_greater = KEY_IS_STRICTLY_LESS(node_ptr->key, key);
368 const bool is_equal = !is_strictly_less && !is_strictly_greater;
369
370 if (is_equal) {
371 return node_ptr;
372 }
373 else if (is_strictly_less) {
374 node_ptr = node_ptr->left_ptr;
375 }
376 else {
377 node_ptr = node_ptr->right_ptr;
378 }
379 }
380 return NULL;
381}
382
389static inline void JOIN(RBTREE_NAME, insert_node)(RBTREE_NODE_TYPE **rootptr_ptr, RBTREE_NODE_TYPE *node_ptr)
390{
391 assert(rootptr_ptr != NULL);
392 assert(node_ptr != NULL);
393#ifndef ALLOW_DUPLICATES
394 assert(RBTREE_CONTAINS_KEY(rootptr_ptr, node_ptr->key) == false);
395#endif
396
397 RBTREE_NODE_TYPE *parent_ptr = NULL;
398 RBTREE_NODE_TYPE *current_ptr = *rootptr_ptr;
399
400 while (current_ptr != NULL) {
401 const bool is_strictly_greater = KEY_IS_STRICTLY_LESS(current_ptr->key, node_ptr->key);
402
403 parent_ptr = current_ptr;
404
405 if (is_strictly_greater) {
406 current_ptr = current_ptr->right_ptr;
407 }
408 else {
409 current_ptr = current_ptr->left_ptr;
410 }
411 }
412
413 node_ptr->left_ptr = node_ptr->right_ptr = NULL;
414 RBTREE_NODE_SET_PARENT_PTR(node_ptr, parent_ptr);
415 RBTREE_NODE_SET_COLOR_TO_RED(node_ptr);
416
417 if (parent_ptr == NULL) {
418 *rootptr_ptr = node_ptr;
419 }
420 else {
421 const int dir = KEY_IS_STRICTLY_LESS(parent_ptr->key, node_ptr->key) ? 1 : 0;
422
423 parent_ptr->child_ptrs[dir] = node_ptr;
424
425 RBTREE_INSERT_FIXUP(rootptr_ptr, node_ptr);
426 }
427}
428
437static inline RBTREE_NODE_TYPE *JOIN(RBTREE_NAME, delete_node)(RBTREE_NODE_TYPE **rootptr_ptr,
438 RBTREE_NODE_TYPE *node_ptr)
439{
440 assert(rootptr_ptr != NULL);
441 assert(node_ptr != NULL);
442
443 if (node_ptr->left_ptr == NULL && node_ptr->right_ptr == NULL) {
444 if (node_ptr == *rootptr_ptr || RBTREE_NODE_IS_RED(node_ptr)) {
445 RBTREE_NODE_TRANSPLANT(rootptr_ptr, node_ptr, NULL);
446 }
447 else {
448 RBTREE_NODE_TYPE *const parent_ptr = RBTREE_NODE_GET_PARENT_PTR(node_ptr);
449
450 const int dir = RBTREE_CHILD_DIR(node_ptr) ? 1 : 0;
451
452 RBTREE_NODE_TRANSPLANT(rootptr_ptr, node_ptr, NULL);
453
454 RBTREE_DELETE_FIXUP(rootptr_ptr, parent_ptr, dir);
455 }
456 }
457 else if (node_ptr->left_ptr == NULL || node_ptr->right_ptr == NULL) {
458 const int dir = node_ptr->left_ptr == NULL;
459
460 assert(RBTREE_NODE_IS_BLACK(node_ptr));
461 assert(RBTREE_NODE_IS_RED(node_ptr->child_ptrs[dir]));
462
463 RBTREE_NODE_SET_COLOR_TO_BLACK(node_ptr->child_ptrs[dir]);
464
465 RBTREE_NODE_TRANSPLANT(rootptr_ptr, node_ptr, node_ptr->child_ptrs[dir]);
466 }
467 else {
468 RBTREE_NODE_TYPE *successor_ptr = node_ptr->right_ptr;
469
470 while (successor_ptr->left_ptr != NULL) {
471 successor_ptr = successor_ptr->left_ptr;
472 }
473
474 const bool prev_successor_black = RBTREE_NODE_IS_BLACK(successor_ptr);
475
476 const int prev_successor_dir = RBTREE_CHILD_DIR(successor_ptr);
477
478 RBTREE_NODE_TYPE *const prev_successor_parent_ptr = RBTREE_NODE_GET_PARENT_PTR(successor_ptr);
479
480 RBTREE_NODE_TYPE *const prev_successor_child_ptr = successor_ptr->right_ptr;
481
482 {
483 if (RBTREE_NODE_GET_PARENT_PTR(successor_ptr) != node_ptr) {
484 RBTREE_NODE_TRANSPLANT(rootptr_ptr, successor_ptr, successor_ptr->right_ptr);
485
486 successor_ptr->right_ptr = node_ptr->right_ptr;
487 RBTREE_NODE_SET_PARENT_PTR(node_ptr->right_ptr, successor_ptr);
488 }
489 RBTREE_NODE_TRANSPLANT(rootptr_ptr, node_ptr, successor_ptr);
490
491 successor_ptr->left_ptr = node_ptr->left_ptr;
492 RBTREE_NODE_SET_PARENT_PTR(node_ptr->left_ptr, successor_ptr);
493
494 RBTREE_NODE_SET_COLOR_TO_COLOR_OF_OTHER(successor_ptr, node_ptr);
495 }
496
497 if (prev_successor_child_ptr != NULL) {
498 assert(prev_successor_black);
499 assert(RBTREE_NODE_IS_RED(prev_successor_child_ptr));
500
501 RBTREE_NODE_SET_COLOR_TO_BLACK(prev_successor_child_ptr);
502 }
503 else if (prev_successor_child_ptr == NULL && prev_successor_black) {
504 RBTREE_NODE_TYPE *actual_successor_ptr =
505 (prev_successor_parent_ptr == node_ptr) ? successor_ptr : prev_successor_parent_ptr;
506
507 RBTREE_DELETE_FIXUP(rootptr_ptr, actual_successor_ptr, prev_successor_dir);
508 }
509 }
510
511 node_ptr->left_ptr = node_ptr->right_ptr = NULL;
512 RBTREE_NODE_SET_PARENT_PTR(node_ptr, NULL);
513
514 return node_ptr;
515}
516
518
519static inline RBTREE_NODE_TYPE *JOIN(internal, JOIN(RBTREE_NAME, rotate_dir))(RBTREE_NODE_TYPE **rootptr_ptr,
520 RBTREE_NODE_TYPE *P, const int dir)
521{
522 assert(rootptr_ptr != NULL);
523 assert(P != NULL);
524 assert(dir == 0 || dir == 1);
525
526 /* Right rotate around P:
527 P S
528 / \ / \
529 S T --> .. P
530 / \ / \ ⟳ / \
531 .. C .. .. C T
532 / \ / \ / \
533 .. .. .. .. .. ..
534
535 Left rotate around P:
536 P S
537 / \ / \
538 T S P ..
539 / \ / \ --> / \
540 .. .. C .. ↺ T C
541 / \ / \ / \
542 .. .. .. .. .. ..
543 */
544
545 RBTREE_NODE_TYPE *G = RBTREE_NODE_GET_PARENT_PTR(P);
546 RBTREE_NODE_TYPE *S = P->child_ptrs[1 - dir];
547 assert(S != NULL);
548 RBTREE_NODE_TYPE *C = S->child_ptrs[dir];
549
550 P->child_ptrs[1 - dir] = C;
551 if (C != NULL) {
552 RBTREE_NODE_SET_PARENT_PTR(C, P);
553 }
554
555 S->child_ptrs[dir] = P;
556 RBTREE_NODE_SET_PARENT_PTR(P, S);
557
558 RBTREE_NODE_SET_PARENT_PTR(S, G);
559 if (G != NULL) {
560 G->child_ptrs[P == G->left_ptr ? 0 : 1] = S;
561 }
562 else {
563 *rootptr_ptr = S;
564 }
565 return S;
566}
567
568static inline void JOIN(internal, JOIN(RBTREE_NAME, insert_fixup))(RBTREE_NODE_TYPE **rootptr_ptr, RBTREE_NODE_TYPE *N)
569{
570 assert(rootptr_ptr != NULL);
571 assert(N != NULL);
572 assert(RBTREE_NODE_IS_RED(N));
573 assert(N != *rootptr_ptr);
574
575 RBTREE_NODE_TYPE *P = RBTREE_NODE_GET_PARENT_PTR(N); // parent
576 RBTREE_NODE_TYPE *G = NULL; // grandparent
577 RBTREE_NODE_TYPE *U = NULL; // uncle
578
579 do {
580 if (RBTREE_NODE_IS_BLACK(P)) {
581 return;
582 }
583 if ((G = RBTREE_NODE_GET_PARENT_PTR(P)) == NULL) {
584 RBTREE_NODE_SET_COLOR_TO_BLACK(P);
585 return;
586 }
587 const int dir = RBTREE_CHILD_DIR(P);
588 U = G->child_ptrs[1 - dir];
589
590 if (U == NULL || RBTREE_NODE_IS_BLACK(U)) {
591 if (N == P->child_ptrs[1 - dir]) {
592 RBTREE_ROTATE_DIR(rootptr_ptr, P, dir);
593 N = P;
594 P = G->child_ptrs[dir];
595 }
596 RBTREE_NODE_SET_COLOR_TO_BLACK(P);
597 RBTREE_NODE_SET_COLOR_TO_RED(G);
598 RBTREE_ROTATE_DIR(rootptr_ptr, G, 1 - dir);
599 return;
600 }
601
602 RBTREE_NODE_SET_COLOR_TO_BLACK(P);
603 RBTREE_NODE_SET_COLOR_TO_BLACK(U);
604 RBTREE_NODE_SET_COLOR_TO_RED(G);
605
606 N = G;
607 P = RBTREE_NODE_GET_PARENT_PTR(N);
608 } while (P != NULL);
609}
610
611static inline void JOIN(internal, JOIN(RBTREE_NAME, node_transplant))(RBTREE_NODE_TYPE **rootptr_ptr,
612 RBTREE_NODE_TYPE *src_node,
613 RBTREE_NODE_TYPE *dest_node)
614{
615 assert(rootptr_ptr != NULL);
616 assert(src_node != NULL);
617
618 RBTREE_NODE_TYPE *src_node_parent_ptr = RBTREE_NODE_GET_PARENT_PTR(src_node);
619
620 if (src_node_parent_ptr == NULL) {
621 *rootptr_ptr = dest_node;
622 }
623 else {
624 src_node_parent_ptr->child_ptrs[RBTREE_CHILD_DIR(src_node)] = dest_node;
625 }
626
627 if (dest_node != NULL) {
628 RBTREE_NODE_SET_PARENT_PTR(dest_node, src_node_parent_ptr);
629 }
630}
631
632static inline void JOIN(internal, JOIN(RBTREE_NAME, delete_fixup))(RBTREE_NODE_TYPE **rootptr_ptr, RBTREE_NODE_TYPE *P,
633 int dir)
634{
635 assert(rootptr_ptr != NULL);
636 assert(P != NULL);
637 assert(dir == 0 || dir == 1);
638
639 RBTREE_NODE_TYPE *N = NULL; // node (temp)
640 RBTREE_NODE_TYPE *S = NULL; // sibling
641 RBTREE_NODE_TYPE *C = NULL; // close nephew
642 RBTREE_NODE_TYPE *D = NULL; // distant nephew
643
644 do {
645 S = P->child_ptrs[1 - dir];
646 D = S->child_ptrs[1 - dir];
647 C = S->child_ptrs[dir];
648
649 if (RBTREE_NODE_IS_RED(S)) {
650 goto Case_3;
651 }
652 if (D != NULL && RBTREE_NODE_IS_RED(D)) {
653 goto Case_6;
654 }
655 if (C != NULL && RBTREE_NODE_IS_RED(C)) {
656 goto Case_5;
657 }
658 if (RBTREE_NODE_IS_RED(P)) {
659 goto Case_4;
660 }
661 RBTREE_NODE_SET_COLOR_TO_RED(S);
662
663 N = P;
664 P = RBTREE_NODE_GET_PARENT_PTR(N);
665 } while (P != NULL && (dir = RBTREE_CHILD_DIR(N), true));
666
667 return;
668Case_3:
669 RBTREE_ROTATE_DIR(rootptr_ptr, P, dir);
670 RBTREE_NODE_SET_COLOR_TO_RED(P);
671 RBTREE_NODE_SET_COLOR_TO_BLACK(S);
672 S = C;
673 D = S->child_ptrs[1 - dir];
674 if (D != NULL && RBTREE_NODE_IS_RED(D)) {
675 goto Case_6;
676 }
677 C = S->child_ptrs[dir];
678 if (C != NULL && RBTREE_NODE_IS_RED(C)) {
679 goto Case_5;
680 }
681Case_4:
682 RBTREE_NODE_SET_COLOR_TO_RED(S);
683 RBTREE_NODE_SET_COLOR_TO_BLACK(P);
684 return;
685Case_5:
686 RBTREE_ROTATE_DIR(rootptr_ptr, S, 1 - dir);
687 RBTREE_NODE_SET_COLOR_TO_RED(S);
688 RBTREE_NODE_SET_COLOR_TO_BLACK(C);
689 D = S;
690 S = C;
691Case_6:
692 RBTREE_ROTATE_DIR(rootptr_ptr, P, dir);
693 RBTREE_NODE_SET_COLOR_TO_COLOR_OF_OTHER(S, P);
694 RBTREE_NODE_SET_COLOR_TO_BLACK(P);
695 RBTREE_NODE_SET_COLOR_TO_BLACK(D);
696 return;
697}
699
700// }}}
701
702// macro undefs: {{{
703
704#undef NAME
705#undef KEY_TYPE
706#undef VALUE_TYPE
707#undef KEY_IS_STRICTLY_LESS
708#undef ALLOW_DUPLICATES
709#undef KEY_MEMBER_IS_FIRST
710
711#undef RBTREE_NAME
712#undef RBTREE_TYPE
713#undef RBTREE_NODE_TYPE
714
715#undef RBTREE_NODE_IS_RED
716#undef RBTREE_NODE_IS_BLACK
717#undef RBTREE_NODE_GET_PARENT_PTR
718#undef RBTREE_NODE_TRANSPLANT
719#undef RBTREE_NODE_SET_COLOR_TO_COLOR_OF_OTHER
720#undef RBTREE_NODE_SET_COLOR_TO_RED
721#undef RBTREE_NODE_SET_COLOR_TO_BLACK
722#undef RBTREE_NODE_SET_PARENT_PTR
723
724#undef RBTREE_CONTAINS_KEY
725#undef RBTREE_INSERT_FIXUP
726#undef RBTREE_DELETE_FIXUP
727#undef RBTREE_CHILD_DIR
728
729// }}}
730
731// vim: ft=c fdm=marker
container_of definition
#define KEY_TYPE
The key type. This must be manually defined before including this header file.
Definition fhashtable.h:132
C preprocessor macros for pasting tokens together.
#define JOIN(a, b)
First expand tokens, then paste them together with a _ in between.
Definition paste.h:35
#define KEY_TYPE
The key type. This must be manually defined before including this header file.
Definition rbtree.h:89
#define KEY_IS_STRICTLY_LESS(a, b)
Used to compare two keys. This must be manually defined before including this header file.
Definition rbtree.h:107
uintptr_t __parent_ptr_with_color_bit
Definition rbtree.h:162
rbtree_node_type * left_ptr
pointer to left node
Definition rbtree.h:166
KEY_TYPE key
node key
Definition rbtree.h:172
rbtree_node_type * right_ptr
pointer to right node
Definition rbtree.h:167