diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/rbtree.c | 83 | ||||
-rw-r--r-- | lib/rbtree_test.c | 58 |
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 | ||
108 | void rb_insert_color(struct rb_node *node, struct rb_root *root) | 108 | static __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 | } |
226 | EXPORT_SYMBOL(rb_insert_color); | ||
227 | 232 | ||
228 | static void __rb_erase_color(struct rb_node *parent, struct rb_root *root) | 233 | static __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 | ||
382 | void rb_erase(struct rb_node *node, struct rb_root *root) | 395 | static __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 | |||
500 | static inline void dummy_propagate(struct rb_node *node, struct rb_node *stop) {} | ||
501 | static inline void dummy_copy(struct rb_node *old, struct rb_node *new) {} | ||
502 | static inline void dummy_rotate(struct rb_node *old, struct rb_node *new) {} | ||
503 | |||
504 | static const struct rb_augment_callbacks dummy_callbacks = { | ||
505 | dummy_propagate, dummy_copy, dummy_rotate | ||
506 | }; | ||
507 | |||
508 | void rb_insert_color(struct rb_node *node, struct rb_root *root) | ||
509 | { | ||
510 | __rb_insert(node, root, dummy_rotate); | ||
511 | } | ||
512 | EXPORT_SYMBOL(rb_insert_color); | ||
513 | |||
514 | void rb_erase(struct rb_node *node, struct rb_root *root) | ||
515 | { | ||
516 | __rb_erase(node, root, &dummy_callbacks); | ||
469 | } | 517 | } |
470 | EXPORT_SYMBOL(rb_erase); | 518 | EXPORT_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 | |||
527 | void __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 | } | ||
532 | EXPORT_SYMBOL(__rb_insert_augmented); | ||
533 | |||
534 | void 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 | } | ||
539 | EXPORT_SYMBOL(rb_erase_augmented); | ||
540 | |||
472 | static void rb_augment_path(struct rb_node *node, rb_augment_f func, void *data) | 541 | static 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 | ||
64 | static void augment_callback(struct rb_node *rb, void *unused) | 64 | static 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 | |||
76 | static 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 | ||
83 | static 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 | |||
93 | static const struct rb_augment_callbacks augment_callbacks = { | ||
94 | augment_propagate, augment_copy, augment_rotate | ||
95 | }; | ||
96 | |||
70 | static void insert_augmented(struct test_node *node, struct rb_root *root) | 97 | static 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 | ||
88 | static void erase_augmented(struct test_node *node, struct rb_root *root) | 120 | static 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 | ||
95 | static void init(void) | 125 | static void init(void) |