pike.git / src / rbtree.c

version» Context lines:

pike.git/src/rbtree.c:8:    *    * Created 2001-04-27 by Martin Stjernholm <mast@lysator.liu.se>    */      #include "global.h"      #include "interpret.h"   #include "pike_error.h"   #include "rbtree_low.h"    - #include <stdlib.h> -  +    #if defined (PIKE_DEBUG) || defined (TEST_MULTISET)      DECLSPEC(noreturn) static void debug_rb_fatal (    struct rb_node_hdr *tree,    const char *fmt, ...) ATTRIBUTE((noreturn, format (printf, 2, 3)));   #define rb_fatal \    (fprintf (stderr, "%s:%d: Fatal in rbtree: ", __FILE__, __LINE__), \    debug_rb_fatal)   DECLSPEC(noreturn) static void debug_custom_rb_fatal (    struct rb_node_hdr *tree, dump_data_fn *dump_data,    void *extra, const char *fmt, ...) ATTRIBUTE((noreturn, format (printf, 4, 5)));   #define custom_rb_fatal \    (fprintf (stderr, "%s:%d: Fatal in rbtree: ", __FILE__, __LINE__), \    debug_custom_rb_fatal)    -  + #else + #define rb_fatal Pike_fatal   #endif      void rbstack_low_push (struct rbstack_ptr *rbstack, struct rb_node_hdr *node)   {    struct rbstack_slice *new = ALLOC_STRUCT (rbstack_slice);    new->up = rbstack->slice;    new->stack[0] = node;   #ifdef RB_STATS    rbstack_slice_allocs++;    new->depth = rbstack->slice->depth;
pike.git/src/rbtree.c:110: Inside #if defined(PIKE_DEBUG)
   else if (rbp1.ssp != rbpos.ssp || rbp1.slice != rbpos.slice)    Pike_fatal ("Didn't find the given position on the stack.\n");   #endif    }    }       RBSTACK_POKE (rbp2, node);    *pos = rbp2;   }    - #if 0 - /* Disabled since these aren't tested and not currently used. */ -  - void rbstack_assign (struct rbstack_ptr *target, struct rbstack_ptr *source) - { -  struct rbstack_slice *src_slice = source->slice; -  struct rbstack_slice *tgt_slice = target->slice; -  - #ifdef PIKE_DEBUG -  if (target->ssp) Pike_fatal ("target rbstack not empty.\n"); - #endif -  -  target->ssp = source->ssp; -  source->ssp = 0; -  -  if (src_slice->up) { -  struct rbstack_slice *prev_slice; -  target->slice = src_slice; -  do { -  prev_slice = src_slice; -  src_slice = src_slice->up; -  } while (src_slice->up); -  MEMCPY ((char *) &tgt_slice->stack, (char *) &src_slice->stack, -  STACK_SLICE_SIZE * sizeof (struct rb_node_hdr *)); -  prev_slice->up = tgt_slice; -  source->slice = src_slice; -  } -  else { -  MEMCPY ((char *) &tgt_slice->stack, (char *) &src_slice->stack, -  target->ssp * sizeof (struct rb_node_hdr *)); - #ifdef RB_STATS -  tgt_slice->maxdepth = src_slice->maxdepth; -  tgt_slice->depth = src_slice->depth; - #endif -  } - } -  - void rbstack_copy (struct rbstack_ptr *target, struct rbstack_ptr *source) - { -  struct rbstack_slice *src_slice = source->slice; -  struct rbstack_slice *tgt_stack_slice = target->slice; -  size_t ssp = source->ssp; -  - #ifdef PIKE_DEBUG -  if (target->ssp) Pike_fatal ("target rbstack not empty.\n"); - #endif -  -  target->ssp = ssp; -  -  if (src_slice->up) { -  struct rbstack_slice *tgt_slice = -  target->slice = ALLOC_STRUCT (rbstack_slice); - #ifdef RB_STATS -  rbstack_slice_allocs++; - #endif -  MEMCPY ((char *) &tgt_slice->stack, (char *) &src_slice->stack, -  ssp * sizeof (struct rb_node_hdr *)); -  ssp = STACK_SLICE_SIZE; -  while ((src_slice = src_slice->up)->up) { -  tgt_slice->up = ALLOC_STRUCT (rbstack_slice); -  tgt_slice = tgt_slice->up; - #ifdef RB_STATS -  rbstack_slice_allocs++; - #endif -  MEMCPY ((char *) &tgt_slice->stack, (char *) &src_slice->stack, -  STACK_SLICE_SIZE * sizeof (struct rb_node_hdr *)); -  } -  tgt_slice->up = tgt_stack_slice; -  } -  -  MEMCPY ((char *) &tgt_stack_slice->stack, (char *) &src_slice->stack, -  ssp * sizeof (struct rb_node_hdr *)); -  - #ifdef RB_STATS -  target->slice->maxdepth = target->slice->depth = source->slice->depth; - #endif - } -  - #endif /* Not tested or used. */ -  +    /* Offsets all the rb_node_hdr pointers in rbstack from their offsets    * relative oldbase to the same relative newbase. Useful if the memory    * block containing the tree has been moved. */   void rbstack_shift (struct rbstack_ptr rbstack,    struct rb_node_hdr *oldbase,    struct rb_node_hdr *newbase)   {    struct rb_node_hdr *node;    while ((node = RBSTACK_PEEK (rbstack))) {    rbstack.slice->stack[rbstack.ssp - 1] =
pike.git/src/rbtree.c:275:    } while (0)      /* node ret    * / \ / \    * / \ / \    * ret c ==> a node    * / \ / \    * / \ / \    * a b b c    */ - static INLINE struct rb_node_hdr *rot_right (struct rb_node_hdr *node) + static inline struct rb_node_hdr *rot_right (struct rb_node_hdr *node)   {    /* Note that we don't need to do anything special to keep the    * pointers in a, b and c intact, even if they're thread    * pointers pointing back to node and ret. */    struct rb_node_hdr *ret = node->prev;    if (ret->flags & RB_THREAD_NEXT) {   #ifdef PIKE_DEBUG    if (ret->next != node) rb_fatal (node, "Bogus next thread pointer.\n");   #endif    ret->flags &= ~RB_THREAD_NEXT;
pike.git/src/rbtree.c:303:   }      /* node ret    * / \ / \    * / \ / \    * a ret ==> node c    * / \ / \    * / \ / \    * b c a b    */ - static INLINE struct rb_node_hdr *rot_left (struct rb_node_hdr *node) + static inline struct rb_node_hdr *rot_left (struct rb_node_hdr *node)   {    struct rb_node_hdr *ret = node->next;    if (ret->flags & RB_THREAD_PREV) {   #ifdef PIKE_DEBUG    if (ret->prev != node) rb_fatal (node, "Bogus prev thread pointer.\n");   #endif    ret->flags &= ~RB_THREAD_PREV;    node->flags |= RB_THREAD_NEXT;    }    else {
pike.git/src/rbtree.c:336: Inside #if defined(PIKE_DEBUG)
   RBSTACK_POP (rbstack, parent);   #ifdef PIKE_DEBUG    if (!parent) rb_fatal (node, "No parent on stack.\n");   #endif    RBSTACK_POP (rbstack, grandparent);    top = grandparent ? grandparent : parent;       while (parent->flags & RB_RED) {    /* Since the root always is black we know there's a grandparent. */   #ifdef PIKE_DEBUG -  if (!grandparent) rb_fatal (parent, "No parent for red node.\n"); +  if (UNLIKELY(!grandparent)) rb_fatal (parent, "No parent for red node.\n");   #endif   #ifdef RB_STATS    rb_add_rebalance_cnt++;   #endif       if (parent == grandparent->prev) {    uncle = grandparent->next;       if (!(grandparent->flags & RB_THREAD_NEXT) && uncle->flags & RB_RED) {    /* Case 1:
pike.git/src/rbtree.c:901:    /* Node has two subtrees, so we can't delete it. Find another one    * to replace its data with. */    next = parent = node;    RBSTACK_PUSH (rbstack, node);    for (unlink = node->next; !(unlink->flags & RB_THREAD_PREV); unlink = unlink->prev) {    parent = unlink;    RBSTACK_PUSH (rbstack, unlink);    }       keep_flags (node, -  MEMCPY ((char *) node + OFFSETOF (rb_node_hdr, flags), +  memcpy ((char *) node + OFFSETOF (rb_node_hdr, flags),    (char *) unlink + OFFSETOF (rb_node_hdr, flags),    node_size - OFFSETOF (rb_node_hdr, flags)));       if (parent == node) {    node = unlink->next;    if (unlink->flags & RB_THREAD_NEXT)    parent->flags |= RB_THREAD_NEXT;    else {   #ifdef PIKE_DEBUG    if (!(node->flags & RB_THREAD_PREV))
pike.git/src/rbtree.c:948:    if (!keep_rbstack) RBSTACK_FREE (rbstack);    }    else    *root = rebalance_after_delete (node, &rbstack, keep_rbstack);       if (keep_rbstack) ADJUST_STACK_TO_NEXT (rbstack, next);    *rbstack_ptr = rbstack;    return unlink;   }    - #if 0 - struct rb_node_hdr *low_rb_unlink_with_move (struct rb_node_hdr **root, -  struct rbstack_ptr *rbstack_ptr, -  int keep_rbstack, -  size_t node_size) - { -  struct rb_node_hdr *node = RBSTACK_PEEK (*rbstack_ptr), *next = rb_next (node); -  struct rb_node_hdr *unlink = -  real_low_rb_unlink_with_move (root, rbstack_ptr, 1, node_size); -  debug_check_rbstack (*root, *rbstack_ptr); -  if (node != unlink) next = node; -  if (RBSTACK_PEEK (*rbstack_ptr) != next) -  Pike_fatal ("Stack got %p on top, but next node is %p.\n", -  RBSTACK_PEEK (*rbstack_ptr), next); -  if (!keep_rbstack) RBSTACK_FREE (*rbstack_ptr); -  return unlink; - } - #endif -  +    /* Like low_rb_unlink_with_move, but relinks the nodes instead of    * moving over the data. Somewhat slower unless the size of the nodes    * is large. */   void low_rb_unlink_without_move (struct rb_node_hdr **root,    struct rbstack_ptr *rbstack_ptr,    int keep_rbstack)   {    struct rb_node_hdr *node, *parent, *unlink, *next;    struct rbstack_ptr rbstack = *rbstack_ptr;    int unlink_flags;
pike.git/src/rbtree.c:1044:    if (unlink_flags & RB_RED) {    if (!keep_rbstack) RBSTACK_FREE (rbstack);    }    else    *root = rebalance_after_delete (node, &rbstack, keep_rbstack);       if (keep_rbstack) ADJUST_STACK_TO_NEXT (rbstack, next);    *rbstack_ptr = rbstack;   }    - #if 0 - void low_rb_unlink_without_move (struct rb_node_hdr **root, -  struct rbstack_ptr *rbstack_ptr, -  int keep_rbstack) - { -  struct rb_node_hdr *node = RBSTACK_PEEK (*rbstack_ptr), *next = rb_next (node); -  real_low_rb_unlink_without_move (root, rbstack_ptr, 1); -  debug_check_rbstack (*root, *rbstack_ptr); -  if (RBSTACK_PEEK (*rbstack_ptr) != next) -  Pike_fatal ("Stack got %p on top, but next node is %p.\n", -  RBSTACK_PEEK (*rbstack_ptr), next); -  if (!keep_rbstack) RBSTACK_FREE (*rbstack_ptr); - } - #endif -  +    /* Constructs a stack from the given root down to the given node. The    * stack is constructed at *rbstack_ptr, and it's updated so that the    * node is on its top on return. The given root must be the root of    * the tree - no thread pointers may point to nodes above it.    *    * Note that this operation isn't very cheap - it uses the thread    * pointers to work itself upwards which means it might be more than    * O(log n), but it should be less than O(n). */   void low_rb_build_stack (struct rb_node_hdr *root, struct rb_node_hdr *node,    struct rbstack_ptr *rbstack_ptr)
pike.git/src/rbtree.c:1274: Inside #if defined(ENABLE_UNUSED_RB_FUNCTIONS)
  }      void rb_remove_node (struct rb_node_hdr **root,    rb_find_fn *find_fn, void *key,    struct rb_node_hdr *to_delete)   {    struct rb_node_hdr *node = *root;    RBSTACK_INIT (rbstack);   #ifdef PIKE_DEBUG    if (!node) Pike_fatal ("Tree is empty.\n"); - #if 0 -  if (find_fn (key, to_delete)) -  Pike_fatal ("Given key doesn't match the node to delete.\n"); +    #endif - #endif +     LOW_RB_TRACK_NEQ (rbstack, node, cmp_res = find_fn (key, node) >= 0 ? 1 : -1, ;, ;);    while (node != to_delete) {    LOW_RB_TRACK_PREV (rbstack, node);   #ifdef PIKE_DEBUG    if (!node) Pike_fatal ("Tree doesn't contain the node to delete.\n");   #endif    }    low_rb_unlink_without_move (root, rbstack);   }   
pike.git/src/rbtree.c:1328: Inside #if defined(ENABLE_UNUSED_RB_FUNCTIONS)
   * node_size. */   struct rb_node_hdr *rb_remove_node_with_move (struct rb_node_hdr **root,    rb_find_fn *find_fn, void *key,    struct rb_node_hdr *to_delete,    size_t node_size)   {    struct rb_node_hdr *node = *root;    RBSTACK_INIT (rbstack);   #ifdef PIKE_DEBUG    if (!node) Pike_fatal ("Tree is empty.\n"); - #if 0 -  if (find_fn (key, to_delete)) -  Pike_fatal ("Given key doesn't match the node to delete.\n"); +    #endif - #endif +     LOW_RB_TRACK_NEQ (rbstack, node, cmp_res = find_fn (key, node) >= 0 ? 1 : -1, ;, ;);    while (node != to_delete) {    LOW_RB_TRACK_PREV (rbstack, node);   #ifdef PIKE_DEBUG    if (!node) Pike_fatal ("Tree doesn't contain the node to delete.\n");   #endif    }    return low_rb_unlink_with_move (root, rbstack, node_size);   }   
pike.git/src/rbtree.c:1734: Inside #if defined(RB_STATS)
  size_t rb_num_finds = 0, rb_find_depth = 0;   size_t rb_num_sidesteps = 0, rb_num_sidestep_ops = 0;   size_t rb_num_tracks = 0, rb_track_depth = 0;   size_t rb_num_sidetracks = 0, rb_num_sidetrack_ops = 0;   size_t rb_max_depth = 0;   size_t rb_num_traverses = 0, rb_num_traverse_ops = 0;   size_t rbstack_slice_allocs = 0;   size_t rb_num_adds = 0, rb_add_rebalance_cnt = 0;   size_t rb_num_deletes = 0, rb_del_rebalance_cnt = 0;    - void reset_rb_stats() + void reset_rb_stats(void)   {    rb_num_sidesteps = rb_num_sidestep_ops = 0;    rb_num_finds = rb_find_depth = 0;    rb_num_tracks = rb_track_depth = 0;    rb_num_sidetracks = rb_num_sidetrack_ops = 0;    rb_max_depth = 0;    rb_num_traverses = rb_num_traverse_ops = 0;    rbstack_slice_allocs = 0;    rb_num_adds = rb_add_rebalance_cnt = 0;    rb_num_deletes = rb_del_rebalance_cnt = 0;
pike.git/src/rbtree.c:1903: Inside #if defined (PIKE_DEBUG) || defined (TEST_MULTISET)
      if (pos && ptr_node == (void *) (ptrdiff_t) -1)    fputs ("(pos outside stack)", stderr);    fputc ('\n', stderr);   }      static void debug_rb_fatal (struct rb_node_hdr *tree, const char *fmt, ...)   {    va_list args;    va_start (args, fmt); -  (void) VFPRINTF (stderr, fmt, args); +  (void) vfprintf (stderr, fmt, args);    fputs ("Dumping tree:\n", stderr);    debug_dump_rb_tree (tree, NULL, NULL);    debug_fatal ("\r");   }      static void debug_custom_rb_fatal (struct rb_node_hdr *tree, dump_data_fn *dump_data,    void *extra, const char *fmt, ...)   {    va_list args;    va_start (args, fmt); -  (void) VFPRINTF (stderr, fmt, args); +  (void) vfprintf (stderr, fmt, args);    fputs ("Dumping tree:\n", stderr);    debug_dump_rb_tree (tree, dump_data, extra);    debug_fatal ("\r");   }      void debug_check_rb_tree (struct rb_node_hdr *root, dump_data_fn *dump_data, void *extra)   {    if (root) {    struct rb_node_hdr *node = root, *n, *n2;    struct rbstack_ptr p;