2001-04-15 Daniel Berlin <dan@cgsoftware.com>
authorDaniel Berlin <dberlin@dberlin.org>
Mon, 16 Apr 2001 14:10:14 +0000 (14:10 +0000)
committerDaniel Berlin <dberlin@dberlin.org>
Mon, 16 Apr 2001 14:10:14 +0000 (14:10 +0000)
* ternary.c: New file - Ternary search tree implementation.

2001-04-15  Daniel Berlin  <dan@cgsoftware.com>

* ternary.h: New file - Ternary search tree header.

include/ChangeLog
include/ternary.h [new file with mode: 0644]
libiberty/ChangeLog
libiberty/ternary.c [new file with mode: 0644]

index a6eb4d9112062bc56457d133ff76b719ca2c7f66..40726172c071985b458c76e99d78af398fb114ce 100644 (file)
@@ -1,3 +1,7 @@
+2001-04-15  Daniel Berlin  <dan@cgsoftware.com>
+
+       * ternary.h: New file - Ternary search tree header.
+
 2001-04-13  Jakub Jelinek  <jakub@redhat.com>
 
        * bfdlink.h (bfd_link_discard): Add discard_sec_merge.
diff --git a/include/ternary.h b/include/ternary.h
new file mode 100644 (file)
index 0000000..2e0c828
--- /dev/null
@@ -0,0 +1,50 @@
+/* ternary.h - Ternary Search Trees
+   Copyright 2001 Free Software Foundation, Inc.
+
+   Contributed by Daniel Berlin (dan@cgsoftware.com)
+
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 2, or (at your option) any
+   later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+   USA.  */
+#ifndef TERNARY_H_
+#define TERNARY_H_
+/* Ternary search trees */
+
+typedef struct ternary_node_def *ternary_tree;
+
+typedef struct ternary_node_def
+{
+  char splitchar;
+  ternary_tree lokid;
+  ternary_tree eqkid;
+  ternary_tree hikid;
+}
+ternary_node;
+
+/* Insert string S into tree P, associating it with DATA. 
+   Return the data in the tree associated with the string if it's
+   already there, and replace is 0.
+   Otherwise, replaces if it it exists, inserts if it doesn't, and
+   returns the data you passed in. */
+void *ternary_insert (ternary_tree *p, char *s, void *data, int replace);
+
+/* Delete the ternary search tree rooted at P. 
+   Does NOT delete the data you associated with the strings. */
+void ternary_cleanup (ternary_tree p);
+
+/* Search the ternary tree for string S, returning the data associated
+   with it if found. */
+void *ternary_search (ternary_tree p, char *s);
+#endif
index 79bef792c20cd8ac9fc89d5c47861728bd2f3541..6816e7f9dc02c106b5c2f3d8feb92790d93b2e3c 100644 (file)
@@ -1,3 +1,8 @@
+2001-04-15  Daniel Berlin  <dan@cgsoftware.com>
+
+       * ternary.c: New file - Ternary search tree implementation.
+       
+
 2001-04-03  Zack Weinberg  <zackw@stanford.edu>
 
        * make-temp-file.c (try): Inline.
diff --git a/libiberty/ternary.c b/libiberty/ternary.c
new file mode 100644 (file)
index 0000000..c5ef3a5
--- /dev/null
@@ -0,0 +1,157 @@
+/* ternary.c - Ternary Search Trees
+   Copyright (C) 2001 Free Software Foundation, Inc.
+
+   Contributed by Daniel Berlin (dan@cgsoftware.com)
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 2, or (at your option) any
+   later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+   USA.  */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#include <stdio.h>
+
+#include "libiberty.h"
+#include "ternary.h"
+
+/* Non-recursive so we don't waste stack space/time on large
+   insertions. */
+
+void *
+ternary_insert (ternary_tree * root, char *s, void *data, int replace)
+{
+  int diff;
+  ternary_tree curr, *pcurr;
+
+  /* Start at the root. */
+  pcurr = root;
+  /* Loop until we find the right position */
+  while ((curr = *pcurr))
+    {
+      /* Calculate the difference */
+      diff = *s - curr->splitchar;
+      /* Handle current char equal to node splitchar */
+      if (diff == 0)
+       {
+         /* Handle the case of a string we already have */
+         if (*s++ == 0)
+           {
+             if (replace)
+               curr->eqkid = (ternary_tree) data;
+             return (void *) curr->eqkid;
+           }
+         pcurr = &(curr->eqkid);
+       }
+      /* Handle current char less than node splitchar */
+      else if (diff < 0)
+       {
+         pcurr = &(curr->lokid);
+       }
+      /* Handle current char greater than node splitchar */
+      else
+       {
+         pcurr = &(curr->hikid);
+       }
+    }
+  /* It's not a duplicate string, and we should insert what's left of
+     the string, into the tree rooted at curr */
+  for (;;)
+    {
+      /* Allocate the memory for the node, and fill it in */
+      *pcurr = (ternary_tree) xmalloc (sizeof (ternary_node));
+      curr = *pcurr;
+      curr->splitchar = *s;
+      curr->lokid = curr->hikid = curr->eqkid = 0;
+
+      /* Place nodes until we hit the end of the string.
+         When we hit it, place the data in the right place, and
+         return.
+       */
+      if (*s++ == 0)
+       {
+         curr->eqkid = (ternary_tree) data;
+         return data;
+       }
+      pcurr = &(curr->eqkid);
+    }
+}
+
+/* Free the ternary search tree rooted at p. */
+void
+ternary_cleanup (ternary_tree p)
+{
+  if (p)
+    {
+      ternary_cleanup (p->lokid);
+      if (p->splitchar)
+       ternary_cleanup (p->eqkid);
+      ternary_cleanup (p->hikid);
+      free (p);
+    }
+}
+
+/* Non-recursive find of a string in the ternary tree */
+void *
+ternary_search (ternary_tree p, char *s)
+{
+  ternary_tree curr;
+  int diff, spchar;
+  spchar = *s;
+  curr = p;
+  /* Loop while we haven't hit a NULL node or returned */
+  while (curr)
+    {
+      /* Calculate the difference */
+      diff = spchar - curr->splitchar;
+      /* Handle the equal case */
+      if (diff == 0)
+       {
+         if (spchar == 0)
+           return (void *) curr->eqkid;
+         spchar = *++s;
+         curr = curr->eqkid;
+       }
+      /* Handle the less than case */
+      else if (diff < 0)
+       curr = curr->lokid;
+      /* All that's left is greater than */
+      else
+       curr = curr->hikid;
+    }
+  return NULL;
+}
+
+/* For those who care, the recursive version of the search. Useful if
+   you want a starting point for pmsearch or nearsearch. */
+static void *
+ternary_recursivesearch (ternary_tree p, char *s)
+{
+  if (!p)
+    return 0;
+  if (*s < p->splitchar)
+    return ternary_recursivesearch (p->lokid, s);
+  else if (*s > p->splitchar)
+    return ternary_recursivesearch (p->hikid, s);
+  else
+    {
+      if (*s == 0)
+       return (void *) p->eqkid;
+      return ternary_recursivesearch (p->eqkid, ++s);
+    }
+}