00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #ifndef RBTREE_LOW_H
00015 #define RBTREE_LOW_H
00016
00017 #include "rbtree.h"
00018
00019
00020
00021
00022
00023 #define STACK_SLICE_SIZE 20
00024
00025
00026
00027
00028
00029 struct rbstack_slice
00030 {
00031 #ifdef RB_STATS
00032 size_t depth, maxdepth;
00033 #endif
00034 struct rbstack_slice *up;
00035 struct rb_node_hdr *stack[STACK_SLICE_SIZE];
00036 };
00037
00038 struct rbstack_ptr
00039 {
00040 struct rbstack_slice *slice;
00041 size_t ssp;
00042 };
00043
00044 void rbstack_push (struct rbstack_ptr *rbstack, struct rb_node_hdr *node);
00045 void rbstack_pop (struct rbstack_ptr *rbstack);
00046 void rbstack_up (struct rbstack_ptr *rbstack);
00047 void rbstack_up_to_root (struct rbstack_ptr *rbstack);
00048 void rbstack_free (struct rbstack_ptr *rbstack);
00049 void rbstack_insert (struct rbstack_ptr *top, struct rbstack_ptr *pos,
00050 struct rb_node_hdr *node);
00051 void rbstack_assign (struct rbstack_ptr *target, struct rbstack_ptr *source);
00052 void rbstack_copy (struct rbstack_ptr *target, struct rbstack_ptr *source);
00053 void rbstack_shift (struct rbstack_ptr rbstack,
00054 struct rb_node_hdr *oldbase,
00055 struct rb_node_hdr *newbase);
00056
00057 #define RBSTACK_INIT(rbstack) \
00058 struct rbstack_slice PIKE_CONCAT3 (_, rbstack, _top_) = { \
00059 DO_IF_RB_STATS (0 COMMA 0 COMMA) \
00060 NULL, \
00061 {NULL,} \
00062 }; \
00063 struct rbstack_ptr rbstack = { \
00064 NULL, \
00065 0 \
00066 }; \
00067 rbstack.slice = &PIKE_CONCAT3 (_, rbstack, _top_)
00068
00069 #define RBSTACK_PUSH(rbstack, node) do { \
00070 if ((rbstack).ssp < STACK_SLICE_SIZE) { \
00071 (rbstack).slice->stack[(rbstack).ssp++] = (node); \
00072 } \
00073 else rbstack_push (&(rbstack), node); \
00074 DO_IF_RB_STATS ( \
00075 if (++(rbstack).slice->depth > (rbstack).slice->maxdepth) \
00076 (rbstack).slice->maxdepth = (rbstack).slice->depth; \
00077 ); \
00078 } while (0)
00079
00080 #define RBSTACK_POP(rbstack, node) do { \
00081 if ((rbstack).ssp) { \
00082 (node) = (rbstack).slice->stack[--(rbstack).ssp]; \
00083 DO_IF_RB_STATS ((rbstack).slice->depth--); \
00084 if (!(rbstack).ssp && (rbstack).slice->up) \
00085 rbstack_pop (&(rbstack)); \
00086 } \
00087 else (node) = NULL; \
00088 } while (0)
00089
00090 #define RBSTACK_POP_IGNORE(rbstack) do { \
00091 if ((rbstack).ssp && !--(rbstack).ssp) { \
00092 DO_IF_RB_STATS ((rbstack).slice->depth--); \
00093 if ((rbstack).slice->up) \
00094 rbstack_pop (&(rbstack)); \
00095 } \
00096 } while (0)
00097
00098 #define RBSTACK_UP(rbstack, node) do { \
00099 if ((rbstack).ssp) { \
00100 (node) = (rbstack).slice->stack[--(rbstack).ssp]; \
00101 if (!(rbstack).ssp && (rbstack).slice->up) \
00102 rbstack_up (&(rbstack)); \
00103 } \
00104 else (node) = NULL; \
00105 } while (0)
00106
00107 #define RBSTACK_UP_IGNORE(rbstack) do { \
00108 if ((rbstack).ssp && !--(rbstack).ssp && (rbstack).slice->up) \
00109 rbstack_up (&(rbstack)); \
00110 } while (0)
00111
00112 #define RBSTACK_PEEK(rbstack) \
00113 ((rbstack).ssp ? (rbstack).slice->stack[(rbstack).ssp - 1] : NULL)
00114
00115 #define RBSTACK_POKE(rbstack, node) do { \
00116 DO_IF_DEBUG (if (!(rbstack).ssp) Pike_fatal ("Using free stack pointer.\n")); \
00117 (rbstack).slice->stack[(rbstack).ssp - 1] = (node); \
00118 } while (0)
00119
00120 #define RBSTACK_UP_TO_ROOT(rbstack, node) do { \
00121 if ((rbstack).ssp) { \
00122 rbstack_up_to_root (&(rbstack)); \
00123 (node) = (rbstack).slice->stack[0]; \
00124 } \
00125 } while (0)
00126
00127 #define RBSTACK_FREE(rbstack) do { \
00128 if ((rbstack).ssp) { \
00129 if ((rbstack).slice->up) rbstack_free (&(rbstack)); \
00130 (rbstack).ssp = 0; \
00131 } \
00132 DO_IF_RB_STATS ( \
00133 rb_num_tracks++; \
00134 rb_track_depth += (rbstack).slice->maxdepth; \
00135 if ((rbstack).slice->maxdepth > rb_max_depth) \
00136 rb_max_depth = (rbstack).slice->maxdepth; \
00137 (rbstack).slice->depth = (rbstack).slice->maxdepth = 0; \
00138 ); \
00139 } while (0)
00140
00141 #define RBSTACK_FREE_SET_ROOT(rbstack, node) do { \
00142 if ((rbstack).ssp) { \
00143 if ((rbstack).slice->up) rbstack_free (&(rbstack)); \
00144 (rbstack).ssp = 0; \
00145 (node) = (rbstack).slice->stack[0]; \
00146 } \
00147 DO_IF_RB_STATS ( \
00148 rb_num_tracks++; \
00149 rb_track_depth += (rbstack).slice->maxdepth; \
00150 if ((rbstack).slice->maxdepth > rb_max_depth) \
00151 rb_max_depth = (rbstack).slice->maxdepth; \
00152 (rbstack).slice->depth = (rbstack).slice->maxdepth = 0; \
00153 ); \
00154 } while (0)
00155
00156 void low_rb_init_root (struct rb_node_hdr *new_root);
00157 void low_rb_link_at_prev (struct rb_node_hdr **root, struct rbstack_ptr rbstack,
00158 struct rb_node_hdr *new);
00159 void low_rb_link_at_next (struct rb_node_hdr **root, struct rbstack_ptr rbstack,
00160 struct rb_node_hdr *new);
00161 struct rb_node_hdr *low_rb_unlink_with_move (struct rb_node_hdr **root,
00162 struct rbstack_ptr *rbstack_ptr,
00163 int keep_rbstack,
00164 size_t node_size);
00165 void low_rb_unlink_without_move (struct rb_node_hdr **root,
00166 struct rbstack_ptr *rbstack_ptr,
00167 int keep_rbstack);
00168 void low_rb_build_stack (struct rb_node_hdr *root, struct rb_node_hdr *node,
00169 struct rbstack_ptr *rbstack);
00170
00171 #if defined (PIKE_DEBUG) || defined (TEST_MULTISET)
00172
00173 typedef void dump_data_fn (struct rb_node_hdr *node, void *extra);
00174 void debug_dump_rb_tree (struct rb_node_hdr *root, dump_data_fn *dump_data, void *extra);
00175 void debug_dump_rbstack (struct rbstack_ptr rbstack, struct rbstack_ptr *pos);
00176 void debug_check_rb_tree (struct rb_node_hdr *root, dump_data_fn *dump_data, void *extra);
00177 void debug_check_rbstack (struct rb_node_hdr *root, struct rbstack_ptr rbstack);
00178
00179 #endif
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192 #define LOW_RB_TRAVERSE(label, rbstack, node, push, p_leaf, p_sub, \
00193 between, n_leaf, n_sub, pop) \
00194 do { \
00195 DO_IF_RB_STATS (rb_num_traverses++); \
00196 if (node) { \
00197 PIKE_CONCAT (enter_, label): \
00198 DO_IF_RB_STATS (rb_num_traverse_ops++); \
00199 {push;} \
00200 if ((node)->flags & RB_THREAD_PREV) \
00201 {p_leaf;} \
00202 else { \
00203 {p_sub;} \
00204 RBSTACK_PUSH (rbstack, node); \
00205 (node) = (node)->prev; \
00206 goto PIKE_CONCAT (enter_, label); \
00207 } \
00208 PIKE_CONCAT (between_, label): \
00209 {between;} \
00210 if ((node)->flags & RB_THREAD_NEXT) \
00211 {n_leaf;} \
00212 else { \
00213 {n_sub;} \
00214 RBSTACK_PUSH (rbstack, node); \
00215 (node) = (node)->next; \
00216 goto PIKE_CONCAT (enter_, label); \
00217 } \
00218 while (1) { \
00219 PIKE_CONCAT (leave_, label): \
00220 DO_IF_RB_STATS (rb_num_traverse_ops++); \
00221 {pop;} \
00222 { \
00223 struct rb_node_hdr *rb_last_ = (node); \
00224 RBSTACK_POP (rbstack, node); \
00225 if (!(node)) break; \
00226 \
00227 \
00228 if (rb_last_ != (node)->next) \
00229 goto PIKE_CONCAT (between_, label); \
00230 } \
00231 } \
00232 } \
00233 } while (0)
00234
00235 #define LOW_RB_DEBUG_TRAVERSE(label, rbstack, node, push, p_leaf, p_sub, \
00236 between, n_leaf, n_sub, pop) \
00237 do { \
00238 size_t PIKE_CONCAT (depth_, label) = 0; \
00239 LOW_RB_TRAVERSE( \
00240 label, rbstack, node, \
00241 fprintf (stderr, "%*s%p enter\n", \
00242 PIKE_CONCAT (depth_, label)++, "", node); {push;}, \
00243 fprintf (stderr, "%*s%p prev leaf\n", \
00244 PIKE_CONCAT (depth_, label), "", node); {p_leaf;}, \
00245 fprintf (stderr, "%*s%p prev subtree\n", \
00246 PIKE_CONCAT (depth_, label), "", node); {p_sub;}, \
00247 fprintf (stderr, "%*s%p between\n", \
00248 PIKE_CONCAT (depth_, label) - 1, "", node); {between;}, \
00249 fprintf (stderr, "%*s%p next leaf\n", \
00250 PIKE_CONCAT (depth_, label), "", node); {n_leaf;}, \
00251 fprintf (stderr, "%*s%p next subtree\n", \
00252 PIKE_CONCAT (depth_, label), "", node); {n_sub;}, \
00253 fprintf (stderr, "%*s%p leave\n", \
00254 --PIKE_CONCAT (depth_, label), "", node); {pop;}); \
00255 } while (0)
00256
00257
00258
00259 #define LOW_RB_FIND(node, cmp, got_lt, got_eq, got_gt) \
00260 do { \
00261 int cmp_res, found_eq_ = 0; \
00262 DO_IF_RB_STATS ( \
00263 size_t stat_depth_count_ = 0; \
00264 rb_num_finds++; \
00265 ); \
00266 while (1) { \
00267 DO_IF_DEBUG (if (!node) Pike_fatal ("Recursing into null node.\n")); \
00268 DO_IF_RB_STATS ( \
00269 if (++stat_depth_count_ > rb_max_depth) \
00270 rb_max_depth = stat_depth_count_; \
00271 rb_find_depth++; \
00272 ); \
00273 {cmp;} \
00274 if (cmp_res < 0) \
00275 if ((node)->flags & RB_THREAD_PREV) \
00276 if (found_eq_) \
00277 (node) = (node)->prev; \
00278 else { \
00279 {got_gt;} \
00280 break; \
00281 } \
00282 else { \
00283 (node) = (node)->prev; \
00284 continue; \
00285 } \
00286 else \
00287 if ((node)->flags & RB_THREAD_NEXT) \
00288 if (!cmp_res) \
00289 {} \
00290 else { \
00291 {got_lt;} \
00292 break; \
00293 } \
00294 else { \
00295 if (!cmp_res) found_eq_ = 1; \
00296 (node) = (node)->next; \
00297 continue; \
00298 } \
00299 {got_eq;} \
00300 break; \
00301 } \
00302 } while (0)
00303
00304
00305 #define LOW_RB_FIND_NEQ(node, cmp, got_lt, got_gt) \
00306 do { \
00307 int cmp_res; \
00308 DO_IF_RB_STATS ( \
00309 size_t stat_depth_count_ = 0; \
00310 rb_num_finds++; \
00311 ); \
00312 while (1) { \
00313 DO_IF_DEBUG (if (!node) Pike_fatal ("Recursing into null node.\n")); \
00314 DO_IF_RB_STATS ( \
00315 if (++stat_depth_count_ > rb_max_depth) \
00316 rb_max_depth = stat_depth_count_; \
00317 rb_find_depth++; \
00318 ); \
00319 {cmp;} \
00320 if (cmp_res < 0) { \
00321 if ((node)->flags & RB_THREAD_PREV) { \
00322 {got_gt;} \
00323 break; \
00324 } \
00325 (node) = (node)->prev; \
00326 } \
00327 else { \
00328 DO_IF_DEBUG (if (!cmp_res) Pike_fatal ("cmp_res 0 not expected.\n")); \
00329 if ((node)->flags & RB_THREAD_NEXT) { \
00330 {got_lt;} \
00331 break; \
00332 } \
00333 (node) = (node)->next; \
00334 } \
00335 } \
00336 } while (0)
00337
00338
00339
00340 #define LOW_RB_TRACK(rbstack, node, cmp, got_lt, got_eq, got_gt) \
00341 do { \
00342 DO_IF_DEBUG ( \
00343 if (RBSTACK_PEEK (rbstack)) Pike_fatal ("The stack is not empty.\n"); \
00344 ); \
00345 DO_IF_RB_STATS (rb_num_finds--); \
00346 LOW_RB_FIND ( \
00347 node, \
00348 { \
00349 DO_IF_RB_STATS (rb_find_depth--); \
00350 RBSTACK_PUSH (rbstack, node); \
00351 {cmp;} \
00352 }, \
00353 got_lt, \
00354 { \
00355 while ((node) != RBSTACK_PEEK (rbstack)) \
00356 RBSTACK_POP_IGNORE (rbstack); \
00357 {got_eq;} \
00358 }, got_gt); \
00359 } while (0)
00360
00361 #define LOW_RB_TRACK_NEQ(rbstack, node, cmp, got_lt, got_gt) \
00362 do { \
00363 DO_IF_DEBUG ( \
00364 if (RBSTACK_PEEK (rbstack)) Pike_fatal ("The stack is not empty.\n"); \
00365 ); \
00366 DO_IF_RB_STATS (rb_num_finds--); \
00367 LOW_RB_FIND_NEQ ( \
00368 node, \
00369 { \
00370 DO_IF_RB_STATS (rb_find_depth--); \
00371 RBSTACK_PUSH (rbstack, node); \
00372 {cmp;} \
00373 }, \
00374 got_lt, got_gt); \
00375 } while (0)
00376
00377
00378 #define LOW_RB_TRACK_FIRST(rbstack, node) \
00379 do { \
00380 DO_IF_DEBUG ( \
00381 if (RBSTACK_PEEK (rbstack)) Pike_fatal ("The stack is not empty.\n"); \
00382 ); \
00383 DO_IF_RB_STATS (rb_num_sidetracks++); \
00384 if (node) { \
00385 struct rb_node_hdr *rb_prev_ = node->prev; \
00386 RBSTACK_PUSH (rbstack, node); \
00387 DO_IF_RB_STATS (rb_num_sidetrack_ops++); \
00388 while (rb_prev_) { \
00389 RBSTACK_PUSH (rbstack, node = rb_prev_); \
00390 DO_IF_RB_STATS (rb_num_sidetrack_ops++); \
00391 rb_prev_ = node->prev; \
00392 } \
00393 } \
00394 } while (0)
00395
00396
00397 #define LOW_RB_TRACK_NEXT(rbstack, node) \
00398 do { \
00399 DO_IF_DEBUG ( \
00400 if (node != RBSTACK_PEEK (rbstack)) \
00401 Pike_fatal ("Given node is not on top of stack.\n"); \
00402 ); \
00403 DO_IF_RB_STATS (rb_num_sidetracks++); \
00404 if (node->flags & RB_THREAD_NEXT) { \
00405 struct rb_node_hdr *rb_next_ = node->next; \
00406 while ((node = RBSTACK_PEEK (rbstack)) != rb_next_) { \
00407 RBSTACK_POP_IGNORE (rbstack); \
00408 DO_IF_RB_STATS (rb_num_sidetrack_ops++); \
00409 } \
00410 } \
00411 else { \
00412 node = node->next; \
00413 while (1) { \
00414 RBSTACK_PUSH (rbstack, node); \
00415 DO_IF_RB_STATS (rb_num_sidetrack_ops++); \
00416 if (node->flags & RB_THREAD_PREV) break; \
00417 node = node->prev; \
00418 } \
00419 } \
00420 } while (0)
00421
00422
00423 #define LOW_RB_TRACK_PREV(rbstack, node) \
00424 do { \
00425 DO_IF_DEBUG ( \
00426 if (node != RBSTACK_PEEK (rbstack)) \
00427 Pike_fatal ("Given node is not on top of stack.\n"); \
00428 ); \
00429 DO_IF_RB_STATS (rb_num_sidetracks++); \
00430 if (node->flags & RB_THREAD_PREV) { \
00431 struct rb_node_hdr *rb_prev_ = node->prev; \
00432 while ((node = RBSTACK_PEEK (rbstack)) != rb_prev_) { \
00433 RBSTACK_POP_IGNORE (rbstack); \
00434 DO_IF_RB_STATS (rb_num_sidetrack_ops++); \
00435 } \
00436 } \
00437 else { \
00438 node = node->prev; \
00439 while (1) { \
00440 RBSTACK_PUSH (rbstack, node); \
00441 DO_IF_RB_STATS (rb_num_sidetrack_ops++); \
00442 if (node->flags & RB_THREAD_NEXT) break; \
00443 node = node->next; \
00444 } \
00445 } \
00446 } while (0)
00447
00448
00449
00450
00451
00452
00453 #define LOW_RB_INSERT(tree, node, cmp, insert, replace) \
00454 do { \
00455 int rb_ins_type_; \
00456 RBSTACK_INIT (rbstack); \
00457 if (((node) = *(tree))) { \
00458 LOW_RB_TRACK ( \
00459 rbstack, node, cmp, \
00460 { \
00461 rb_ins_type_ = 1; \
00462 }, { \
00463 rb_ins_type_ = 0; \
00464 {replace;} \
00465 RBSTACK_FREE (rbstack); \
00466 }, { \
00467 rb_ins_type_ = 2; \
00468 }); \
00469 } \
00470 else rb_ins_type_ = 3; \
00471 if (rb_ins_type_) { \
00472 DO_IF_DEBUG ((node) = 0); \
00473 {insert;} \
00474 switch (rb_ins_type_) { \
00475 case 1: low_rb_link_at_next ((tree), rbstack, (node)); break; \
00476 case 2: low_rb_link_at_prev ((tree), rbstack, (node)); break; \
00477 case 3: low_rb_init_root (*(tree) = (node)); break; \
00478 } \
00479 } \
00480 } while (0)
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496 #define LOW_RB_MERGE(label, a, b, res, length, operation, \
00497 prep_a, prep_b, cmp, copy_a, free_a, copy_b, free_b) \
00498 do { \
00499 struct rb_node_hdr *new_node; \
00500 int cmp_res, op_ = 0; \
00501 \
00502 \
00503 \
00504 \
00505 \
00506 a = rb_last (a); \
00507 b = rb_last (b); \
00508 res = 0; \
00509 \
00510 while (1) { \
00511 \
00512 \
00513 if (a) {prep_a;} \
00514 if (b) { \
00515 {prep_b;} \
00516 if (a) { \
00517 {cmp;} \
00518 \
00519 if (cmp_res > 0) \
00520 op_ = operation >> 8; \
00521 else if (cmp_res < 0) \
00522 op_ = operation; \
00523 else \
00524 op_ = operation >> 4; \
00525 } \
00526 else if (operation & PIKE_ARRAY_OP_B) \
00527 goto PIKE_CONCAT (label, _copy_b); \
00528 else \
00529 goto PIKE_CONCAT (label, _free_b); \
00530 } \
00531 else \
00532 if (a) \
00533 if (operation & (PIKE_ARRAY_OP_A << 8)) \
00534 goto PIKE_CONCAT (label, _copy_a); \
00535 else \
00536 goto PIKE_CONCAT (label, _free_a); \
00537 else \
00538 break; \
00539 \
00540 if (op_ & PIKE_ARRAY_OP_B) { \
00541 PIKE_CONCAT (label, _copy_b):; \
00542 {copy_b;} \
00543 new_node->next = res, res = new_node; \
00544 length++; \
00545 b = rb_prev (b); \
00546 } \
00547 else if (op_ & PIKE_ARRAY_OP_SKIP_B) { \
00548 PIKE_CONCAT (label, _free_b):; \
00549 new_node = rb_prev (b); \
00550 {free_b;} \
00551 b = new_node; \
00552 } \
00553 \
00554 if (a) { \
00555 if (op_ & PIKE_ARRAY_OP_A) { \
00556 if (!(op_ & PIKE_ARRAY_OP_B)) { \
00557 PIKE_CONCAT (label, _copy_a):; \
00558 {copy_a;} \
00559 new_node->next = res, res = new_node; \
00560 length++; \
00561 a = rb_prev (a); \
00562 } \
00563 } \
00564 else if (op_ & PIKE_ARRAY_OP_SKIP_A) { \
00565 PIKE_CONCAT (label, _free_a):; \
00566 new_node = rb_prev (a); \
00567 {free_a;} \
00568 a = new_node; \
00569 } \
00570 } \
00571 } \
00572 } while (0)
00573
00574 #endif