1 /* SPDX-License-Identifier: GPL-2.0-or-later * 1 2 /* 3 Red Black Trees 4 (C) 1999 Andrea Arcangeli <andrea@suse.de> 5 (C) 2002 David Woodhouse <dwmw2@infradead.o 6 (C) 2012 Michel Lespinasse <walken@google.c 7 8 9 linux/include/linux/rbtree_augmented.h 10 */ 11 12 #ifndef _LINUX_RBTREE_AUGMENTED_H 13 #define _LINUX_RBTREE_AUGMENTED_H 14 15 #include <linux/compiler.h> 16 #include <linux/rbtree.h> 17 #include <linux/rcupdate.h> 18 19 /* 20 * Please note - only struct rb_augment_callba 21 * rb_insert_augmented() and rb_erase_augmente 22 * The rest are implementation details you are 23 * 24 * See Documentation/core-api/rbtree.rst for d 25 */ 26 27 struct rb_augment_callbacks { 28 void (*propagate)(struct rb_node *node 29 void (*copy)(struct rb_node *old, stru 30 void (*rotate)(struct rb_node *old, st 31 }; 32 33 extern void __rb_insert_augmented(struct rb_no 34 void (*augment_rotate)(struct rb_node 35 36 /* 37 * Fixup the rbtree and update the augmented i 38 * 39 * On insertion, the user must update the augm 40 * leading to the inserted node, then call rb_ 41 * rb_insert_augmented() instead of the usual 42 * If rb_insert_augmented() rebalances the rbt 43 * a user provided function to update the augm 44 * affected subtrees. 45 */ 46 static inline void 47 rb_insert_augmented(struct rb_node *node, stru 48 const struct rb_augment_ca 49 { 50 __rb_insert_augmented(node, root, augm 51 } 52 53 static inline void 54 rb_insert_augmented_cached(struct rb_node *nod 55 struct rb_root_cach 56 const struct rb_aug 57 { 58 if (newleft) 59 root->rb_leftmost = node; 60 rb_insert_augmented(node, &root->rb_ro 61 } 62 63 static __always_inline struct rb_node * 64 rb_add_augmented_cached(struct rb_node *node, 65 bool (*less)(struct rb 66 const struct rb_augmen 67 { 68 struct rb_node **link = &tree->rb_root 69 struct rb_node *parent = NULL; 70 bool leftmost = true; 71 72 while (*link) { 73 parent = *link; 74 if (less(node, parent)) { 75 link = &parent->rb_lef 76 } else { 77 link = &parent->rb_rig 78 leftmost = false; 79 } 80 } 81 82 rb_link_node(node, parent, link); 83 augment->propagate(parent, NULL); /* s 84 rb_insert_augmented_cached(node, tree, 85 86 return leftmost ? node : NULL; 87 } 88 89 /* 90 * Template for declaring augmented rbtree cal 91 * 92 * RBSTATIC: 'static' or empty 93 * RBNAME: name of the rb_augment_callbac 94 * RBSTRUCT: struct type of the tree nodes 95 * RBFIELD: name of struct rb_node field w 96 * RBAUGMENTED: name of field within RBSTRUCT 97 * RBCOMPUTE: name of function that recomput 98 */ 99 100 #define RB_DECLARE_CALLBACKS(RBSTATIC, RBNAME, 101 RBSTRUCT, RBFIELD 102 static inline void 103 RBNAME ## _propagate(struct rb_node *rb, struc 104 { 105 while (rb != stop) { 106 RBSTRUCT *node = rb_entry(rb, 107 if (RBCOMPUTE(node, true)) 108 break; 109 rb = rb_parent(&node->RBFIELD) 110 } 111 } 112 static inline void 113 RBNAME ## _copy(struct rb_node *rb_old, struct 114 { 115 RBSTRUCT *old = rb_entry(rb_old, RBSTR 116 RBSTRUCT *new = rb_entry(rb_new, RBSTR 117 new->RBAUGMENTED = old->RBAUGMENTED; 118 } 119 static void 120 RBNAME ## _rotate(struct rb_node *rb_old, stru 121 { 122 RBSTRUCT *old = rb_entry(rb_old, RBSTR 123 RBSTRUCT *new = rb_entry(rb_new, RBSTR 124 new->RBAUGMENTED = old->RBAUGMENTED; 125 RBCOMPUTE(old, false); 126 } 127 RBSTATIC const struct rb_augment_callbacks RBN 128 .propagate = RBNAME ## _propagate, 129 .copy = RBNAME ## _copy, 130 .rotate = RBNAME ## _rotate 131 }; 132 133 /* 134 * Template for declaring augmented rbtree cal 135 * computing RBAUGMENTED scalar as max(RBCOMPU 136 * 137 * RBSTATIC: 'static' or empty 138 * RBNAME: name of the rb_augment_callbac 139 * RBSTRUCT: struct type of the tree nodes 140 * RBFIELD: name of struct rb_node field w 141 * RBTYPE: type of the RBAUGMENTED field 142 * RBAUGMENTED: name of RBTYPE field within RB 143 * RBCOMPUTE: name of function that returns 144 */ 145 146 #define RB_DECLARE_CALLBACKS_MAX(RBSTATIC, RBN 147 RBTYPE, RBAUG 148 static inline bool RBNAME ## _compute_max(RBST 149 { 150 RBSTRUCT *child; 151 RBTYPE max = RBCOMPUTE(node); 152 if (node->RBFIELD.rb_left) { 153 child = rb_entry(node->RBFIELD 154 if (child->RBAUGMENTED > max) 155 max = child->RBAUGMENT 156 } 157 if (node->RBFIELD.rb_right) { 158 child = rb_entry(node->RBFIELD 159 if (child->RBAUGMENTED > max) 160 max = child->RBAUGMENT 161 } 162 if (exit && node->RBAUGMENTED == max) 163 return true; 164 node->RBAUGMENTED = max; 165 return false; 166 } 167 RB_DECLARE_CALLBACKS(RBSTATIC, RBNAME, 168 RBSTRUCT, RBFIELD, RBAUGM 169 170 171 #define RB_RED 0 172 #define RB_BLACK 1 173 174 #define __rb_parent(pc) ((struct rb_node *) 175 176 #define __rb_color(pc) ((pc) & 1) 177 #define __rb_is_black(pc) __rb_color(pc) 178 #define __rb_is_red(pc) (!__rb_color(pc)) 179 #define rb_color(rb) __rb_color((rb)->__ 180 #define rb_is_red(rb) __rb_is_red((rb)->_ 181 #define rb_is_black(rb) __rb_is_black((rb)- 182 183 static inline void rb_set_parent(struct rb_nod 184 { 185 rb->__rb_parent_color = rb_color(rb) + 186 } 187 188 static inline void rb_set_parent_color(struct 189 struct 190 { 191 rb->__rb_parent_color = (unsigned long 192 } 193 194 static inline void 195 __rb_change_child(struct rb_node *old, struct 196 struct rb_node *parent, stru 197 { 198 if (parent) { 199 if (parent->rb_left == old) 200 WRITE_ONCE(parent->rb_ 201 else 202 WRITE_ONCE(parent->rb_ 203 } else 204 WRITE_ONCE(root->rb_node, new) 205 } 206 207 static inline void 208 __rb_change_child_rcu(struct rb_node *old, str 209 struct rb_node *parent, 210 { 211 if (parent) { 212 if (parent->rb_left == old) 213 rcu_assign_pointer(par 214 else 215 rcu_assign_pointer(par 216 } else 217 rcu_assign_pointer(root->rb_no 218 } 219 220 extern void __rb_erase_color(struct rb_node *p 221 void (*augment_rotate)(struct rb_node 222 223 static __always_inline struct rb_node * 224 __rb_erase_augmented(struct rb_node *node, str 225 const struct rb_augment_c 226 { 227 struct rb_node *child = node->rb_right 228 struct rb_node *tmp = node->rb_left; 229 struct rb_node *parent, *rebalance; 230 unsigned long pc; 231 232 if (!tmp) { 233 /* 234 * Case 1: node to erase has n 235 * 236 * Note that if there is one c 237 * and node must be black due 238 * so as to bypass __rb_erase_ 239 */ 240 pc = node->__rb_parent_color; 241 parent = __rb_parent(pc); 242 __rb_change_child(node, child, 243 if (child) { 244 child->__rb_parent_col 245 rebalance = NULL; 246 } else 247 rebalance = __rb_is_bl 248 tmp = parent; 249 } else if (!child) { 250 /* Still case 1, but this time 251 tmp->__rb_parent_color = pc = 252 parent = __rb_parent(pc); 253 __rb_change_child(node, tmp, p 254 rebalance = NULL; 255 tmp = parent; 256 } else { 257 struct rb_node *successor = ch 258 259 tmp = child->rb_left; 260 if (!tmp) { 261 /* 262 * Case 2: node's succ 263 * 264 * (n) (s) 265 * / \ / \ 266 * (x) (s) -> (x) ( 267 * \ 268 * (c) 269 */ 270 parent = successor; 271 child2 = successor->rb 272 273 augment->copy(node, su 274 } else { 275 /* 276 * Case 3: node's succ 277 * node's right child 278 * 279 * (n) (s) 280 * / \ / \ 281 * (x) (y) -> (x) ( 282 * / / 283 * (p) (p) 284 * / / 285 * (s) (c) 286 * \ 287 * (c) 288 */ 289 do { 290 parent = succe 291 successor = tm 292 tmp = tmp->rb_ 293 } while (tmp); 294 child2 = successor->rb 295 WRITE_ONCE(parent->rb_ 296 WRITE_ONCE(successor-> 297 rb_set_parent(child, s 298 299 augment->copy(node, su 300 augment->propagate(par 301 } 302 303 tmp = node->rb_left; 304 WRITE_ONCE(successor->rb_left, 305 rb_set_parent(tmp, successor); 306 307 pc = node->__rb_parent_color; 308 tmp = __rb_parent(pc); 309 __rb_change_child(node, succes 310 311 if (child2) { 312 rb_set_parent_color(ch 313 rebalance = NULL; 314 } else { 315 rebalance = rb_is_blac 316 } 317 successor->__rb_parent_color = 318 tmp = successor; 319 } 320 321 augment->propagate(tmp, NULL); 322 return rebalance; 323 } 324 325 static __always_inline void 326 rb_erase_augmented(struct rb_node *node, struc 327 const struct rb_augment_cal 328 { 329 struct rb_node *rebalance = __rb_erase 330 if (rebalance) 331 __rb_erase_color(rebalance, ro 332 } 333 334 static __always_inline void 335 rb_erase_augmented_cached(struct rb_node *node 336 const struct rb_augm 337 { 338 if (root->rb_leftmost == node) 339 root->rb_leftmost = rb_next(no 340 rb_erase_augmented(node, &root->rb_roo 341 } 342 343 #endif /* _LINUX_RBTREE_AUGMENTED_H */ 344
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.