diff options
Diffstat (limited to 'Documentation/rbtree.txt')
-rw-r--r-- | Documentation/rbtree.txt | 190 |
1 files changed, 157 insertions, 33 deletions
diff --git a/Documentation/rbtree.txt b/Documentation/rbtree.txt index 8d32d85a5234..0a0b6dce3e08 100644 --- a/Documentation/rbtree.txt +++ b/Documentation/rbtree.txt | |||
@@ -193,24 +193,42 @@ Example: | |||
193 | Support for Augmented rbtrees | 193 | Support for Augmented rbtrees |
194 | ----------------------------- | 194 | ----------------------------- |
195 | 195 | ||
196 | Augmented rbtree is an rbtree with "some" additional data stored in each node. | 196 | Augmented rbtree is an rbtree with "some" additional data stored in |
197 | This data can be used to augment some new functionality to rbtree. | 197 | each node, where the additional data for node N must be a function of |
198 | Augmented rbtree is an optional feature built on top of basic rbtree | 198 | the contents of all nodes in the subtree rooted at N. This data can |
199 | infrastructure. An rbtree user who wants this feature will have to call the | 199 | be used to augment some new functionality to rbtree. Augmented rbtree |
200 | augmentation functions with the user provided augmentation callback | 200 | is an optional feature built on top of basic rbtree infrastructure. |
201 | when inserting and erasing nodes. | 201 | An rbtree user who wants this feature will have to call the augmentation |
202 | functions with the user provided augmentation callback when inserting | ||
203 | and erasing nodes. | ||
202 | 204 | ||
203 | On insertion, the user must call rb_augment_insert() once the new node is in | 205 | On insertion, the user must update the augmented information on the path |
204 | place. This will cause the augmentation function callback to be called for | 206 | leading to the inserted node, then call rb_link_node() as usual and |
205 | each node between the new node and the root which has been affected by the | 207 | rb_augment_inserted() instead of the usual rb_insert_color() call. |
206 | insertion. | 208 | If rb_augment_inserted() rebalances the rbtree, it will callback into |
209 | a user provided function to update the augmented information on the | ||
210 | affected subtrees. | ||
207 | 211 | ||
208 | When erasing a node, the user must call rb_augment_erase_begin() first to | 212 | When erasing a node, the user must call rb_erase_augmented() instead of |
209 | retrieve the deepest node on the rebalance path. Then, after erasing the | 213 | rb_erase(). rb_erase_augmented() calls back into user provided functions |
210 | original node, the user must call rb_augment_erase_end() with the deepest | 214 | to updated the augmented information on affected subtrees. |
211 | node found earlier. This will cause the augmentation function to be called | ||
212 | for each affected node between the deepest node and the root. | ||
213 | 215 | ||
216 | In both cases, the callbacks are provided through struct rb_augment_callbacks. | ||
217 | 3 callbacks must be defined: | ||
218 | |||
219 | - A propagation callback, which updates the augmented value for a given | ||
220 | node and its ancestors, up to a given stop point (or NULL to update | ||
221 | all the way to the root). | ||
222 | |||
223 | - A copy callback, which copies the augmented value for a given subtree | ||
224 | to a newly assigned subtree root. | ||
225 | |||
226 | - A tree rotation callback, which copies the augmented value for a given | ||
227 | subtree to a newly assigned subtree root AND recomputes the augmented | ||
228 | information for the former subtree root. | ||
229 | |||
230 | |||
231 | Sample usage: | ||
214 | 232 | ||
215 | Interval tree is an example of augmented rb tree. Reference - | 233 | Interval tree is an example of augmented rb tree. Reference - |
216 | "Introduction to Algorithms" by Cormen, Leiserson, Rivest and Stein. | 234 | "Introduction to Algorithms" by Cormen, Leiserson, Rivest and Stein. |
@@ -230,26 +248,132 @@ and its immediate children. And this will be used in O(log n) lookup | |||
230 | for lowest match (lowest start address among all possible matches) | 248 | for lowest match (lowest start address among all possible matches) |
231 | with something like: | 249 | with something like: |
232 | 250 | ||
233 | find_lowest_match(lo, hi, node) | 251 | struct interval_tree_node * |
252 | interval_tree_first_match(struct rb_root *root, | ||
253 | unsigned long start, unsigned long last) | ||
234 | { | 254 | { |
235 | lowest_match = NULL; | 255 | struct interval_tree_node *node; |
236 | while (node) { | 256 | |
237 | if (max_hi(node->left) > lo) { | 257 | if (!root->rb_node) |
238 | // Lowest overlap if any must be on left side | 258 | return NULL; |
239 | node = node->left; | 259 | node = rb_entry(root->rb_node, struct interval_tree_node, rb); |
240 | } else if (overlap(lo, hi, node)) { | 260 | |
241 | lowest_match = node; | 261 | while (true) { |
242 | break; | 262 | if (node->rb.rb_left) { |
243 | } else if (lo > node->lo) { | 263 | struct interval_tree_node *left = |
244 | // Lowest overlap if any must be on right side | 264 | rb_entry(node->rb.rb_left, |
245 | node = node->right; | 265 | struct interval_tree_node, rb); |
246 | } else { | 266 | if (left->__subtree_last >= start) { |
247 | break; | 267 | /* |
268 | * Some nodes in left subtree satisfy Cond2. | ||
269 | * Iterate to find the leftmost such node N. | ||
270 | * If it also satisfies Cond1, that's the match | ||
271 | * we are looking for. Otherwise, there is no | ||
272 | * matching interval as nodes to the right of N | ||
273 | * can't satisfy Cond1 either. | ||
274 | */ | ||
275 | node = left; | ||
276 | continue; | ||
277 | } | ||
248 | } | 278 | } |
279 | if (node->start <= last) { /* Cond1 */ | ||
280 | if (node->last >= start) /* Cond2 */ | ||
281 | return node; /* node is leftmost match */ | ||
282 | if (node->rb.rb_right) { | ||
283 | node = rb_entry(node->rb.rb_right, | ||
284 | struct interval_tree_node, rb); | ||
285 | if (node->__subtree_last >= start) | ||
286 | continue; | ||
287 | } | ||
288 | } | ||
289 | return NULL; /* No match */ | ||
290 | } | ||
291 | } | ||
292 | |||
293 | Insertion/removal are defined using the following augmented callbacks: | ||
294 | |||
295 | static inline unsigned long | ||
296 | compute_subtree_last(struct interval_tree_node *node) | ||
297 | { | ||
298 | unsigned long max = node->last, subtree_last; | ||
299 | if (node->rb.rb_left) { | ||
300 | subtree_last = rb_entry(node->rb.rb_left, | ||
301 | struct interval_tree_node, rb)->__subtree_last; | ||
302 | if (max < subtree_last) | ||
303 | max = subtree_last; | ||
304 | } | ||
305 | if (node->rb.rb_right) { | ||
306 | subtree_last = rb_entry(node->rb.rb_right, | ||
307 | struct interval_tree_node, rb)->__subtree_last; | ||
308 | if (max < subtree_last) | ||
309 | max = subtree_last; | ||
310 | } | ||
311 | return max; | ||
312 | } | ||
313 | |||
314 | static void augment_propagate(struct rb_node *rb, struct rb_node *stop) | ||
315 | { | ||
316 | while (rb != stop) { | ||
317 | struct interval_tree_node *node = | ||
318 | rb_entry(rb, struct interval_tree_node, rb); | ||
319 | unsigned long subtree_last = compute_subtree_last(node); | ||
320 | if (node->__subtree_last == subtree_last) | ||
321 | break; | ||
322 | node->__subtree_last = subtree_last; | ||
323 | rb = rb_parent(&node->rb); | ||
324 | } | ||
325 | } | ||
326 | |||
327 | static void augment_copy(struct rb_node *rb_old, struct rb_node *rb_new) | ||
328 | { | ||
329 | struct interval_tree_node *old = | ||
330 | rb_entry(rb_old, struct interval_tree_node, rb); | ||
331 | struct interval_tree_node *new = | ||
332 | rb_entry(rb_new, struct interval_tree_node, rb); | ||
333 | |||
334 | new->__subtree_last = old->__subtree_last; | ||
335 | } | ||
336 | |||
337 | static void augment_rotate(struct rb_node *rb_old, struct rb_node *rb_new) | ||
338 | { | ||
339 | struct interval_tree_node *old = | ||
340 | rb_entry(rb_old, struct interval_tree_node, rb); | ||
341 | struct interval_tree_node *new = | ||
342 | rb_entry(rb_new, struct interval_tree_node, rb); | ||
343 | |||
344 | new->__subtree_last = old->__subtree_last; | ||
345 | old->__subtree_last = compute_subtree_last(old); | ||
346 | } | ||
347 | |||
348 | static const struct rb_augment_callbacks augment_callbacks = { | ||
349 | augment_propagate, augment_copy, augment_rotate | ||
350 | }; | ||
351 | |||
352 | void interval_tree_insert(struct interval_tree_node *node, | ||
353 | struct rb_root *root) | ||
354 | { | ||
355 | struct rb_node **link = &root->rb_node, *rb_parent = NULL; | ||
356 | unsigned long start = node->start, last = node->last; | ||
357 | struct interval_tree_node *parent; | ||
358 | |||
359 | while (*link) { | ||
360 | rb_parent = *link; | ||
361 | parent = rb_entry(rb_parent, struct interval_tree_node, rb); | ||
362 | if (parent->__subtree_last < last) | ||
363 | parent->__subtree_last = last; | ||
364 | if (start < parent->start) | ||
365 | link = &parent->rb.rb_left; | ||
366 | else | ||
367 | link = &parent->rb.rb_right; | ||
249 | } | 368 | } |
250 | return lowest_match; | 369 | |
370 | node->__subtree_last = last; | ||
371 | rb_link_node(&node->rb, rb_parent, link); | ||
372 | rb_insert_augmented(&node->rb, root, &augment_callbacks); | ||
251 | } | 373 | } |
252 | 374 | ||
253 | Finding exact match will be to first find lowest match and then to follow | 375 | void interval_tree_remove(struct interval_tree_node *node, |
254 | successor nodes looking for exact match, until the start of a node is beyond | 376 | struct rb_root *root) |
255 | the hi value we are looking for. | 377 | { |
378 | rb_erase_augmented(&node->rb, root, &augment_callbacks); | ||
379 | } | ||