augmented rbtree: add new RB_DECLARE_CALLBACKS_MAX macro
[linux-2.6-block.git] / tools / include / linux / rbtree_augmented.h
index ddd01006ece571c594c90ac9c17f1ec7abcbfbfd..4e8c4c76e9a2628bde041e62b2ba220a3ba7a2e5 100644 (file)
@@ -32,17 +32,16 @@ struct rb_augment_callbacks {
        void (*rotate)(struct rb_node *old, struct rb_node *new);
 };
 
-extern void __rb_insert_augmented(struct rb_node *node,
-                                 struct rb_root *root,
-                                 bool newleft, struct rb_node **leftmost,
+extern void __rb_insert_augmented(struct rb_node *node, struct rb_root *root,
        void (*augment_rotate)(struct rb_node *old, struct rb_node *new));
+
 /*
  * Fixup the rbtree and update the augmented information when rebalancing.
  *
  * On insertion, the user must update the augmented information on the path
  * leading to the inserted node, then call rb_link_node() as usual and
- * rb_augment_inserted() instead of the usual rb_insert_color() call.
- * If rb_augment_inserted() rebalances the rbtree, it will callback into
+ * rb_insert_augmented() instead of the usual rb_insert_color() call.
+ * If rb_insert_augmented() rebalances the rbtree, it will callback into
  * a user provided function to update the augmented information on the
  * affected subtrees.
  */
@@ -50,7 +49,7 @@ static inline void
 rb_insert_augmented(struct rb_node *node, struct rb_root *root,
                    const struct rb_augment_callbacks *augment)
 {
-       __rb_insert_augmented(node, root, false, NULL, augment->rotate);
+       __rb_insert_augmented(node, root, augment->rotate);
 }
 
 static inline void
@@ -58,45 +57,92 @@ rb_insert_augmented_cached(struct rb_node *node,
                           struct rb_root_cached *root, bool newleft,
                           const struct rb_augment_callbacks *augment)
 {
-       __rb_insert_augmented(node, &root->rb_root,
-                             newleft, &root->rb_leftmost, augment->rotate);
+       if (newleft)
+               root->rb_leftmost = node;
+       rb_insert_augmented(node, &root->rb_root, augment);
 }
 
-#define RB_DECLARE_CALLBACKS(rbstatic, rbname, rbstruct, rbfield,      \
-                            rbtype, rbaugmented, rbcompute)            \
+/*
+ * Template for declaring augmented rbtree callbacks (generic case)
+ *
+ * RBSTATIC:    'static' or empty
+ * RBNAME:      name of the rb_augment_callbacks structure
+ * RBSTRUCT:    struct type of the tree nodes
+ * RBFIELD:     name of struct rb_node field within RBSTRUCT
+ * RBTYPE:      type of the RBAUGMENTED field
+ * RBAUGMENTED: name of RBTYPE field within RBSTRUCT holding data for subtree
+ * RBCOMPUTE:   name of function that recomputes the RBAUGMENTED data
+ */
+
+#define RB_DECLARE_CALLBACKS(RBSTATIC, RBNAME, RBSTRUCT, RBFIELD,      \
+                            RBTYPE, RBAUGMENTED, RBCOMPUTE)            \
 static inline void                                                     \
-rbname ## _propagate(struct rb_node *rb, struct rb_node *stop)         \
+RBNAME ## _propagate(struct rb_node *rb, struct rb_node *stop)         \
 {                                                                      \
        while (rb != stop) {                                            \
-               rbstruct *node = rb_entry(rb, rbstruct, rbfield);       \
-               rbtype augmented = rbcompute(node);                     \
-               if (node->rbaugmented == augmented)                     \
+               RBSTRUCT *node = rb_entry(rb, RBSTRUCT, RBFIELD);       \
+               RBTYPE augmented = RBCOMPUTE(node);                     \
+               if (node->RBAUGMENTED == augmented)                     \
                        break;                                          \
-               node->rbaugmented = augmented;                          \
-               rb = rb_parent(&node->rbfield);                         \
+               node->RBAUGMENTED = augmented;                          \
+               rb = rb_parent(&node->RBFIELD);                         \
        }                                                               \
 }                                                                      \
 static inline void                                                     \
-rbname ## _copy(struct rb_node *rb_old, struct rb_node *rb_new)                \
+RBNAME ## _copy(struct rb_node *rb_old, struct rb_node *rb_new)                \
 {                                                                      \
-       rbstruct *old = rb_entry(rb_old, rbstruct, rbfield);            \
-       rbstruct *new = rb_entry(rb_new, rbstruct, rbfield);            \
-       new->rbaugmented = old->rbaugmented;                            \
+       RBSTRUCT *old = rb_entry(rb_old, RBSTRUCT, RBFIELD);            \
+       RBSTRUCT *new = rb_entry(rb_new, RBSTRUCT, RBFIELD);            \
+       new->RBAUGMENTED = old->RBAUGMENTED;                            \
 }                                                                      \
 static void                                                            \
-rbname ## _rotate(struct rb_node *rb_old, struct rb_node *rb_new)      \
+RBNAME ## _rotate(struct rb_node *rb_old, struct rb_node *rb_new)      \
 {                                                                      \
-       rbstruct *old = rb_entry(rb_old, rbstruct, rbfield);            \
-       rbstruct *new = rb_entry(rb_new, rbstruct, rbfield);            \
-       new->rbaugmented = old->rbaugmented;                            \
-       old->rbaugmented = rbcompute(old);                              \
+       RBSTRUCT *old = rb_entry(rb_old, RBSTRUCT, RBFIELD);            \
+       RBSTRUCT *new = rb_entry(rb_new, RBSTRUCT, RBFIELD);            \
+       new->RBAUGMENTED = old->RBAUGMENTED;                            \
+       old->RBAUGMENTED = RBCOMPUTE(old);                              \
 }                                                                      \
-rbstatic const struct rb_augment_callbacks rbname = {                  \
-       .propagate = rbname ## _propagate,                              \
-       .copy = rbname ## _copy,                                        \
-       .rotate = rbname ## _rotate                                     \
+RBSTATIC const struct rb_augment_callbacks RBNAME = {                  \
+       .propagate = RBNAME ## _propagate,                              \
+       .copy = RBNAME ## _copy,                                        \
+       .rotate = RBNAME ## _rotate                                     \
 };
 
+/*
+ * Template for declaring augmented rbtree callbacks,
+ * computing RBAUGMENTED scalar as max(RBCOMPUTE(node)) for all subtree nodes.
+ *
+ * RBSTATIC:    'static' or empty
+ * RBNAME:      name of the rb_augment_callbacks structure
+ * RBSTRUCT:    struct type of the tree nodes
+ * RBFIELD:     name of struct rb_node field within RBSTRUCT
+ * RBTYPE:      type of the RBAUGMENTED field
+ * RBAUGMENTED: name of RBTYPE field within RBSTRUCT holding data for subtree
+ * RBCOMPUTE:   name of function that returns the per-node RBTYPE scalar
+ */
+
+#define RB_DECLARE_CALLBACKS_MAX(RBSTATIC, RBNAME, RBSTRUCT, RBFIELD,        \
+                                RBTYPE, RBAUGMENTED, RBCOMPUTE)              \
+static inline RBTYPE RBNAME ## _compute_max(RBSTRUCT *node)                  \
+{                                                                            \
+       RBSTRUCT *child;                                                      \
+       RBTYPE max = RBCOMPUTE(node);                                         \
+       if (node->RBFIELD.rb_left) {                                          \
+               child = rb_entry(node->RBFIELD.rb_left, RBSTRUCT, RBFIELD);   \
+               if (child->RBAUGMENTED > max)                                 \
+                       max = child->RBAUGMENTED;                             \
+       }                                                                     \
+       if (node->RBFIELD.rb_right) {                                         \
+               child = rb_entry(node->RBFIELD.rb_right, RBSTRUCT, RBFIELD);  \
+               if (child->RBAUGMENTED > max)                                 \
+                       max = child->RBAUGMENTED;                             \
+       }                                                                     \
+       return max;                                                           \
+}                                                                            \
+RB_DECLARE_CALLBACKS(RBSTATIC, RBNAME, RBSTRUCT, RBFIELD,                    \
+                    RBTYPE, RBAUGMENTED, RBNAME ## _compute_max)
+
 
 #define        RB_RED          0
 #define        RB_BLACK        1
@@ -139,7 +185,6 @@ extern void __rb_erase_color(struct rb_node *parent, struct rb_root *root,
 
 static __always_inline struct rb_node *
 __rb_erase_augmented(struct rb_node *node, struct rb_root *root,
-                    struct rb_node **leftmost,
                     const struct rb_augment_callbacks *augment)
 {
        struct rb_node *child = node->rb_right;
@@ -147,9 +192,6 @@ __rb_erase_augmented(struct rb_node *node, struct rb_root *root,
        struct rb_node *parent, *rebalance;
        unsigned long pc;
 
-       if (leftmost && node == *leftmost)
-               *leftmost = rb_next(node);
-
        if (!tmp) {
                /*
                 * Case 1: node to erase has no more than 1 child (easy!)
@@ -249,8 +291,7 @@ static __always_inline void
 rb_erase_augmented(struct rb_node *node, struct rb_root *root,
                   const struct rb_augment_callbacks *augment)
 {
-       struct rb_node *rebalance = __rb_erase_augmented(node, root,
-                                                        NULL, augment);
+       struct rb_node *rebalance = __rb_erase_augmented(node, root, augment);
        if (rebalance)
                __rb_erase_color(rebalance, root, augment->rotate);
 }
@@ -259,11 +300,9 @@ static __always_inline void
 rb_erase_augmented_cached(struct rb_node *node, struct rb_root_cached *root,
                          const struct rb_augment_callbacks *augment)
 {
-       struct rb_node *rebalance = __rb_erase_augmented(node, &root->rb_root,
-                                                        &root->rb_leftmost,
-                                                        augment);
-       if (rebalance)
-               __rb_erase_color(rebalance, &root->rb_root, augment->rotate);
+       if (root->rb_leftmost == node)
+               root->rb_leftmost = rb_next(node);
+       rb_erase_augmented(node, &root->rb_root, augment);
 }
 
 #endif /* _TOOLS_LINUX_RBTREE_AUGMENTED_H */