diff options
| -rw-r--r-- | Documentation/rbtree.txt | 58 | ||||
| -rw-r--r-- | include/linux/rbtree.h | 5 | ||||
| -rw-r--r-- | lib/rbtree.c | 48 |
3 files changed, 106 insertions, 5 deletions
diff --git a/Documentation/rbtree.txt b/Documentation/rbtree.txt index aae8355d3166..221f38be98f4 100644 --- a/Documentation/rbtree.txt +++ b/Documentation/rbtree.txt | |||
| @@ -190,3 +190,61 @@ Example: | |||
| 190 | for (node = rb_first(&mytree); node; node = rb_next(node)) | 190 | for (node = rb_first(&mytree); node; node = rb_next(node)) |
| 191 | printk("key=%s\n", rb_entry(node, struct mytype, node)->keystring); | 191 | printk("key=%s\n", rb_entry(node, struct mytype, node)->keystring); |
| 192 | 192 | ||
| 193 | Support for Augmented rbtrees | ||
| 194 | ----------------------------- | ||
| 195 | |||
| 196 | Augmented rbtree is an rbtree with "some" additional data stored in each node. | ||
| 197 | This data can be used to augment some new functionality to rbtree. | ||
| 198 | Augmented rbtree is an optional feature built on top of basic rbtree | ||
| 199 | infrastructure. rbtree user who wants this feature will have an augment | ||
| 200 | callback function in rb_root initialized. | ||
| 201 | |||
| 202 | This callback function will be called from rbtree core routines whenever | ||
| 203 | a node has a change in one or both of its children. It is the responsibility | ||
| 204 | of the callback function to recalculate the additional data that is in the | ||
| 205 | rb node using new children information. Note that if this new additional | ||
| 206 | data affects the parent node's additional data, then callback function has | ||
| 207 | to handle it and do the recursive updates. | ||
| 208 | |||
| 209 | |||
| 210 | Interval tree is an example of augmented rb tree. Reference - | ||
| 211 | "Introduction to Algorithms" by Cormen, Leiserson, Rivest and Stein. | ||
| 212 | More details about interval trees: | ||
| 213 | |||
| 214 | Classical rbtree has a single key and it cannot be directly used to store | ||
| 215 | interval ranges like [lo:hi] and do a quick lookup for any overlap with a new | ||
| 216 | lo:hi or to find whether there is an exact match for a new lo:hi. | ||
| 217 | |||
| 218 | However, rbtree can be augmented to store such interval ranges in a structured | ||
| 219 | way making it possible to do efficient lookup and exact match. | ||
| 220 | |||
| 221 | This "extra information" stored in each node is the maximum hi | ||
| 222 | (max_hi) value among all the nodes that are its descendents. This | ||
| 223 | information can be maintained at each node just be looking at the node | ||
| 224 | and its immediate children. And this will be used in O(log n) lookup | ||
| 225 | for lowest match (lowest start address among all possible matches) | ||
| 226 | with something like: | ||
| 227 | |||
| 228 | find_lowest_match(lo, hi, node) | ||
| 229 | { | ||
| 230 | lowest_match = NULL; | ||
| 231 | while (node) { | ||
| 232 | if (max_hi(node->left) > lo) { | ||
| 233 | // Lowest overlap if any must be on left side | ||
| 234 | node = node->left; | ||
| 235 | } else if (overlap(lo, hi, node)) { | ||
| 236 | lowest_match = node; | ||
| 237 | break; | ||
| 238 | } else if (lo > node->lo) { | ||
| 239 | // Lowest overlap if any must be on right side | ||
| 240 | node = node->right; | ||
| 241 | } else { | ||
| 242 | break; | ||
| 243 | } | ||
| 244 | } | ||
| 245 | return lowest_match; | ||
| 246 | } | ||
| 247 | |||
| 248 | Finding exact match will be to first find lowest match and then to follow | ||
| 249 | successor nodes looking for exact match, until the start of a node is beyond | ||
| 250 | the hi value we are looking for. | ||
diff --git a/include/linux/rbtree.h b/include/linux/rbtree.h index 9c295411d01f..8e33a256ea0e 100644 --- a/include/linux/rbtree.h +++ b/include/linux/rbtree.h | |||
| @@ -110,6 +110,7 @@ struct rb_node | |||
| 110 | struct rb_root | 110 | struct rb_root |
| 111 | { | 111 | { |
| 112 | struct rb_node *rb_node; | 112 | struct rb_node *rb_node; |
| 113 | void (*augment_cb)(struct rb_node *node); | ||
| 113 | }; | 114 | }; |
| 114 | 115 | ||
| 115 | 116 | ||
| @@ -129,7 +130,9 @@ static inline void rb_set_color(struct rb_node *rb, int color) | |||
| 129 | rb->rb_parent_color = (rb->rb_parent_color & ~1) | color; | 130 | rb->rb_parent_color = (rb->rb_parent_color & ~1) | color; |
| 130 | } | 131 | } |
| 131 | 132 | ||
| 132 | #define RB_ROOT (struct rb_root) { NULL, } | 133 | #define RB_ROOT (struct rb_root) { NULL, NULL, } |
| 134 | #define RB_AUGMENT_ROOT(x) (struct rb_root) { NULL, x} | ||
| 135 | |||
| 133 | #define rb_entry(ptr, type, member) container_of(ptr, type, member) | 136 | #define rb_entry(ptr, type, member) container_of(ptr, type, member) |
| 134 | 137 | ||
| 135 | #define RB_EMPTY_ROOT(root) ((root)->rb_node == NULL) | 138 | #define RB_EMPTY_ROOT(root) ((root)->rb_node == NULL) |
diff --git a/lib/rbtree.c b/lib/rbtree.c index e2aa3be29858..15e10b1afdd2 100644 --- a/lib/rbtree.c +++ b/lib/rbtree.c | |||
| @@ -44,6 +44,11 @@ static void __rb_rotate_left(struct rb_node *node, struct rb_root *root) | |||
| 44 | else | 44 | else |
| 45 | root->rb_node = right; | 45 | root->rb_node = right; |
| 46 | rb_set_parent(node, right); | 46 | rb_set_parent(node, right); |
| 47 | |||
| 48 | if (root->augment_cb) { | ||
| 49 | root->augment_cb(node); | ||
| 50 | root->augment_cb(right); | ||
| 51 | } | ||
| 47 | } | 52 | } |
| 48 | 53 | ||
| 49 | static void __rb_rotate_right(struct rb_node *node, struct rb_root *root) | 54 | static void __rb_rotate_right(struct rb_node *node, struct rb_root *root) |
| @@ -67,12 +72,20 @@ static void __rb_rotate_right(struct rb_node *node, struct rb_root *root) | |||
| 67 | else | 72 | else |
| 68 | root->rb_node = left; | 73 | root->rb_node = left; |
| 69 | rb_set_parent(node, left); | 74 | rb_set_parent(node, left); |
| 75 | |||
| 76 | if (root->augment_cb) { | ||
| 77 | root->augment_cb(node); | ||
| 78 | root->augment_cb(left); | ||
| 79 | } | ||
| 70 | } | 80 | } |
| 71 | 81 | ||
| 72 | void rb_insert_color(struct rb_node *node, struct rb_root *root) | 82 | void rb_insert_color(struct rb_node *node, struct rb_root *root) |
| 73 | { | 83 | { |
| 74 | struct rb_node *parent, *gparent; | 84 | struct rb_node *parent, *gparent; |
| 75 | 85 | ||
| 86 | if (root->augment_cb) | ||
| 87 | root->augment_cb(node); | ||
| 88 | |||
| 76 | while ((parent = rb_parent(node)) && rb_is_red(parent)) | 89 | while ((parent = rb_parent(node)) && rb_is_red(parent)) |
| 77 | { | 90 | { |
| 78 | gparent = rb_parent(parent); | 91 | gparent = rb_parent(parent); |
| @@ -227,12 +240,15 @@ void rb_erase(struct rb_node *node, struct rb_root *root) | |||
| 227 | else | 240 | else |
| 228 | { | 241 | { |
| 229 | struct rb_node *old = node, *left; | 242 | struct rb_node *old = node, *left; |
| 243 | int old_parent_cb = 0; | ||
| 244 | int successor_parent_cb = 0; | ||
| 230 | 245 | ||
| 231 | node = node->rb_right; | 246 | node = node->rb_right; |
| 232 | while ((left = node->rb_left) != NULL) | 247 | while ((left = node->rb_left) != NULL) |
| 233 | node = left; | 248 | node = left; |
| 234 | 249 | ||
| 235 | if (rb_parent(old)) { | 250 | if (rb_parent(old)) { |
| 251 | old_parent_cb = 1; | ||
| 236 | if (rb_parent(old)->rb_left == old) | 252 | if (rb_parent(old)->rb_left == old) |
| 237 | rb_parent(old)->rb_left = node; | 253 | rb_parent(old)->rb_left = node; |
| 238 | else | 254 | else |
| @@ -247,8 +263,10 @@ void rb_erase(struct rb_node *node, struct rb_root *root) | |||
| 247 | if (parent == old) { | 263 | if (parent == old) { |
| 248 | parent = node; | 264 | parent = node; |
| 249 | } else { | 265 | } else { |
| 266 | successor_parent_cb = 1; | ||
| 250 | if (child) | 267 | if (child) |
| 251 | rb_set_parent(child, parent); | 268 | rb_set_parent(child, parent); |
| 269 | |||
| 252 | parent->rb_left = child; | 270 | parent->rb_left = child; |
| 253 | 271 | ||
| 254 | node->rb_right = old->rb_right; | 272 | node->rb_right = old->rb_right; |
| @@ -259,6 +277,24 @@ void rb_erase(struct rb_node *node, struct rb_root *root) | |||
| 259 | node->rb_left = old->rb_left; | 277 | node->rb_left = old->rb_left; |
| 260 | rb_set_parent(old->rb_left, node); | 278 | rb_set_parent(old->rb_left, node); |
| 261 | 279 | ||
| 280 | if (root->augment_cb) { | ||
| 281 | /* | ||
| 282 | * Here, three different nodes can have new children. | ||
| 283 | * The parent of the successor node that was selected | ||
| 284 | * to replace the node to be erased. | ||
| 285 | * The node that is getting erased and is now replaced | ||
| 286 | * by its successor. | ||
| 287 | * The parent of the node getting erased-replaced. | ||
| 288 | */ | ||
| 289 | if (successor_parent_cb) | ||
| 290 | root->augment_cb(parent); | ||
| 291 | |||
| 292 | root->augment_cb(node); | ||
| 293 | |||
| 294 | if (old_parent_cb) | ||
| 295 | root->augment_cb(rb_parent(old)); | ||
| 296 | } | ||
| 297 | |||
| 262 | goto color; | 298 | goto color; |
| 263 | } | 299 | } |
| 264 | 300 | ||
| @@ -267,15 +303,19 @@ void rb_erase(struct rb_node *node, struct rb_root *root) | |||
| 267 | 303 | ||
| 268 | if (child) | 304 | if (child) |
| 269 | rb_set_parent(child, parent); | 305 | rb_set_parent(child, parent); |
| 270 | if (parent) | 306 | |
| 271 | { | 307 | if (parent) { |
| 272 | if (parent->rb_left == node) | 308 | if (parent->rb_left == node) |
| 273 | parent->rb_left = child; | 309 | parent->rb_left = child; |
| 274 | else | 310 | else |
| 275 | parent->rb_right = child; | 311 | parent->rb_right = child; |
| 276 | } | 312 | |
| 277 | else | 313 | if (root->augment_cb) |
| 314 | root->augment_cb(parent); | ||
| 315 | |||
| 316 | } else { | ||
| 278 | root->rb_node = child; | 317 | root->rb_node = child; |
| 318 | } | ||
| 279 | 319 | ||
| 280 | color: | 320 | color: |
| 281 | if (color == RB_BLACK) | 321 | if (color == RB_BLACK) |
