1 1.1.1.2 christos #ifndef JEMALLOC_INTERNAL_RB_H 2 1.1.1.2 christos #define JEMALLOC_INTERNAL_RB_H 3 1.1.1.2 christos 4 1.1.1.3 christos #include "jemalloc/internal/jemalloc_preamble.h" 5 1.1.1.3 christos #include "jemalloc/internal/safety_check.h" 6 1.1.1.3 christos 7 1.1 christos /*- 8 1.1 christos ******************************************************************************* 9 1.1 christos * 10 1.1 christos * cpp macro implementation of left-leaning 2-3 red-black trees. Parent 11 1.1 christos * pointers are not used, and color bits are stored in the least significant 12 1.1 christos * bit of right-child pointers (if RB_COMPACT is defined), thus making node 13 1.1 christos * linkage as compact as is possible for red-black trees. 14 1.1 christos * 15 1.1 christos * Usage: 16 1.1 christos * 17 1.1 christos * #include <stdint.h> 18 1.1 christos * #include <stdbool.h> 19 1.1 christos * #define NDEBUG // (Optional, see assert(3).) 20 1.1 christos * #include <assert.h> 21 1.1 christos * #define RB_COMPACT // (Optional, embed color bits in right-child pointers.) 22 1.1 christos * #include <rb.h> 23 1.1 christos * ... 24 1.1 christos * 25 1.1 christos ******************************************************************************* 26 1.1 christos */ 27 1.1 christos 28 1.1 christos #ifndef __PGI 29 1.1.1.3 christos # define RB_COMPACT 30 1.1 christos #endif 31 1.1 christos 32 1.1.1.2 christos /* 33 1.1.1.2 christos * Each node in the RB tree consumes at least 1 byte of space (for the linkage 34 1.1.1.2 christos * if nothing else, so there are a maximum of sizeof(void *) << 3 rb tree nodes 35 1.1.1.2 christos * in any process (and thus, at most sizeof(void *) << 3 nodes in any rb tree). 36 1.1.1.2 christos * The choice of algorithm bounds the depth of a tree to twice the binary log of 37 1.1.1.2 christos * the number of elements in the tree; the following bound follows. 38 1.1.1.2 christos */ 39 1.1.1.2 christos #define RB_MAX_DEPTH (sizeof(void *) << 4) 40 1.1.1.2 christos 41 1.1.1.3 christos /* clang-format off */ 42 1.1 christos #ifdef RB_COMPACT 43 1.1 christos /* Node structure. */ 44 1.1 christos #define rb_node(a_type) \ 45 1.1 christos struct { \ 46 1.1 christos a_type *rbn_left; \ 47 1.1 christos a_type *rbn_right_red; \ 48 1.1 christos } 49 1.1 christos #else 50 1.1 christos #define rb_node(a_type) \ 51 1.1 christos struct { \ 52 1.1 christos a_type *rbn_left; \ 53 1.1 christos a_type *rbn_right; \ 54 1.1 christos bool rbn_red; \ 55 1.1 christos } 56 1.1 christos #endif 57 1.1 christos 58 1.1 christos /* Root structure. */ 59 1.1 christos #define rb_tree(a_type) \ 60 1.1 christos struct { \ 61 1.1 christos a_type *rbt_root; \ 62 1.1 christos } 63 1.1 christos 64 1.1 christos /* Left accessors. */ 65 1.1 christos #define rbtn_left_get(a_type, a_field, a_node) \ 66 1.1 christos ((a_node)->a_field.rbn_left) 67 1.1 christos #define rbtn_left_set(a_type, a_field, a_node, a_left) do { \ 68 1.1 christos (a_node)->a_field.rbn_left = a_left; \ 69 1.1 christos } while (0) 70 1.1 christos 71 1.1 christos #ifdef RB_COMPACT 72 1.1 christos /* Right accessors. */ 73 1.1 christos #define rbtn_right_get(a_type, a_field, a_node) \ 74 1.1 christos ((a_type *) (((intptr_t) (a_node)->a_field.rbn_right_red) \ 75 1.1 christos & ((ssize_t)-2))) 76 1.1 christos #define rbtn_right_set(a_type, a_field, a_node, a_right) do { \ 77 1.1 christos (a_node)->a_field.rbn_right_red = (a_type *) (((uintptr_t) a_right) \ 78 1.1 christos | (((uintptr_t) (a_node)->a_field.rbn_right_red) & ((size_t)1))); \ 79 1.1 christos } while (0) 80 1.1 christos 81 1.1 christos /* Color accessors. */ 82 1.1 christos #define rbtn_red_get(a_type, a_field, a_node) \ 83 1.1 christos ((bool) (((uintptr_t) (a_node)->a_field.rbn_right_red) \ 84 1.1 christos & ((size_t)1))) 85 1.1 christos #define rbtn_color_set(a_type, a_field, a_node, a_red) do { \ 86 1.1 christos (a_node)->a_field.rbn_right_red = (a_type *) ((((intptr_t) \ 87 1.1 christos (a_node)->a_field.rbn_right_red) & ((ssize_t)-2)) \ 88 1.1 christos | ((ssize_t)a_red)); \ 89 1.1 christos } while (0) 90 1.1 christos #define rbtn_red_set(a_type, a_field, a_node) do { \ 91 1.1 christos (a_node)->a_field.rbn_right_red = (a_type *) (((uintptr_t) \ 92 1.1 christos (a_node)->a_field.rbn_right_red) | ((size_t)1)); \ 93 1.1 christos } while (0) 94 1.1 christos #define rbtn_black_set(a_type, a_field, a_node) do { \ 95 1.1 christos (a_node)->a_field.rbn_right_red = (a_type *) (((intptr_t) \ 96 1.1 christos (a_node)->a_field.rbn_right_red) & ((ssize_t)-2)); \ 97 1.1 christos } while (0) 98 1.1 christos 99 1.1 christos /* Node initializer. */ 100 1.1 christos #define rbt_node_new(a_type, a_field, a_rbt, a_node) do { \ 101 1.1 christos /* Bookkeeping bit cannot be used by node pointer. */ \ 102 1.1 christos assert(((uintptr_t)(a_node) & 0x1) == 0); \ 103 1.1 christos rbtn_left_set(a_type, a_field, (a_node), NULL); \ 104 1.1 christos rbtn_right_set(a_type, a_field, (a_node), NULL); \ 105 1.1 christos rbtn_red_set(a_type, a_field, (a_node)); \ 106 1.1 christos } while (0) 107 1.1 christos #else 108 1.1 christos /* Right accessors. */ 109 1.1 christos #define rbtn_right_get(a_type, a_field, a_node) \ 110 1.1 christos ((a_node)->a_field.rbn_right) 111 1.1 christos #define rbtn_right_set(a_type, a_field, a_node, a_right) do { \ 112 1.1 christos (a_node)->a_field.rbn_right = a_right; \ 113 1.1 christos } while (0) 114 1.1 christos 115 1.1 christos /* Color accessors. */ 116 1.1 christos #define rbtn_red_get(a_type, a_field, a_node) \ 117 1.1 christos ((a_node)->a_field.rbn_red) 118 1.1 christos #define rbtn_color_set(a_type, a_field, a_node, a_red) do { \ 119 1.1 christos (a_node)->a_field.rbn_red = (a_red); \ 120 1.1 christos } while (0) 121 1.1 christos #define rbtn_red_set(a_type, a_field, a_node) do { \ 122 1.1 christos (a_node)->a_field.rbn_red = true; \ 123 1.1 christos } while (0) 124 1.1 christos #define rbtn_black_set(a_type, a_field, a_node) do { \ 125 1.1 christos (a_node)->a_field.rbn_red = false; \ 126 1.1 christos } while (0) 127 1.1 christos 128 1.1 christos /* Node initializer. */ 129 1.1 christos #define rbt_node_new(a_type, a_field, a_rbt, a_node) do { \ 130 1.1 christos rbtn_left_set(a_type, a_field, (a_node), NULL); \ 131 1.1 christos rbtn_right_set(a_type, a_field, (a_node), NULL); \ 132 1.1 christos rbtn_red_set(a_type, a_field, (a_node)); \ 133 1.1 christos } while (0) 134 1.1 christos #endif 135 1.1 christos 136 1.1 christos /* Tree initializer. */ 137 1.1 christos #define rb_new(a_type, a_field, a_rbt) do { \ 138 1.1 christos (a_rbt)->rbt_root = NULL; \ 139 1.1 christos } while (0) 140 1.1 christos 141 1.1 christos /* Internal utility macros. */ 142 1.1 christos #define rbtn_first(a_type, a_field, a_rbt, a_root, r_node) do { \ 143 1.1 christos (r_node) = (a_root); \ 144 1.1 christos if ((r_node) != NULL) { \ 145 1.1 christos for (; \ 146 1.1 christos rbtn_left_get(a_type, a_field, (r_node)) != NULL; \ 147 1.1 christos (r_node) = rbtn_left_get(a_type, a_field, (r_node))) { \ 148 1.1 christos } \ 149 1.1 christos } \ 150 1.1 christos } while (0) 151 1.1 christos 152 1.1 christos #define rbtn_last(a_type, a_field, a_rbt, a_root, r_node) do { \ 153 1.1 christos (r_node) = (a_root); \ 154 1.1 christos if ((r_node) != NULL) { \ 155 1.1 christos for (; rbtn_right_get(a_type, a_field, (r_node)) != NULL; \ 156 1.1 christos (r_node) = rbtn_right_get(a_type, a_field, (r_node))) { \ 157 1.1 christos } \ 158 1.1 christos } \ 159 1.1 christos } while (0) 160 1.1 christos 161 1.1 christos #define rbtn_rotate_left(a_type, a_field, a_node, r_node) do { \ 162 1.1 christos (r_node) = rbtn_right_get(a_type, a_field, (a_node)); \ 163 1.1 christos rbtn_right_set(a_type, a_field, (a_node), \ 164 1.1 christos rbtn_left_get(a_type, a_field, (r_node))); \ 165 1.1 christos rbtn_left_set(a_type, a_field, (r_node), (a_node)); \ 166 1.1 christos } while (0) 167 1.1 christos 168 1.1 christos #define rbtn_rotate_right(a_type, a_field, a_node, r_node) do { \ 169 1.1 christos (r_node) = rbtn_left_get(a_type, a_field, (a_node)); \ 170 1.1 christos rbtn_left_set(a_type, a_field, (a_node), \ 171 1.1 christos rbtn_right_get(a_type, a_field, (r_node))); \ 172 1.1 christos rbtn_right_set(a_type, a_field, (r_node), (a_node)); \ 173 1.1 christos } while (0) 174 1.1 christos 175 1.1.1.2 christos #define rb_summarized_only_false(...) 176 1.1.1.2 christos #define rb_summarized_only_true(...) __VA_ARGS__ 177 1.1.1.2 christos #define rb_empty_summarize(a_node, a_lchild, a_rchild) false 178 1.1.1.2 christos 179 1.1 christos /* 180 1.1.1.2 christos * The rb_proto() and rb_summarized_proto() macros generate function prototypes 181 1.1.1.2 christos * that correspond to the functions generated by an equivalently parameterized 182 1.1.1.2 christos * call to rb_gen() or rb_summarized_gen(), respectively. 183 1.1 christos */ 184 1.1 christos 185 1.1 christos #define rb_proto(a_attr, a_prefix, a_rbt_type, a_type) \ 186 1.1.1.2 christos rb_proto_impl(a_attr, a_prefix, a_rbt_type, a_type, false) 187 1.1.1.2 christos #define rb_summarized_proto(a_attr, a_prefix, a_rbt_type, a_type) \ 188 1.1.1.2 christos rb_proto_impl(a_attr, a_prefix, a_rbt_type, a_type, true) 189 1.1.1.2 christos #define rb_proto_impl(a_attr, a_prefix, a_rbt_type, a_type, \ 190 1.1.1.2 christos a_is_summarized) \ 191 1.1 christos a_attr void \ 192 1.1 christos a_prefix##new(a_rbt_type *rbtree); \ 193 1.1 christos a_attr bool \ 194 1.1 christos a_prefix##empty(a_rbt_type *rbtree); \ 195 1.1 christos a_attr a_type * \ 196 1.1 christos a_prefix##first(a_rbt_type *rbtree); \ 197 1.1 christos a_attr a_type * \ 198 1.1 christos a_prefix##last(a_rbt_type *rbtree); \ 199 1.1 christos a_attr a_type * \ 200 1.1 christos a_prefix##next(a_rbt_type *rbtree, a_type *node); \ 201 1.1 christos a_attr a_type * \ 202 1.1 christos a_prefix##prev(a_rbt_type *rbtree, a_type *node); \ 203 1.1 christos a_attr a_type * \ 204 1.1 christos a_prefix##search(a_rbt_type *rbtree, const a_type *key); \ 205 1.1 christos a_attr a_type * \ 206 1.1 christos a_prefix##nsearch(a_rbt_type *rbtree, const a_type *key); \ 207 1.1 christos a_attr a_type * \ 208 1.1 christos a_prefix##psearch(a_rbt_type *rbtree, const a_type *key); \ 209 1.1 christos a_attr void \ 210 1.1 christos a_prefix##insert(a_rbt_type *rbtree, a_type *node); \ 211 1.1 christos a_attr void \ 212 1.1 christos a_prefix##remove(a_rbt_type *rbtree, a_type *node); \ 213 1.1 christos a_attr a_type * \ 214 1.1 christos a_prefix##iter(a_rbt_type *rbtree, a_type *start, a_type *(*cb)( \ 215 1.1 christos a_rbt_type *, a_type *, void *), void *arg); \ 216 1.1 christos a_attr a_type * \ 217 1.1 christos a_prefix##reverse_iter(a_rbt_type *rbtree, a_type *start, \ 218 1.1 christos a_type *(*cb)(a_rbt_type *, a_type *, void *), void *arg); \ 219 1.1 christos a_attr void \ 220 1.1 christos a_prefix##destroy(a_rbt_type *rbtree, void (*cb)(a_type *, void *), \ 221 1.1.1.2 christos void *arg); \ 222 1.1.1.2 christos /* Extended API */ \ 223 1.1.1.2 christos rb_summarized_only_##a_is_summarized( \ 224 1.1.1.2 christos a_attr void \ 225 1.1.1.2 christos a_prefix##update_summaries(a_rbt_type *rbtree, a_type *node); \ 226 1.1.1.2 christos a_attr bool \ 227 1.1.1.2 christos a_prefix##empty_filtered(a_rbt_type *rbtree, \ 228 1.1.1.2 christos bool (*filter_node)(void *, a_type *), \ 229 1.1.1.2 christos bool (*filter_subtree)(void *, a_type *), \ 230 1.1.1.2 christos void *filter_ctx); \ 231 1.1.1.2 christos a_attr a_type * \ 232 1.1.1.2 christos a_prefix##first_filtered(a_rbt_type *rbtree, \ 233 1.1.1.2 christos bool (*filter_node)(void *, a_type *), \ 234 1.1.1.2 christos bool (*filter_subtree)(void *, a_type *), \ 235 1.1.1.2 christos void *filter_ctx); \ 236 1.1.1.2 christos a_attr a_type * \ 237 1.1.1.2 christos a_prefix##last_filtered(a_rbt_type *rbtree, \ 238 1.1.1.2 christos bool (*filter_node)(void *, a_type *), \ 239 1.1.1.2 christos bool (*filter_subtree)(void *, a_type *), \ 240 1.1.1.2 christos void *filter_ctx); \ 241 1.1.1.2 christos a_attr a_type * \ 242 1.1.1.2 christos a_prefix##next_filtered(a_rbt_type *rbtree, a_type *node, \ 243 1.1.1.2 christos bool (*filter_node)(void *, a_type *), \ 244 1.1.1.2 christos bool (*filter_subtree)(void *, a_type *), \ 245 1.1.1.2 christos void *filter_ctx); \ 246 1.1.1.2 christos a_attr a_type * \ 247 1.1.1.2 christos a_prefix##prev_filtered(a_rbt_type *rbtree, a_type *node, \ 248 1.1.1.2 christos bool (*filter_node)(void *, a_type *), \ 249 1.1.1.2 christos bool (*filter_subtree)(void *, a_type *), \ 250 1.1.1.2 christos void *filter_ctx); \ 251 1.1.1.2 christos a_attr a_type * \ 252 1.1.1.2 christos a_prefix##search_filtered(a_rbt_type *rbtree, const a_type *key, \ 253 1.1.1.2 christos bool (*filter_node)(void *, a_type *), \ 254 1.1.1.2 christos bool (*filter_subtree)(void *, a_type *), \ 255 1.1.1.2 christos void *filter_ctx); \ 256 1.1.1.2 christos a_attr a_type * \ 257 1.1.1.2 christos a_prefix##nsearch_filtered(a_rbt_type *rbtree, const a_type *key, \ 258 1.1.1.2 christos bool (*filter_node)(void *, a_type *), \ 259 1.1.1.2 christos bool (*filter_subtree)(void *, a_type *), \ 260 1.1.1.2 christos void *filter_ctx); \ 261 1.1.1.2 christos a_attr a_type * \ 262 1.1.1.2 christos a_prefix##psearch_filtered(a_rbt_type *rbtree, const a_type *key, \ 263 1.1.1.2 christos bool (*filter_node)(void *, a_type *), \ 264 1.1.1.2 christos bool (*filter_subtree)(void *, a_type *), \ 265 1.1.1.2 christos void *filter_ctx); \ 266 1.1.1.2 christos a_attr a_type * \ 267 1.1.1.2 christos a_prefix##iter_filtered(a_rbt_type *rbtree, a_type *start, \ 268 1.1.1.2 christos a_type *(*cb)(a_rbt_type *, a_type *, void *), void *arg, \ 269 1.1.1.2 christos bool (*filter_node)(void *, a_type *), \ 270 1.1.1.2 christos bool (*filter_subtree)(void *, a_type *), \ 271 1.1.1.2 christos void *filter_ctx); \ 272 1.1.1.2 christos a_attr a_type * \ 273 1.1.1.2 christos a_prefix##reverse_iter_filtered(a_rbt_type *rbtree, a_type *start, \ 274 1.1.1.2 christos a_type *(*cb)(a_rbt_type *, a_type *, void *), void *arg, \ 275 1.1.1.2 christos bool (*filter_node)(void *, a_type *), \ 276 1.1.1.2 christos bool (*filter_subtree)(void *, a_type *), \ 277 1.1.1.2 christos void *filter_ctx); \ 278 1.1.1.2 christos ) 279 1.1 christos 280 1.1 christos /* 281 1.1 christos * The rb_gen() macro generates a type-specific red-black tree implementation, 282 1.1 christos * based on the above cpp macros. 283 1.1 christos * Arguments: 284 1.1 christos * 285 1.1.1.2 christos * a_attr: 286 1.1.1.2 christos * Function attribute for generated functions (ex: static). 287 1.1.1.2 christos * a_prefix: 288 1.1.1.2 christos * Prefix for generated functions (ex: ex_). 289 1.1.1.2 christos * a_rb_type: 290 1.1.1.2 christos * Type for red-black tree data structure (ex: ex_t). 291 1.1.1.2 christos * a_type: 292 1.1.1.2 christos * Type for red-black tree node data structure (ex: ex_node_t). 293 1.1.1.2 christos * a_field: 294 1.1.1.2 christos * Name of red-black tree node linkage (ex: ex_link). 295 1.1.1.2 christos * a_cmp: 296 1.1.1.2 christos * Node comparison function name, with the following prototype: 297 1.1.1.2 christos * 298 1.1.1.2 christos * int a_cmp(a_type *a_node, a_type *a_other); 299 1.1.1.2 christos * ^^^^^^ 300 1.1.1.2 christos * or a_key 301 1.1.1.2 christos * Interpretation of comparison function return values: 302 1.1.1.2 christos * -1 : a_node < a_other 303 1.1.1.2 christos * 0 : a_node == a_other 304 1.1.1.2 christos * 1 : a_node > a_other 305 1.1.1.2 christos * In all cases, the a_node or a_key macro argument is the first argument to 306 1.1.1.2 christos * the comparison function, which makes it possible to write comparison 307 1.1.1.2 christos * functions that treat the first argument specially. a_cmp must be a total 308 1.1.1.2 christos * order on values inserted into the tree -- duplicates are not allowed. 309 1.1 christos * 310 1.1 christos * Assuming the following setup: 311 1.1 christos * 312 1.1 christos * typedef struct ex_node_s ex_node_t; 313 1.1 christos * struct ex_node_s { 314 1.1 christos * rb_node(ex_node_t) ex_link; 315 1.1 christos * }; 316 1.1 christos * typedef rb_tree(ex_node_t) ex_t; 317 1.1 christos * rb_gen(static, ex_, ex_t, ex_node_t, ex_link, ex_cmp) 318 1.1 christos * 319 1.1 christos * The following API is generated: 320 1.1 christos * 321 1.1 christos * static void 322 1.1 christos * ex_new(ex_t *tree); 323 1.1 christos * Description: Initialize a red-black tree structure. 324 1.1 christos * Args: 325 1.1 christos * tree: Pointer to an uninitialized red-black tree object. 326 1.1 christos * 327 1.1 christos * static bool 328 1.1 christos * ex_empty(ex_t *tree); 329 1.1 christos * Description: Determine whether tree is empty. 330 1.1 christos * Args: 331 1.1 christos * tree: Pointer to an initialized red-black tree object. 332 1.1 christos * Ret: True if tree is empty, false otherwise. 333 1.1 christos * 334 1.1 christos * static ex_node_t * 335 1.1 christos * ex_first(ex_t *tree); 336 1.1 christos * static ex_node_t * 337 1.1 christos * ex_last(ex_t *tree); 338 1.1 christos * Description: Get the first/last node in tree. 339 1.1 christos * Args: 340 1.1 christos * tree: Pointer to an initialized red-black tree object. 341 1.1 christos * Ret: First/last node in tree, or NULL if tree is empty. 342 1.1 christos * 343 1.1 christos * static ex_node_t * 344 1.1 christos * ex_next(ex_t *tree, ex_node_t *node); 345 1.1 christos * static ex_node_t * 346 1.1 christos * ex_prev(ex_t *tree, ex_node_t *node); 347 1.1 christos * Description: Get node's successor/predecessor. 348 1.1 christos * Args: 349 1.1 christos * tree: Pointer to an initialized red-black tree object. 350 1.1 christos * node: A node in tree. 351 1.1 christos * Ret: node's successor/predecessor in tree, or NULL if node is 352 1.1 christos * last/first. 353 1.1 christos * 354 1.1 christos * static ex_node_t * 355 1.1 christos * ex_search(ex_t *tree, const ex_node_t *key); 356 1.1 christos * Description: Search for node that matches key. 357 1.1 christos * Args: 358 1.1 christos * tree: Pointer to an initialized red-black tree object. 359 1.1 christos * key : Search key. 360 1.1 christos * Ret: Node in tree that matches key, or NULL if no match. 361 1.1 christos * 362 1.1 christos * static ex_node_t * 363 1.1 christos * ex_nsearch(ex_t *tree, const ex_node_t *key); 364 1.1 christos * static ex_node_t * 365 1.1 christos * ex_psearch(ex_t *tree, const ex_node_t *key); 366 1.1 christos * Description: Search for node that matches key. If no match is found, 367 1.1 christos * return what would be key's successor/predecessor, were 368 1.1 christos * key in tree. 369 1.1 christos * Args: 370 1.1 christos * tree: Pointer to an initialized red-black tree object. 371 1.1 christos * key : Search key. 372 1.1 christos * Ret: Node in tree that matches key, or if no match, hypothetical node's 373 1.1 christos * successor/predecessor (NULL if no successor/predecessor). 374 1.1 christos * 375 1.1 christos * static void 376 1.1 christos * ex_insert(ex_t *tree, ex_node_t *node); 377 1.1 christos * Description: Insert node into tree. 378 1.1 christos * Args: 379 1.1 christos * tree: Pointer to an initialized red-black tree object. 380 1.1 christos * node: Node to be inserted into tree. 381 1.1 christos * 382 1.1 christos * static void 383 1.1 christos * ex_remove(ex_t *tree, ex_node_t *node); 384 1.1 christos * Description: Remove node from tree. 385 1.1 christos * Args: 386 1.1 christos * tree: Pointer to an initialized red-black tree object. 387 1.1 christos * node: Node in tree to be removed. 388 1.1 christos * 389 1.1 christos * static ex_node_t * 390 1.1 christos * ex_iter(ex_t *tree, ex_node_t *start, ex_node_t *(*cb)(ex_t *, 391 1.1 christos * ex_node_t *, void *), void *arg); 392 1.1 christos * static ex_node_t * 393 1.1 christos * ex_reverse_iter(ex_t *tree, ex_node_t *start, ex_node *(*cb)(ex_t *, 394 1.1 christos * ex_node_t *, void *), void *arg); 395 1.1 christos * Description: Iterate forward/backward over tree, starting at node. If 396 1.1 christos * tree is modified, iteration must be immediately 397 1.1 christos * terminated by the callback function that causes the 398 1.1 christos * modification. 399 1.1 christos * Args: 400 1.1 christos * tree : Pointer to an initialized red-black tree object. 401 1.1 christos * start: Node at which to start iteration, or NULL to start at 402 1.1 christos * first/last node. 403 1.1 christos * cb : Callback function, which is called for each node during 404 1.1 christos * iteration. Under normal circumstances the callback function 405 1.1 christos * should return NULL, which causes iteration to continue. If a 406 1.1 christos * callback function returns non-NULL, iteration is immediately 407 1.1 christos * terminated and the non-NULL return value is returned by the 408 1.1 christos * iterator. This is useful for re-starting iteration after 409 1.1 christos * modifying tree. 410 1.1 christos * arg : Opaque pointer passed to cb(). 411 1.1 christos * Ret: NULL if iteration completed, or the non-NULL callback return value 412 1.1 christos * that caused termination of the iteration. 413 1.1 christos * 414 1.1 christos * static void 415 1.1 christos * ex_destroy(ex_t *tree, void (*cb)(ex_node_t *, void *), void *arg); 416 1.1 christos * Description: Iterate over the tree with post-order traversal, remove 417 1.1 christos * each node, and run the callback if non-null. This is 418 1.1 christos * used for destroying a tree without paying the cost to 419 1.1 christos * rebalance it. The tree must not be otherwise altered 420 1.1 christos * during traversal. 421 1.1 christos * Args: 422 1.1 christos * tree: Pointer to an initialized red-black tree object. 423 1.1 christos * cb : Callback function, which, if non-null, is called for each node 424 1.1 christos * during iteration. There is no way to stop iteration once it 425 1.1 christos * has begun. 426 1.1 christos * arg : Opaque pointer passed to cb(). 427 1.1.1.2 christos * 428 1.1.1.2 christos * The rb_summarized_gen() macro generates all the functions above, but has an 429 1.1.1.2 christos * expanded interface. In introduces the notion of summarizing subtrees, and of 430 1.1.1.2 christos * filtering searches in the tree according to the information contained in 431 1.1.1.2 christos * those summaries. 432 1.1.1.2 christos * The extra macro argument is: 433 1.1.1.2 christos * a_summarize: 434 1.1.1.2 christos * Tree summarization function name, with the following prototype: 435 1.1.1.2 christos * 436 1.1.1.2 christos * bool a_summarize(a_type *a_node, const a_type *a_left_child, 437 1.1.1.2 christos * const a_type *a_right_child); 438 1.1.1.2 christos * 439 1.1.1.2 christos * This function should update a_node with the summary of the subtree rooted 440 1.1.1.2 christos * there, using the data contained in it and the summaries in a_left_child 441 1.1.1.2 christos * and a_right_child. One or both of them may be NULL. When the tree 442 1.1.1.2 christos * changes due to an insertion or removal, it updates the summaries of all 443 1.1.1.2 christos * nodes whose subtrees have changed (always updating the summaries of 444 1.1.1.2 christos * children before their parents). If the user alters a node in the tree in 445 1.1.1.2 christos * a way that may change its summary, they can call the generated 446 1.1.1.2 christos * update_summaries function to bubble up the summary changes to the root. 447 1.1.1.2 christos * It should return true if the summary changed (or may have changed), and 448 1.1.1.2 christos * false if it didn't (which will allow the implementation to terminate 449 1.1.1.2 christos * "bubbling up" the summaries early). 450 1.1.1.2 christos * As the parameter names indicate, the children are ordered as they are in 451 1.1.1.2 christos * the tree, a_left_child, if it is not NULL, compares less than a_node, 452 1.1.1.2 christos * which in turn compares less than a_right_child (if a_right_child is not 453 1.1.1.2 christos * NULL). 454 1.1.1.2 christos * 455 1.1.1.2 christos * Using the same setup as above but replacing the macro with 456 1.1.1.2 christos * rb_summarized_gen(static, ex_, ex_t, ex_node_t, ex_link, ex_cmp, 457 1.1.1.2 christos * ex_summarize) 458 1.1.1.2 christos * 459 1.1.1.2 christos * Generates all the previous functions, but adds some more: 460 1.1.1.2 christos * 461 1.1.1.2 christos * static void 462 1.1.1.2 christos * ex_update_summaries(ex_t *tree, ex_node_t *node); 463 1.1.1.2 christos * Description: Recompute all summaries of ancestors of node. 464 1.1.1.2 christos * Args: 465 1.1.1.2 christos * tree: Pointer to an initialized red-black tree object. 466 1.1.1.2 christos * node: The element of the tree whose summary may have changed. 467 1.1.1.2 christos * 468 1.1.1.2 christos * For each of ex_empty, ex_first, ex_last, ex_next, ex_prev, ex_search, 469 1.1.1.2 christos * ex_nsearch, ex_psearch, ex_iter, and ex_reverse_iter, an additional function 470 1.1.1.2 christos * is generated as well, with the suffix _filtered (e.g. ex_empty_filtered, 471 1.1.1.2 christos * ex_first_filtered, etc.). These use the concept of a "filter"; a binary 472 1.1.1.2 christos * property some node either satisfies or does not satisfy. Clever use of the 473 1.1.1.2 christos * a_summary argument to rb_summarized_gen can allow efficient computation of 474 1.1.1.2 christos * these predicates across whole subtrees of the tree. 475 1.1.1.2 christos * The extended API functions accept three additional arguments after the 476 1.1.1.2 christos * arguments to the corresponding non-extended equivalent. 477 1.1.1.2 christos * 478 1.1.1.2 christos * ex_fn(..., bool (*filter_node)(void *, ex_node_t *), 479 1.1.1.2 christos * bool (*filter_subtree)(void *, ex_node_t *), void *filter_ctx); 480 1.1.1.2 christos * filter_node : Returns true if the node passes the filter. 481 1.1.1.2 christos * filter_subtree : Returns true if some node in the subtree rooted at 482 1.1.1.2 christos * node passes the filter. 483 1.1.1.2 christos * filter_ctx : A context argument passed to the filters. 484 1.1.1.2 christos * 485 1.1.1.2 christos * For a more concrete example of summarizing and filtering, suppose we're using 486 1.1.1.2 christos * the red-black tree to track a set of integers: 487 1.1.1.2 christos * 488 1.1.1.2 christos * struct ex_node_s { 489 1.1.1.2 christos * rb_node(ex_node_t) ex_link; 490 1.1.1.2 christos * unsigned data; 491 1.1.1.2 christos * }; 492 1.1.1.2 christos * 493 1.1.1.2 christos * Suppose, for some application-specific reason, we want to be able to quickly 494 1.1.1.2 christos * find numbers in the set which are divisible by large powers of 2 (say, for 495 1.1.1.2 christos * aligned allocation purposes). We augment the node with a summary field: 496 1.1.1.2 christos * 497 1.1.1.2 christos * struct ex_node_s { 498 1.1.1.2 christos * rb_node(ex_node_t) ex_link; 499 1.1.1.2 christos * unsigned data; 500 1.1.1.2 christos * unsigned max_subtree_ffs; 501 1.1.1.2 christos * } 502 1.1.1.2 christos * 503 1.1.1.2 christos * and define our summarization function as follows: 504 1.1.1.2 christos * 505 1.1.1.2 christos * bool 506 1.1.1.2 christos * ex_summarize(ex_node_t *node, const ex_node_t *lchild, 507 1.1.1.2 christos * const ex_node_t *rchild) { 508 1.1.1.2 christos * unsigned new_max_subtree_ffs = ffs(node->data); 509 1.1.1.2 christos * if (lchild != NULL && lchild->max_subtree_ffs > new_max_subtree_ffs) { 510 1.1.1.2 christos * new_max_subtree_ffs = lchild->max_subtree_ffs; 511 1.1.1.2 christos * } 512 1.1.1.2 christos * if (rchild != NULL && rchild->max_subtree_ffs > new_max_subtree_ffs) { 513 1.1.1.2 christos * new_max_subtree_ffs = rchild->max_subtree_ffs; 514 1.1.1.2 christos * } 515 1.1.1.2 christos * bool changed = (node->max_subtree_ffs != new_max_subtree_ffs) 516 1.1.1.2 christos * node->max_subtree_ffs = new_max_subtree_ffs; 517 1.1.1.2 christos * // This could be "return true" without any correctness or big-O 518 1.1.1.2 christos * // performance changes; but practically, precisely reporting summary 519 1.1.1.2 christos * // changes reduces the amount of work that has to be done when "bubbling 520 1.1.1.2 christos * // up" summary changes. 521 1.1.1.2 christos * return changed; 522 1.1.1.2 christos * } 523 1.1.1.2 christos * 524 1.1.1.2 christos * We can now implement our filter functions as follows: 525 1.1.1.2 christos * bool 526 1.1.1.2 christos * ex_filter_node(void *filter_ctx, ex_node_t *node) { 527 1.1.1.2 christos * unsigned required_ffs = *(unsigned *)filter_ctx; 528 1.1.1.2 christos * return ffs(node->data) >= required_ffs; 529 1.1.1.2 christos * } 530 1.1.1.2 christos * bool 531 1.1.1.2 christos * ex_filter_subtree(void *filter_ctx, ex_node_t *node) { 532 1.1.1.2 christos * unsigned required_ffs = *(unsigned *)filter_ctx; 533 1.1.1.2 christos * return node->max_subtree_ffs >= required_ffs; 534 1.1.1.2 christos * } 535 1.1.1.2 christos * 536 1.1.1.2 christos * We can now easily search for, e.g., the smallest integer in the set that's 537 1.1.1.2 christos * divisible by 128: 538 1.1.1.2 christos * ex_node_t * 539 1.1.1.2 christos * find_div_128(ex_tree_t *tree) { 540 1.1.1.2 christos * unsigned min_ffs = 7; 541 1.1.1.2 christos * return ex_first_filtered(tree, &ex_filter_node, &ex_filter_subtree, 542 1.1.1.2 christos * &min_ffs); 543 1.1.1.2 christos * } 544 1.1.1.2 christos * 545 1.1.1.2 christos * We could with similar ease: 546 1.1.1.2 christos * - Fnd the next multiple of 128 in the set that's larger than 12345 (with 547 1.1.1.2 christos * ex_nsearch_filtered) 548 1.1.1.2 christos * - Iterate over just those multiples of 64 that are in the set (with 549 1.1.1.2 christos * ex_iter_filtered) 550 1.1.1.2 christos * - Determine if the set contains any multiples of 1024 (with 551 1.1.1.2 christos * ex_empty_filtered). 552 1.1.1.2 christos * 553 1.1.1.2 christos * Some possibly subtle API notes: 554 1.1.1.2 christos * - The node argument to ex_next_filtered and ex_prev_filtered need not pass 555 1.1.1.2 christos * the filter; it will find the next/prev node that passes the filter. 556 1.1.1.2 christos * - ex_search_filtered will fail even for a node in the tree, if that node does 557 1.1.1.2 christos * not pass the filter. ex_psearch_filtered and ex_nsearch_filtered behave 558 1.1.1.2 christos * similarly; they may return a node larger/smaller than the key, even if a 559 1.1.1.2 christos * node equivalent to the key is in the tree (but does not pass the filter). 560 1.1.1.2 christos * - Similarly, if the start argument to a filtered iteration function does not 561 1.1.1.2 christos * pass the filter, the callback won't be invoked on it. 562 1.1.1.2 christos * 563 1.1.1.2 christos * These should make sense after a moment's reflection; each post-condition is 564 1.1.1.2 christos * the same as with the unfiltered version, with the added constraint that the 565 1.1.1.2 christos * returned node must pass the filter. 566 1.1 christos */ 567 1.1.1.3 christos JEMALLOC_ALWAYS_INLINE void 568 1.1.1.3 christos rb_remove_safety_checks(const void *nodep, const char *function_name) { 569 1.1.1.3 christos if (!config_opt_safety_checks) { 570 1.1.1.3 christos return; 571 1.1.1.3 christos } 572 1.1.1.3 christos if (unlikely(nodep == NULL)) { 573 1.1.1.3 christos safety_check_fail( 574 1.1.1.3 christos "<jemalloc>: Invalid deallocation detected in %s: " 575 1.1.1.3 christos "attempting to remove node from tree but node was " 576 1.1.1.3 christos "not found. Possibly caused by double free bugs.", 577 1.1.1.3 christos function_name); 578 1.1.1.3 christos } 579 1.1.1.3 christos } 580 1.1.1.3 christos 581 1.1 christos #define rb_gen(a_attr, a_prefix, a_rbt_type, a_type, a_field, a_cmp) \ 582 1.1.1.2 christos rb_gen_impl(a_attr, a_prefix, a_rbt_type, a_type, a_field, a_cmp, \ 583 1.1.1.2 christos rb_empty_summarize, false) 584 1.1.1.2 christos #define rb_summarized_gen(a_attr, a_prefix, a_rbt_type, a_type, \ 585 1.1.1.2 christos a_field, a_cmp, a_summarize) \ 586 1.1.1.2 christos rb_gen_impl(a_attr, a_prefix, a_rbt_type, a_type, a_field, a_cmp, \ 587 1.1.1.2 christos a_summarize, true) 588 1.1.1.2 christos 589 1.1.1.2 christos #define rb_gen_impl(a_attr, a_prefix, a_rbt_type, a_type, \ 590 1.1.1.2 christos a_field, a_cmp, a_summarize, a_is_summarized) \ 591 1.1.1.2 christos typedef struct { \ 592 1.1.1.2 christos a_type *node; \ 593 1.1.1.2 christos int cmp; \ 594 1.1.1.2 christos } a_prefix##path_entry_t; \ 595 1.1.1.2 christos static inline void \ 596 1.1.1.2 christos a_prefix##summarize_range(a_prefix##path_entry_t *rfirst, \ 597 1.1.1.2 christos a_prefix##path_entry_t *rlast) { \ 598 1.1.1.2 christos while ((uintptr_t)rlast >= (uintptr_t)rfirst) { \ 599 1.1.1.2 christos a_type *node = rlast->node; \ 600 1.1.1.2 christos /* Avoid a warning when a_summarize is rb_empty_summarize. */ \ 601 1.1.1.2 christos (void)node; \ 602 1.1.1.2 christos bool changed = a_summarize(node, rbtn_left_get(a_type, a_field, \ 603 1.1.1.2 christos node), rbtn_right_get(a_type, a_field, node)); \ 604 1.1.1.2 christos if (!changed) { \ 605 1.1.1.2 christos break; \ 606 1.1.1.2 christos } \ 607 1.1.1.2 christos rlast--; \ 608 1.1.1.2 christos } \ 609 1.1.1.2 christos } \ 610 1.1.1.2 christos /* On the remove pathways, we sometimes swap the node being removed */\ 611 1.1.1.2 christos /* and its first successor; in such cases we need to do two range */\ 612 1.1.1.2 christos /* updates; one from the node to its (former) swapped successor, the */\ 613 1.1.1.2 christos /* next from that successor to the root (with either allowed to */\ 614 1.1.1.2 christos /* bail out early if appropriate. */\ 615 1.1.1.2 christos static inline void \ 616 1.1.1.2 christos a_prefix##summarize_swapped_range(a_prefix##path_entry_t *rfirst, \ 617 1.1.1.2 christos a_prefix##path_entry_t *rlast, a_prefix##path_entry_t *swap_loc) { \ 618 1.1.1.2 christos if (swap_loc == NULL || rlast <= swap_loc) { \ 619 1.1.1.2 christos a_prefix##summarize_range(rfirst, rlast); \ 620 1.1.1.2 christos } else { \ 621 1.1.1.2 christos a_prefix##summarize_range(swap_loc + 1, rlast); \ 622 1.1.1.2 christos (void)a_summarize(swap_loc->node, \ 623 1.1.1.2 christos rbtn_left_get(a_type, a_field, swap_loc->node), \ 624 1.1.1.2 christos rbtn_right_get(a_type, a_field, swap_loc->node)); \ 625 1.1.1.2 christos a_prefix##summarize_range(rfirst, swap_loc - 1); \ 626 1.1.1.2 christos } \ 627 1.1.1.2 christos } \ 628 1.1 christos a_attr void \ 629 1.1 christos a_prefix##new(a_rbt_type *rbtree) { \ 630 1.1 christos rb_new(a_type, a_field, rbtree); \ 631 1.1 christos } \ 632 1.1 christos a_attr bool \ 633 1.1 christos a_prefix##empty(a_rbt_type *rbtree) { \ 634 1.1 christos return (rbtree->rbt_root == NULL); \ 635 1.1 christos } \ 636 1.1 christos a_attr a_type * \ 637 1.1 christos a_prefix##first(a_rbt_type *rbtree) { \ 638 1.1 christos a_type *ret; \ 639 1.1 christos rbtn_first(a_type, a_field, rbtree, rbtree->rbt_root, ret); \ 640 1.1 christos return ret; \ 641 1.1 christos } \ 642 1.1 christos a_attr a_type * \ 643 1.1 christos a_prefix##last(a_rbt_type *rbtree) { \ 644 1.1 christos a_type *ret; \ 645 1.1 christos rbtn_last(a_type, a_field, rbtree, rbtree->rbt_root, ret); \ 646 1.1 christos return ret; \ 647 1.1 christos } \ 648 1.1 christos a_attr a_type * \ 649 1.1 christos a_prefix##next(a_rbt_type *rbtree, a_type *node) { \ 650 1.1 christos a_type *ret; \ 651 1.1 christos if (rbtn_right_get(a_type, a_field, node) != NULL) { \ 652 1.1 christos rbtn_first(a_type, a_field, rbtree, rbtn_right_get(a_type, \ 653 1.1 christos a_field, node), ret); \ 654 1.1 christos } else { \ 655 1.1 christos a_type *tnode = rbtree->rbt_root; \ 656 1.1 christos assert(tnode != NULL); \ 657 1.1 christos ret = NULL; \ 658 1.1 christos while (true) { \ 659 1.1 christos int cmp = (a_cmp)(node, tnode); \ 660 1.1 christos if (cmp < 0) { \ 661 1.1 christos ret = tnode; \ 662 1.1 christos tnode = rbtn_left_get(a_type, a_field, tnode); \ 663 1.1 christos } else if (cmp > 0) { \ 664 1.1 christos tnode = rbtn_right_get(a_type, a_field, tnode); \ 665 1.1 christos } else { \ 666 1.1 christos break; \ 667 1.1 christos } \ 668 1.1 christos assert(tnode != NULL); \ 669 1.1 christos } \ 670 1.1 christos } \ 671 1.1 christos return ret; \ 672 1.1 christos } \ 673 1.1 christos a_attr a_type * \ 674 1.1 christos a_prefix##prev(a_rbt_type *rbtree, a_type *node) { \ 675 1.1 christos a_type *ret; \ 676 1.1 christos if (rbtn_left_get(a_type, a_field, node) != NULL) { \ 677 1.1 christos rbtn_last(a_type, a_field, rbtree, rbtn_left_get(a_type, \ 678 1.1 christos a_field, node), ret); \ 679 1.1 christos } else { \ 680 1.1 christos a_type *tnode = rbtree->rbt_root; \ 681 1.1 christos assert(tnode != NULL); \ 682 1.1 christos ret = NULL; \ 683 1.1 christos while (true) { \ 684 1.1 christos int cmp = (a_cmp)(node, tnode); \ 685 1.1 christos if (cmp < 0) { \ 686 1.1 christos tnode = rbtn_left_get(a_type, a_field, tnode); \ 687 1.1 christos } else if (cmp > 0) { \ 688 1.1 christos ret = tnode; \ 689 1.1 christos tnode = rbtn_right_get(a_type, a_field, tnode); \ 690 1.1 christos } else { \ 691 1.1 christos break; \ 692 1.1 christos } \ 693 1.1 christos assert(tnode != NULL); \ 694 1.1 christos } \ 695 1.1 christos } \ 696 1.1 christos return ret; \ 697 1.1 christos } \ 698 1.1 christos a_attr a_type * \ 699 1.1 christos a_prefix##search(a_rbt_type *rbtree, const a_type *key) { \ 700 1.1 christos a_type *ret; \ 701 1.1 christos int cmp; \ 702 1.1 christos ret = rbtree->rbt_root; \ 703 1.1 christos while (ret != NULL \ 704 1.1 christos && (cmp = (a_cmp)(key, ret)) != 0) { \ 705 1.1 christos if (cmp < 0) { \ 706 1.1 christos ret = rbtn_left_get(a_type, a_field, ret); \ 707 1.1 christos } else { \ 708 1.1 christos ret = rbtn_right_get(a_type, a_field, ret); \ 709 1.1 christos } \ 710 1.1 christos } \ 711 1.1 christos return ret; \ 712 1.1 christos } \ 713 1.1 christos a_attr a_type * \ 714 1.1 christos a_prefix##nsearch(a_rbt_type *rbtree, const a_type *key) { \ 715 1.1 christos a_type *ret; \ 716 1.1 christos a_type *tnode = rbtree->rbt_root; \ 717 1.1 christos ret = NULL; \ 718 1.1 christos while (tnode != NULL) { \ 719 1.1 christos int cmp = (a_cmp)(key, tnode); \ 720 1.1 christos if (cmp < 0) { \ 721 1.1 christos ret = tnode; \ 722 1.1 christos tnode = rbtn_left_get(a_type, a_field, tnode); \ 723 1.1 christos } else if (cmp > 0) { \ 724 1.1 christos tnode = rbtn_right_get(a_type, a_field, tnode); \ 725 1.1 christos } else { \ 726 1.1 christos ret = tnode; \ 727 1.1 christos break; \ 728 1.1 christos } \ 729 1.1 christos } \ 730 1.1 christos return ret; \ 731 1.1 christos } \ 732 1.1 christos a_attr a_type * \ 733 1.1 christos a_prefix##psearch(a_rbt_type *rbtree, const a_type *key) { \ 734 1.1 christos a_type *ret; \ 735 1.1 christos a_type *tnode = rbtree->rbt_root; \ 736 1.1 christos ret = NULL; \ 737 1.1 christos while (tnode != NULL) { \ 738 1.1 christos int cmp = (a_cmp)(key, tnode); \ 739 1.1 christos if (cmp < 0) { \ 740 1.1 christos tnode = rbtn_left_get(a_type, a_field, tnode); \ 741 1.1 christos } else if (cmp > 0) { \ 742 1.1 christos ret = tnode; \ 743 1.1 christos tnode = rbtn_right_get(a_type, a_field, tnode); \ 744 1.1 christos } else { \ 745 1.1 christos ret = tnode; \ 746 1.1 christos break; \ 747 1.1 christos } \ 748 1.1 christos } \ 749 1.1 christos return ret; \ 750 1.1 christos } \ 751 1.1 christos a_attr void \ 752 1.1 christos a_prefix##insert(a_rbt_type *rbtree, a_type *node) { \ 753 1.1.1.2 christos a_prefix##path_entry_t path[RB_MAX_DEPTH]; \ 754 1.1.1.2 christos a_prefix##path_entry_t *pathp; \ 755 1.1 christos rbt_node_new(a_type, a_field, rbtree, node); \ 756 1.1 christos /* Wind. */ \ 757 1.1 christos path->node = rbtree->rbt_root; \ 758 1.1 christos for (pathp = path; pathp->node != NULL; pathp++) { \ 759 1.1 christos int cmp = pathp->cmp = a_cmp(node, pathp->node); \ 760 1.1 christos assert(cmp != 0); \ 761 1.1 christos if (cmp < 0) { \ 762 1.1 christos pathp[1].node = rbtn_left_get(a_type, a_field, \ 763 1.1 christos pathp->node); \ 764 1.1 christos } else { \ 765 1.1 christos pathp[1].node = rbtn_right_get(a_type, a_field, \ 766 1.1 christos pathp->node); \ 767 1.1 christos } \ 768 1.1 christos } \ 769 1.1 christos pathp->node = node; \ 770 1.1.1.2 christos /* A loop invariant we maintain is that all nodes with */\ 771 1.1.1.2 christos /* out-of-date summaries live in path[0], path[1], ..., *pathp. */\ 772 1.1.1.2 christos /* To maintain this, we have to summarize node, since we */\ 773 1.1.1.2 christos /* decrement pathp before the first iteration. */\ 774 1.1.1.2 christos assert(rbtn_left_get(a_type, a_field, node) == NULL); \ 775 1.1.1.2 christos assert(rbtn_right_get(a_type, a_field, node) == NULL); \ 776 1.1.1.2 christos (void)a_summarize(node, NULL, NULL); \ 777 1.1 christos /* Unwind. */ \ 778 1.1 christos for (pathp--; (uintptr_t)pathp >= (uintptr_t)path; pathp--) { \ 779 1.1 christos a_type *cnode = pathp->node; \ 780 1.1 christos if (pathp->cmp < 0) { \ 781 1.1 christos a_type *left = pathp[1].node; \ 782 1.1 christos rbtn_left_set(a_type, a_field, cnode, left); \ 783 1.1 christos if (rbtn_red_get(a_type, a_field, left)) { \ 784 1.1 christos a_type *leftleft = rbtn_left_get(a_type, a_field, left);\ 785 1.1 christos if (leftleft != NULL && rbtn_red_get(a_type, a_field, \ 786 1.1 christos leftleft)) { \ 787 1.1 christos /* Fix up 4-node. */ \ 788 1.1 christos a_type *tnode; \ 789 1.1 christos rbtn_black_set(a_type, a_field, leftleft); \ 790 1.1 christos rbtn_rotate_right(a_type, a_field, cnode, tnode); \ 791 1.1.1.2 christos (void)a_summarize(cnode, \ 792 1.1.1.2 christos rbtn_left_get(a_type, a_field, cnode), \ 793 1.1.1.2 christos rbtn_right_get(a_type, a_field, cnode)); \ 794 1.1 christos cnode = tnode; \ 795 1.1 christos } \ 796 1.1 christos } else { \ 797 1.1.1.2 christos a_prefix##summarize_range(path, pathp); \ 798 1.1 christos return; \ 799 1.1 christos } \ 800 1.1 christos } else { \ 801 1.1 christos a_type *right = pathp[1].node; \ 802 1.1 christos rbtn_right_set(a_type, a_field, cnode, right); \ 803 1.1 christos if (rbtn_red_get(a_type, a_field, right)) { \ 804 1.1 christos a_type *left = rbtn_left_get(a_type, a_field, cnode); \ 805 1.1 christos if (left != NULL && rbtn_red_get(a_type, a_field, \ 806 1.1 christos left)) { \ 807 1.1 christos /* Split 4-node. */ \ 808 1.1 christos rbtn_black_set(a_type, a_field, left); \ 809 1.1 christos rbtn_black_set(a_type, a_field, right); \ 810 1.1 christos rbtn_red_set(a_type, a_field, cnode); \ 811 1.1 christos } else { \ 812 1.1 christos /* Lean left. */ \ 813 1.1 christos a_type *tnode; \ 814 1.1 christos bool tred = rbtn_red_get(a_type, a_field, cnode); \ 815 1.1 christos rbtn_rotate_left(a_type, a_field, cnode, tnode); \ 816 1.1 christos rbtn_color_set(a_type, a_field, tnode, tred); \ 817 1.1 christos rbtn_red_set(a_type, a_field, cnode); \ 818 1.1.1.2 christos (void)a_summarize(cnode, \ 819 1.1.1.2 christos rbtn_left_get(a_type, a_field, cnode), \ 820 1.1.1.2 christos rbtn_right_get(a_type, a_field, cnode)); \ 821 1.1 christos cnode = tnode; \ 822 1.1 christos } \ 823 1.1 christos } else { \ 824 1.1.1.2 christos a_prefix##summarize_range(path, pathp); \ 825 1.1 christos return; \ 826 1.1 christos } \ 827 1.1 christos } \ 828 1.1 christos pathp->node = cnode; \ 829 1.1.1.2 christos (void)a_summarize(cnode, \ 830 1.1.1.2 christos rbtn_left_get(a_type, a_field, cnode), \ 831 1.1.1.2 christos rbtn_right_get(a_type, a_field, cnode)); \ 832 1.1 christos } \ 833 1.1 christos /* Set root, and make it black. */ \ 834 1.1 christos rbtree->rbt_root = path->node; \ 835 1.1 christos rbtn_black_set(a_type, a_field, rbtree->rbt_root); \ 836 1.1 christos } \ 837 1.1 christos a_attr void \ 838 1.1 christos a_prefix##remove(a_rbt_type *rbtree, a_type *node) { \ 839 1.1.1.2 christos a_prefix##path_entry_t path[RB_MAX_DEPTH]; \ 840 1.1.1.2 christos a_prefix##path_entry_t *pathp; \ 841 1.1.1.2 christos a_prefix##path_entry_t *nodep; \ 842 1.1.1.2 christos a_prefix##path_entry_t *swap_loc; \ 843 1.1.1.2 christos /* This is a "real" sentinel -- NULL means we didn't swap the */\ 844 1.1.1.2 christos /* node to be pruned with one of its successors, and so */\ 845 1.1.1.2 christos /* summarization can terminate early whenever some summary */\ 846 1.1.1.2 christos /* doesn't change. */\ 847 1.1.1.2 christos swap_loc = NULL; \ 848 1.1.1.2 christos /* This is just to silence a compiler warning. */ \ 849 1.1.1.2 christos nodep = NULL; \ 850 1.1 christos /* Wind. */ \ 851 1.1 christos path->node = rbtree->rbt_root; \ 852 1.1 christos for (pathp = path; pathp->node != NULL; pathp++) { \ 853 1.1 christos int cmp = pathp->cmp = a_cmp(node, pathp->node); \ 854 1.1 christos if (cmp < 0) { \ 855 1.1 christos pathp[1].node = rbtn_left_get(a_type, a_field, \ 856 1.1 christos pathp->node); \ 857 1.1 christos } else { \ 858 1.1 christos pathp[1].node = rbtn_right_get(a_type, a_field, \ 859 1.1 christos pathp->node); \ 860 1.1 christos if (cmp == 0) { \ 861 1.1 christos /* Find node's successor, in preparation for swap. */ \ 862 1.1 christos pathp->cmp = 1; \ 863 1.1 christos nodep = pathp; \ 864 1.1 christos for (pathp++; pathp->node != NULL; pathp++) { \ 865 1.1 christos pathp->cmp = -1; \ 866 1.1 christos pathp[1].node = rbtn_left_get(a_type, a_field, \ 867 1.1 christos pathp->node); \ 868 1.1 christos } \ 869 1.1 christos break; \ 870 1.1 christos } \ 871 1.1 christos } \ 872 1.1 christos } \ 873 1.1.1.3 christos rb_remove_safety_checks(nodep, __func__); \ 874 1.1.1.3 christos assert(nodep != NULL); \ 875 1.1 christos assert(nodep->node == node); \ 876 1.1 christos pathp--; \ 877 1.1 christos if (pathp->node != node) { \ 878 1.1 christos /* Swap node with its successor. */ \ 879 1.1.1.2 christos swap_loc = nodep; \ 880 1.1 christos bool tred = rbtn_red_get(a_type, a_field, pathp->node); \ 881 1.1 christos rbtn_color_set(a_type, a_field, pathp->node, \ 882 1.1 christos rbtn_red_get(a_type, a_field, node)); \ 883 1.1 christos rbtn_left_set(a_type, a_field, pathp->node, \ 884 1.1 christos rbtn_left_get(a_type, a_field, node)); \ 885 1.1 christos /* If node's successor is its right child, the following code */\ 886 1.1 christos /* will do the wrong thing for the right child pointer. */\ 887 1.1 christos /* However, it doesn't matter, because the pointer will be */\ 888 1.1 christos /* properly set when the successor is pruned. */\ 889 1.1 christos rbtn_right_set(a_type, a_field, pathp->node, \ 890 1.1 christos rbtn_right_get(a_type, a_field, node)); \ 891 1.1 christos rbtn_color_set(a_type, a_field, node, tred); \ 892 1.1 christos /* The pruned leaf node's child pointers are never accessed */\ 893 1.1 christos /* again, so don't bother setting them to nil. */\ 894 1.1 christos nodep->node = pathp->node; \ 895 1.1 christos pathp->node = node; \ 896 1.1 christos if (nodep == path) { \ 897 1.1 christos rbtree->rbt_root = nodep->node; \ 898 1.1 christos } else { \ 899 1.1 christos if (nodep[-1].cmp < 0) { \ 900 1.1 christos rbtn_left_set(a_type, a_field, nodep[-1].node, \ 901 1.1 christos nodep->node); \ 902 1.1 christos } else { \ 903 1.1 christos rbtn_right_set(a_type, a_field, nodep[-1].node, \ 904 1.1 christos nodep->node); \ 905 1.1 christos } \ 906 1.1 christos } \ 907 1.1 christos } else { \ 908 1.1 christos a_type *left = rbtn_left_get(a_type, a_field, node); \ 909 1.1 christos if (left != NULL) { \ 910 1.1 christos /* node has no successor, but it has a left child. */\ 911 1.1 christos /* Splice node out, without losing the left child. */\ 912 1.1 christos assert(!rbtn_red_get(a_type, a_field, node)); \ 913 1.1 christos assert(rbtn_red_get(a_type, a_field, left)); \ 914 1.1 christos rbtn_black_set(a_type, a_field, left); \ 915 1.1 christos if (pathp == path) { \ 916 1.1 christos rbtree->rbt_root = left; \ 917 1.1.1.2 christos /* Nothing to summarize -- the subtree rooted at the */\ 918 1.1.1.2 christos /* node's left child hasn't changed, and it's now the */\ 919 1.1.1.2 christos /* root. */\ 920 1.1 christos } else { \ 921 1.1 christos if (pathp[-1].cmp < 0) { \ 922 1.1 christos rbtn_left_set(a_type, a_field, pathp[-1].node, \ 923 1.1 christos left); \ 924 1.1 christos } else { \ 925 1.1 christos rbtn_right_set(a_type, a_field, pathp[-1].node, \ 926 1.1 christos left); \ 927 1.1 christos } \ 928 1.1.1.2 christos a_prefix##summarize_swapped_range(path, &pathp[-1], \ 929 1.1.1.2 christos swap_loc); \ 930 1.1 christos } \ 931 1.1 christos return; \ 932 1.1 christos } else if (pathp == path) { \ 933 1.1 christos /* The tree only contained one node. */ \ 934 1.1 christos rbtree->rbt_root = NULL; \ 935 1.1 christos return; \ 936 1.1 christos } \ 937 1.1 christos } \ 938 1.1.1.2 christos /* We've now established the invariant that the node has no right */\ 939 1.1.1.2 christos /* child (well, morally; we didn't bother nulling it out if we */\ 940 1.1.1.2 christos /* swapped it with its successor), and that the only nodes with */\ 941 1.1.1.2 christos /* out-of-date summaries live in path[0], path[1], ..., pathp[-1].*/\ 942 1.1 christos if (rbtn_red_get(a_type, a_field, pathp->node)) { \ 943 1.1 christos /* Prune red node, which requires no fixup. */ \ 944 1.1 christos assert(pathp[-1].cmp < 0); \ 945 1.1 christos rbtn_left_set(a_type, a_field, pathp[-1].node, NULL); \ 946 1.1.1.2 christos a_prefix##summarize_swapped_range(path, &pathp[-1], swap_loc); \ 947 1.1 christos return; \ 948 1.1 christos } \ 949 1.1 christos /* The node to be pruned is black, so unwind until balance is */\ 950 1.1 christos /* restored. */\ 951 1.1 christos pathp->node = NULL; \ 952 1.1 christos for (pathp--; (uintptr_t)pathp >= (uintptr_t)path; pathp--) { \ 953 1.1 christos assert(pathp->cmp != 0); \ 954 1.1 christos if (pathp->cmp < 0) { \ 955 1.1 christos rbtn_left_set(a_type, a_field, pathp->node, \ 956 1.1 christos pathp[1].node); \ 957 1.1 christos if (rbtn_red_get(a_type, a_field, pathp->node)) { \ 958 1.1 christos a_type *right = rbtn_right_get(a_type, a_field, \ 959 1.1 christos pathp->node); \ 960 1.1 christos a_type *rightleft = rbtn_left_get(a_type, a_field, \ 961 1.1 christos right); \ 962 1.1 christos a_type *tnode; \ 963 1.1 christos if (rightleft != NULL && rbtn_red_get(a_type, a_field, \ 964 1.1 christos rightleft)) { \ 965 1.1 christos /* In the following diagrams, ||, //, and \\ */\ 966 1.1 christos /* indicate the path to the removed node. */\ 967 1.1 christos /* */\ 968 1.1 christos /* || */\ 969 1.1 christos /* pathp(r) */\ 970 1.1 christos /* // \ */\ 971 1.1 christos /* (b) (b) */\ 972 1.1 christos /* / */\ 973 1.1 christos /* (r) */\ 974 1.1 christos /* */\ 975 1.1 christos rbtn_black_set(a_type, a_field, pathp->node); \ 976 1.1 christos rbtn_rotate_right(a_type, a_field, right, tnode); \ 977 1.1 christos rbtn_right_set(a_type, a_field, pathp->node, tnode);\ 978 1.1 christos rbtn_rotate_left(a_type, a_field, pathp->node, \ 979 1.1 christos tnode); \ 980 1.1.1.2 christos (void)a_summarize(pathp->node, \ 981 1.1.1.2 christos rbtn_left_get(a_type, a_field, pathp->node), \ 982 1.1.1.2 christos rbtn_right_get(a_type, a_field, pathp->node)); \ 983 1.1.1.2 christos (void)a_summarize(right, \ 984 1.1.1.2 christos rbtn_left_get(a_type, a_field, right), \ 985 1.1.1.2 christos rbtn_right_get(a_type, a_field, right)); \ 986 1.1 christos } else { \ 987 1.1 christos /* || */\ 988 1.1 christos /* pathp(r) */\ 989 1.1 christos /* // \ */\ 990 1.1 christos /* (b) (b) */\ 991 1.1 christos /* / */\ 992 1.1 christos /* (b) */\ 993 1.1 christos /* */\ 994 1.1 christos rbtn_rotate_left(a_type, a_field, pathp->node, \ 995 1.1 christos tnode); \ 996 1.1.1.2 christos (void)a_summarize(pathp->node, \ 997 1.1.1.2 christos rbtn_left_get(a_type, a_field, pathp->node), \ 998 1.1.1.2 christos rbtn_right_get(a_type, a_field, pathp->node)); \ 999 1.1 christos } \ 1000 1.1.1.2 christos (void)a_summarize(tnode, rbtn_left_get(a_type, a_field, \ 1001 1.1.1.2 christos tnode), rbtn_right_get(a_type, a_field, tnode)); \ 1002 1.1 christos /* Balance restored, but rotation modified subtree */\ 1003 1.1 christos /* root. */\ 1004 1.1 christos assert((uintptr_t)pathp > (uintptr_t)path); \ 1005 1.1 christos if (pathp[-1].cmp < 0) { \ 1006 1.1 christos rbtn_left_set(a_type, a_field, pathp[-1].node, \ 1007 1.1 christos tnode); \ 1008 1.1 christos } else { \ 1009 1.1 christos rbtn_right_set(a_type, a_field, pathp[-1].node, \ 1010 1.1 christos tnode); \ 1011 1.1 christos } \ 1012 1.1.1.2 christos a_prefix##summarize_swapped_range(path, &pathp[-1], \ 1013 1.1.1.2 christos swap_loc); \ 1014 1.1 christos return; \ 1015 1.1 christos } else { \ 1016 1.1 christos a_type *right = rbtn_right_get(a_type, a_field, \ 1017 1.1 christos pathp->node); \ 1018 1.1 christos a_type *rightleft = rbtn_left_get(a_type, a_field, \ 1019 1.1 christos right); \ 1020 1.1 christos if (rightleft != NULL && rbtn_red_get(a_type, a_field, \ 1021 1.1 christos rightleft)) { \ 1022 1.1 christos /* || */\ 1023 1.1 christos /* pathp(b) */\ 1024 1.1 christos /* // \ */\ 1025 1.1 christos /* (b) (b) */\ 1026 1.1 christos /* / */\ 1027 1.1 christos /* (r) */\ 1028 1.1 christos a_type *tnode; \ 1029 1.1 christos rbtn_black_set(a_type, a_field, rightleft); \ 1030 1.1 christos rbtn_rotate_right(a_type, a_field, right, tnode); \ 1031 1.1 christos rbtn_right_set(a_type, a_field, pathp->node, tnode);\ 1032 1.1 christos rbtn_rotate_left(a_type, a_field, pathp->node, \ 1033 1.1 christos tnode); \ 1034 1.1.1.2 christos (void)a_summarize(pathp->node, \ 1035 1.1.1.2 christos rbtn_left_get(a_type, a_field, pathp->node), \ 1036 1.1.1.2 christos rbtn_right_get(a_type, a_field, pathp->node)); \ 1037 1.1.1.2 christos (void)a_summarize(right, \ 1038 1.1.1.2 christos rbtn_left_get(a_type, a_field, right), \ 1039 1.1.1.2 christos rbtn_right_get(a_type, a_field, right)); \ 1040 1.1.1.2 christos (void)a_summarize(tnode, \ 1041 1.1.1.2 christos rbtn_left_get(a_type, a_field, tnode), \ 1042 1.1.1.2 christos rbtn_right_get(a_type, a_field, tnode)); \ 1043 1.1 christos /* Balance restored, but rotation modified */\ 1044 1.1 christos /* subtree root, which may actually be the tree */\ 1045 1.1 christos /* root. */\ 1046 1.1 christos if (pathp == path) { \ 1047 1.1 christos /* Set root. */ \ 1048 1.1 christos rbtree->rbt_root = tnode; \ 1049 1.1 christos } else { \ 1050 1.1 christos if (pathp[-1].cmp < 0) { \ 1051 1.1 christos rbtn_left_set(a_type, a_field, \ 1052 1.1 christos pathp[-1].node, tnode); \ 1053 1.1 christos } else { \ 1054 1.1 christos rbtn_right_set(a_type, a_field, \ 1055 1.1 christos pathp[-1].node, tnode); \ 1056 1.1 christos } \ 1057 1.1.1.2 christos a_prefix##summarize_swapped_range(path, \ 1058 1.1.1.2 christos &pathp[-1], swap_loc); \ 1059 1.1 christos } \ 1060 1.1 christos return; \ 1061 1.1 christos } else { \ 1062 1.1 christos /* || */\ 1063 1.1 christos /* pathp(b) */\ 1064 1.1 christos /* // \ */\ 1065 1.1 christos /* (b) (b) */\ 1066 1.1 christos /* / */\ 1067 1.1 christos /* (b) */\ 1068 1.1 christos a_type *tnode; \ 1069 1.1 christos rbtn_red_set(a_type, a_field, pathp->node); \ 1070 1.1 christos rbtn_rotate_left(a_type, a_field, pathp->node, \ 1071 1.1 christos tnode); \ 1072 1.1.1.2 christos (void)a_summarize(pathp->node, \ 1073 1.1.1.2 christos rbtn_left_get(a_type, a_field, pathp->node), \ 1074 1.1.1.2 christos rbtn_right_get(a_type, a_field, pathp->node)); \ 1075 1.1.1.2 christos (void)a_summarize(tnode, \ 1076 1.1.1.2 christos rbtn_left_get(a_type, a_field, tnode), \ 1077 1.1.1.2 christos rbtn_right_get(a_type, a_field, tnode)); \ 1078 1.1 christos pathp->node = tnode; \ 1079 1.1 christos } \ 1080 1.1 christos } \ 1081 1.1 christos } else { \ 1082 1.1 christos a_type *left; \ 1083 1.1 christos rbtn_right_set(a_type, a_field, pathp->node, \ 1084 1.1 christos pathp[1].node); \ 1085 1.1 christos left = rbtn_left_get(a_type, a_field, pathp->node); \ 1086 1.1 christos if (rbtn_red_get(a_type, a_field, left)) { \ 1087 1.1 christos a_type *tnode; \ 1088 1.1 christos a_type *leftright = rbtn_right_get(a_type, a_field, \ 1089 1.1 christos left); \ 1090 1.1 christos a_type *leftrightleft = rbtn_left_get(a_type, a_field, \ 1091 1.1 christos leftright); \ 1092 1.1 christos if (leftrightleft != NULL && rbtn_red_get(a_type, \ 1093 1.1 christos a_field, leftrightleft)) { \ 1094 1.1 christos /* || */\ 1095 1.1 christos /* pathp(b) */\ 1096 1.1 christos /* / \\ */\ 1097 1.1 christos /* (r) (b) */\ 1098 1.1 christos /* \ */\ 1099 1.1 christos /* (b) */\ 1100 1.1 christos /* / */\ 1101 1.1 christos /* (r) */\ 1102 1.1 christos a_type *unode; \ 1103 1.1 christos rbtn_black_set(a_type, a_field, leftrightleft); \ 1104 1.1 christos rbtn_rotate_right(a_type, a_field, pathp->node, \ 1105 1.1 christos unode); \ 1106 1.1 christos rbtn_rotate_right(a_type, a_field, pathp->node, \ 1107 1.1 christos tnode); \ 1108 1.1 christos rbtn_right_set(a_type, a_field, unode, tnode); \ 1109 1.1 christos rbtn_rotate_left(a_type, a_field, unode, tnode); \ 1110 1.1.1.2 christos (void)a_summarize(pathp->node, \ 1111 1.1.1.2 christos rbtn_left_get(a_type, a_field, pathp->node), \ 1112 1.1.1.2 christos rbtn_right_get(a_type, a_field, pathp->node)); \ 1113 1.1.1.2 christos (void)a_summarize(unode, \ 1114 1.1.1.2 christos rbtn_left_get(a_type, a_field, unode), \ 1115 1.1.1.2 christos rbtn_right_get(a_type, a_field, unode)); \ 1116 1.1 christos } else { \ 1117 1.1 christos /* || */\ 1118 1.1 christos /* pathp(b) */\ 1119 1.1 christos /* / \\ */\ 1120 1.1 christos /* (r) (b) */\ 1121 1.1 christos /* \ */\ 1122 1.1 christos /* (b) */\ 1123 1.1 christos /* / */\ 1124 1.1 christos /* (b) */\ 1125 1.1 christos assert(leftright != NULL); \ 1126 1.1 christos rbtn_red_set(a_type, a_field, leftright); \ 1127 1.1 christos rbtn_rotate_right(a_type, a_field, pathp->node, \ 1128 1.1 christos tnode); \ 1129 1.1 christos rbtn_black_set(a_type, a_field, tnode); \ 1130 1.1.1.2 christos (void)a_summarize(pathp->node, \ 1131 1.1.1.2 christos rbtn_left_get(a_type, a_field, pathp->node), \ 1132 1.1.1.2 christos rbtn_right_get(a_type, a_field, pathp->node)); \ 1133 1.1 christos } \ 1134 1.1.1.2 christos (void)a_summarize(tnode, \ 1135 1.1.1.2 christos rbtn_left_get(a_type, a_field, tnode), \ 1136 1.1.1.2 christos rbtn_right_get(a_type, a_field, tnode)); \ 1137 1.1 christos /* Balance restored, but rotation modified subtree */\ 1138 1.1 christos /* root, which may actually be the tree root. */\ 1139 1.1 christos if (pathp == path) { \ 1140 1.1 christos /* Set root. */ \ 1141 1.1 christos rbtree->rbt_root = tnode; \ 1142 1.1 christos } else { \ 1143 1.1 christos if (pathp[-1].cmp < 0) { \ 1144 1.1 christos rbtn_left_set(a_type, a_field, pathp[-1].node, \ 1145 1.1 christos tnode); \ 1146 1.1 christos } else { \ 1147 1.1 christos rbtn_right_set(a_type, a_field, pathp[-1].node, \ 1148 1.1 christos tnode); \ 1149 1.1 christos } \ 1150 1.1.1.2 christos a_prefix##summarize_swapped_range(path, &pathp[-1], \ 1151 1.1.1.2 christos swap_loc); \ 1152 1.1 christos } \ 1153 1.1 christos return; \ 1154 1.1 christos } else if (rbtn_red_get(a_type, a_field, pathp->node)) { \ 1155 1.1 christos a_type *leftleft = rbtn_left_get(a_type, a_field, left);\ 1156 1.1 christos if (leftleft != NULL && rbtn_red_get(a_type, a_field, \ 1157 1.1 christos leftleft)) { \ 1158 1.1 christos /* || */\ 1159 1.1 christos /* pathp(r) */\ 1160 1.1 christos /* / \\ */\ 1161 1.1 christos /* (b) (b) */\ 1162 1.1 christos /* / */\ 1163 1.1 christos /* (r) */\ 1164 1.1 christos a_type *tnode; \ 1165 1.1 christos rbtn_black_set(a_type, a_field, pathp->node); \ 1166 1.1 christos rbtn_red_set(a_type, a_field, left); \ 1167 1.1 christos rbtn_black_set(a_type, a_field, leftleft); \ 1168 1.1 christos rbtn_rotate_right(a_type, a_field, pathp->node, \ 1169 1.1 christos tnode); \ 1170 1.1.1.2 christos (void)a_summarize(pathp->node, \ 1171 1.1.1.2 christos rbtn_left_get(a_type, a_field, pathp->node), \ 1172 1.1.1.2 christos rbtn_right_get(a_type, a_field, pathp->node)); \ 1173 1.1.1.2 christos (void)a_summarize(tnode, \ 1174 1.1.1.2 christos rbtn_left_get(a_type, a_field, tnode), \ 1175 1.1.1.2 christos rbtn_right_get(a_type, a_field, tnode)); \ 1176 1.1 christos /* Balance restored, but rotation modified */\ 1177 1.1 christos /* subtree root. */\ 1178 1.1 christos assert((uintptr_t)pathp > (uintptr_t)path); \ 1179 1.1 christos if (pathp[-1].cmp < 0) { \ 1180 1.1 christos rbtn_left_set(a_type, a_field, pathp[-1].node, \ 1181 1.1 christos tnode); \ 1182 1.1 christos } else { \ 1183 1.1 christos rbtn_right_set(a_type, a_field, pathp[-1].node, \ 1184 1.1 christos tnode); \ 1185 1.1 christos } \ 1186 1.1.1.2 christos a_prefix##summarize_swapped_range(path, &pathp[-1], \ 1187 1.1.1.2 christos swap_loc); \ 1188 1.1 christos return; \ 1189 1.1 christos } else { \ 1190 1.1 christos /* || */\ 1191 1.1 christos /* pathp(r) */\ 1192 1.1 christos /* / \\ */\ 1193 1.1 christos /* (b) (b) */\ 1194 1.1 christos /* / */\ 1195 1.1 christos /* (b) */\ 1196 1.1 christos rbtn_red_set(a_type, a_field, left); \ 1197 1.1 christos rbtn_black_set(a_type, a_field, pathp->node); \ 1198 1.1 christos /* Balance restored. */ \ 1199 1.1.1.2 christos a_prefix##summarize_swapped_range(path, pathp, \ 1200 1.1.1.2 christos swap_loc); \ 1201 1.1 christos return; \ 1202 1.1 christos } \ 1203 1.1 christos } else { \ 1204 1.1 christos a_type *leftleft = rbtn_left_get(a_type, a_field, left);\ 1205 1.1 christos if (leftleft != NULL && rbtn_red_get(a_type, a_field, \ 1206 1.1 christos leftleft)) { \ 1207 1.1 christos /* || */\ 1208 1.1 christos /* pathp(b) */\ 1209 1.1 christos /* / \\ */\ 1210 1.1 christos /* (b) (b) */\ 1211 1.1 christos /* / */\ 1212 1.1 christos /* (r) */\ 1213 1.1 christos a_type *tnode; \ 1214 1.1 christos rbtn_black_set(a_type, a_field, leftleft); \ 1215 1.1 christos rbtn_rotate_right(a_type, a_field, pathp->node, \ 1216 1.1 christos tnode); \ 1217 1.1.1.2 christos (void)a_summarize(pathp->node, \ 1218 1.1.1.2 christos rbtn_left_get(a_type, a_field, pathp->node), \ 1219 1.1.1.2 christos rbtn_right_get(a_type, a_field, pathp->node)); \ 1220 1.1.1.2 christos (void)a_summarize(tnode, \ 1221 1.1.1.2 christos rbtn_left_get(a_type, a_field, tnode), \ 1222 1.1.1.2 christos rbtn_right_get(a_type, a_field, tnode)); \ 1223 1.1 christos /* Balance restored, but rotation modified */\ 1224 1.1 christos /* subtree root, which may actually be the tree */\ 1225 1.1 christos /* root. */\ 1226 1.1 christos if (pathp == path) { \ 1227 1.1 christos /* Set root. */ \ 1228 1.1 christos rbtree->rbt_root = tnode; \ 1229 1.1 christos } else { \ 1230 1.1 christos if (pathp[-1].cmp < 0) { \ 1231 1.1 christos rbtn_left_set(a_type, a_field, \ 1232 1.1 christos pathp[-1].node, tnode); \ 1233 1.1 christos } else { \ 1234 1.1 christos rbtn_right_set(a_type, a_field, \ 1235 1.1 christos pathp[-1].node, tnode); \ 1236 1.1 christos } \ 1237 1.1.1.2 christos a_prefix##summarize_swapped_range(path, \ 1238 1.1.1.2 christos &pathp[-1], swap_loc); \ 1239 1.1 christos } \ 1240 1.1 christos return; \ 1241 1.1 christos } else { \ 1242 1.1 christos /* || */\ 1243 1.1 christos /* pathp(b) */\ 1244 1.1 christos /* / \\ */\ 1245 1.1 christos /* (b) (b) */\ 1246 1.1 christos /* / */\ 1247 1.1 christos /* (b) */\ 1248 1.1 christos rbtn_red_set(a_type, a_field, left); \ 1249 1.1.1.2 christos (void)a_summarize(pathp->node, \ 1250 1.1.1.2 christos rbtn_left_get(a_type, a_field, pathp->node), \ 1251 1.1.1.2 christos rbtn_right_get(a_type, a_field, pathp->node)); \ 1252 1.1 christos } \ 1253 1.1 christos } \ 1254 1.1 christos } \ 1255 1.1 christos } \ 1256 1.1 christos /* Set root. */ \ 1257 1.1 christos rbtree->rbt_root = path->node; \ 1258 1.1 christos assert(!rbtn_red_get(a_type, a_field, rbtree->rbt_root)); \ 1259 1.1 christos } \ 1260 1.1 christos a_attr a_type * \ 1261 1.1 christos a_prefix##iter_recurse(a_rbt_type *rbtree, a_type *node, \ 1262 1.1 christos a_type *(*cb)(a_rbt_type *, a_type *, void *), void *arg) { \ 1263 1.1 christos if (node == NULL) { \ 1264 1.1 christos return NULL; \ 1265 1.1 christos } else { \ 1266 1.1 christos a_type *ret; \ 1267 1.1 christos if ((ret = a_prefix##iter_recurse(rbtree, rbtn_left_get(a_type, \ 1268 1.1 christos a_field, node), cb, arg)) != NULL || (ret = cb(rbtree, node, \ 1269 1.1 christos arg)) != NULL) { \ 1270 1.1 christos return ret; \ 1271 1.1 christos } \ 1272 1.1 christos return a_prefix##iter_recurse(rbtree, rbtn_right_get(a_type, \ 1273 1.1 christos a_field, node), cb, arg); \ 1274 1.1 christos } \ 1275 1.1 christos } \ 1276 1.1 christos a_attr a_type * \ 1277 1.1 christos a_prefix##iter_start(a_rbt_type *rbtree, a_type *start, a_type *node, \ 1278 1.1 christos a_type *(*cb)(a_rbt_type *, a_type *, void *), void *arg) { \ 1279 1.1 christos int cmp = a_cmp(start, node); \ 1280 1.1 christos if (cmp < 0) { \ 1281 1.1 christos a_type *ret; \ 1282 1.1 christos if ((ret = a_prefix##iter_start(rbtree, start, \ 1283 1.1 christos rbtn_left_get(a_type, a_field, node), cb, arg)) != NULL || \ 1284 1.1 christos (ret = cb(rbtree, node, arg)) != NULL) { \ 1285 1.1 christos return ret; \ 1286 1.1 christos } \ 1287 1.1 christos return a_prefix##iter_recurse(rbtree, rbtn_right_get(a_type, \ 1288 1.1 christos a_field, node), cb, arg); \ 1289 1.1 christos } else if (cmp > 0) { \ 1290 1.1 christos return a_prefix##iter_start(rbtree, start, \ 1291 1.1 christos rbtn_right_get(a_type, a_field, node), cb, arg); \ 1292 1.1 christos } else { \ 1293 1.1 christos a_type *ret; \ 1294 1.1 christos if ((ret = cb(rbtree, node, arg)) != NULL) { \ 1295 1.1 christos return ret; \ 1296 1.1 christos } \ 1297 1.1 christos return a_prefix##iter_recurse(rbtree, rbtn_right_get(a_type, \ 1298 1.1 christos a_field, node), cb, arg); \ 1299 1.1 christos } \ 1300 1.1 christos } \ 1301 1.1 christos a_attr a_type * \ 1302 1.1 christos a_prefix##iter(a_rbt_type *rbtree, a_type *start, a_type *(*cb)( \ 1303 1.1 christos a_rbt_type *, a_type *, void *), void *arg) { \ 1304 1.1 christos a_type *ret; \ 1305 1.1 christos if (start != NULL) { \ 1306 1.1 christos ret = a_prefix##iter_start(rbtree, start, rbtree->rbt_root, \ 1307 1.1 christos cb, arg); \ 1308 1.1 christos } else { \ 1309 1.1 christos ret = a_prefix##iter_recurse(rbtree, rbtree->rbt_root, cb, arg);\ 1310 1.1 christos } \ 1311 1.1 christos return ret; \ 1312 1.1 christos } \ 1313 1.1 christos a_attr a_type * \ 1314 1.1 christos a_prefix##reverse_iter_recurse(a_rbt_type *rbtree, a_type *node, \ 1315 1.1 christos a_type *(*cb)(a_rbt_type *, a_type *, void *), void *arg) { \ 1316 1.1 christos if (node == NULL) { \ 1317 1.1 christos return NULL; \ 1318 1.1 christos } else { \ 1319 1.1 christos a_type *ret; \ 1320 1.1 christos if ((ret = a_prefix##reverse_iter_recurse(rbtree, \ 1321 1.1 christos rbtn_right_get(a_type, a_field, node), cb, arg)) != NULL || \ 1322 1.1 christos (ret = cb(rbtree, node, arg)) != NULL) { \ 1323 1.1 christos return ret; \ 1324 1.1 christos } \ 1325 1.1 christos return a_prefix##reverse_iter_recurse(rbtree, \ 1326 1.1 christos rbtn_left_get(a_type, a_field, node), cb, arg); \ 1327 1.1 christos } \ 1328 1.1 christos } \ 1329 1.1 christos a_attr a_type * \ 1330 1.1 christos a_prefix##reverse_iter_start(a_rbt_type *rbtree, a_type *start, \ 1331 1.1 christos a_type *node, a_type *(*cb)(a_rbt_type *, a_type *, void *), \ 1332 1.1 christos void *arg) { \ 1333 1.1 christos int cmp = a_cmp(start, node); \ 1334 1.1 christos if (cmp > 0) { \ 1335 1.1 christos a_type *ret; \ 1336 1.1 christos if ((ret = a_prefix##reverse_iter_start(rbtree, start, \ 1337 1.1 christos rbtn_right_get(a_type, a_field, node), cb, arg)) != NULL || \ 1338 1.1 christos (ret = cb(rbtree, node, arg)) != NULL) { \ 1339 1.1 christos return ret; \ 1340 1.1 christos } \ 1341 1.1 christos return a_prefix##reverse_iter_recurse(rbtree, \ 1342 1.1 christos rbtn_left_get(a_type, a_field, node), cb, arg); \ 1343 1.1 christos } else if (cmp < 0) { \ 1344 1.1 christos return a_prefix##reverse_iter_start(rbtree, start, \ 1345 1.1 christos rbtn_left_get(a_type, a_field, node), cb, arg); \ 1346 1.1 christos } else { \ 1347 1.1 christos a_type *ret; \ 1348 1.1 christos if ((ret = cb(rbtree, node, arg)) != NULL) { \ 1349 1.1 christos return ret; \ 1350 1.1 christos } \ 1351 1.1 christos return a_prefix##reverse_iter_recurse(rbtree, \ 1352 1.1 christos rbtn_left_get(a_type, a_field, node), cb, arg); \ 1353 1.1 christos } \ 1354 1.1 christos } \ 1355 1.1 christos a_attr a_type * \ 1356 1.1 christos a_prefix##reverse_iter(a_rbt_type *rbtree, a_type *start, \ 1357 1.1 christos a_type *(*cb)(a_rbt_type *, a_type *, void *), void *arg) { \ 1358 1.1 christos a_type *ret; \ 1359 1.1 christos if (start != NULL) { \ 1360 1.1 christos ret = a_prefix##reverse_iter_start(rbtree, start, \ 1361 1.1 christos rbtree->rbt_root, cb, arg); \ 1362 1.1 christos } else { \ 1363 1.1 christos ret = a_prefix##reverse_iter_recurse(rbtree, rbtree->rbt_root, \ 1364 1.1 christos cb, arg); \ 1365 1.1 christos } \ 1366 1.1 christos return ret; \ 1367 1.1 christos } \ 1368 1.1 christos a_attr void \ 1369 1.1 christos a_prefix##destroy_recurse(a_rbt_type *rbtree, a_type *node, void (*cb)( \ 1370 1.1 christos a_type *, void *), void *arg) { \ 1371 1.1 christos if (node == NULL) { \ 1372 1.1 christos return; \ 1373 1.1 christos } \ 1374 1.1 christos a_prefix##destroy_recurse(rbtree, rbtn_left_get(a_type, a_field, \ 1375 1.1 christos node), cb, arg); \ 1376 1.1 christos rbtn_left_set(a_type, a_field, (node), NULL); \ 1377 1.1 christos a_prefix##destroy_recurse(rbtree, rbtn_right_get(a_type, a_field, \ 1378 1.1 christos node), cb, arg); \ 1379 1.1 christos rbtn_right_set(a_type, a_field, (node), NULL); \ 1380 1.1 christos if (cb) { \ 1381 1.1 christos cb(node, arg); \ 1382 1.1 christos } \ 1383 1.1 christos } \ 1384 1.1 christos a_attr void \ 1385 1.1 christos a_prefix##destroy(a_rbt_type *rbtree, void (*cb)(a_type *, void *), \ 1386 1.1 christos void *arg) { \ 1387 1.1 christos a_prefix##destroy_recurse(rbtree, rbtree->rbt_root, cb, arg); \ 1388 1.1 christos rbtree->rbt_root = NULL; \ 1389 1.1.1.2 christos } \ 1390 1.1.1.2 christos /* BEGIN SUMMARIZED-ONLY IMPLEMENTATION */ \ 1391 1.1.1.2 christos rb_summarized_only_##a_is_summarized( \ 1392 1.1.1.2 christos static inline a_prefix##path_entry_t * \ 1393 1.1.1.2 christos a_prefix##wind(a_rbt_type *rbtree, \ 1394 1.1.1.2 christos a_prefix##path_entry_t path[RB_MAX_DEPTH], a_type *node) { \ 1395 1.1.1.2 christos a_prefix##path_entry_t *pathp; \ 1396 1.1.1.2 christos path->node = rbtree->rbt_root; \ 1397 1.1.1.2 christos for (pathp = path; ; pathp++) { \ 1398 1.1.1.2 christos assert((size_t)(pathp - path) < RB_MAX_DEPTH); \ 1399 1.1.1.2 christos pathp->cmp = a_cmp(node, pathp->node); \ 1400 1.1.1.2 christos if (pathp->cmp < 0) { \ 1401 1.1.1.2 christos pathp[1].node = rbtn_left_get(a_type, a_field, \ 1402 1.1.1.2 christos pathp->node); \ 1403 1.1.1.2 christos } else if (pathp->cmp == 0) { \ 1404 1.1.1.2 christos return pathp; \ 1405 1.1.1.2 christos } else { \ 1406 1.1.1.2 christos pathp[1].node = rbtn_right_get(a_type, a_field, \ 1407 1.1.1.2 christos pathp->node); \ 1408 1.1.1.2 christos } \ 1409 1.1.1.2 christos } \ 1410 1.1.1.2 christos unreachable(); \ 1411 1.1.1.2 christos } \ 1412 1.1.1.2 christos a_attr void \ 1413 1.1.1.2 christos a_prefix##update_summaries(a_rbt_type *rbtree, a_type *node) { \ 1414 1.1.1.2 christos a_prefix##path_entry_t path[RB_MAX_DEPTH]; \ 1415 1.1.1.2 christos a_prefix##path_entry_t *pathp = a_prefix##wind(rbtree, path, node); \ 1416 1.1.1.2 christos a_prefix##summarize_range(path, pathp); \ 1417 1.1.1.2 christos } \ 1418 1.1.1.2 christos a_attr bool \ 1419 1.1.1.2 christos a_prefix##empty_filtered(a_rbt_type *rbtree, \ 1420 1.1.1.2 christos bool (*filter_node)(void *, a_type *), \ 1421 1.1.1.2 christos bool (*filter_subtree)(void *, a_type *), \ 1422 1.1.1.2 christos void *filter_ctx) { \ 1423 1.1.1.2 christos a_type *node = rbtree->rbt_root; \ 1424 1.1.1.2 christos return node == NULL || !filter_subtree(filter_ctx, node); \ 1425 1.1.1.2 christos } \ 1426 1.1.1.2 christos static inline a_type * \ 1427 1.1.1.2 christos a_prefix##first_filtered_from_node(a_type *node, \ 1428 1.1.1.2 christos bool (*filter_node)(void *, a_type *), \ 1429 1.1.1.2 christos bool (*filter_subtree)(void *, a_type *), \ 1430 1.1.1.2 christos void *filter_ctx) { \ 1431 1.1.1.2 christos assert(node != NULL && filter_subtree(filter_ctx, node)); \ 1432 1.1.1.2 christos while (true) { \ 1433 1.1.1.2 christos a_type *left = rbtn_left_get(a_type, a_field, node); \ 1434 1.1.1.2 christos a_type *right = rbtn_right_get(a_type, a_field, node); \ 1435 1.1.1.2 christos if (left != NULL && filter_subtree(filter_ctx, left)) { \ 1436 1.1.1.2 christos node = left; \ 1437 1.1.1.2 christos } else if (filter_node(filter_ctx, node)) { \ 1438 1.1.1.2 christos return node; \ 1439 1.1.1.2 christos } else { \ 1440 1.1.1.2 christos assert(right != NULL \ 1441 1.1.1.2 christos && filter_subtree(filter_ctx, right)); \ 1442 1.1.1.2 christos node = right; \ 1443 1.1.1.2 christos } \ 1444 1.1.1.2 christos } \ 1445 1.1.1.2 christos unreachable(); \ 1446 1.1.1.2 christos } \ 1447 1.1.1.2 christos a_attr a_type * \ 1448 1.1.1.2 christos a_prefix##first_filtered(a_rbt_type *rbtree, \ 1449 1.1.1.2 christos bool (*filter_node)(void *, a_type *), \ 1450 1.1.1.2 christos bool (*filter_subtree)(void *, a_type *), \ 1451 1.1.1.2 christos void *filter_ctx) { \ 1452 1.1.1.2 christos a_type *node = rbtree->rbt_root; \ 1453 1.1.1.2 christos if (node == NULL || !filter_subtree(filter_ctx, node)) { \ 1454 1.1.1.2 christos return NULL; \ 1455 1.1.1.2 christos } \ 1456 1.1.1.2 christos return a_prefix##first_filtered_from_node(node, filter_node, \ 1457 1.1.1.2 christos filter_subtree, filter_ctx); \ 1458 1.1.1.2 christos } \ 1459 1.1.1.2 christos static inline a_type * \ 1460 1.1.1.2 christos a_prefix##last_filtered_from_node(a_type *node, \ 1461 1.1.1.2 christos bool (*filter_node)(void *, a_type *), \ 1462 1.1.1.2 christos bool (*filter_subtree)(void *, a_type *), \ 1463 1.1.1.2 christos void *filter_ctx) { \ 1464 1.1.1.2 christos assert(node != NULL && filter_subtree(filter_ctx, node)); \ 1465 1.1.1.2 christos while (true) { \ 1466 1.1.1.2 christos a_type *left = rbtn_left_get(a_type, a_field, node); \ 1467 1.1.1.2 christos a_type *right = rbtn_right_get(a_type, a_field, node); \ 1468 1.1.1.2 christos if (right != NULL && filter_subtree(filter_ctx, right)) { \ 1469 1.1.1.2 christos node = right; \ 1470 1.1.1.2 christos } else if (filter_node(filter_ctx, node)) { \ 1471 1.1.1.2 christos return node; \ 1472 1.1.1.2 christos } else { \ 1473 1.1.1.2 christos assert(left != NULL \ 1474 1.1.1.2 christos && filter_subtree(filter_ctx, left)); \ 1475 1.1.1.2 christos node = left; \ 1476 1.1.1.2 christos } \ 1477 1.1.1.2 christos } \ 1478 1.1.1.2 christos unreachable(); \ 1479 1.1.1.2 christos } \ 1480 1.1.1.2 christos a_attr a_type * \ 1481 1.1.1.2 christos a_prefix##last_filtered(a_rbt_type *rbtree, \ 1482 1.1.1.2 christos bool (*filter_node)(void *, a_type *), \ 1483 1.1.1.2 christos bool (*filter_subtree)(void *, a_type *), \ 1484 1.1.1.2 christos void *filter_ctx) { \ 1485 1.1.1.2 christos a_type *node = rbtree->rbt_root; \ 1486 1.1.1.2 christos if (node == NULL || !filter_subtree(filter_ctx, node)) { \ 1487 1.1.1.2 christos return NULL; \ 1488 1.1.1.2 christos } \ 1489 1.1.1.2 christos return a_prefix##last_filtered_from_node(node, filter_node, \ 1490 1.1.1.2 christos filter_subtree, filter_ctx); \ 1491 1.1.1.2 christos } \ 1492 1.1.1.2 christos /* Internal implementation function. Search for a node comparing */\ 1493 1.1.1.2 christos /* equal to key matching the filter. If such a node is in the tree, */\ 1494 1.1.1.2 christos /* return it. Additionally, the caller has the option to ask for */\ 1495 1.1.1.2 christos /* bounds on the next / prev node in the tree passing the filter. */\ 1496 1.1.1.2 christos /* If nextbound is true, then this function will do one of the */\ 1497 1.1.1.2 christos /* following: */\ 1498 1.1.1.2 christos /* - Fill in *nextbound_node with the smallest node in the tree */\ 1499 1.1.1.2 christos /* greater than key passing the filter, and NULL-out */\ 1500 1.1.1.2 christos /* *nextbound_subtree. */\ 1501 1.1.1.2 christos /* - Fill in *nextbound_subtree with a parent of that node which is */\ 1502 1.1.1.2 christos /* not a parent of the searched-for node, and NULL-out */\ 1503 1.1.1.2 christos /* *nextbound_node. */\ 1504 1.1.1.2 christos /* - NULL-out both *nextbound_node and *nextbound_subtree, in which */\ 1505 1.1.1.2 christos /* case no node greater than key but passing the filter is in the */\ 1506 1.1.1.2 christos /* tree. */\ 1507 1.1.1.2 christos /* The prevbound case is similar. If the caller knows that key is in */\ 1508 1.1.1.2 christos /* the tree and that the subtree rooted at key does not contain a */\ 1509 1.1.1.2 christos /* node satisfying the bound being searched for, then they can pass */\ 1510 1.1.1.2 christos /* false for include_subtree, in which case we won't bother searching */\ 1511 1.1.1.2 christos /* there (risking a cache miss). */\ 1512 1.1.1.2 christos /* */\ 1513 1.1.1.2 christos /* This API is unfortunately complex; but the logic for filtered */\ 1514 1.1.1.2 christos /* searches is very subtle, and otherwise we would have to repeat it */\ 1515 1.1.1.2 christos /* multiple times for filtered search, nsearch, psearch, next, and */\ 1516 1.1.1.2 christos /* prev. */\ 1517 1.1.1.2 christos static inline a_type * \ 1518 1.1.1.2 christos a_prefix##search_with_filter_bounds(a_rbt_type *rbtree, \ 1519 1.1.1.2 christos const a_type *key, \ 1520 1.1.1.2 christos bool (*filter_node)(void *, a_type *), \ 1521 1.1.1.2 christos bool (*filter_subtree)(void *, a_type *), \ 1522 1.1.1.2 christos void *filter_ctx, \ 1523 1.1.1.2 christos bool include_subtree, \ 1524 1.1.1.2 christos bool nextbound, a_type **nextbound_node, a_type **nextbound_subtree, \ 1525 1.1.1.2 christos bool prevbound, a_type **prevbound_node, a_type **prevbound_subtree) {\ 1526 1.1.1.2 christos if (nextbound) { \ 1527 1.1.1.2 christos *nextbound_node = NULL; \ 1528 1.1.1.2 christos *nextbound_subtree = NULL; \ 1529 1.1.1.2 christos } \ 1530 1.1.1.2 christos if (prevbound) { \ 1531 1.1.1.2 christos *prevbound_node = NULL; \ 1532 1.1.1.2 christos *prevbound_subtree = NULL; \ 1533 1.1.1.2 christos } \ 1534 1.1.1.2 christos a_type *tnode = rbtree->rbt_root; \ 1535 1.1.1.2 christos while (tnode != NULL && filter_subtree(filter_ctx, tnode)) { \ 1536 1.1.1.2 christos int cmp = a_cmp(key, tnode); \ 1537 1.1.1.2 christos a_type *tleft = rbtn_left_get(a_type, a_field, tnode); \ 1538 1.1.1.2 christos a_type *tright = rbtn_right_get(a_type, a_field, tnode); \ 1539 1.1.1.2 christos if (cmp < 0) { \ 1540 1.1.1.2 christos if (nextbound) { \ 1541 1.1.1.2 christos if (filter_node(filter_ctx, tnode)) { \ 1542 1.1.1.2 christos *nextbound_node = tnode; \ 1543 1.1.1.2 christos *nextbound_subtree = NULL; \ 1544 1.1.1.2 christos } else if (tright != NULL && filter_subtree( \ 1545 1.1.1.2 christos filter_ctx, tright)) { \ 1546 1.1.1.2 christos *nextbound_node = NULL; \ 1547 1.1.1.2 christos *nextbound_subtree = tright; \ 1548 1.1.1.2 christos } \ 1549 1.1.1.2 christos } \ 1550 1.1.1.2 christos tnode = tleft; \ 1551 1.1.1.2 christos } else if (cmp > 0) { \ 1552 1.1.1.2 christos if (prevbound) { \ 1553 1.1.1.2 christos if (filter_node(filter_ctx, tnode)) { \ 1554 1.1.1.2 christos *prevbound_node = tnode; \ 1555 1.1.1.2 christos *prevbound_subtree = NULL; \ 1556 1.1.1.2 christos } else if (tleft != NULL && filter_subtree( \ 1557 1.1.1.2 christos filter_ctx, tleft)) { \ 1558 1.1.1.2 christos *prevbound_node = NULL; \ 1559 1.1.1.2 christos *prevbound_subtree = tleft; \ 1560 1.1.1.2 christos } \ 1561 1.1.1.2 christos } \ 1562 1.1.1.2 christos tnode = tright; \ 1563 1.1.1.2 christos } else { \ 1564 1.1.1.2 christos if (filter_node(filter_ctx, tnode)) { \ 1565 1.1.1.2 christos return tnode; \ 1566 1.1.1.2 christos } \ 1567 1.1.1.2 christos if (include_subtree) { \ 1568 1.1.1.2 christos if (prevbound && tleft != NULL && filter_subtree( \ 1569 1.1.1.2 christos filter_ctx, tleft)) { \ 1570 1.1.1.2 christos *prevbound_node = NULL; \ 1571 1.1.1.2 christos *prevbound_subtree = tleft; \ 1572 1.1.1.2 christos } \ 1573 1.1.1.2 christos if (nextbound && tright != NULL && filter_subtree( \ 1574 1.1.1.2 christos filter_ctx, tright)) { \ 1575 1.1.1.2 christos *nextbound_node = NULL; \ 1576 1.1.1.2 christos *nextbound_subtree = tright; \ 1577 1.1.1.2 christos } \ 1578 1.1.1.2 christos } \ 1579 1.1.1.2 christos return NULL; \ 1580 1.1.1.2 christos } \ 1581 1.1.1.2 christos } \ 1582 1.1.1.2 christos return NULL; \ 1583 1.1.1.2 christos } \ 1584 1.1.1.2 christos a_attr a_type * \ 1585 1.1.1.2 christos a_prefix##next_filtered(a_rbt_type *rbtree, a_type *node, \ 1586 1.1.1.2 christos bool (*filter_node)(void *, a_type *), \ 1587 1.1.1.2 christos bool (*filter_subtree)(void *, a_type *), \ 1588 1.1.1.2 christos void *filter_ctx) { \ 1589 1.1.1.2 christos a_type *nright = rbtn_right_get(a_type, a_field, node); \ 1590 1.1.1.2 christos if (nright != NULL && filter_subtree(filter_ctx, nright)) { \ 1591 1.1.1.2 christos return a_prefix##first_filtered_from_node(nright, filter_node, \ 1592 1.1.1.2 christos filter_subtree, filter_ctx); \ 1593 1.1.1.2 christos } \ 1594 1.1.1.2 christos a_type *node_candidate; \ 1595 1.1.1.2 christos a_type *subtree_candidate; \ 1596 1.1.1.2 christos a_type *search_result = a_prefix##search_with_filter_bounds( \ 1597 1.1.1.2 christos rbtree, node, filter_node, filter_subtree, filter_ctx, \ 1598 1.1.1.2 christos /* include_subtree */ false, \ 1599 1.1.1.2 christos /* nextbound */ true, &node_candidate, &subtree_candidate, \ 1600 1.1.1.2 christos /* prevbound */ false, NULL, NULL); \ 1601 1.1.1.2 christos assert(node == search_result \ 1602 1.1.1.2 christos || !filter_node(filter_ctx, node)); \ 1603 1.1.1.2 christos if (node_candidate != NULL) { \ 1604 1.1.1.2 christos return node_candidate; \ 1605 1.1.1.2 christos } \ 1606 1.1.1.2 christos if (subtree_candidate != NULL) { \ 1607 1.1.1.2 christos return a_prefix##first_filtered_from_node( \ 1608 1.1.1.2 christos subtree_candidate, filter_node, filter_subtree, \ 1609 1.1.1.2 christos filter_ctx); \ 1610 1.1.1.2 christos } \ 1611 1.1.1.2 christos return NULL; \ 1612 1.1.1.2 christos } \ 1613 1.1.1.2 christos a_attr a_type * \ 1614 1.1.1.2 christos a_prefix##prev_filtered(a_rbt_type *rbtree, a_type *node, \ 1615 1.1.1.2 christos bool (*filter_node)(void *, a_type *), \ 1616 1.1.1.2 christos bool (*filter_subtree)(void *, a_type *), \ 1617 1.1.1.2 christos void *filter_ctx) { \ 1618 1.1.1.2 christos a_type *nleft = rbtn_left_get(a_type, a_field, node); \ 1619 1.1.1.2 christos if (nleft != NULL && filter_subtree(filter_ctx, nleft)) { \ 1620 1.1.1.2 christos return a_prefix##last_filtered_from_node(nleft, filter_node, \ 1621 1.1.1.2 christos filter_subtree, filter_ctx); \ 1622 1.1.1.2 christos } \ 1623 1.1.1.2 christos a_type *node_candidate; \ 1624 1.1.1.2 christos a_type *subtree_candidate; \ 1625 1.1.1.2 christos a_type *search_result = a_prefix##search_with_filter_bounds( \ 1626 1.1.1.2 christos rbtree, node, filter_node, filter_subtree, filter_ctx, \ 1627 1.1.1.2 christos /* include_subtree */ false, \ 1628 1.1.1.2 christos /* nextbound */ false, NULL, NULL, \ 1629 1.1.1.2 christos /* prevbound */ true, &node_candidate, &subtree_candidate); \ 1630 1.1.1.2 christos assert(node == search_result \ 1631 1.1.1.2 christos || !filter_node(filter_ctx, node)); \ 1632 1.1.1.2 christos if (node_candidate != NULL) { \ 1633 1.1.1.2 christos return node_candidate; \ 1634 1.1.1.2 christos } \ 1635 1.1.1.2 christos if (subtree_candidate != NULL) { \ 1636 1.1.1.2 christos return a_prefix##last_filtered_from_node( \ 1637 1.1.1.2 christos subtree_candidate, filter_node, filter_subtree, \ 1638 1.1.1.2 christos filter_ctx); \ 1639 1.1.1.2 christos } \ 1640 1.1.1.2 christos return NULL; \ 1641 1.1.1.2 christos } \ 1642 1.1.1.2 christos a_attr a_type * \ 1643 1.1.1.2 christos a_prefix##search_filtered(a_rbt_type *rbtree, const a_type *key, \ 1644 1.1.1.2 christos bool (*filter_node)(void *, a_type *), \ 1645 1.1.1.2 christos bool (*filter_subtree)(void *, a_type *), \ 1646 1.1.1.2 christos void *filter_ctx) { \ 1647 1.1.1.2 christos a_type *result = a_prefix##search_with_filter_bounds(rbtree, key, \ 1648 1.1.1.2 christos filter_node, filter_subtree, filter_ctx, \ 1649 1.1.1.2 christos /* include_subtree */ false, \ 1650 1.1.1.2 christos /* nextbound */ false, NULL, NULL, \ 1651 1.1.1.2 christos /* prevbound */ false, NULL, NULL); \ 1652 1.1.1.2 christos return result; \ 1653 1.1.1.2 christos } \ 1654 1.1.1.2 christos a_attr a_type * \ 1655 1.1.1.2 christos a_prefix##nsearch_filtered(a_rbt_type *rbtree, const a_type *key, \ 1656 1.1.1.2 christos bool (*filter_node)(void *, a_type *), \ 1657 1.1.1.2 christos bool (*filter_subtree)(void *, a_type *), \ 1658 1.1.1.2 christos void *filter_ctx) { \ 1659 1.1.1.2 christos a_type *node_candidate; \ 1660 1.1.1.2 christos a_type *subtree_candidate; \ 1661 1.1.1.2 christos a_type *result = a_prefix##search_with_filter_bounds(rbtree, key, \ 1662 1.1.1.2 christos filter_node, filter_subtree, filter_ctx, \ 1663 1.1.1.2 christos /* include_subtree */ true, \ 1664 1.1.1.2 christos /* nextbound */ true, &node_candidate, &subtree_candidate, \ 1665 1.1.1.2 christos /* prevbound */ false, NULL, NULL); \ 1666 1.1.1.2 christos if (result != NULL) { \ 1667 1.1.1.2 christos return result; \ 1668 1.1.1.2 christos } \ 1669 1.1.1.2 christos if (node_candidate != NULL) { \ 1670 1.1.1.2 christos return node_candidate; \ 1671 1.1.1.2 christos } \ 1672 1.1.1.2 christos if (subtree_candidate != NULL) { \ 1673 1.1.1.2 christos return a_prefix##first_filtered_from_node( \ 1674 1.1.1.2 christos subtree_candidate, filter_node, filter_subtree, \ 1675 1.1.1.2 christos filter_ctx); \ 1676 1.1.1.2 christos } \ 1677 1.1.1.2 christos return NULL; \ 1678 1.1.1.2 christos } \ 1679 1.1.1.2 christos a_attr a_type * \ 1680 1.1.1.2 christos a_prefix##psearch_filtered(a_rbt_type *rbtree, const a_type *key, \ 1681 1.1.1.2 christos bool (*filter_node)(void *, a_type *), \ 1682 1.1.1.2 christos bool (*filter_subtree)(void *, a_type *), \ 1683 1.1.1.2 christos void *filter_ctx) { \ 1684 1.1.1.2 christos a_type *node_candidate; \ 1685 1.1.1.2 christos a_type *subtree_candidate; \ 1686 1.1.1.2 christos a_type *result = a_prefix##search_with_filter_bounds(rbtree, key, \ 1687 1.1.1.2 christos filter_node, filter_subtree, filter_ctx, \ 1688 1.1.1.2 christos /* include_subtree */ true, \ 1689 1.1.1.2 christos /* nextbound */ false, NULL, NULL, \ 1690 1.1.1.2 christos /* prevbound */ true, &node_candidate, &subtree_candidate); \ 1691 1.1.1.2 christos if (result != NULL) { \ 1692 1.1.1.2 christos return result; \ 1693 1.1.1.2 christos } \ 1694 1.1.1.2 christos if (node_candidate != NULL) { \ 1695 1.1.1.2 christos return node_candidate; \ 1696 1.1.1.2 christos } \ 1697 1.1.1.2 christos if (subtree_candidate != NULL) { \ 1698 1.1.1.2 christos return a_prefix##last_filtered_from_node( \ 1699 1.1.1.2 christos subtree_candidate, filter_node, filter_subtree, \ 1700 1.1.1.2 christos filter_ctx); \ 1701 1.1.1.2 christos } \ 1702 1.1.1.2 christos return NULL; \ 1703 1.1.1.2 christos } \ 1704 1.1.1.2 christos a_attr a_type * \ 1705 1.1.1.2 christos a_prefix##iter_recurse_filtered(a_rbt_type *rbtree, a_type *node, \ 1706 1.1.1.2 christos a_type *(*cb)(a_rbt_type *, a_type *, void *), void *arg, \ 1707 1.1.1.2 christos bool (*filter_node)(void *, a_type *), \ 1708 1.1.1.2 christos bool (*filter_subtree)(void *, a_type *), \ 1709 1.1.1.2 christos void *filter_ctx) { \ 1710 1.1.1.2 christos if (node == NULL || !filter_subtree(filter_ctx, node)) { \ 1711 1.1.1.2 christos return NULL; \ 1712 1.1.1.2 christos } \ 1713 1.1.1.2 christos a_type *ret; \ 1714 1.1.1.2 christos a_type *left = rbtn_left_get(a_type, a_field, node); \ 1715 1.1.1.2 christos a_type *right = rbtn_right_get(a_type, a_field, node); \ 1716 1.1.1.2 christos ret = a_prefix##iter_recurse_filtered(rbtree, left, cb, arg, \ 1717 1.1.1.2 christos filter_node, filter_subtree, filter_ctx); \ 1718 1.1.1.2 christos if (ret != NULL) { \ 1719 1.1.1.2 christos return ret; \ 1720 1.1.1.2 christos } \ 1721 1.1.1.2 christos if (filter_node(filter_ctx, node)) { \ 1722 1.1.1.2 christos ret = cb(rbtree, node, arg); \ 1723 1.1.1.2 christos } \ 1724 1.1.1.2 christos if (ret != NULL) { \ 1725 1.1.1.2 christos return ret; \ 1726 1.1.1.2 christos } \ 1727 1.1.1.2 christos return a_prefix##iter_recurse_filtered(rbtree, right, cb, arg, \ 1728 1.1.1.2 christos filter_node, filter_subtree, filter_ctx); \ 1729 1.1.1.2 christos } \ 1730 1.1.1.2 christos a_attr a_type * \ 1731 1.1.1.2 christos a_prefix##iter_start_filtered(a_rbt_type *rbtree, a_type *start, \ 1732 1.1.1.2 christos a_type *node, a_type *(*cb)(a_rbt_type *, a_type *, void *), \ 1733 1.1.1.2 christos void *arg, bool (*filter_node)(void *, a_type *), \ 1734 1.1.1.2 christos bool (*filter_subtree)(void *, a_type *), \ 1735 1.1.1.2 christos void *filter_ctx) { \ 1736 1.1.1.2 christos if (!filter_subtree(filter_ctx, node)) { \ 1737 1.1.1.2 christos return NULL; \ 1738 1.1.1.2 christos } \ 1739 1.1.1.2 christos int cmp = a_cmp(start, node); \ 1740 1.1.1.2 christos a_type *ret; \ 1741 1.1.1.2 christos a_type *left = rbtn_left_get(a_type, a_field, node); \ 1742 1.1.1.2 christos a_type *right = rbtn_right_get(a_type, a_field, node); \ 1743 1.1.1.2 christos if (cmp < 0) { \ 1744 1.1.1.2 christos ret = a_prefix##iter_start_filtered(rbtree, start, left, cb, \ 1745 1.1.1.2 christos arg, filter_node, filter_subtree, filter_ctx); \ 1746 1.1.1.2 christos if (ret != NULL) { \ 1747 1.1.1.2 christos return ret; \ 1748 1.1.1.2 christos } \ 1749 1.1.1.2 christos if (filter_node(filter_ctx, node)) { \ 1750 1.1.1.2 christos ret = cb(rbtree, node, arg); \ 1751 1.1.1.2 christos if (ret != NULL) { \ 1752 1.1.1.2 christos return ret; \ 1753 1.1.1.2 christos } \ 1754 1.1.1.2 christos } \ 1755 1.1.1.2 christos return a_prefix##iter_recurse_filtered(rbtree, right, cb, arg, \ 1756 1.1.1.2 christos filter_node, filter_subtree, filter_ctx); \ 1757 1.1.1.2 christos } else if (cmp > 0) { \ 1758 1.1.1.2 christos return a_prefix##iter_start_filtered(rbtree, start, right, \ 1759 1.1.1.2 christos cb, arg, filter_node, filter_subtree, filter_ctx); \ 1760 1.1.1.2 christos } else { \ 1761 1.1.1.2 christos if (filter_node(filter_ctx, node)) { \ 1762 1.1.1.2 christos ret = cb(rbtree, node, arg); \ 1763 1.1.1.2 christos if (ret != NULL) { \ 1764 1.1.1.2 christos return ret; \ 1765 1.1.1.2 christos } \ 1766 1.1.1.2 christos } \ 1767 1.1.1.2 christos return a_prefix##iter_recurse_filtered(rbtree, right, cb, arg, \ 1768 1.1.1.2 christos filter_node, filter_subtree, filter_ctx); \ 1769 1.1.1.2 christos } \ 1770 1.1.1.2 christos } \ 1771 1.1.1.2 christos a_attr a_type * \ 1772 1.1.1.2 christos a_prefix##iter_filtered(a_rbt_type *rbtree, a_type *start, \ 1773 1.1.1.2 christos a_type *(*cb)(a_rbt_type *, a_type *, void *), void *arg, \ 1774 1.1.1.2 christos bool (*filter_node)(void *, a_type *), \ 1775 1.1.1.2 christos bool (*filter_subtree)(void *, a_type *), \ 1776 1.1.1.2 christos void *filter_ctx) { \ 1777 1.1.1.2 christos a_type *ret; \ 1778 1.1.1.2 christos if (start != NULL) { \ 1779 1.1.1.2 christos ret = a_prefix##iter_start_filtered(rbtree, start, \ 1780 1.1.1.2 christos rbtree->rbt_root, cb, arg, filter_node, filter_subtree, \ 1781 1.1.1.2 christos filter_ctx); \ 1782 1.1.1.2 christos } else { \ 1783 1.1.1.2 christos ret = a_prefix##iter_recurse_filtered(rbtree, rbtree->rbt_root, \ 1784 1.1.1.2 christos cb, arg, filter_node, filter_subtree, filter_ctx); \ 1785 1.1.1.2 christos } \ 1786 1.1.1.2 christos return ret; \ 1787 1.1.1.2 christos } \ 1788 1.1.1.2 christos a_attr a_type * \ 1789 1.1.1.2 christos a_prefix##reverse_iter_recurse_filtered(a_rbt_type *rbtree, \ 1790 1.1.1.2 christos a_type *node, a_type *(*cb)(a_rbt_type *, a_type *, void *), \ 1791 1.1.1.2 christos void *arg, \ 1792 1.1.1.2 christos bool (*filter_node)(void *, a_type *), \ 1793 1.1.1.2 christos bool (*filter_subtree)(void *, a_type *), \ 1794 1.1.1.2 christos void *filter_ctx) { \ 1795 1.1.1.2 christos if (node == NULL || !filter_subtree(filter_ctx, node)) { \ 1796 1.1.1.2 christos return NULL; \ 1797 1.1.1.2 christos } \ 1798 1.1.1.2 christos a_type *ret; \ 1799 1.1.1.2 christos a_type *left = rbtn_left_get(a_type, a_field, node); \ 1800 1.1.1.2 christos a_type *right = rbtn_right_get(a_type, a_field, node); \ 1801 1.1.1.2 christos ret = a_prefix##reverse_iter_recurse_filtered(rbtree, right, cb, \ 1802 1.1.1.2 christos arg, filter_node, filter_subtree, filter_ctx); \ 1803 1.1.1.2 christos if (ret != NULL) { \ 1804 1.1.1.2 christos return ret; \ 1805 1.1.1.2 christos } \ 1806 1.1.1.2 christos if (filter_node(filter_ctx, node)) { \ 1807 1.1.1.2 christos ret = cb(rbtree, node, arg); \ 1808 1.1.1.2 christos } \ 1809 1.1.1.2 christos if (ret != NULL) { \ 1810 1.1.1.2 christos return ret; \ 1811 1.1.1.2 christos } \ 1812 1.1.1.2 christos return a_prefix##reverse_iter_recurse_filtered(rbtree, left, cb, \ 1813 1.1.1.2 christos arg, filter_node, filter_subtree, filter_ctx); \ 1814 1.1.1.2 christos } \ 1815 1.1.1.2 christos a_attr a_type * \ 1816 1.1.1.2 christos a_prefix##reverse_iter_start_filtered(a_rbt_type *rbtree, a_type *start,\ 1817 1.1.1.2 christos a_type *node, a_type *(*cb)(a_rbt_type *, a_type *, void *), \ 1818 1.1.1.2 christos void *arg, bool (*filter_node)(void *, a_type *), \ 1819 1.1.1.2 christos bool (*filter_subtree)(void *, a_type *), \ 1820 1.1.1.2 christos void *filter_ctx) { \ 1821 1.1.1.2 christos if (!filter_subtree(filter_ctx, node)) { \ 1822 1.1.1.2 christos return NULL; \ 1823 1.1.1.2 christos } \ 1824 1.1.1.2 christos int cmp = a_cmp(start, node); \ 1825 1.1.1.2 christos a_type *ret; \ 1826 1.1.1.2 christos a_type *left = rbtn_left_get(a_type, a_field, node); \ 1827 1.1.1.2 christos a_type *right = rbtn_right_get(a_type, a_field, node); \ 1828 1.1.1.2 christos if (cmp > 0) { \ 1829 1.1.1.2 christos ret = a_prefix##reverse_iter_start_filtered(rbtree, start, \ 1830 1.1.1.2 christos right, cb, arg, filter_node, filter_subtree, filter_ctx); \ 1831 1.1.1.2 christos if (ret != NULL) { \ 1832 1.1.1.2 christos return ret; \ 1833 1.1.1.2 christos } \ 1834 1.1.1.2 christos if (filter_node(filter_ctx, node)) { \ 1835 1.1.1.2 christos ret = cb(rbtree, node, arg); \ 1836 1.1.1.2 christos if (ret != NULL) { \ 1837 1.1.1.2 christos return ret; \ 1838 1.1.1.2 christos } \ 1839 1.1.1.2 christos } \ 1840 1.1.1.2 christos return a_prefix##reverse_iter_recurse_filtered(rbtree, left, cb,\ 1841 1.1.1.2 christos arg, filter_node, filter_subtree, filter_ctx); \ 1842 1.1.1.2 christos } else if (cmp < 0) { \ 1843 1.1.1.2 christos return a_prefix##reverse_iter_start_filtered(rbtree, start, \ 1844 1.1.1.2 christos left, cb, arg, filter_node, filter_subtree, filter_ctx); \ 1845 1.1.1.2 christos } else { \ 1846 1.1.1.2 christos if (filter_node(filter_ctx, node)) { \ 1847 1.1.1.2 christos ret = cb(rbtree, node, arg); \ 1848 1.1.1.2 christos if (ret != NULL) { \ 1849 1.1.1.2 christos return ret; \ 1850 1.1.1.2 christos } \ 1851 1.1.1.2 christos } \ 1852 1.1.1.2 christos return a_prefix##reverse_iter_recurse_filtered(rbtree, left, cb,\ 1853 1.1.1.2 christos arg, filter_node, filter_subtree, filter_ctx); \ 1854 1.1.1.2 christos } \ 1855 1.1.1.2 christos } \ 1856 1.1.1.2 christos a_attr a_type * \ 1857 1.1.1.2 christos a_prefix##reverse_iter_filtered(a_rbt_type *rbtree, a_type *start, \ 1858 1.1.1.2 christos a_type *(*cb)(a_rbt_type *, a_type *, void *), void *arg, \ 1859 1.1.1.2 christos bool (*filter_node)(void *, a_type *), \ 1860 1.1.1.2 christos bool (*filter_subtree)(void *, a_type *), \ 1861 1.1.1.2 christos void *filter_ctx) { \ 1862 1.1.1.2 christos a_type *ret; \ 1863 1.1.1.2 christos if (start != NULL) { \ 1864 1.1.1.2 christos ret = a_prefix##reverse_iter_start_filtered(rbtree, start, \ 1865 1.1.1.2 christos rbtree->rbt_root, cb, arg, filter_node, filter_subtree, \ 1866 1.1.1.2 christos filter_ctx); \ 1867 1.1.1.2 christos } else { \ 1868 1.1.1.2 christos ret = a_prefix##reverse_iter_recurse_filtered(rbtree, \ 1869 1.1.1.2 christos rbtree->rbt_root, cb, arg, filter_node, filter_subtree, \ 1870 1.1.1.2 christos filter_ctx); \ 1871 1.1.1.2 christos } \ 1872 1.1.1.2 christos return ret; \ 1873 1.1.1.2 christos } \ 1874 1.1.1.2 christos ) /* end rb_summarized_only */ 1875 1.1.1.3 christos /* clang-format on */ 1876 1.1 christos 1877 1.1.1.2 christos #endif /* JEMALLOC_INTERNAL_RB_H */ 1878