#include #include /* Callbacks for augmented rbtree insert and remove */ static inline unsigned long compute_subtree_last(struct interval_tree_node *node) { unsigned long max = node->last, subtree_last; if (node->rb.rb_left) { subtree_last = rb_entry(node->rb.rb_left, struct interval_tree_node, rb)->__subtree_last; if (max < subtree_last) max = subtree_last; } if (node->rb.rb_right) { subtree_last = rb_entry(node->rb.rb_right, struct interval_tree_node, rb)->__subtree_last; if (max < subtree_last) max = subtree_last; } return max; } RB_DECLARE_CALLBACKS(static, augment_callbacks, struct interval_tree_node, rb, unsigned long, __subtree_last, compute_subtree_last) /* Insert / remove interval nodes from the tree */ void interval_tree_insert(struct interval_tree_node *node, struct rb_root *root) { struct rb_node **link = &root->rb_node, *rb_parent = NULL; unsigned long start = node->start, last = node->last; struct interval_tree_node *parent; while (*link) { rb_parent = *link; parent = rb_entry(rb_parent, struct interval_tree_node, rb); if (parent->__subtree_last < last) parent->__subtree_last = last; if (start < parent->start) link = &parent->rb.rb_left; else link = &parent->rb.rb_right; } node->__subtree_last = last; rb_link_node(&node->rb, rb_parent, link); rb_insert_augmented(&node->rb, root, &augment_callbacks); } void interval_tree_remove(struct interval_tree_node *node, struct rb_root *root) { rb_erase_augmented(&node->rb, root, &augment_callbacks); } /* * Iterate over intervals intersecting [start;last] * * Note that a node's interval intersects [start;last] iff: * Cond1: node->start <= last * and * Cond2: start <= node->last */ static struct interval_tree_node * subtree_search(struct interval_tree_node *node, unsigned long start, unsigned long last) { while (true) { /* * Loop invariant: start <= node->__subtree_last * (Cond2 is satisfied by one of the subtree nodes) */ if (node->rb.rb_left) { struct interval_tree_node *left = rb_entry(node->rb.rb_left, struct interval_tree_node, rb); if (start <= left->__subtree_last) { /* * Some nodes in left subtree satisfy Cond2. * Iterate to find the leftmost such node N. * If it also satisfies Cond1, that's the match * we are looking for. Otherwise, there is no * matching interval as nodes to the right of N * can't satisfy Cond1 either. */ node = left; continue; } } if (node->start <= last) { /* Cond1 */ if (start <= node->last) /* Cond2 */ return node; /* node is leftmost match */ if (node->rb.rb_right) { node = rb_entry(node->rb.rb_right, struct interval_tree_node, rb); if (start <= node->__subtree_last) continue; } } return NULL; /* No match */ } } struct interval_tree_node * interval_tree_iter_first(struct rb_root *root, unsigned long start, unsigned long last) { struct interval_tree_node *node; if (!root->rb_node) return NULL; node = rb_entry(root->rb_node, struct interval_tree_node, rb); if (node->__subtree_last < start) return NULL; return subtree_search(node, start, last); } struct interval_tree_node * interval_tree_iter_next(struct interval_tree_node *node, unsigned long start, unsigned long last) { struct rb_node *rb = node->rb.rb_right, *prev; while (true) { /* * Loop invariants: * Cond1: node->start <= last * rb == node->rb.rb_right * * First, search right subtree if suitable */ if (rb) { struct interval_tree_node *right = rb_entry(rb, struct interval_tree_node, rb); if (start <= right->__subtree_last) return subtree_search(right, start, last); } /* Move up the tree until we come from a node's left child */ do { rb = rb_parent(&node->rb); if (!rb) return NULL; prev = &node->rb; node = rb_entry(rb, struct interval_tree_node, rb); rb = node->rb.rb_right; } while (prev == rb); /* Check if the node intersects [start;last] */ if (last < node->start) /* !Cond1 */ return NULL; else if (start <= node->last) /* Cond2 */ return node; } }