blob: 6fd540b1e4990153981225813044a7c53deb81d7 [file] [log] [blame]
Michel Lespinassefff3fd82012-10-08 16:31:23 -07001#include <linux/init.h>
2#include <linux/interval_tree.h>
3
4/* Callbacks for augmented rbtree insert and remove */
5
6static inline unsigned long
7compute_subtree_last(struct interval_tree_node *node)
8{
9 unsigned long max = node->last, subtree_last;
10 if (node->rb.rb_left) {
11 subtree_last = rb_entry(node->rb.rb_left,
12 struct interval_tree_node, rb)->__subtree_last;
13 if (max < subtree_last)
14 max = subtree_last;
15 }
16 if (node->rb.rb_right) {
17 subtree_last = rb_entry(node->rb.rb_right,
18 struct interval_tree_node, rb)->__subtree_last;
19 if (max < subtree_last)
20 max = subtree_last;
21 }
22 return max;
23}
24
25RB_DECLARE_CALLBACKS(static, augment_callbacks, struct interval_tree_node, rb,
26 unsigned long, __subtree_last, compute_subtree_last)
27
28/* Insert / remove interval nodes from the tree */
29
30void interval_tree_insert(struct interval_tree_node *node,
31 struct rb_root *root)
32{
33 struct rb_node **link = &root->rb_node, *rb_parent = NULL;
34 unsigned long start = node->start, last = node->last;
35 struct interval_tree_node *parent;
36
37 while (*link) {
38 rb_parent = *link;
39 parent = rb_entry(rb_parent, struct interval_tree_node, rb);
40 if (parent->__subtree_last < last)
41 parent->__subtree_last = last;
42 if (start < parent->start)
43 link = &parent->rb.rb_left;
44 else
45 link = &parent->rb.rb_right;
46 }
47
48 node->__subtree_last = last;
49 rb_link_node(&node->rb, rb_parent, link);
50 rb_insert_augmented(&node->rb, root, &augment_callbacks);
51}
52
53void interval_tree_remove(struct interval_tree_node *node,
54 struct rb_root *root)
55{
56 rb_erase_augmented(&node->rb, root, &augment_callbacks);
57}
58
59/*
60 * Iterate over intervals intersecting [start;last]
61 *
62 * Note that a node's interval intersects [start;last] iff:
63 * Cond1: node->start <= last
64 * and
65 * Cond2: start <= node->last
66 */
67
68static struct interval_tree_node *
69subtree_search(struct interval_tree_node *node,
70 unsigned long start, unsigned long last)
71{
72 while (true) {
73 /*
74 * Loop invariant: start <= node->__subtree_last
75 * (Cond2 is satisfied by one of the subtree nodes)
76 */
77 if (node->rb.rb_left) {
78 struct interval_tree_node *left =
79 rb_entry(node->rb.rb_left,
80 struct interval_tree_node, rb);
81 if (start <= left->__subtree_last) {
82 /*
83 * Some nodes in left subtree satisfy Cond2.
84 * Iterate to find the leftmost such node N.
85 * If it also satisfies Cond1, that's the match
86 * we are looking for. Otherwise, there is no
87 * matching interval as nodes to the right of N
88 * can't satisfy Cond1 either.
89 */
90 node = left;
91 continue;
92 }
93 }
94 if (node->start <= last) { /* Cond1 */
95 if (start <= node->last) /* Cond2 */
96 return node; /* node is leftmost match */
97 if (node->rb.rb_right) {
98 node = rb_entry(node->rb.rb_right,
99 struct interval_tree_node, rb);
100 if (start <= node->__subtree_last)
101 continue;
102 }
103 }
104 return NULL; /* No match */
105 }
106}
107
108struct interval_tree_node *
109interval_tree_iter_first(struct rb_root *root,
110 unsigned long start, unsigned long last)
111{
112 struct interval_tree_node *node;
113
114 if (!root->rb_node)
115 return NULL;
116 node = rb_entry(root->rb_node, struct interval_tree_node, rb);
117 if (node->__subtree_last < start)
118 return NULL;
119 return subtree_search(node, start, last);
120}
121
122struct interval_tree_node *
123interval_tree_iter_next(struct interval_tree_node *node,
124 unsigned long start, unsigned long last)
125{
126 struct rb_node *rb = node->rb.rb_right, *prev;
127
128 while (true) {
129 /*
130 * Loop invariants:
131 * Cond1: node->start <= last
132 * rb == node->rb.rb_right
133 *
134 * First, search right subtree if suitable
135 */
136 if (rb) {
137 struct interval_tree_node *right =
138 rb_entry(rb, struct interval_tree_node, rb);
139 if (start <= right->__subtree_last)
140 return subtree_search(right, start, last);
141 }
142
143 /* Move up the tree until we come from a node's left child */
144 do {
145 rb = rb_parent(&node->rb);
146 if (!rb)
147 return NULL;
148 prev = &node->rb;
149 node = rb_entry(rb, struct interval_tree_node, rb);
150 rb = node->rb.rb_right;
151 } while (prev == rb);
152
153 /* Check if the node intersects [start;last] */
154 if (last < node->start) /* !Cond1 */
155 return NULL;
156 else if (start <= node->last) /* Cond2 */
157 return node;
158 }
159}