1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27#ifndef _TOOLS_LINUX_RBTREE_AUGMENTED_H
28#define _TOOLS_LINUX_RBTREE_AUGMENTED_H
29
30#include <linux/compiler.h>
31#include <linux/rbtree.h>
32
33
34
35
36
37
38
39
40
41struct rb_augment_callbacks {
42 void (*propagate)(struct rb_node *node, struct rb_node *stop);
43 void (*copy)(struct rb_node *old, struct rb_node *new);
44 void (*rotate)(struct rb_node *old, struct rb_node *new);
45};
46
47extern void __rb_insert_augmented(struct rb_node *node, struct rb_root *root,
48 void (*augment_rotate)(struct rb_node *old, struct rb_node *new));
49
50
51
52
53
54
55
56
57
58
59
60static inline void
61rb_insert_augmented(struct rb_node *node, struct rb_root *root,
62 const struct rb_augment_callbacks *augment)
63{
64 __rb_insert_augmented(node, root, augment->rotate);
65}
66
67static inline void
68rb_insert_augmented_cached(struct rb_node *node,
69 struct rb_root_cached *root, bool newleft,
70 const struct rb_augment_callbacks *augment)
71{
72 if (newleft)
73 root->rb_leftmost = node;
74 rb_insert_augmented(node, &root->rb_root, augment);
75}
76
77
78
79
80
81
82
83
84
85
86
87
88#define RB_DECLARE_CALLBACKS(RBSTATIC, RBNAME, \
89 RBSTRUCT, RBFIELD, RBAUGMENTED, RBCOMPUTE) \
90static inline void \
91RBNAME ## _propagate(struct rb_node *rb, struct rb_node *stop) \
92{ \
93 while (rb != stop) { \
94 RBSTRUCT *node = rb_entry(rb, RBSTRUCT, RBFIELD); \
95 if (RBCOMPUTE(node, true)) \
96 break; \
97 rb = rb_parent(&node->RBFIELD); \
98 } \
99} \
100static inline void \
101RBNAME ## _copy(struct rb_node *rb_old, struct rb_node *rb_new) \
102{ \
103 RBSTRUCT *old = rb_entry(rb_old, RBSTRUCT, RBFIELD); \
104 RBSTRUCT *new = rb_entry(rb_new, RBSTRUCT, RBFIELD); \
105 new->RBAUGMENTED = old->RBAUGMENTED; \
106} \
107static void \
108RBNAME ## _rotate(struct rb_node *rb_old, struct rb_node *rb_new) \
109{ \
110 RBSTRUCT *old = rb_entry(rb_old, RBSTRUCT, RBFIELD); \
111 RBSTRUCT *new = rb_entry(rb_new, RBSTRUCT, RBFIELD); \
112 new->RBAUGMENTED = old->RBAUGMENTED; \
113 RBCOMPUTE(old, false); \
114} \
115RBSTATIC const struct rb_augment_callbacks RBNAME = { \
116 .propagate = RBNAME ## _propagate, \
117 .copy = RBNAME ## _copy, \
118 .rotate = RBNAME ## _rotate \
119};
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134#define RB_DECLARE_CALLBACKS_MAX(RBSTATIC, RBNAME, RBSTRUCT, RBFIELD, \
135 RBTYPE, RBAUGMENTED, RBCOMPUTE) \
136static inline bool RBNAME ## _compute_max(RBSTRUCT *node, bool exit) \
137{ \
138 RBSTRUCT *child; \
139 RBTYPE max = RBCOMPUTE(node); \
140 if (node->RBFIELD.rb_left) { \
141 child = rb_entry(node->RBFIELD.rb_left, RBSTRUCT, RBFIELD); \
142 if (child->RBAUGMENTED > max) \
143 max = child->RBAUGMENTED; \
144 } \
145 if (node->RBFIELD.rb_right) { \
146 child = rb_entry(node->RBFIELD.rb_right, RBSTRUCT, RBFIELD); \
147 if (child->RBAUGMENTED > max) \
148 max = child->RBAUGMENTED; \
149 } \
150 if (exit && node->RBAUGMENTED == max) \
151 return true; \
152 node->RBAUGMENTED = max; \
153 return false; \
154} \
155RB_DECLARE_CALLBACKS(RBSTATIC, RBNAME, \
156 RBSTRUCT, RBFIELD, RBAUGMENTED, RBNAME ## _compute_max)
157
158
159#define RB_RED 0
160#define RB_BLACK 1
161
162#define __rb_parent(pc) ((struct rb_node *)(pc & ~3))
163
164#define __rb_color(pc) ((pc) & 1)
165#define __rb_is_black(pc) __rb_color(pc)
166#define __rb_is_red(pc) (!__rb_color(pc))
167#define rb_color(rb) __rb_color((rb)->__rb_parent_color)
168#define rb_is_red(rb) __rb_is_red((rb)->__rb_parent_color)
169#define rb_is_black(rb) __rb_is_black((rb)->__rb_parent_color)
170
171static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p)
172{
173 rb->__rb_parent_color = rb_color(rb) | (unsigned long)p;
174}
175
176static inline void rb_set_parent_color(struct rb_node *rb,
177 struct rb_node *p, int color)
178{
179 rb->__rb_parent_color = (unsigned long)p | color;
180}
181
182static inline void
183__rb_change_child(struct rb_node *old, struct rb_node *new,
184 struct rb_node *parent, struct rb_root *root)
185{
186 if (parent) {
187 if (parent->rb_left == old)
188 WRITE_ONCE(parent->rb_left, new);
189 else
190 WRITE_ONCE(parent->rb_right, new);
191 } else
192 WRITE_ONCE(root->rb_node, new);
193}
194
195extern void __rb_erase_color(struct rb_node *parent, struct rb_root *root,
196 void (*augment_rotate)(struct rb_node *old, struct rb_node *new));
197
198static __always_inline struct rb_node *
199__rb_erase_augmented(struct rb_node *node, struct rb_root *root,
200 const struct rb_augment_callbacks *augment)
201{
202 struct rb_node *child = node->rb_right;
203 struct rb_node *tmp = node->rb_left;
204 struct rb_node *parent, *rebalance;
205 unsigned long pc;
206
207 if (!tmp) {
208
209
210
211
212
213
214
215 pc = node->__rb_parent_color;
216 parent = __rb_parent(pc);
217 __rb_change_child(node, child, parent, root);
218 if (child) {
219 child->__rb_parent_color = pc;
220 rebalance = NULL;
221 } else
222 rebalance = __rb_is_black(pc) ? parent : NULL;
223 tmp = parent;
224 } else if (!child) {
225
226 tmp->__rb_parent_color = pc = node->__rb_parent_color;
227 parent = __rb_parent(pc);
228 __rb_change_child(node, tmp, parent, root);
229 rebalance = NULL;
230 tmp = parent;
231 } else {
232 struct rb_node *successor = child, *child2;
233
234 tmp = child->rb_left;
235 if (!tmp) {
236
237
238
239
240
241
242
243
244
245 parent = successor;
246 child2 = successor->rb_right;
247
248 augment->copy(node, successor);
249 } else {
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264 do {
265 parent = successor;
266 successor = tmp;
267 tmp = tmp->rb_left;
268 } while (tmp);
269 child2 = successor->rb_right;
270 WRITE_ONCE(parent->rb_left, child2);
271 WRITE_ONCE(successor->rb_right, child);
272 rb_set_parent(child, successor);
273
274 augment->copy(node, successor);
275 augment->propagate(parent, successor);
276 }
277
278 tmp = node->rb_left;
279 WRITE_ONCE(successor->rb_left, tmp);
280 rb_set_parent(tmp, successor);
281
282 pc = node->__rb_parent_color;
283 tmp = __rb_parent(pc);
284 __rb_change_child(node, successor, tmp, root);
285
286 if (child2) {
287 successor->__rb_parent_color = pc;
288 rb_set_parent_color(child2, parent, RB_BLACK);
289 rebalance = NULL;
290 } else {
291 unsigned long pc2 = successor->__rb_parent_color;
292 successor->__rb_parent_color = pc;
293 rebalance = __rb_is_black(pc2) ? parent : NULL;
294 }
295 tmp = successor;
296 }
297
298 augment->propagate(tmp, NULL);
299 return rebalance;
300}
301
302static __always_inline void
303rb_erase_augmented(struct rb_node *node, struct rb_root *root,
304 const struct rb_augment_callbacks *augment)
305{
306 struct rb_node *rebalance = __rb_erase_augmented(node, root, augment);
307 if (rebalance)
308 __rb_erase_color(rebalance, root, augment->rotate);
309}
310
311static __always_inline void
312rb_erase_augmented_cached(struct rb_node *node, struct rb_root_cached *root,
313 const struct rb_augment_callbacks *augment)
314{
315 if (root->rb_leftmost == node)
316 root->rb_leftmost = rb_next(node);
317 rb_erase_augmented(node, &root->rb_root, augment);
318}
319
320#endif
321