├── README.md ├── example.c ├── rb3ptr.c └── rb3ptr.h /README.md: -------------------------------------------------------------------------------- 1 | website: http://jstimpfle.de/projects/rb3ptr/rb3ptr.html 2 | -------------------------------------------------------------------------------- /example.c: -------------------------------------------------------------------------------- 1 | /* 2 | This is some example code to get you started with rb3ptr. We're only covering 3 | the basics here, not really exercising rb3ptr's flexibility. 4 | 5 | To build, change to the directory containing these files (rb3ptr.c, rb3ptr.h, 6 | examples.c) and run 7 | 8 | gcc -Wall -I. rb3ptr.c example.c -o test 9 | 10 | To see more of rb3ptr's API, look at rb3ptr.h, which includes some 11 | documentation. 12 | 13 | For a better (but more involved) example what you can do with rb3ptr, check 14 | out the textrope implementation in my project "astedit" at 15 | http://jstimpfle.de/projects/astedit/astedit.html. Since the nodes in that 16 | textrope don't even have a natural ordering, that project uses the low-level 17 | primitives to define custom iteration functions. 18 | */ 19 | 20 | #include // offsetof() 21 | #include 22 | #include 23 | #include 24 | 25 | enum { 26 | NUM_FOOS = 1024 27 | }; 28 | 29 | /* Declare a container data structure, carrying some data, and including a 30 | * `struct rb3_head` link structure. The link structure will be used to link the 31 | * node in a tree. 32 | */ 33 | 34 | struct Foo { 35 | struct rb3_head head; 36 | int val; 37 | }; 38 | 39 | /* Define how to get from an embedded link structure to the embedding struct Foo 40 | * 41 | * You could simply use a macro like container_of() which is used in the Linux 42 | * kernel, but I think it's nonstandard. So I'm not using it in this file. 43 | */ 44 | 45 | static struct Foo *get_foo(struct rb3_head *head) 46 | { 47 | return (struct Foo *)((char *) head - offsetof(struct Foo, head)); 48 | } 49 | 50 | /* 51 | * Define a helper function to drive iteration down a tree. With this you can 52 | * use high-level functions like rb3_insert() and rb3_delete(), to avoid having 53 | * to write custom iteration code. (But you can still do that of course) 54 | * 55 | * The functions that you can hand to rb3_insert() or rb3_delete() will often 56 | * compare two nodes, but in general they take a single struct rb3_head and an 57 | * additional context argument, which can be whatever you like. You can see in 58 | * main() that we hand a struct Foo to rb3_insert() and rb3_delete(). That's 59 | * why we can cast the context argumentback to that struct Foo here. 60 | */ 61 | 62 | static int compare_foos(struct rb3_head *a, void *data) 63 | { 64 | struct Foo *x = get_foo(a); 65 | struct Foo *y = data; 66 | if (x->val > y->val) 67 | return 1; 68 | else if (x->val < y->val) 69 | return -1; 70 | return 0; 71 | } 72 | 73 | /* 74 | * Test insertions and deletions. 75 | */ 76 | 77 | int main(void) 78 | { 79 | struct rb3_tree tree; 80 | struct rb3_head *iter; 81 | struct Foo *foo; 82 | size_t i; 83 | 84 | rb3_reset_tree(&tree); 85 | foo = malloc(NUM_FOOS * sizeof (struct Foo)); 86 | 87 | /* make up some random values for the nodes. */ 88 | for (i = 0; i < NUM_FOOS; i++) 89 | foo[i].val = rand(); 90 | 91 | /* insert the random nodes. */ 92 | for (i = 0; i < NUM_FOOS; i++) 93 | rb3_insert(&tree, &foo[i].head, compare_foos, &foo[i]); 94 | 95 | /* Iterate over the tree using in-order traversal. We expect to print 96 | * a sorted sequence here due to the way we defined the ordering 97 | * function that we gave to rb3_insert(). */ 98 | for (iter = rb3_get_min(&tree); 99 | iter != NULL; 100 | iter = rb3_get_next(iter)) 101 | printf("iter %d\n", get_foo(iter)->val); 102 | 103 | /* Remove all the nodes from the tree. To guarantee that each node is 104 | * found we should use the same (or at least a compatible) ordering 105 | * function. */ 106 | for (i = 0; i < NUM_FOOS; i++) 107 | rb3_delete(&tree, compare_foos, &foo[i].head); 108 | 109 | free(foo); 110 | 111 | return 0; 112 | } 113 | -------------------------------------------------------------------------------- /rb3ptr.c: -------------------------------------------------------------------------------- 1 | /* rb3ptr -- Intrusively linked 3-pointer Red-black tree implementation */ 2 | 3 | /* Copyright (C) 2019, Jens Stimpfle */ 4 | 5 | /* 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | this software and associated documentation files (the "Software"), to deal in 8 | the Software without restriction, including without limitation the rights to 9 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | the Software, and to permit persons to whom the Software is furnished to do so, 11 | subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | #include 25 | #include // offsetof() 26 | 27 | enum { 28 | _RB3_DIR_BIT = 1 << 0, 29 | _RB3_COLOR_BIT = 1 << 1, 30 | _RB3_BLACK = 0, 31 | _RB3_RED = _RB3_COLOR_BIT, 32 | }; 33 | 34 | static inline rb3_ptr rb3_child_ptr(struct rb3_head *head, int color) 35 | { 36 | return (rb3_ptr) head | color; 37 | } 38 | 39 | static inline rb3_ptr rb3_parent_ptr(struct rb3_head *head, int dir) 40 | { 41 | return (rb3_ptr) head | dir; 42 | } 43 | 44 | static inline struct rb3_head *rb3_get_black_child(struct rb3_head *head, int dir) 45 | { 46 | return (struct rb3_head *) head->child[dir]; 47 | } 48 | 49 | static inline int rb3_get_color_bit(struct rb3_head *head, int dir) 50 | { 51 | return head->child[dir] & _RB3_COLOR_BIT; 52 | } 53 | 54 | static inline int rb3_is_red(struct rb3_head *head, int dir) 55 | { 56 | return rb3_get_color_bit(head, dir) != 0; 57 | } 58 | 59 | static inline void rb3_set_red(struct rb3_head *head, int dir) 60 | { 61 | head->child[dir] |= _RB3_COLOR_BIT; 62 | } 63 | 64 | static inline void rb3_set_black(struct rb3_head *head, int dir) 65 | { 66 | head->child[dir] &= ~_RB3_COLOR_BIT; 67 | } 68 | 69 | static inline void rb3_connect(struct rb3_head *head, int dir, struct rb3_head *child, int color) 70 | { 71 | head->child[dir] = rb3_child_ptr(child, color); 72 | child->parent = rb3_parent_ptr(head, dir); 73 | } 74 | 75 | static inline void rb3_connect_null(struct rb3_head *head, int dir, struct rb3_head *child, int color) 76 | { 77 | head->child[dir] = rb3_child_ptr(child, color); 78 | if (child) 79 | child->parent = rb3_parent_ptr(head, dir); 80 | } 81 | 82 | struct rb3_tree *rb3_get_containing_tree(struct rb3_head *head) 83 | { 84 | while (rb3_get_parent(head)) 85 | head = rb3_get_parent(head); 86 | return (struct rb3_tree *) ((char *) head - (offsetof(struct rb3_head, child[0]))); 87 | } 88 | 89 | static struct rb3_head *rb3_get_minmax_in_subtree(struct rb3_head *head, int dir) 90 | { 91 | if (!head) 92 | return _RB3_NULL; 93 | while (rb3_has_child(head, dir)) 94 | head = rb3_get_child(head, dir); 95 | return head; 96 | } 97 | 98 | struct rb3_head *rb3_get_minmax(struct rb3_tree *tree, int dir) 99 | { 100 | return rb3_get_minmax_in_subtree(rb3_get_root(tree), dir); 101 | } 102 | 103 | struct rb3_head *rb3_get_prevnext_descendant(struct rb3_head *head, int dir) 104 | { 105 | return rb3_get_minmax_in_subtree(rb3_get_child(head, dir), !dir); 106 | } 107 | 108 | struct rb3_head *rb3_get_prevnext_ancestor(struct rb3_head *head, int dir) 109 | { 110 | /* 111 | * Note: the direction is "reversed" for our purposes here, since 112 | * the bit indicates the direction from the parent to `head` 113 | */ 114 | while (head && rb3_get_parent_dir(head) == dir) { 115 | head = rb3_get_parent(head); 116 | } 117 | if (head) { 118 | head = rb3_get_parent(head); 119 | if (!head || rb3_is_base(head)) 120 | return _RB3_NULL; 121 | return head; 122 | } 123 | return _RB3_NULL; 124 | } 125 | 126 | struct rb3_head *rb3_get_prevnext(struct rb3_head *head, int dir) 127 | { 128 | if (rb3_has_child(head, dir)) 129 | return rb3_get_prevnext_descendant(head, dir); 130 | else 131 | return rb3_get_prevnext_ancestor(head, dir); 132 | } 133 | 134 | void rb3_update_augment(struct rb3_head *head, rb3_augment_func *augment) 135 | { 136 | while (!rb3_is_base(head)) { 137 | augment(head); 138 | head = rb3_get_parent(head); 139 | } 140 | } 141 | 142 | static void rb3_rebalance_after_link(struct rb3_head *head, rb3_augment_func *augment) 143 | { 144 | struct rb3_head *pnt; 145 | struct rb3_head *gpnt; 146 | struct rb3_head *ggpnt; 147 | int left; 148 | int right; 149 | int gdir; 150 | int ggdir; 151 | 152 | if (!rb3_get_parent(rb3_get_parent(head))) { 153 | rb3_set_black(rb3_get_parent(head), RB3_LEFT); 154 | if (augment) 155 | augment(head); 156 | return; 157 | } 158 | 159 | if (!rb3_is_red(rb3_get_parent(rb3_get_parent(head)), rb3_get_parent_dir(rb3_get_parent(head)))) { 160 | /* parent is black */ 161 | if (augment) 162 | rb3_update_augment(head, augment); 163 | return; 164 | } 165 | 166 | /* 167 | * Since parent is red parent can't be the root. 168 | * So we have at least a grandparent node, and grand-grandparent 169 | * is either a real node or the base head. 170 | */ 171 | pnt = rb3_get_parent(head); 172 | gpnt = rb3_get_parent(pnt); 173 | ggpnt = rb3_get_parent(gpnt); 174 | left = rb3_get_parent_dir(head); 175 | right = !rb3_get_parent_dir(head); 176 | gdir = rb3_get_parent_dir(pnt); 177 | ggdir = rb3_get_parent_dir(gpnt); 178 | 179 | if (rb3_is_red(gpnt, !gdir)) { 180 | /* uncle and parent are both red */ 181 | rb3_set_red(ggpnt, ggdir); 182 | rb3_set_black(gpnt, RB3_LEFT); 183 | rb3_set_black(gpnt, RB3_RIGHT); 184 | if (augment) 185 | rb3_update_augment(head, augment); 186 | rb3_rebalance_after_link(gpnt, augment); 187 | } else if (gdir == right) { 188 | rb3_connect_null(pnt, left, rb3_get_black_child(head, right), _RB3_BLACK); 189 | rb3_connect_null(gpnt, right, rb3_get_black_child(head, left), _RB3_BLACK); 190 | rb3_connect(head, left, gpnt, _RB3_RED); 191 | rb3_connect(head, right, pnt, _RB3_RED); 192 | rb3_connect(ggpnt, ggdir, head, _RB3_BLACK); 193 | if (augment) { 194 | augment(pnt); 195 | augment(gpnt); 196 | rb3_update_augment(head, augment); 197 | } 198 | } else { 199 | rb3_connect_null(gpnt, left, rb3_get_black_child(pnt, right), _RB3_BLACK); 200 | rb3_connect(pnt, right, gpnt, _RB3_RED); 201 | rb3_connect(ggpnt, ggdir, pnt, _RB3_BLACK); 202 | if (augment) { 203 | augment(gpnt); 204 | rb3_update_augment(head, augment); 205 | } 206 | } 207 | } 208 | 209 | static void rb3_rebalance_after_unlink(struct rb3_head *pnt, int pdir, rb3_augment_func *augment) 210 | { 211 | struct rb3_head *gpnt; 212 | struct rb3_head *sibling; 213 | struct rb3_head *sleft; 214 | struct rb3_head *sleftleft; 215 | struct rb3_head *sleftright; 216 | enum rb3_dir left; 217 | enum rb3_dir right; 218 | enum rb3_dir gdir; 219 | 220 | if (!rb3_get_parent(pnt)) 221 | return; 222 | 223 | left = pdir; // define "left" as the direction from parent to deleted node 224 | right = !pdir; 225 | gpnt = rb3_get_parent(pnt); 226 | gdir = rb3_get_parent_dir(pnt); 227 | sibling = rb3_get_child(pnt, right); 228 | sleft = rb3_get_child(sibling, left); 229 | 230 | if (rb3_is_red(pnt, right)) { 231 | /* sibling is red */ 232 | rb3_connect(pnt, right, sleft, _RB3_BLACK); 233 | rb3_connect(sibling, left, pnt, _RB3_RED); 234 | rb3_connect(gpnt, gdir, sibling, _RB3_BLACK); 235 | if (augment) 236 | augment(sleft); 237 | rb3_rebalance_after_unlink(pnt, pdir, augment); 238 | } else if (rb3_is_red(sibling, right)) { 239 | /* outer child of sibling is red */ 240 | rb3_connect_null(pnt, right, sleft, rb3_get_color_bit(sibling, left)); 241 | rb3_connect(sibling, left, pnt, _RB3_BLACK); 242 | rb3_connect(gpnt, gdir, sibling, rb3_get_color_bit(gpnt, gdir)); 243 | if (augment) { 244 | rb3_update_augment(pnt, augment); 245 | } 246 | rb3_set_black(sibling, right); 247 | } else if (rb3_is_red(sibling, left)) { 248 | /* inner child of sibling is red */ 249 | sleftleft = rb3_get_child(sleft, left); 250 | sleftright = rb3_get_child(sleft, right); 251 | rb3_connect_null(pnt, right, sleftleft, _RB3_BLACK); 252 | rb3_connect_null(sibling, left, sleftright, _RB3_BLACK); 253 | rb3_connect(sleft, left, pnt, _RB3_BLACK); 254 | rb3_connect(sleft, right, sibling, _RB3_BLACK); 255 | rb3_connect(gpnt, gdir, sleft, rb3_get_color_bit(gpnt, gdir)); 256 | if (augment) { 257 | augment(sibling); 258 | rb3_update_augment(pnt, augment); 259 | } 260 | } else if (rb3_is_red(gpnt, gdir)) { 261 | /* parent is red */ 262 | rb3_set_red(pnt, right); 263 | rb3_set_black(gpnt, gdir); 264 | if (augment) 265 | rb3_update_augment(pnt, augment); 266 | } else { 267 | /* all relevant nodes are black */ 268 | rb3_set_red(pnt, right); 269 | if (augment) 270 | augment(pnt); 271 | rb3_rebalance_after_unlink(gpnt, gdir, augment); 272 | } 273 | } 274 | 275 | void rb3_link_and_rebalance_and_maybe_augment(struct rb3_head *head, struct rb3_head *parent, int dir, rb3_augment_func *augment) 276 | { 277 | _RB3_ASSERT(dir == RB3_LEFT || dir == RB3_RIGHT); 278 | _RB3_ASSERT(!rb3_has_child(parent, dir)); 279 | 280 | parent->child[dir] = rb3_child_ptr(head, _RB3_RED); 281 | head->parent = rb3_parent_ptr(parent, dir); 282 | head->child[RB3_LEFT] = rb3_child_ptr(_RB3_NULL, _RB3_BLACK); 283 | head->child[RB3_RIGHT] = rb3_child_ptr(_RB3_NULL, _RB3_BLACK); 284 | rb3_rebalance_after_link(head, augment); 285 | } 286 | 287 | void rb3_replace_and_maybe_augment(struct rb3_head *head, struct rb3_head *newhead, rb3_augment_func *augment) 288 | { 289 | struct rb3_head *left; 290 | struct rb3_head *right; 291 | struct rb3_head *parent; 292 | int pdir; 293 | int pcol; 294 | 295 | *newhead = *head; 296 | 297 | left = rb3_get_child(head, RB3_LEFT); 298 | right = rb3_get_child(head, RB3_RIGHT); 299 | parent = rb3_get_parent(head); 300 | pdir = rb3_get_parent_dir(head); 301 | pcol = rb3_get_color_bit(parent, pdir); 302 | 303 | if (left) 304 | left->parent = rb3_parent_ptr(newhead, RB3_LEFT); 305 | if (right) 306 | right->parent = rb3_parent_ptr(newhead, RB3_RIGHT); 307 | parent->child[pdir] = rb3_child_ptr(newhead, pcol); 308 | 309 | if (augment) 310 | rb3_update_augment(newhead, augment); 311 | } 312 | 313 | static void rb3_unlink_noninternal_and_rebalance_and_maybe_augment(struct rb3_head *head, rb3_augment_func *augment) 314 | { 315 | struct rb3_head *pnt; 316 | struct rb3_head *cld; 317 | int pdir; 318 | int dir; 319 | 320 | dir = rb3_get_child(head, RB3_RIGHT) ? RB3_RIGHT : RB3_LEFT; 321 | pnt = rb3_get_parent(head); 322 | cld = rb3_get_child(head, dir); 323 | pdir = rb3_get_parent_dir(head); 324 | 325 | int mustRebalance = !rb3_is_red(pnt, pdir) && !rb3_is_red(head, dir); 326 | 327 | /* since we added the possibility for augmentation, 328 | we need to remove `head` *before* the rebalancing that we do below. 329 | (Otherwise the augmentation function would still see the to-be-deleted child). */ 330 | rb3_connect_null(pnt, pdir, cld, _RB3_BLACK); 331 | 332 | if (mustRebalance) 333 | /* To be deleted node is black (and child cannot be repainted) 334 | * => height decreased */ 335 | rb3_rebalance_after_unlink(pnt, pdir, augment); 336 | else if (augment) 337 | /* the augment wasn't done since we didn't rebalance. So we need to do it separately. 338 | TODO: Could we restrict the augmentation done during rebalancing to just the 339 | nodes that aren't not be augmented by a regular rb3_augment_ancestors(pnt, augment)? */ 340 | rb3_update_augment(pnt, augment); 341 | } 342 | 343 | static void rb3_unlink_internal_and_rebalance_and_maybe_augment(struct rb3_head *head, rb3_augment_func *augment) 344 | { 345 | struct rb3_head *subst; 346 | 347 | subst = rb3_get_next_descendant(head); 348 | rb3_unlink_noninternal_and_rebalance_and_maybe_augment(subst, augment); 349 | rb3_replace_and_maybe_augment(head, subst, augment); 350 | } 351 | 352 | void rb3_unlink_and_rebalance_and_maybe_augment(struct rb3_head *head, rb3_augment_func *augment) 353 | { 354 | if (rb3_has_child(head, RB3_LEFT) && rb3_has_child(head, RB3_RIGHT)) 355 | rb3_unlink_internal_and_rebalance_and_maybe_augment(head, augment); 356 | else 357 | rb3_unlink_noninternal_and_rebalance_and_maybe_augment(head, augment); 358 | } 359 | 360 | struct rb3_head *rb3_find_parent_in_subtree(struct rb3_head *parent, int dir, rb3_cmp cmp, void *data, struct rb3_head **parent_out, int *dir_out) 361 | { 362 | return rb3_INLINE_find(parent, dir, cmp, data, parent_out, dir_out); 363 | } 364 | 365 | struct rb3_head *rb3_insert(struct rb3_tree *tree, struct rb3_head *head, rb3_cmp cmp, void *data) 366 | { 367 | struct rb3_head *found; 368 | struct rb3_head *parent; 369 | int dir; 370 | 371 | parent = rb3_get_base(tree); 372 | dir = RB3_LEFT; 373 | found = rb3_find_parent_in_subtree(parent, dir, cmp, data, &parent, &dir); 374 | if (found) 375 | return found; 376 | rb3_link_and_rebalance(head, parent, dir); 377 | return _RB3_NULL; 378 | } 379 | 380 | struct rb3_head *rb3_delete(struct rb3_tree *tree, rb3_cmp cmp, void *data) 381 | { 382 | struct rb3_head *found; 383 | 384 | found = rb3_find(tree, cmp, data); 385 | if (found) { 386 | rb3_unlink_and_rebalance(found); 387 | return found; 388 | } 389 | return _RB3_NULL; 390 | } 391 | 392 | struct rb3_head *rb3_find_parent(struct rb3_tree *tree, rb3_cmp cmp, void *data, struct rb3_head **parent_out, int *dir_out) 393 | { 394 | return rb3_find_parent_in_subtree(rb3_get_base(tree), RB3_LEFT, cmp, data, parent_out, dir_out); 395 | } 396 | 397 | struct rb3_head *rb3_find(struct rb3_tree *tree, rb3_cmp cmp, void *data) 398 | { 399 | return rb3_find_parent_in_subtree(rb3_get_base(tree), RB3_LEFT, cmp, data, _RB3_NULL, _RB3_NULL); 400 | } 401 | 402 | void rb3_link_and_rebalance(struct rb3_head *head, struct rb3_head *parent, int dir) 403 | { 404 | rb3_link_and_rebalance_and_maybe_augment(head, parent, dir, _RB3_NULL); 405 | } 406 | 407 | void rb3_unlink_and_rebalance(struct rb3_head *head) 408 | { 409 | rb3_unlink_and_rebalance_and_maybe_augment(head, _RB3_NULL); 410 | } 411 | 412 | void rb3_replace(struct rb3_head *head, struct rb3_head *newhead) 413 | { 414 | rb3_replace_and_maybe_augment(head, newhead, _RB3_NULL); 415 | } 416 | 417 | void rb3_link_and_rebalance_and_augment(struct rb3_head *head, struct rb3_head *parent, int dir, rb3_augment_func *augment) 418 | { 419 | rb3_link_and_rebalance_and_maybe_augment(head, parent, dir, augment); 420 | } 421 | 422 | void rb3_unlink_and_rebalance_and_augment(struct rb3_head *head, rb3_augment_func *augment) 423 | { 424 | rb3_unlink_and_rebalance_and_maybe_augment(head, augment); 425 | } 426 | 427 | void rb3_replace_and_augment(struct rb3_head *head, struct rb3_head *newhead, rb3_augment_func *augment) 428 | { 429 | rb3_replace_and_maybe_augment(head, newhead, augment); 430 | } 431 | 432 | 433 | /* DEBUG STUFF */ 434 | 435 | #include 436 | static void visit_inorder_helper(struct rb3_head *head, int isred) 437 | { 438 | if (!head) 439 | return; 440 | printf(" ("); 441 | visit_inorder_helper(rb3_get_child(head, RB3_LEFT), rb3_is_red(head, RB3_LEFT)); 442 | printf("%s", isred ? "R" : "B"); 443 | visit_inorder_helper(rb3_get_child(head, RB3_RIGHT), rb3_is_red(head, RB3_RIGHT)); 444 | printf(")"); 445 | } 446 | 447 | static void visit_inorder(struct rb3_tree *tree) 448 | { 449 | visit_inorder_helper(rb3_get_root(tree), 0); 450 | printf("\n"); 451 | } 452 | 453 | static int rb3_is_valid_tree_helper(struct rb3_head *head, int isred, int dir, int *depth) 454 | { 455 | int i; 456 | int depths[2] = { 1,1 }; 457 | 458 | *depth = 1; 459 | 460 | if (!head) { 461 | if (isred) { 462 | printf("red leaf child!\n"); 463 | return 0; 464 | } 465 | return 1; 466 | } 467 | 468 | if (rb3_get_parent_dir(head) != dir) { 469 | printf("Directions messed up!\n"); 470 | return 0; 471 | } 472 | 473 | for (i = 0; i < 2; i++) { 474 | if (isred && rb3_get_color_bit(head, i)) { 475 | printf("two red in a row!\n"); 476 | return 0; 477 | } 478 | if (!rb3_is_valid_tree_helper(rb3_get_child(head, i), 479 | rb3_is_red(head, i), i, &depths[i])) 480 | return 0; 481 | } 482 | if (depths[0] != depths[1]) { 483 | printf("Unbalanced tree! got %d and %d\n", depths[0], depths[1]); 484 | return 0; 485 | } 486 | *depth = depths[0] + !isred; 487 | 488 | return 1; 489 | } 490 | 491 | int rb3_check_tree(struct rb3_tree *tree) 492 | { 493 | int depth; 494 | int valid; 495 | 496 | if (rb3_is_red(&tree->base, RB3_LEFT)) { 497 | printf("Error! root is red.\n"); 498 | return 0; 499 | } 500 | 501 | valid = rb3_is_valid_tree_helper(rb3_get_root(tree), 0, 0, &depth); 502 | if (!valid) 503 | visit_inorder(tree); 504 | return valid; 505 | } 506 | -------------------------------------------------------------------------------- /rb3ptr.h: -------------------------------------------------------------------------------- 1 | /* rb3ptr -- Intrusively linked 3-pointer Red-black tree implementation */ 2 | 3 | /* Copyright (C) 2019, Jens Stimpfle */ 4 | 5 | /* 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | this software and associated documentation files (the "Software"), to deal in 8 | the Software without restriction, including without limitation the rights to 9 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | the Software, and to permit persons to whom the Software is furnished to do so, 11 | subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | #ifdef RB3PTR_H_INCLUDED 25 | #error rb3ptr.h included twice! 26 | #endif 27 | #define RB3PTR_H_INCLUDED 28 | 29 | #ifndef UINTPTR_MAX /* detect stdint.h */ 30 | #include /* uintptr_t */ 31 | #endif 32 | 33 | #ifndef _RB3_ASSERT 34 | #ifndef assert 35 | #include 36 | #endif 37 | #define _RB3_ASSERT(x) assert(x) 38 | #endif 39 | 40 | #ifndef _RB3_NULL 41 | #ifndef NULL 42 | #include 43 | #endif 44 | #define _RB3_NULL NULL 45 | #endif 46 | 47 | 48 | #ifdef __cplusplus // not yet tested 49 | extern "C" { 50 | #endif 51 | 52 | 53 | /** 54 | * Directions for navigation in the tree. 55 | */ 56 | enum rb3_dir { 57 | RB3_LEFT = 0, 58 | RB3_RIGHT = 1, 59 | }; 60 | 61 | /** 62 | * This type is used to efficiently store a pointer (at least 4-byte aligned) 63 | * and some more information in the unused low bits. 64 | */ 65 | typedef uintptr_t rb3_ptr; 66 | 67 | /** 68 | * Node type for 3-pointer Red-black trees. 69 | * Contains left, right, and parent pointers. 70 | * The left and right pointers have additional color bits. 71 | * The parent pointer contains a direction bit indicating the direction 72 | * to this child. 73 | */ 74 | struct rb3_head { 75 | rb3_ptr child[2]; 76 | rb3_ptr parent; 77 | }; 78 | 79 | /** 80 | * Tree type. It's just a fake base head that is wrapped for type safety and 81 | * future extensibility. 82 | */ 83 | struct rb3_tree { 84 | struct rb3_head base; 85 | }; 86 | 87 | /** 88 | * User-provided comparison function. It is used during tree searches. 89 | * At each visited node, the function is called with that node as first 90 | * argument and some additional user-provided data. 91 | * 92 | * It should returns a value less than, equal to, or greater than, 0, 93 | * depending on whether the node compares less than, equal to, or greater 94 | * than, the user-provided data. 95 | */ 96 | typedef int rb3_cmp(struct rb3_head *head, void *data); 97 | 98 | /** 99 | * User-provided augment function. Used to do recomputations when a child changed. 100 | */ 101 | typedef void rb3_augment_func(struct rb3_head *head /*, void *data */); 102 | 103 | /** 104 | * Initialize an rb3_head. 105 | * After initialization, rb3_is_head_linked() will return false. 106 | */ 107 | static inline void rb3_reset_head(struct rb3_head *head) 108 | { 109 | head->child[RB3_LEFT] = 0; 110 | head->child[RB3_RIGHT] = 0; 111 | head->parent = 0; 112 | } 113 | 114 | /** 115 | * Initialize an rb3_tree. 116 | */ 117 | static inline void rb3_reset_tree(struct rb3_tree *tree) 118 | { 119 | tree->base.child[RB3_LEFT] = 0; 120 | /* ! see doc of rb3_is_base(). */ 121 | tree->base.child[RB3_RIGHT] = 3; 122 | tree->base.parent = 0; 123 | } 124 | 125 | /** 126 | * Get base head of tree. 127 | * 128 | * Warning: the base head is never embedded in a client payload structure. 129 | * It's just a link to host the real root of the tree as its left child. 130 | */ 131 | static inline struct rb3_head *rb3_get_base(struct rb3_tree *tree) 132 | { 133 | return &tree->base; 134 | } 135 | 136 | /** 137 | * Test if given head is base of tree. 138 | */ 139 | static inline int rb3_is_base(struct rb3_head *head) 140 | { 141 | /* We could check for the parent pointer being null, but by having 142 | * a special sentinel right child value instead, we can make this 143 | * function distinguish the base from unlinked pointers as well. 144 | * 145 | * A side effect is that this breaks programs with trees that are not 146 | * initialized with rb3_init(), which could be a good or a bad thing, 147 | * I don't know. */ 148 | return head->child[RB3_RIGHT] == 3; 149 | } 150 | 151 | /** 152 | * Check if a non-base head is linked in a (any) tree. 153 | */ 154 | static inline int rb3_is_head_linked(struct rb3_head *head) 155 | { 156 | return head->parent != 0; 157 | } 158 | 159 | /** 160 | * Get child in given direction, or NULL if there is no such child. `dir` 161 | * must be RB3_LEFT or RB3_RIGHT. 162 | */ 163 | static inline struct rb3_head *rb3_get_child(struct rb3_head *head, int dir) 164 | { 165 | return (struct rb3_head *)((head->child[dir]) & ~3); 166 | } 167 | 168 | /* 169 | * Test if a (left or right) child exists. 170 | * This is slightly more efficient than calling rb3_get_child() and comparing 171 | * to NULL. 172 | */ 173 | static inline int rb3_has_child(struct rb3_head *head, int dir) 174 | { 175 | return head->child[dir] != 0; 176 | } 177 | 178 | /** 179 | * Get direction from parent to child by testing the direction. 180 | * 181 | * Return RB3_LEFT or RB3_RIGHT, depending on whether this node is the left or 182 | * right child of its parent node. If the given node is the root node, 183 | * RB3_LEFT is returned. (Technically the root node is the left child of the 184 | * base node). 185 | * 186 | * This is more convenient and (in theory) more efficient than getting the 187 | * parent and testing its left and right child. 188 | */ 189 | static inline int rb3_get_parent_dir(struct rb3_head *head) 190 | { 191 | return head->parent & 1; 192 | } 193 | 194 | /** 195 | * Get parent head, or NULL if given node is the base head. 196 | * 197 | * Note that normally you don't want to visit the base head but stop already 198 | * at the root node. 199 | */ 200 | static inline struct rb3_head *rb3_get_parent(struct rb3_head *head) 201 | { 202 | return (struct rb3_head *)(head->parent & ~3); 203 | } 204 | 205 | /** 206 | * Get topmost element of tree (or NULL if empty) 207 | */ 208 | static inline struct rb3_head *rb3_get_root(struct rb3_tree *tree) 209 | { 210 | return rb3_get_child(&tree->base, RB3_LEFT); 211 | } 212 | 213 | /** 214 | * Check if tree is empty. 215 | */ 216 | static inline int rb3_is_empty(struct rb3_tree *tree) 217 | { 218 | struct rb3_head *base = rb3_get_base(tree); 219 | return !rb3_has_child(base, RB3_LEFT); 220 | } 221 | 222 | /** 223 | * Get minimum or maximum node in the tree, depending on the value of `dir` 224 | * (RB3_LEFT or RB3_RIGHT) 225 | * 226 | * Time complexity: O(log n) 227 | */ 228 | extern struct rb3_head *rb3_get_minmax(struct rb3_tree *tree, int dir); 229 | 230 | /** 231 | * Get minimum (leftmost) element, or NULL if tree is empty. 232 | * 233 | * Time complexity: O(log n) 234 | */ 235 | static inline struct rb3_head *rb3_get_min(struct rb3_tree *tree) 236 | { 237 | return rb3_get_minmax(tree, RB3_LEFT); 238 | } 239 | 240 | /** 241 | * Get previous or next in-order descendant, depending on the value of `dir` 242 | * (RB3_LEFT or RB3_RIGHT). 243 | * 244 | * Time complexity: O(log n) 245 | */ 246 | extern struct rb3_head *rb3_get_prevnext_descendant(struct rb3_head *head, int dir); 247 | 248 | /** 249 | * Get previous or next in-order ancestor, depending on the value of `dir` 250 | * (RB3_LEFT or RB3_RIGHT). 251 | * 252 | * Time complexity: O(log n) 253 | */ 254 | extern struct rb3_head *rb3_get_prevnext_ancestor(struct rb3_head *head, int dir); 255 | 256 | /** 257 | * Get previous or next in-order node, depending on the value of `dir`. 258 | * 259 | * Time complexity: O(log n), amortized over sequential scan: O(1) 260 | */ 261 | extern struct rb3_head *rb3_get_prevnext(struct rb3_head *head, int dir); 262 | 263 | /** 264 | * Get maximum (rightmost) element, or NULL if tree is empty 265 | * 266 | * Time complexity: O(log n) 267 | */ 268 | static inline struct rb3_head *rb3_get_max(struct rb3_tree *tree) 269 | { 270 | return rb3_get_minmax(tree, RB3_RIGHT); 271 | } 272 | 273 | /** 274 | * Get previous in-order node (maximal node in the tree that sorts before the 275 | * given element) or NULL if no such element is in the tree. 276 | * 277 | * Time complexity: O(log n), amortized over sequential scan: O(1) 278 | */ 279 | static inline struct rb3_head *rb3_get_prev(struct rb3_head *head) 280 | { 281 | return rb3_get_prevnext(head, RB3_LEFT); 282 | } 283 | 284 | /** 285 | * Get next in-order node (minimal node in the tree that sorts after the given 286 | * element) or NULL if no such element is in the tree. 287 | * 288 | * Time complexity: O(log n), amortized over sequential scan: O(1) 289 | */ 290 | static inline struct rb3_head *rb3_get_next(struct rb3_head *head) 291 | { 292 | return rb3_get_prevnext(head, RB3_RIGHT); 293 | } 294 | 295 | /** 296 | * Get previous in-order descendant (maximal descendant node that sorts before 297 | * the given element) or NULL if no such element is in the tree. 298 | * 299 | * Time complexity: O(log n) 300 | */ 301 | static inline struct rb3_head *rb3_get_prev_descendant(struct rb3_head *head) 302 | { 303 | return rb3_get_prevnext_descendant(head, RB3_LEFT); 304 | } 305 | 306 | /** 307 | * Get next in-order descendant (minimal descendant node that sorts after the 308 | * given element) or NULL if no such element is in the tree. 309 | * 310 | * Time complexity: O(log n) 311 | */ 312 | static inline struct rb3_head *rb3_get_next_descendant(struct rb3_head *head) 313 | { 314 | return rb3_get_prevnext_descendant(head, RB3_RIGHT); 315 | } 316 | 317 | /** 318 | * Get previous in-order ancestor (maximal ancestor node that sorts before the 319 | * given element) or NULL if no such element is in the tree. 320 | * 321 | * Time complexity: O(log n) 322 | */ 323 | static inline struct rb3_head *rb3_get_prev_ancestor(struct rb3_head *head) 324 | { 325 | return rb3_get_prevnext_ancestor(head, RB3_LEFT); 326 | } 327 | 328 | /** 329 | * Get next in-order ancestor (minimal ancestor node that sorts after the 330 | * given element) or NULL if no such element is in the tree. 331 | * 332 | * Time complexity: O(log n) 333 | */ 334 | static inline struct rb3_head *rb3_get_next_ancestor(struct rb3_head *head) 335 | { 336 | return rb3_get_prevnext_ancestor(head, RB3_RIGHT); 337 | } 338 | 339 | /** 340 | * Find a node in `tree` using `cmp` to direct the search. At each visited 341 | * node in the tree `cmp` is called with that node and `data` as arguments. 342 | * If a node that compares equal is found, it is returned. Otherwise, NULL is 343 | * returned. 344 | * 345 | * Time complexity: O(log n) 346 | */ 347 | extern struct rb3_head *rb3_find(struct rb3_tree *tree, rb3_cmp cmp, void *data); 348 | 349 | /** 350 | * Find a suitable insertion point for a new node in `tree` using `cmp` and 351 | * `data` to direct the search. At each visited node in the tree `cmp` is 352 | * called with that node and `data` as arguments. If a node that compares 353 | * equal is found, it is returned. Otherwise, NULL is returned and the 354 | * insertion point is returned as parent node and child direction in 355 | * `parent_out` and `dir_out`. 356 | * 357 | * Time complexity: O(log n) 358 | */ 359 | extern struct rb3_head *rb3_find_parent(struct rb3_tree *tree, rb3_cmp cmp, void *data, struct rb3_head **parent_out, int *dir_out); 360 | 361 | /** 362 | * Link `head` into `tree` below another node in the given direction (RB3_LEFT 363 | * or RB3_RIGHT). The new node must replace a leaf. You can use 364 | * rb3_find_parent() to find the insertion point. 365 | * 366 | * `head` must not be linked into another tree when this function is called. 367 | * 368 | * Time complexity: O(log n) 369 | */ 370 | extern void rb3_link_and_rebalance(struct rb3_head *head, struct rb3_head *parent, int dir); 371 | 372 | /** 373 | * Unlink `head` from its current tree. 374 | * 375 | * Time complexity: O(log n) 376 | */ 377 | extern void rb3_unlink_and_rebalance(struct rb3_head *head); 378 | 379 | /** 380 | * Replace `head` with `newhead`. `head` must be linked in a tree and 381 | * `newhead` must not be linked in a tree. 382 | */ 383 | extern void rb3_replace(struct rb3_head *head, struct rb3_head *newhead); 384 | 385 | /** 386 | * Like rb3_link_and_rebalance(), but call an augmentation function for each 387 | * subtree that has been changed. 388 | */ 389 | extern void rb3_link_and_rebalance_and_augment(struct rb3_head *head, struct rb3_head *parent, int dir, rb3_augment_func *augment); 390 | 391 | /** 392 | * Like rb3_unlink_and_rebalance(), but call an augmentation function for each 393 | * subtree that has been changed. 394 | */ 395 | extern void rb3_unlink_and_rebalance_and_augment(struct rb3_head *head, rb3_augment_func *augment); 396 | 397 | /** 398 | * Like rb3_replace(), but call an augmentation function for each subtree that has changed. 399 | */ 400 | extern void rb3_replace_and_augment(struct rb3_head *head, struct rb3_head *newhead, rb3_augment_func *augment); 401 | 402 | /** 403 | * Update by calling the augmentation func for `head` and all its ancestors. 404 | */ 405 | extern void rb3_update_augment(struct rb3_head *head, rb3_augment_func *augment); 406 | 407 | /** 408 | * Find suitable insertion point for a new node in a subtree, directed by the 409 | * given search function. The subtree is given by its parent node `parent` and 410 | * child direction `dir`. The insertion point and its child direction are 411 | * returned in `parent_out` and `dir_out`. 412 | * 413 | * If the searched node is already in the tree (the compare function returns 414 | * 0), it is returned. In this case `parent_out` and `dir_out` are left 415 | * untouched. Otherwise NULL is returned. 416 | */ 417 | extern struct rb3_head *rb3_find_parent_in_subtree(struct rb3_head *parent, int dir, rb3_cmp cmp, void *data, struct rb3_head **parent_out, int *dir_out); 418 | 419 | /** 420 | * Insert `head` into `tree` using `cmp` and `data` to direct the search. At 421 | * each visited node in the tree `cmp` is called with that node and `data` as 422 | * arguments (in that order). If a node that compares equal is found, it is 423 | * returned. Otherwise, `head` is inserted into the tree and NULL is 424 | * returned. 425 | * 426 | * Time complexity: O(log n) 427 | */ 428 | extern struct rb3_head *rb3_insert(struct rb3_tree *tree, struct rb3_head *head, rb3_cmp cmp, void *data); 429 | 430 | /** 431 | * Find and delete a node from `tree` using `cmp` to direct the search. At 432 | * each visited node in the tree `cmp` is called with that node and `head` as 433 | * arguments (in that order). If a node that compares equal is found, it is 434 | * unlinked from the tree and returned. Otherwise, NULL is returned. 435 | * 436 | * Time complexity: O(log n) 437 | */ 438 | extern struct rb3_head *rb3_delete(struct rb3_tree *tree, rb3_cmp cmp, void *data); 439 | 440 | /** 441 | * Given a node that is known to be linked in _some_ tree, find that tree. 442 | * 443 | * This involves a little hackery with offsetof(3) 444 | */ 445 | extern struct rb3_tree *rb3_get_containing_tree(struct rb3_head *head); 446 | 447 | 448 | /* 449 | XXX: is inlining the search function advantageous? 450 | */ 451 | static inline struct rb3_head *rb3_INLINE_find(struct rb3_head *parent, int dir, rb3_cmp cmp, void *data, struct rb3_head **parent_out, int *dir_out) 452 | { 453 | _RB3_ASSERT(parent != _RB3_NULL); 454 | while (rb3_has_child(parent, dir)) { 455 | parent = rb3_get_child(parent, dir); 456 | int r = cmp(parent, data); 457 | if (r == 0) 458 | return parent; 459 | dir = (r < 0) ? RB3_RIGHT : RB3_LEFT; 460 | } 461 | if (parent_out) 462 | *parent_out = parent; 463 | if (dir_out) 464 | *dir_out = dir; 465 | return _RB3_NULL; 466 | } 467 | 468 | /**************** DEBUG STUFF *******************/ 469 | int rb3_check_tree(struct rb3_tree *tree); 470 | /************************************************/ 471 | 472 | #ifdef __cplusplus 473 | } // extern "C" 474 | #endif 475 | --------------------------------------------------------------------------------