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 | ||