Main Page | Class List | Directories | File List | Class Members | File Members

rbtree_low.h

Go to the documentation of this file.
00001 /*
00002 || This file is part of Pike. For copyright information see COPYRIGHT.
00003 || Pike is distributed under GPL, LGPL and MPL. See the file COPYING
00004 || for more information.
00005 || $Id: rbtree_low.h,v 1.8 2004/05/28 09:42:44 mast Exp $
00006 */
00007 
00008 /* The lower level api for using rbtree. This is in a separate file
00009  * since it's quite macro heavy.
00010  *
00011  * Created 2001-04-27 by Martin Stjernholm
00012  */
00013 
00014 #ifndef RBTREE_LOW_H
00015 #define RBTREE_LOW_H
00016 
00017 #include "rbtree.h"
00018 
00019 /* A sliced stack is used to track the way down in a tree, so we can
00020  * back up again easily while rebalancing it. The first slice is
00021  * allocated on the C stack. */
00022 
00023 #define STACK_SLICE_SIZE 20
00024 /* This is in the worst possible case enough for trees of size
00025  * 2^(20/2) = 1024 before allocating another slice, but in the typical
00026  * case it's enough for trees with up to about 2^(20-1) = 524288
00027  * elements. */
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;                   /* Only zero when the stack is empty. */
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 /* Traverses the tree in depth-first order:
00182  * push         Run when entering the node. Preceded by an enter_* label.
00183  * p_leaf       Run when the prev pointer of the node isn't a subtree.
00184  * p_sub        Run when the prev pointer of the node is a subtree.
00185  * between      Run after the prev subtree has been recursed and before
00186  *              the next subtree is examined. Preceded by a between_*
00187  *              label.
00188  * n_leaf       Run when the next pointer of the node isn't a subtree.
00189  * n_sub        Run when the next pointer of the node is a subtree.
00190  * pop          Run when leaving the node. Preceded by a leave_* label.
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           /* Compare with next and not prev to avoid an infinite */     \
00227           /* loop if a node (incorrectly) got prev == next. */          \
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 /* The `cmp' code should set the variable cmp_res to the result of the
00258  * comparison between the key and the current node `node'. */
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 /* Variant of LOW_RB_FIND that assumes that `cmp' never returns 0. */
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 /* Tracks the way down a tree to a specific node and updates the stack
00339  * as necessary for low_rb_link_* and low_rb_unlink_*. */
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 /* Goes to the first node in a tree while keeping the stack updated. */
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 /* Goes to the next node in order while keeping the stack updated. */
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 /* Goes to the previous node in order while keeping the stack updated. */
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 /* An alternative to rb_insert, which might or might not insert the
00449  * newly created node. This one compares nodes like LOW_RB_FIND and
00450  * will only run the code `insert' when a new node actually is to be
00451  * inserted, otherwise it runs the code `replace' on the matching
00452  * existing node. */
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;     /* Got less - link at next. */          \
00462         }, {                                                            \
00463           rb_ins_type_ = 0;     /* Got equal - replace. */              \
00464           {replace;}                                                    \
00465           RBSTACK_FREE (rbstack);                                       \
00466         }, {                                                            \
00467           rb_ins_type_ = 2;     /* Got greater - link at prev. */       \
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 /* Merges the two trees a and b in linear time (no more, no less). The
00483  * operation argument describes the way to merge, like the one given
00484  * to merge() in array.c. cmp does the comparison between a and b to
00485  * cmp_res, copy_a and copy_b copy the nodes a and b resp, to
00486  * new_node. free_a and free_b free the nodes a and b resp. prep_a and
00487  * prep_b is run for every visited node in a and b resp, before any of
00488  * the other code blocks.
00489  *
00490  * The result in res is a list linked by the next pointers, and length
00491  * is set to the length of it. These are suitable for rb_make_tree.
00492  *
00493  * NB: It doesn't handle making duplicates of the same node, i.e.
00494  * PIKE_ARRAY_OP_A without PIKE_ARRAY_OP_SKIP_A. Not a problem since
00495  * none of the currently defined operations use that. */
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; /* Init only to avoid warnings. */            \
00501     /* Traverse backwards so that the merge "gravitates" towards the */ \
00502     /* end when duplicate entries are processed, e.g. */                \
00503     /* (<1:1, 1:2>) | (<1:3>) produces (<1:1, 1:3>) and not */          \
00504     /* (<1:3, 1:2>). */                                                 \
00505                                                                         \
00506     a = rb_last (a);                                                    \
00507     b = rb_last (b);                                                    \
00508     res = 0;                                                            \
00509                                                                         \
00510     while (1) {                                                         \
00511       /* A bit quirky code to avoid expanding the code blocks more */   \
00512       /* than once. */                                                  \
00513       if (a) {prep_a;}                                                  \
00514       if (b) {                                                          \
00515         {prep_b;}                                                       \
00516         if (a) {                                                        \
00517           {cmp;}                                                        \
00518           /* Result reversed due to backward direction. */              \
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  /* RBTREE_H */

Generated on Fri Jul 22 23:44:27 2005 for Pike by  doxygen 1.3.9.1