diff options
| author | Michel Lespinasse <walken@google.com> | 2012-10-08 19:31:33 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-09 03:22:40 -0400 |
| commit | 9c079add0d0f45220f4bb37febf0621137ec2d38 (patch) | |
| tree | ce6ba6d7e2d517a2004de856c882f2a08af12be2 /lib | |
| parent | 147e615f83c2c36caf89e7a3bf78090ade6f266c (diff) | |
rbtree: move augmented rbtree functionality to rbtree_augmented.h
Provide rb_insert_augmented() and rb_erase_augmented() through a new
rbtree_augmented.h include file. rb_erase_augmented() is defined there as
an __always_inline function, in order to allow inlining of augmented
rbtree callbacks into it. Since this generates a relatively large
function, each augmented rbtree user should make sure to have a single
call site.
Signed-off-by: Michel Lespinasse <walken@google.com>
Cc: Rik van Riel <riel@redhat.com>
Cc: Hillf Danton <dhillf@gmail.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Andrea Arcangeli <aarcange@redhat.com>
Cc: David Woodhouse <dwmw2@infradead.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/rbtree.c | 162 | ||||
| -rw-r--r-- | lib/rbtree_test.c | 2 |
2 files changed, 12 insertions, 152 deletions
diff --git a/lib/rbtree.c b/lib/rbtree.c index c0088ca345f9..4f56a11d67fa 100644 --- a/lib/rbtree.c +++ b/lib/rbtree.c | |||
| @@ -21,7 +21,7 @@ | |||
| 21 | linux/lib/rbtree.c | 21 | linux/lib/rbtree.c |
| 22 | */ | 22 | */ |
| 23 | 23 | ||
| 24 | #include <linux/rbtree.h> | 24 | #include <linux/rbtree_augmented.h> |
| 25 | #include <linux/export.h> | 25 | #include <linux/export.h> |
| 26 | 26 | ||
| 27 | /* | 27 | /* |
| @@ -44,52 +44,16 @@ | |||
| 44 | * parentheses and have some accompanying text comment. | 44 | * parentheses and have some accompanying text comment. |
| 45 | */ | 45 | */ |
| 46 | 46 | ||
| 47 | #define RB_RED 0 | ||
| 48 | #define RB_BLACK 1 | ||
| 49 | |||
| 50 | #define __rb_parent(pc) ((struct rb_node *)(pc & ~3)) | ||
| 51 | |||
| 52 | #define __rb_color(pc) ((pc) & 1) | ||
| 53 | #define __rb_is_black(pc) __rb_color(pc) | ||
| 54 | #define __rb_is_red(pc) (!__rb_color(pc)) | ||
| 55 | #define rb_color(rb) __rb_color((rb)->__rb_parent_color) | ||
| 56 | #define rb_is_red(rb) __rb_is_red((rb)->__rb_parent_color) | ||
| 57 | #define rb_is_black(rb) __rb_is_black((rb)->__rb_parent_color) | ||
| 58 | |||
| 59 | static inline void rb_set_black(struct rb_node *rb) | 47 | static inline void rb_set_black(struct rb_node *rb) |
| 60 | { | 48 | { |
| 61 | rb->__rb_parent_color |= RB_BLACK; | 49 | rb->__rb_parent_color |= RB_BLACK; |
| 62 | } | 50 | } |
| 63 | 51 | ||
| 64 | static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p) | ||
| 65 | { | ||
| 66 | rb->__rb_parent_color = rb_color(rb) | (unsigned long)p; | ||
| 67 | } | ||
| 68 | |||
| 69 | static inline void rb_set_parent_color(struct rb_node *rb, | ||
| 70 | struct rb_node *p, int color) | ||
| 71 | { | ||
| 72 | rb->__rb_parent_color = (unsigned long)p | color; | ||
| 73 | } | ||
| 74 | |||
| 75 | static inline struct rb_node *rb_red_parent(struct rb_node *red) | 52 | static inline struct rb_node *rb_red_parent(struct rb_node *red) |
| 76 | { | 53 | { |
| 77 | return (struct rb_node *)red->__rb_parent_color; | 54 | return (struct rb_node *)red->__rb_parent_color; |
| 78 | } | 55 | } |
| 79 | 56 | ||
| 80 | static inline void | ||
| 81 | __rb_change_child(struct rb_node *old, struct rb_node *new, | ||
| 82 | struct rb_node *parent, struct rb_root *root) | ||
| 83 | { | ||
| 84 | if (parent) { | ||
| 85 | if (parent->rb_left == old) | ||
| 86 | parent->rb_left = new; | ||
| 87 | else | ||
| 88 | parent->rb_right = new; | ||
| 89 | } else | ||
| 90 | root->rb_node = new; | ||
| 91 | } | ||
| 92 | |||
| 93 | /* | 57 | /* |
| 94 | * Helper function for rotations: | 58 | * Helper function for rotations: |
| 95 | * - old's parent and color get assigned to new | 59 | * - old's parent and color get assigned to new |
| @@ -230,9 +194,9 @@ __rb_insert(struct rb_node *node, struct rb_root *root, | |||
| 230 | } | 194 | } |
| 231 | } | 195 | } |
| 232 | 196 | ||
| 233 | static __always_inline void | 197 | __always_inline void |
| 234 | __rb_erase_color(struct rb_node *parent, struct rb_root *root, | 198 | __rb_erase_color(struct rb_node *parent, struct rb_root *root, |
| 235 | const struct rb_augment_callbacks *augment) | 199 | void (*augment_rotate)(struct rb_node *old, struct rb_node *new)) |
| 236 | { | 200 | { |
| 237 | struct rb_node *node = NULL, *sibling, *tmp1, *tmp2; | 201 | struct rb_node *node = NULL, *sibling, *tmp1, *tmp2; |
| 238 | 202 | ||
| @@ -261,7 +225,7 @@ __rb_erase_color(struct rb_node *parent, struct rb_root *root, | |||
| 261 | rb_set_parent_color(tmp1, parent, RB_BLACK); | 225 | rb_set_parent_color(tmp1, parent, RB_BLACK); |
| 262 | __rb_rotate_set_parents(parent, sibling, root, | 226 | __rb_rotate_set_parents(parent, sibling, root, |
| 263 | RB_RED); | 227 | RB_RED); |
| 264 | augment->rotate(parent, sibling); | 228 | augment_rotate(parent, sibling); |
| 265 | sibling = tmp1; | 229 | sibling = tmp1; |
| 266 | } | 230 | } |
| 267 | tmp1 = sibling->rb_right; | 231 | tmp1 = sibling->rb_right; |
| @@ -313,7 +277,7 @@ __rb_erase_color(struct rb_node *parent, struct rb_root *root, | |||
| 313 | if (tmp1) | 277 | if (tmp1) |
| 314 | rb_set_parent_color(tmp1, sibling, | 278 | rb_set_parent_color(tmp1, sibling, |
| 315 | RB_BLACK); | 279 | RB_BLACK); |
| 316 | augment->rotate(sibling, tmp2); | 280 | augment_rotate(sibling, tmp2); |
| 317 | tmp1 = sibling; | 281 | tmp1 = sibling; |
| 318 | sibling = tmp2; | 282 | sibling = tmp2; |
| 319 | } | 283 | } |
| @@ -336,7 +300,7 @@ __rb_erase_color(struct rb_node *parent, struct rb_root *root, | |||
| 336 | rb_set_parent(tmp2, parent); | 300 | rb_set_parent(tmp2, parent); |
| 337 | __rb_rotate_set_parents(parent, sibling, root, | 301 | __rb_rotate_set_parents(parent, sibling, root, |
| 338 | RB_BLACK); | 302 | RB_BLACK); |
| 339 | augment->rotate(parent, sibling); | 303 | augment_rotate(parent, sibling); |
| 340 | break; | 304 | break; |
| 341 | } else { | 305 | } else { |
| 342 | sibling = parent->rb_left; | 306 | sibling = parent->rb_left; |
| @@ -347,7 +311,7 @@ __rb_erase_color(struct rb_node *parent, struct rb_root *root, | |||
| 347 | rb_set_parent_color(tmp1, parent, RB_BLACK); | 311 | rb_set_parent_color(tmp1, parent, RB_BLACK); |
| 348 | __rb_rotate_set_parents(parent, sibling, root, | 312 | __rb_rotate_set_parents(parent, sibling, root, |
| 349 | RB_RED); | 313 | RB_RED); |
| 350 | augment->rotate(parent, sibling); | 314 | augment_rotate(parent, sibling); |
| 351 | sibling = tmp1; | 315 | sibling = tmp1; |
| 352 | } | 316 | } |
| 353 | tmp1 = sibling->rb_left; | 317 | tmp1 = sibling->rb_left; |
| @@ -374,7 +338,7 @@ __rb_erase_color(struct rb_node *parent, struct rb_root *root, | |||
| 374 | if (tmp1) | 338 | if (tmp1) |
| 375 | rb_set_parent_color(tmp1, sibling, | 339 | rb_set_parent_color(tmp1, sibling, |
| 376 | RB_BLACK); | 340 | RB_BLACK); |
| 377 | augment->rotate(sibling, tmp2); | 341 | augment_rotate(sibling, tmp2); |
| 378 | tmp1 = sibling; | 342 | tmp1 = sibling; |
| 379 | sibling = tmp2; | 343 | sibling = tmp2; |
| 380 | } | 344 | } |
| @@ -386,109 +350,12 @@ __rb_erase_color(struct rb_node *parent, struct rb_root *root, | |||
| 386 | rb_set_parent(tmp2, parent); | 350 | rb_set_parent(tmp2, parent); |
| 387 | __rb_rotate_set_parents(parent, sibling, root, | 351 | __rb_rotate_set_parents(parent, sibling, root, |
| 388 | RB_BLACK); | 352 | RB_BLACK); |
| 389 | augment->rotate(parent, sibling); | 353 | augment_rotate(parent, sibling); |
| 390 | break; | 354 | break; |
| 391 | } | 355 | } |
| 392 | } | 356 | } |
| 393 | } | 357 | } |
| 394 | 358 | EXPORT_SYMBOL(__rb_erase_color); | |
| 395 | static __always_inline void | ||
| 396 | __rb_erase(struct rb_node *node, struct rb_root *root, | ||
| 397 | const struct rb_augment_callbacks *augment) | ||
| 398 | { | ||
| 399 | struct rb_node *child = node->rb_right, *tmp = node->rb_left; | ||
| 400 | struct rb_node *parent, *rebalance; | ||
| 401 | unsigned long pc; | ||
| 402 | |||
| 403 | if (!tmp) { | ||
| 404 | /* | ||
| 405 | * Case 1: node to erase has no more than 1 child (easy!) | ||
| 406 | * | ||
| 407 | * Note that if there is one child it must be red due to 5) | ||
| 408 | * and node must be black due to 4). We adjust colors locally | ||
| 409 | * so as to bypass __rb_erase_color() later on. | ||
| 410 | */ | ||
| 411 | pc = node->__rb_parent_color; | ||
| 412 | parent = __rb_parent(pc); | ||
| 413 | __rb_change_child(node, child, parent, root); | ||
| 414 | if (child) { | ||
| 415 | child->__rb_parent_color = pc; | ||
| 416 | rebalance = NULL; | ||
| 417 | } else | ||
| 418 | rebalance = __rb_is_black(pc) ? parent : NULL; | ||
| 419 | tmp = parent; | ||
| 420 | } else if (!child) { | ||
| 421 | /* Still case 1, but this time the child is node->rb_left */ | ||
| 422 | tmp->__rb_parent_color = pc = node->__rb_parent_color; | ||
| 423 | parent = __rb_parent(pc); | ||
| 424 | __rb_change_child(node, tmp, parent, root); | ||
| 425 | rebalance = NULL; | ||
| 426 | tmp = parent; | ||
| 427 | } else { | ||
| 428 | struct rb_node *successor = child, *child2; | ||
| 429 | tmp = child->rb_left; | ||
| 430 | if (!tmp) { | ||
| 431 | /* | ||
| 432 | * Case 2: node's successor is its right child | ||
| 433 | * | ||
| 434 | * (n) (s) | ||
| 435 | * / \ / \ | ||
| 436 | * (x) (s) -> (x) (c) | ||
| 437 | * \ | ||
| 438 | * (c) | ||
| 439 | */ | ||
| 440 | parent = successor; | ||
| 441 | child2 = successor->rb_right; | ||
| 442 | augment->copy(node, successor); | ||
| 443 | } else { | ||
| 444 | /* | ||
| 445 | * Case 3: node's successor is leftmost under | ||
| 446 | * node's right child subtree | ||
| 447 | * | ||
| 448 | * (n) (s) | ||
| 449 | * / \ / \ | ||
| 450 | * (x) (y) -> (x) (y) | ||
| 451 | * / / | ||
| 452 | * (p) (p) | ||
| 453 | * / / | ||
| 454 | * (s) (c) | ||
| 455 | * \ | ||
| 456 | * (c) | ||
| 457 | */ | ||
| 458 | do { | ||
| 459 | parent = successor; | ||
| 460 | successor = tmp; | ||
| 461 | tmp = tmp->rb_left; | ||
| 462 | } while (tmp); | ||
| 463 | parent->rb_left = child2 = successor->rb_right; | ||
| 464 | successor->rb_right = child; | ||
| 465 | rb_set_parent(child, successor); | ||
| 466 | augment->copy(node, successor); | ||
| 467 | augment->propagate(parent, successor); | ||
| 468 | } | ||
| 469 | |||
| 470 | successor->rb_left = tmp = node->rb_left; | ||
| 471 | rb_set_parent(tmp, successor); | ||
| 472 | |||
| 473 | pc = node->__rb_parent_color; | ||
| 474 | tmp = __rb_parent(pc); | ||
| 475 | __rb_change_child(node, successor, tmp, root); | ||
| 476 | if (child2) { | ||
| 477 | successor->__rb_parent_color = pc; | ||
| 478 | rb_set_parent_color(child2, parent, RB_BLACK); | ||
| 479 | rebalance = NULL; | ||
| 480 | } else { | ||
| 481 | unsigned long pc2 = successor->__rb_parent_color; | ||
| 482 | successor->__rb_parent_color = pc; | ||
| 483 | rebalance = __rb_is_black(pc2) ? parent : NULL; | ||
| 484 | } | ||
| 485 | tmp = successor; | ||
| 486 | } | ||
| 487 | |||
| 488 | augment->propagate(tmp, NULL); | ||
| 489 | if (rebalance) | ||
| 490 | __rb_erase_color(rebalance, root, augment); | ||
| 491 | } | ||
| 492 | 359 | ||
| 493 | /* | 360 | /* |
| 494 | * Non-augmented rbtree manipulation functions. | 361 | * Non-augmented rbtree manipulation functions. |
| @@ -513,7 +380,7 @@ EXPORT_SYMBOL(rb_insert_color); | |||
| 513 | 380 | ||
| 514 | void rb_erase(struct rb_node *node, struct rb_root *root) | 381 | void rb_erase(struct rb_node *node, struct rb_root *root) |
| 515 | { | 382 | { |
| 516 | __rb_erase(node, root, &dummy_callbacks); | 383 | rb_erase_augmented(node, root, &dummy_callbacks); |
| 517 | } | 384 | } |
| 518 | EXPORT_SYMBOL(rb_erase); | 385 | EXPORT_SYMBOL(rb_erase); |
| 519 | 386 | ||
| @@ -531,13 +398,6 @@ void __rb_insert_augmented(struct rb_node *node, struct rb_root *root, | |||
| 531 | } | 398 | } |
| 532 | EXPORT_SYMBOL(__rb_insert_augmented); | 399 | EXPORT_SYMBOL(__rb_insert_augmented); |
| 533 | 400 | ||
| 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 | |||
| 541 | /* | 401 | /* |
| 542 | * This function returns the first node (in sort order) of the tree. | 402 | * This function returns the first node (in sort order) of the tree. |
| 543 | */ | 403 | */ |
diff --git a/lib/rbtree_test.c b/lib/rbtree_test.c index b20e99969b0f..268b23951fec 100644 --- a/lib/rbtree_test.c +++ b/lib/rbtree_test.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | #include <linux/module.h> | 1 | #include <linux/module.h> |
| 2 | #include <linux/rbtree.h> | 2 | #include <linux/rbtree_augmented.h> |
| 3 | #include <linux/random.h> | 3 | #include <linux/random.h> |
| 4 | #include <asm/timex.h> | 4 | #include <asm/timex.h> |
| 5 | 5 | ||
