]> pd.if.org Git - jsw/blobdiff - jsw_atree.c
removed dos line ending carriage return
[jsw] / jsw_atree.c
index 0029dde4ceda39ca302f50b0401811b18f897f66..ba66bd0ccb6eb984c285a178c2b6f93383de0122 100644 (file)
-/*\r
-  Andersson tree library\r
-\r
-    > Created (Julienne Walker): September 10, 2005\r
-    > Corrections (James Bucanek): April 10, 2006\r
-      1) Typo in jsw_aerase:\r
-           up != 0 should be top != 0\r
-      2) Bug in jsw_aerase:\r
-           skew ( path[top] ) should be skew ( up )\r
-           split ( path[top] ) should be split ( up )\r
-      3) Bug in skew and split macros:\r
-           Condition should test for nil\r
-      4) Bug in jsw_aerase:\r
-           Search for successor should save the path\r
-*/\r
-#include "jsw_atree.h"\r
-\r
-#ifdef __cplusplus\r
-#include <cstdlib>\r
-\r
-using std::malloc;\r
-using std::free;\r
-using std::size_t;\r
-#else\r
-#include <stdlib.h>\r
-#endif\r
-\r
-#ifndef HEIGHT_LIMIT\r
-#define HEIGHT_LIMIT 64 /* Tallest allowable tree */\r
-#endif\r
-\r
-typedef struct jsw_anode {\r
-  int               level;   /* Horizontal level for balance */\r
-  void             *data;    /* User-defined content */\r
-  struct jsw_anode *link[2]; /* Left (0) and right (1) links */\r
-} jsw_anode_t;\r
-\r
-struct jsw_atree {\r
-  jsw_anode_t *root; /* Top of the tree */\r
-  jsw_anode_t *nil;  /* End of tree sentinel */\r
-  cmp_f        cmp;  /* Compare two items */\r
-  dup_f        dup;  /* Clone an item (user-defined) */\r
-  rel_f        rel;  /* Destroy an item (user-defined) */\r
-  size_t       size; /* Number of items (user-defined) */\r
-};\r
-\r
-struct jsw_atrav {\r
-  jsw_atree_t *tree;               /* Paired tree */\r
-  jsw_anode_t *it;                 /* Current node */\r
-  jsw_anode_t *path[HEIGHT_LIMIT]; /* Traversal path */\r
-  size_t       top;                /* Top of stack */\r
-};\r
-\r
-/* Remove left horizontal links */\r
-#define skew(t) do {                                      \\r
-  if ( t->link[0]->level == t->level && t->level != 0 ) { \\r
-    jsw_anode_t *save = t->link[0];                       \\r
-    t->link[0] = save->link[1];                           \\r
-    save->link[1] = t;                                    \\r
-    t = save;                                             \\r
-  }                                                       \\r
-} while(0)\r
-\r
-/* Remove consecutive horizontal links */\r
-#define split(t) do {                                              \\r
-  if ( t->link[1]->link[1]->level == t->level && t->level != 0 ) { \\r
-    jsw_anode_t *save = t->link[1];                                \\r
-    t->link[1] = save->link[0];                                    \\r
-    save->link[0] = t;                                             \\r
-    t = save;                                                      \\r
-    ++t->level;                                                    \\r
-  }                                                                \\r
-} while(0)\r
-\r
-static jsw_anode_t *new_node ( jsw_atree_t *tree, void *data )\r
-{\r
-  jsw_anode_t *rn = (jsw_anode_t *)malloc ( sizeof *rn );\r
-\r
-  if ( rn == NULL )\r
-    return tree->nil;\r
-\r
-  rn->level = 1;\r
-  rn->data = tree->dup ( data );\r
-  rn->link[0] = rn->link[1] = tree->nil;\r
-\r
-  return rn;\r
-}\r
-\r
-jsw_atree_t *jsw_anew ( cmp_f cmp, dup_f dup, rel_f rel )\r
-{\r
-  jsw_atree_t *rt = (jsw_atree_t *)malloc ( sizeof *rt );\r
-\r
-  if ( rt == NULL )\r
-    return NULL;\r
-\r
-  /* Initialize sentinel */\r
-  rt->nil = (jsw_anode_t *)malloc ( sizeof *rt->nil );\r
-  if ( rt->nil == NULL ) {\r
-    free ( rt );\r
-    return NULL;\r
-  }\r
-\r
-  rt->nil->data = NULL; /* Simplifies some ops */\r
-  rt->nil->level = 0;\r
-  rt->nil->link[0] = rt->nil->link[1] = rt->nil;\r
-\r
-  /* Initialize tree */\r
-  rt->root = rt->nil;\r
-  rt->cmp = cmp;\r
-  rt->dup = dup;\r
-  rt->rel = rel;\r
-  rt->size = 0;\r
-\r
-  return rt;\r
-}\r
-\r
-void jsw_adelete ( jsw_atree_t *tree )\r
-{\r
-  jsw_anode_t *it = tree->root;\r
-  jsw_anode_t *save;\r
-\r
-  /* Destruction by rotation */\r
-  while ( it != tree->nil ) {\r
-    if ( it->link[0] == tree->nil ) {\r
-      /* Remove node */\r
-      save = it->link[1];\r
-      tree->rel ( it->data );\r
-      free ( it );\r
-    }\r
-    else {\r
-      /* Rotate right */\r
-      save = it->link[0];\r
-      it->link[0] = save->link[1];\r
-      save->link[1] = it;\r
-    }\r
-\r
-    it = save;\r
-  }\r
-\r
-  /* Finalize destruction */\r
-  free ( tree->nil );\r
-  free ( tree );\r
-}\r
-\r
-void *jsw_afind ( jsw_atree_t *tree, void *data )\r
-{\r
-  jsw_anode_t *it = tree->root;\r
-\r
-  while ( it != tree->nil ) {\r
-    int cmp = tree->cmp ( it->data, data );\r
-\r
-    if ( cmp == 0 )\r
-      break;\r
-\r
-    it = it->link[cmp < 0];\r
-  }\r
-\r
-  /* nil->data == NULL */\r
-  return it->data;\r
-}\r
-\r
-int jsw_ainsert ( jsw_atree_t *tree, void *data )\r
-{\r
-  if ( tree->root == tree->nil ) {\r
-    /* Empty tree case */\r
-    tree->root = new_node ( tree, data );\r
-    if ( tree->root == tree->nil )\r
-      return 0;\r
-  }\r
-  else {\r
-    jsw_anode_t *it = tree->root;\r
-    jsw_anode_t *path[HEIGHT_LIMIT];\r
-    int top = 0, dir;\r
-\r
-    /* Find a spot and save the path */\r
-    for ( ; ; ) {\r
-      path[top++] = it;\r
-      dir = tree->cmp ( it->data, data ) < 0;\r
-\r
-      if ( it->link[dir] == tree->nil )\r
-        break;\r
-\r
-      it = it->link[dir];\r
-    }\r
-\r
-    /* Create a new item */\r
-    it->link[dir] = new_node ( tree, data );\r
-    if ( it->link[dir] == tree->nil )\r
-      return 0;\r
-\r
-    /* Walk back and rebalance */\r
-    while ( --top >= 0 ) {\r
-      /* Which child? */\r
-      if ( top != 0 )\r
-        dir = path[top - 1]->link[1] == path[top];\r
-\r
-      skew ( path[top] );\r
-      split ( path[top] );\r
-\r
-      /* Fix the parent */\r
-      if ( top != 0 )\r
-        path[top - 1]->link[dir] = path[top];\r
-      else\r
-        tree->root = path[top];\r
-    }\r
-  }\r
-\r
-  ++tree->size;\r
-\r
-  return 1;\r
-}\r
-\r
-int jsw_aerase ( jsw_atree_t *tree, void *data )\r
-{\r
-  if ( tree->root == tree->nil )\r
-    return 0;\r
-  else {\r
-    jsw_anode_t *it = tree->root;\r
-    jsw_anode_t *path[HEIGHT_LIMIT];\r
-    int top = 0, dir, cmp;\r
-\r
-    /* Find node to remove and save path */\r
-    for ( ; ; ) {\r
-      path[top++] = it;\r
-\r
-      if ( it == tree->nil )\r
-        return 0;\r
-\r
-      cmp = tree->cmp ( it->data, data );\r
-      if ( cmp == 0 )\r
-        break;\r
-\r
-      dir = cmp < 0;\r
-      it = it->link[dir];\r
-    }\r
-\r
-    /* Remove the found node */\r
-    if ( it->link[0] == tree->nil\r
-      || it->link[1] == tree->nil )\r
-    {\r
-      /* Single child case */\r
-      int dir2 = it->link[0] == tree->nil;\r
-\r
-      /* Unlink the item */\r
-      if ( --top != 0 )\r
-        path[top - 1]->link[dir] = it->link[dir2];\r
-      else\r
-        tree->root = it->link[1];\r
-\r
-      tree->rel ( it->data );\r
-      free ( it );\r
-    }\r
-    else {\r
-      /* Two child case */\r
-      jsw_anode_t *heir = it->link[1];\r
-      jsw_anode_t *prev = it;\r
-\r
-      while ( heir->link[0] != tree->nil ) {\r
-        path[top++] = prev = heir;\r
-        heir = heir->link[0];\r
-      }\r
-\r
-      /*\r
-        Order is important!\r
-        (free item, replace item, free heir)\r
-      */\r
-      tree->rel ( it->data );\r
-      it->data = heir->data;\r
-      prev->link[prev == it] = heir->link[1];\r
-      free ( heir );\r
-    }\r
-\r
-    /* Walk back up and rebalance */\r
-    while ( --top >= 0 ) {\r
-      jsw_anode_t *up = path[top];\r
-\r
-      if ( top != 0 )\r
-        dir = path[top - 1]->link[1] == up;\r
-\r
-      /* Rebalance (aka. black magic) */\r
-      if ( up->link[0]->level < up->level - 1\r
-        || up->link[1]->level < up->level - 1 )\r
-      {\r
-        if ( up->link[1]->level > --up->level )\r
-          up->link[1]->level = up->level;\r
-\r
-        /* Order is important! */\r
-        skew ( up );\r
-        skew ( up->link[1] );\r
-        skew ( up->link[1]->link[1] );\r
-        split ( up );\r
-        split ( up->link[1] );\r
-      }\r
-\r
-      /* Fix the parent */\r
-      if ( top != 0 )\r
-        path[top - 1]->link[dir] = up;\r
-      else\r
-        tree->root = up;\r
-    }\r
-  }\r
-\r
-  --tree->size;\r
-\r
-  return 1;\r
-}\r
-\r
-size_t jsw_asize ( jsw_atree_t *tree )\r
-{\r
-  return tree->size;\r
-}\r
-\r
-jsw_atrav_t *jsw_atnew ( void )\r
-{\r
-  return malloc ( sizeof ( jsw_atrav_t ) );\r
-}\r
-\r
-void jsw_atdelete ( jsw_atrav_t *trav )\r
-{\r
-  free ( trav );\r
-}\r
-\r
-/*\r
-  First step in traversal,\r
-  handles min and max\r
-*/\r
-static void *start ( jsw_atrav_t *trav,\r
-  jsw_atree_t *tree, int dir )\r
-{\r
-  trav->tree = tree;\r
-  trav->it = tree->root;\r
-  trav->top = 0;\r
-\r
-  /* Build a path to work with */\r
-  if ( trav->it != tree->nil ) {\r
-    while ( trav->it->link[dir] != tree->nil ) {\r
-      trav->path[trav->top++] = trav->it;\r
-      trav->it = trav->it->link[dir];\r
-    }\r
-  }\r
-\r
-  /* Could be nil, but nil->data == NULL */\r
-  return trav->it->data;\r
-}\r
-\r
-/*\r
-  Subsequent traversal steps,\r
-  handles ascending and descending\r
-*/\r
-static void *move ( jsw_atrav_t *trav, int dir )\r
-{\r
-  jsw_anode_t *nil = trav->tree->nil;\r
-\r
-  if ( trav->it->link[dir] != nil ) {\r
-    /* Continue down this branch */\r
-    trav->path[trav->top++] = trav->it;\r
-    trav->it = trav->it->link[dir];\r
-\r
-    while ( trav->it->link[!dir] != nil ) {\r
-      trav->path[trav->top++] = trav->it;\r
-      trav->it = trav->it->link[!dir];\r
-    }\r
-  }\r
-  else {\r
-    /* Move to the next branch */\r
-    jsw_anode_t *last;\r
-\r
-    do {\r
-      if ( trav->top == 0 ) {\r
-        trav->it = nil;\r
-        break;\r
-      }\r
-\r
-      last = trav->it;\r
-      trav->it = trav->path[--trav->top];\r
-    } while ( last == trav->it->link[dir] );\r
-  }\r
-\r
-  /* Could be nil, but nil->data == NULL */\r
-  return trav->it->data;\r
-}\r
-\r
-void *jsw_atfirst ( jsw_atrav_t *trav, jsw_atree_t *tree )\r
-{\r
-  return start ( trav, tree, 0 ); /* Min value */\r
-}\r
-\r
-void *jsw_atlast ( jsw_atrav_t *trav, jsw_atree_t *tree )\r
-{\r
-  return start ( trav, tree, 1 ); /* Max value */\r
-}\r
-\r
-void *jsw_atnext ( jsw_atrav_t *trav )\r
-{\r
-  return move ( trav, 1 ); /* Toward larger items */\r
-}\r
-\r
-void *jsw_atprev ( jsw_atrav_t *trav )\r
-{\r
-  return move ( trav, 0 ); /* Toward smaller items */\r
-}\r
+/*
+  Andersson tree library
+
+    > Created (Julienne Walker): September 10, 2005
+    > Corrections (James Bucanek): April 10, 2006
+      1) Typo in jsw_aerase:
+           up != 0 should be top != 0
+      2) Bug in jsw_aerase:
+           skew ( path[top] ) should be skew ( up )
+           split ( path[top] ) should be split ( up )
+      3) Bug in skew and split macros:
+           Condition should test for nil
+      4) Bug in jsw_aerase:
+           Search for successor should save the path
+*/
+#include "jsw_atree.h"
+
+#ifdef __cplusplus
+#include <cstdlib>
+
+using std::malloc;
+using std::free;
+using std::size_t;
+#else
+#include <stdlib.h>
+#endif
+
+#ifndef HEIGHT_LIMIT
+#define HEIGHT_LIMIT 64 /* Tallest allowable tree */
+#endif
+
+typedef struct jsw_anode {
+  int               level;   /* Horizontal level for balance */
+  void             *data;    /* User-defined content */
+  struct jsw_anode *link[2]; /* Left (0) and right (1) links */
+} jsw_anode_t;
+
+struct jsw_atree {
+  jsw_anode_t *root; /* Top of the tree */
+  jsw_anode_t *nil;  /* End of tree sentinel */
+  cmp_f        cmp;  /* Compare two items */
+  dup_f        dup;  /* Clone an item (user-defined) */
+  rel_f        rel;  /* Destroy an item (user-defined) */
+  size_t       size; /* Number of items (user-defined) */
+};
+
+struct jsw_atrav {
+  jsw_atree_t *tree;               /* Paired tree */
+  jsw_anode_t *it;                 /* Current node */
+  jsw_anode_t *path[HEIGHT_LIMIT]; /* Traversal path */
+  size_t       top;                /* Top of stack */
+};
+
+/* Remove left horizontal links */
+#define skew(t) do {                                      \
+  if ( t->link[0]->level == t->level && t->level != 0 ) { \
+    jsw_anode_t *save = t->link[0];                       \
+    t->link[0] = save->link[1];                           \
+    save->link[1] = t;                                    \
+    t = save;                                             \
+  }                                                       \
+} while(0)
+
+/* Remove consecutive horizontal links */
+#define split(t) do {                                              \
+  if ( t->link[1]->link[1]->level == t->level && t->level != 0 ) { \
+    jsw_anode_t *save = t->link[1];                                \
+    t->link[1] = save->link[0];                                    \
+    save->link[0] = t;                                             \
+    t = save;                                                      \
+    ++t->level;                                                    \
+  }                                                                \
+} while(0)
+
+static jsw_anode_t *new_node ( jsw_atree_t *tree, void *data )
+{
+  jsw_anode_t *rn = (jsw_anode_t *)malloc ( sizeof *rn );
+
+  if ( rn == NULL )
+    return tree->nil;
+
+  rn->level = 1;
+  rn->data = tree->dup ( data );
+  rn->link[0] = rn->link[1] = tree->nil;
+
+  return rn;
+}
+
+jsw_atree_t *jsw_anew ( cmp_f cmp, dup_f dup, rel_f rel )
+{
+  jsw_atree_t *rt = (jsw_atree_t *)malloc ( sizeof *rt );
+
+  if ( rt == NULL )
+    return NULL;
+
+  /* Initialize sentinel */
+  rt->nil = (jsw_anode_t *)malloc ( sizeof *rt->nil );
+  if ( rt->nil == NULL ) {
+    free ( rt );
+    return NULL;
+  }
+
+  rt->nil->data = NULL; /* Simplifies some ops */
+  rt->nil->level = 0;
+  rt->nil->link[0] = rt->nil->link[1] = rt->nil;
+
+  /* Initialize tree */
+  rt->root = rt->nil;
+  rt->cmp = cmp;
+  rt->dup = dup;
+  rt->rel = rel;
+  rt->size = 0;
+
+  return rt;
+}
+
+void jsw_adelete ( jsw_atree_t *tree )
+{
+  jsw_anode_t *it = tree->root;
+  jsw_anode_t *save;
+
+  /* Destruction by rotation */
+  while ( it != tree->nil ) {
+    if ( it->link[0] == tree->nil ) {
+      /* Remove node */
+      save = it->link[1];
+      tree->rel ( it->data );
+      free ( it );
+    }
+    else {
+      /* Rotate right */
+      save = it->link[0];
+      it->link[0] = save->link[1];
+      save->link[1] = it;
+    }
+
+    it = save;
+  }
+
+  /* Finalize destruction */
+  free ( tree->nil );
+  free ( tree );
+}
+
+void *jsw_afind ( jsw_atree_t *tree, void *data )
+{
+  jsw_anode_t *it = tree->root;
+
+  while ( it != tree->nil ) {
+    int cmp = tree->cmp ( it->data, data );
+
+    if ( cmp == 0 )
+      break;
+
+    it = it->link[cmp < 0];
+  }
+
+  /* nil->data == NULL */
+  return it->data;
+}
+
+int jsw_ainsert ( jsw_atree_t *tree, void *data )
+{
+  if ( tree->root == tree->nil ) {
+    /* Empty tree case */
+    tree->root = new_node ( tree, data );
+    if ( tree->root == tree->nil )
+      return 0;
+  }
+  else {
+    jsw_anode_t *it = tree->root;
+    jsw_anode_t *path[HEIGHT_LIMIT];
+    int top = 0, dir;
+
+    /* Find a spot and save the path */
+    for ( ; ; ) {
+      path[top++] = it;
+      dir = tree->cmp ( it->data, data ) < 0;
+
+      if ( it->link[dir] == tree->nil )
+        break;
+
+      it = it->link[dir];
+    }
+
+    /* Create a new item */
+    it->link[dir] = new_node ( tree, data );
+    if ( it->link[dir] == tree->nil )
+      return 0;
+
+    /* Walk back and rebalance */
+    while ( --top >= 0 ) {
+      /* Which child? */
+      if ( top != 0 )
+        dir = path[top - 1]->link[1] == path[top];
+
+      skew ( path[top] );
+      split ( path[top] );
+
+      /* Fix the parent */
+      if ( top != 0 )
+        path[top - 1]->link[dir] = path[top];
+      else
+        tree->root = path[top];
+    }
+  }
+
+  ++tree->size;
+
+  return 1;
+}
+
+int jsw_aerase ( jsw_atree_t *tree, void *data )
+{
+  if ( tree->root == tree->nil )
+    return 0;
+  else {
+    jsw_anode_t *it = tree->root;
+    jsw_anode_t *path[HEIGHT_LIMIT];
+    int top = 0, dir, cmp;
+
+    /* Find node to remove and save path */
+    for ( ; ; ) {
+      path[top++] = it;
+
+      if ( it == tree->nil )
+        return 0;
+
+      cmp = tree->cmp ( it->data, data );
+      if ( cmp == 0 )
+        break;
+
+      dir = cmp < 0;
+      it = it->link[dir];
+    }
+
+    /* Remove the found node */
+    if ( it->link[0] == tree->nil
+      || it->link[1] == tree->nil )
+    {
+      /* Single child case */
+      int dir2 = it->link[0] == tree->nil;
+
+      /* Unlink the item */
+      if ( --top != 0 )
+        path[top - 1]->link[dir] = it->link[dir2];
+      else
+        tree->root = it->link[1];
+
+      tree->rel ( it->data );
+      free ( it );
+    }
+    else {
+      /* Two child case */
+      jsw_anode_t *heir = it->link[1];
+      jsw_anode_t *prev = it;
+
+      while ( heir->link[0] != tree->nil ) {
+        path[top++] = prev = heir;
+        heir = heir->link[0];
+      }
+
+      /*
+        Order is important!
+        (free item, replace item, free heir)
+      */
+      tree->rel ( it->data );
+      it->data = heir->data;
+      prev->link[prev == it] = heir->link[1];
+      free ( heir );
+    }
+
+    /* Walk back up and rebalance */
+    while ( --top >= 0 ) {
+      jsw_anode_t *up = path[top];
+
+      if ( top != 0 )
+        dir = path[top - 1]->link[1] == up;
+
+      /* Rebalance (aka. black magic) */
+      if ( up->link[0]->level < up->level - 1
+        || up->link[1]->level < up->level - 1 )
+      {
+        if ( up->link[1]->level > --up->level )
+          up->link[1]->level = up->level;
+
+        /* Order is important! */
+        skew ( up );
+        skew ( up->link[1] );
+        skew ( up->link[1]->link[1] );
+        split ( up );
+        split ( up->link[1] );
+      }
+
+      /* Fix the parent */
+      if ( top != 0 )
+        path[top - 1]->link[dir] = up;
+      else
+        tree->root = up;
+    }
+  }
+
+  --tree->size;
+
+  return 1;
+}
+
+size_t jsw_asize ( jsw_atree_t *tree )
+{
+  return tree->size;
+}
+
+jsw_atrav_t *jsw_atnew ( void )
+{
+  return malloc ( sizeof ( jsw_atrav_t ) );
+}
+
+void jsw_atdelete ( jsw_atrav_t *trav )
+{
+  free ( trav );
+}
+
+/*
+  First step in traversal,
+  handles min and max
+*/
+static void *start ( jsw_atrav_t *trav,
+  jsw_atree_t *tree, int dir )
+{
+  trav->tree = tree;
+  trav->it = tree->root;
+  trav->top = 0;
+
+  /* Build a path to work with */
+  if ( trav->it != tree->nil ) {
+    while ( trav->it->link[dir] != tree->nil ) {
+      trav->path[trav->top++] = trav->it;
+      trav->it = trav->it->link[dir];
+    }
+  }
+
+  /* Could be nil, but nil->data == NULL */
+  return trav->it->data;
+}
+
+/*
+  Subsequent traversal steps,
+  handles ascending and descending
+*/
+static void *move ( jsw_atrav_t *trav, int dir )
+{
+  jsw_anode_t *nil = trav->tree->nil;
+
+  if ( trav->it->link[dir] != nil ) {
+    /* Continue down this branch */
+    trav->path[trav->top++] = trav->it;
+    trav->it = trav->it->link[dir];
+
+    while ( trav->it->link[!dir] != nil ) {
+      trav->path[trav->top++] = trav->it;
+      trav->it = trav->it->link[!dir];
+    }
+  }
+  else {
+    /* Move to the next branch */
+    jsw_anode_t *last;
+
+    do {
+      if ( trav->top == 0 ) {
+        trav->it = nil;
+        break;
+      }
+
+      last = trav->it;
+      trav->it = trav->path[--trav->top];
+    } while ( last == trav->it->link[dir] );
+  }
+
+  /* Could be nil, but nil->data == NULL */
+  return trav->it->data;
+}
+
+void *jsw_atfirst ( jsw_atrav_t *trav, jsw_atree_t *tree )
+{
+  return start ( trav, tree, 0 ); /* Min value */
+}
+
+void *jsw_atlast ( jsw_atrav_t *trav, jsw_atree_t *tree )
+{
+  return start ( trav, tree, 1 ); /* Max value */
+}
+
+void *jsw_atnext ( jsw_atrav_t *trav )
+{
+  return move ( trav, 1 ); /* Toward larger items */
+}
+
+void *jsw_atprev ( jsw_atrav_t *trav )
+{
+  return move ( trav, 0 ); /* Toward smaller items */
+}