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