aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorMichel Lespinasse <walken@google.com>2012-10-08 19:31:33 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-10-09 03:22:40 -0400
commit9c079add0d0f45220f4bb37febf0621137ec2d38 (patch)
treece6ba6d7e2d517a2004de856c882f2a08af12be2 /lib
parent147e615f83c2c36caf89e7a3bf78090ade6f266c (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.c162
-rw-r--r--lib/rbtree_test.c2
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
59static inline void rb_set_black(struct rb_node *rb) 47static 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
64static 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
69static 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
75static inline struct rb_node *rb_red_parent(struct rb_node *red) 52static 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
80static 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
233static __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 358EXPORT_SYMBOL(__rb_erase_color);
395static __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
514void rb_erase(struct rb_node *node, struct rb_root *root) 381void 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}
518EXPORT_SYMBOL(rb_erase); 385EXPORT_SYMBOL(rb_erase);
519 386
@@ -531,13 +398,6 @@ void __rb_insert_augmented(struct rb_node *node, struct rb_root *root,
531} 398}
532EXPORT_SYMBOL(__rb_insert_augmented); 399EXPORT_SYMBOL(__rb_insert_augmented);
533 400
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
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