aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/rbtree.c83
-rw-r--r--lib/rbtree_test.c58
2 files changed, 120 insertions, 21 deletions
diff --git a/lib/rbtree.c b/lib/rbtree.c
index 938061ecbe61..a37ee7954b8f 100644
--- a/lib/rbtree.c
+++ b/lib/rbtree.c
@@ -105,7 +105,9 @@ __rb_rotate_set_parents(struct rb_node *old, struct rb_node *new,
105 __rb_change_child(old, new, parent, root); 105 __rb_change_child(old, new, parent, root);
106} 106}
107 107
108void rb_insert_color(struct rb_node *node, struct rb_root *root) 108static __always_inline void
109__rb_insert(struct rb_node *node, struct rb_root *root,
110 void (*augment_rotate)(struct rb_node *old, struct rb_node *new))
109{ 111{
110 struct rb_node *parent = rb_red_parent(node), *gparent, *tmp; 112 struct rb_node *parent = rb_red_parent(node), *gparent, *tmp;
111 113
@@ -169,6 +171,7 @@ void rb_insert_color(struct rb_node *node, struct rb_root *root)
169 rb_set_parent_color(tmp, parent, 171 rb_set_parent_color(tmp, parent,
170 RB_BLACK); 172 RB_BLACK);
171 rb_set_parent_color(parent, node, RB_RED); 173 rb_set_parent_color(parent, node, RB_RED);
174 augment_rotate(parent, node);
172 parent = node; 175 parent = node;
173 tmp = node->rb_right; 176 tmp = node->rb_right;
174 } 177 }
@@ -187,6 +190,7 @@ void rb_insert_color(struct rb_node *node, struct rb_root *root)
187 if (tmp) 190 if (tmp)
188 rb_set_parent_color(tmp, gparent, RB_BLACK); 191 rb_set_parent_color(tmp, gparent, RB_BLACK);
189 __rb_rotate_set_parents(gparent, parent, root, RB_RED); 192 __rb_rotate_set_parents(gparent, parent, root, RB_RED);
193 augment_rotate(gparent, parent);
190 break; 194 break;
191 } else { 195 } else {
192 tmp = gparent->rb_left; 196 tmp = gparent->rb_left;
@@ -209,6 +213,7 @@ void rb_insert_color(struct rb_node *node, struct rb_root *root)
209 rb_set_parent_color(tmp, parent, 213 rb_set_parent_color(tmp, parent,
210 RB_BLACK); 214 RB_BLACK);
211 rb_set_parent_color(parent, node, RB_RED); 215 rb_set_parent_color(parent, node, RB_RED);
216 augment_rotate(parent, node);
212 parent = node; 217 parent = node;
213 tmp = node->rb_left; 218 tmp = node->rb_left;
214 } 219 }
@@ -219,13 +224,15 @@ void rb_insert_color(struct rb_node *node, struct rb_root *root)
219 if (tmp) 224 if (tmp)
220 rb_set_parent_color(tmp, gparent, RB_BLACK); 225 rb_set_parent_color(tmp, gparent, RB_BLACK);
221 __rb_rotate_set_parents(gparent, parent, root, RB_RED); 226 __rb_rotate_set_parents(gparent, parent, root, RB_RED);
227 augment_rotate(gparent, parent);
222 break; 228 break;
223 } 229 }
224 } 230 }
225} 231}
226EXPORT_SYMBOL(rb_insert_color);
227 232
228static void __rb_erase_color(struct rb_node *parent, struct rb_root *root) 233static __always_inline void
234__rb_erase_color(struct rb_node *parent, struct rb_root *root,
235 const struct rb_augment_callbacks *augment)
229{ 236{
230 struct rb_node *node = NULL, *sibling, *tmp1, *tmp2; 237 struct rb_node *node = NULL, *sibling, *tmp1, *tmp2;
231 238
@@ -254,6 +261,7 @@ static void __rb_erase_color(struct rb_node *parent, struct rb_root *root)
254 rb_set_parent_color(tmp1, parent, RB_BLACK); 261 rb_set_parent_color(tmp1, parent, RB_BLACK);
255 __rb_rotate_set_parents(parent, sibling, root, 262 __rb_rotate_set_parents(parent, sibling, root,
256 RB_RED); 263 RB_RED);
264 augment->rotate(parent, sibling);
257 sibling = tmp1; 265 sibling = tmp1;
258 } 266 }
259 tmp1 = sibling->rb_right; 267 tmp1 = sibling->rb_right;
@@ -305,6 +313,7 @@ static void __rb_erase_color(struct rb_node *parent, struct rb_root *root)
305 if (tmp1) 313 if (tmp1)
306 rb_set_parent_color(tmp1, sibling, 314 rb_set_parent_color(tmp1, sibling,
307 RB_BLACK); 315 RB_BLACK);
316 augment->rotate(sibling, tmp2);
308 tmp1 = sibling; 317 tmp1 = sibling;
309 sibling = tmp2; 318 sibling = tmp2;
310 } 319 }
@@ -327,6 +336,7 @@ static void __rb_erase_color(struct rb_node *parent, struct rb_root *root)
327 rb_set_parent(tmp2, parent); 336 rb_set_parent(tmp2, parent);
328 __rb_rotate_set_parents(parent, sibling, root, 337 __rb_rotate_set_parents(parent, sibling, root,
329 RB_BLACK); 338 RB_BLACK);
339 augment->rotate(parent, sibling);
330 break; 340 break;
331 } else { 341 } else {
332 sibling = parent->rb_left; 342 sibling = parent->rb_left;
@@ -337,6 +347,7 @@ static void __rb_erase_color(struct rb_node *parent, struct rb_root *root)
337 rb_set_parent_color(tmp1, parent, RB_BLACK); 347 rb_set_parent_color(tmp1, parent, RB_BLACK);
338 __rb_rotate_set_parents(parent, sibling, root, 348 __rb_rotate_set_parents(parent, sibling, root,
339 RB_RED); 349 RB_RED);
350 augment->rotate(parent, sibling);
340 sibling = tmp1; 351 sibling = tmp1;
341 } 352 }
342 tmp1 = sibling->rb_left; 353 tmp1 = sibling->rb_left;
@@ -363,6 +374,7 @@ static void __rb_erase_color(struct rb_node *parent, struct rb_root *root)
363 if (tmp1) 374 if (tmp1)
364 rb_set_parent_color(tmp1, sibling, 375 rb_set_parent_color(tmp1, sibling,
365 RB_BLACK); 376 RB_BLACK);
377 augment->rotate(sibling, tmp2);
366 tmp1 = sibling; 378 tmp1 = sibling;
367 sibling = tmp2; 379 sibling = tmp2;
368 } 380 }
@@ -374,12 +386,15 @@ static void __rb_erase_color(struct rb_node *parent, struct rb_root *root)
374 rb_set_parent(tmp2, parent); 386 rb_set_parent(tmp2, parent);
375 __rb_rotate_set_parents(parent, sibling, root, 387 __rb_rotate_set_parents(parent, sibling, root,
376 RB_BLACK); 388 RB_BLACK);
389 augment->rotate(parent, sibling);
377 break; 390 break;
378 } 391 }
379 } 392 }
380} 393}
381 394
382void rb_erase(struct rb_node *node, struct rb_root *root) 395static __always_inline void
396__rb_erase(struct rb_node *node, struct rb_root *root,
397 const struct rb_augment_callbacks *augment)
383{ 398{
384 struct rb_node *child = node->rb_right, *tmp = node->rb_left; 399 struct rb_node *child = node->rb_right, *tmp = node->rb_left;
385 struct rb_node *parent, *rebalance; 400 struct rb_node *parent, *rebalance;
@@ -401,12 +416,14 @@ void rb_erase(struct rb_node *node, struct rb_root *root)
401 rebalance = NULL; 416 rebalance = NULL;
402 } else 417 } else
403 rebalance = __rb_is_black(pc) ? parent : NULL; 418 rebalance = __rb_is_black(pc) ? parent : NULL;
419 tmp = parent;
404 } else if (!child) { 420 } else if (!child) {
405 /* Still case 1, but this time the child is node->rb_left */ 421 /* Still case 1, but this time the child is node->rb_left */
406 tmp->__rb_parent_color = pc = node->__rb_parent_color; 422 tmp->__rb_parent_color = pc = node->__rb_parent_color;
407 parent = __rb_parent(pc); 423 parent = __rb_parent(pc);
408 __rb_change_child(node, tmp, parent, root); 424 __rb_change_child(node, tmp, parent, root);
409 rebalance = NULL; 425 rebalance = NULL;
426 tmp = parent;
410 } else { 427 } else {
411 struct rb_node *successor = child, *child2; 428 struct rb_node *successor = child, *child2;
412 tmp = child->rb_left; 429 tmp = child->rb_left;
@@ -420,8 +437,9 @@ void rb_erase(struct rb_node *node, struct rb_root *root)
420 * \ 437 * \
421 * (c) 438 * (c)
422 */ 439 */
423 parent = child; 440 parent = successor;
424 child2 = child->rb_right; 441 child2 = successor->rb_right;
442 augment->copy(node, successor);
425 } else { 443 } else {
426 /* 444 /*
427 * Case 3: node's successor is leftmost under 445 * Case 3: node's successor is leftmost under
@@ -445,6 +463,8 @@ void rb_erase(struct rb_node *node, struct rb_root *root)
445 parent->rb_left = child2 = successor->rb_right; 463 parent->rb_left = child2 = successor->rb_right;
446 successor->rb_right = child; 464 successor->rb_right = child;
447 rb_set_parent(child, successor); 465 rb_set_parent(child, successor);
466 augment->copy(node, successor);
467 augment->propagate(parent, successor);
448 } 468 }
449 469
450 successor->rb_left = tmp = node->rb_left; 470 successor->rb_left = tmp = node->rb_left;
@@ -462,13 +482,62 @@ void rb_erase(struct rb_node *node, struct rb_root *root)
462 successor->__rb_parent_color = pc; 482 successor->__rb_parent_color = pc;
463 rebalance = __rb_is_black(pc2) ? parent : NULL; 483 rebalance = __rb_is_black(pc2) ? parent : NULL;
464 } 484 }
485 tmp = successor;
465 } 486 }
466 487
488 augment->propagate(tmp, NULL);
467 if (rebalance) 489 if (rebalance)
468 __rb_erase_color(rebalance, root); 490 __rb_erase_color(rebalance, root, augment);
491}
492
493/*
494 * Non-augmented rbtree manipulation functions.
495 *
496 * We use dummy augmented callbacks here, and have the compiler optimize them
497 * out of the rb_insert_color() and rb_erase() function definitions.
498 */
499
500static inline void dummy_propagate(struct rb_node *node, struct rb_node *stop) {}
501static inline void dummy_copy(struct rb_node *old, struct rb_node *new) {}
502static inline void dummy_rotate(struct rb_node *old, struct rb_node *new) {}
503
504static const struct rb_augment_callbacks dummy_callbacks = {
505 dummy_propagate, dummy_copy, dummy_rotate
506};
507
508void rb_insert_color(struct rb_node *node, struct rb_root *root)
509{
510 __rb_insert(node, root, dummy_rotate);
511}
512EXPORT_SYMBOL(rb_insert_color);
513
514void rb_erase(struct rb_node *node, struct rb_root *root)
515{
516 __rb_erase(node, root, &dummy_callbacks);
469} 517}
470EXPORT_SYMBOL(rb_erase); 518EXPORT_SYMBOL(rb_erase);
471 519
520/*
521 * Augmented rbtree manipulation functions.
522 *
523 * This instantiates the same __always_inline functions as in the non-augmented
524 * case, but this time with user-defined callbacks.
525 */
526
527void __rb_insert_augmented(struct rb_node *node, struct rb_root *root,
528 void (*augment_rotate)(struct rb_node *old, struct rb_node *new))
529{
530 __rb_insert(node, root, augment_rotate);
531}
532EXPORT_SYMBOL(__rb_insert_augmented);
533
534void rb_erase_augmented(struct rb_node *node, struct rb_root *root,
535 const struct rb_augment_callbacks *augment)
536{
537 __rb_erase(node, root, augment);
538}
539EXPORT_SYMBOL(rb_erase_augmented);
540
472static void rb_augment_path(struct rb_node *node, rb_augment_f func, void *data) 541static void rb_augment_path(struct rb_node *node, rb_augment_f func, void *data)
473{ 542{
474 struct rb_node *parent; 543 struct rb_node *parent;
diff --git a/lib/rbtree_test.c b/lib/rbtree_test.c
index 66e41d4bfc39..e28345df09bf 100644
--- a/lib/rbtree_test.c
+++ b/lib/rbtree_test.c
@@ -61,35 +61,65 @@ static inline u32 augment_recompute(struct test_node *node)
61 return max; 61 return max;
62} 62}
63 63
64static void augment_callback(struct rb_node *rb, void *unused) 64static void augment_propagate(struct rb_node *rb, struct rb_node *stop)
65{ 65{
66 struct test_node *node = rb_entry(rb, struct test_node, rb); 66 while (rb != stop) {
67 node->augmented = augment_recompute(node); 67 struct test_node *node = rb_entry(rb, struct test_node, rb);
68 u32 augmented = augment_recompute(node);
69 if (node->augmented == augmented)
70 break;
71 node->augmented = augmented;
72 rb = rb_parent(&node->rb);
73 }
74}
75
76static void augment_copy(struct rb_node *rb_old, struct rb_node *rb_new)
77{
78 struct test_node *old = rb_entry(rb_old, struct test_node, rb);
79 struct test_node *new = rb_entry(rb_new, struct test_node, rb);
80 new->augmented = old->augmented;
68} 81}
69 82
83static void augment_rotate(struct rb_node *rb_old, struct rb_node *rb_new)
84{
85 struct test_node *old = rb_entry(rb_old, struct test_node, rb);
86 struct test_node *new = rb_entry(rb_new, struct test_node, rb);
87
88 /* Rotation doesn't change subtree's augmented value */
89 new->augmented = old->augmented;
90 old->augmented = augment_recompute(old);
91}
92
93static const struct rb_augment_callbacks augment_callbacks = {
94 augment_propagate, augment_copy, augment_rotate
95};
96
70static void insert_augmented(struct test_node *node, struct rb_root *root) 97static void insert_augmented(struct test_node *node, struct rb_root *root)
71{ 98{
72 struct rb_node **new = &root->rb_node, *parent = NULL; 99 struct rb_node **new = &root->rb_node, *rb_parent = NULL;
73 u32 key = node->key; 100 u32 key = node->key;
101 u32 val = node->val;
102 struct test_node *parent;
74 103
75 while (*new) { 104 while (*new) {
76 parent = *new; 105 rb_parent = *new;
77 if (key < rb_entry(parent, struct test_node, rb)->key) 106 parent = rb_entry(rb_parent, struct test_node, rb);
78 new = &parent->rb_left; 107 if (parent->augmented < val)
108 parent->augmented = val;
109 if (key < parent->key)
110 new = &parent->rb.rb_left;
79 else 111 else
80 new = &parent->rb_right; 112 new = &parent->rb.rb_right;
81 } 113 }
82 114
83 rb_link_node(&node->rb, parent, new); 115 node->augmented = val;
84 rb_insert_color(&node->rb, root); 116 rb_link_node(&node->rb, rb_parent, new);
85 rb_augment_insert(&node->rb, augment_callback, NULL); 117 rb_insert_augmented(&node->rb, root, &augment_callbacks);
86} 118}
87 119
88static void erase_augmented(struct test_node *node, struct rb_root *root) 120static void erase_augmented(struct test_node *node, struct rb_root *root)
89{ 121{
90 struct rb_node *deepest = rb_augment_erase_begin(&node->rb); 122 rb_erase_augmented(&node->rb, root, &augment_callbacks);
91 rb_erase(&node->rb, root);
92 rb_augment_erase_end(deepest, augment_callback, NULL);
93} 123}
94 124
95static void init(void) 125static void init(void)