xref: /openbsd-src/gnu/lib/libiberty/src/ternary.c (revision 20fce977aadac3358da45d5027d7d19cdc03b0fe)
19588ddcfSespie /* ternary.c - Ternary Search Trees
29588ddcfSespie    Copyright (C) 2001 Free Software Foundation, Inc.
39588ddcfSespie 
49588ddcfSespie    Contributed by Daniel Berlin (dan@cgsoftware.com)
59588ddcfSespie 
69588ddcfSespie    This program is free software; you can redistribute it and/or modify it
79588ddcfSespie    under the terms of the GNU General Public License as published by the
89588ddcfSespie    Free Software Foundation; either version 2, or (at your option) any
99588ddcfSespie    later version.
109588ddcfSespie 
119588ddcfSespie    This program is distributed in the hope that it will be useful,
129588ddcfSespie    but WITHOUT ANY WARRANTY; without even the implied warranty of
139588ddcfSespie    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
149588ddcfSespie    GNU General Public License for more details.
159588ddcfSespie 
169588ddcfSespie    You should have received a copy of the GNU General Public License
179588ddcfSespie    along with this program; if not, write to the Free Software
18*20fce977Smiod    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301,
199588ddcfSespie    USA.  */
209588ddcfSespie #ifdef HAVE_CONFIG_H
219588ddcfSespie #include "config.h"
229588ddcfSespie #endif
239588ddcfSespie 
249588ddcfSespie #ifdef HAVE_STDLIB_H
259588ddcfSespie #include <stdlib.h>
269588ddcfSespie #endif
279588ddcfSespie 
289588ddcfSespie #include <stdio.h>
299588ddcfSespie 
309588ddcfSespie #include "libiberty.h"
319588ddcfSespie #include "ternary.h"
329588ddcfSespie 
339588ddcfSespie /* Non-recursive so we don't waste stack space/time on large
349588ddcfSespie    insertions. */
359588ddcfSespie 
369588ddcfSespie PTR
ternary_insert(ternary_tree * root,const char * s,PTR data,int replace)37*20fce977Smiod ternary_insert (ternary_tree *root, const char *s, PTR data, int replace)
389588ddcfSespie {
399588ddcfSespie   int diff;
409588ddcfSespie   ternary_tree curr, *pcurr;
419588ddcfSespie 
429588ddcfSespie   /* Start at the root. */
439588ddcfSespie   pcurr = root;
449588ddcfSespie   /* Loop until we find the right position */
459588ddcfSespie   while ((curr = *pcurr))
469588ddcfSespie     {
479588ddcfSespie       /* Calculate the difference */
489588ddcfSespie       diff = *s - curr->splitchar;
499588ddcfSespie       /* Handle current char equal to node splitchar */
509588ddcfSespie       if (diff == 0)
519588ddcfSespie 	{
529588ddcfSespie 	  /* Handle the case of a string we already have */
539588ddcfSespie 	  if (*s++ == 0)
549588ddcfSespie 	    {
559588ddcfSespie 	      if (replace)
569588ddcfSespie 		curr->eqkid = (ternary_tree) data;
579588ddcfSespie 	      return (PTR) curr->eqkid;
589588ddcfSespie 	    }
599588ddcfSespie 	  pcurr = &(curr->eqkid);
609588ddcfSespie 	}
619588ddcfSespie       /* Handle current char less than node splitchar */
629588ddcfSespie       else if (diff < 0)
639588ddcfSespie 	{
649588ddcfSespie 	  pcurr = &(curr->lokid);
659588ddcfSespie 	}
669588ddcfSespie       /* Handle current char greater than node splitchar */
679588ddcfSespie       else
689588ddcfSespie 	{
699588ddcfSespie 	  pcurr = &(curr->hikid);
709588ddcfSespie 	}
719588ddcfSespie     }
729588ddcfSespie   /* It's not a duplicate string, and we should insert what's left of
739588ddcfSespie      the string, into the tree rooted at curr */
749588ddcfSespie   for (;;)
759588ddcfSespie     {
769588ddcfSespie       /* Allocate the memory for the node, and fill it in */
77*20fce977Smiod       *pcurr = XNEW (ternary_node);
789588ddcfSespie       curr = *pcurr;
799588ddcfSespie       curr->splitchar = *s;
809588ddcfSespie       curr->lokid = curr->hikid = curr->eqkid = 0;
819588ddcfSespie 
829588ddcfSespie       /* Place nodes until we hit the end of the string.
839588ddcfSespie          When we hit it, place the data in the right place, and
849588ddcfSespie          return.
859588ddcfSespie        */
869588ddcfSespie       if (*s++ == 0)
879588ddcfSespie 	{
889588ddcfSespie 	  curr->eqkid = (ternary_tree) data;
899588ddcfSespie 	  return data;
909588ddcfSespie 	}
919588ddcfSespie       pcurr = &(curr->eqkid);
929588ddcfSespie     }
939588ddcfSespie }
949588ddcfSespie 
959588ddcfSespie /* Free the ternary search tree rooted at p. */
969588ddcfSespie void
ternary_cleanup(ternary_tree p)97*20fce977Smiod ternary_cleanup (ternary_tree p)
989588ddcfSespie {
999588ddcfSespie   if (p)
1009588ddcfSespie     {
1019588ddcfSespie       ternary_cleanup (p->lokid);
1029588ddcfSespie       if (p->splitchar)
1039588ddcfSespie 	ternary_cleanup (p->eqkid);
1049588ddcfSespie       ternary_cleanup (p->hikid);
1059588ddcfSespie       free (p);
1069588ddcfSespie     }
1079588ddcfSespie }
1089588ddcfSespie 
1099588ddcfSespie /* Non-recursive find of a string in the ternary tree */
1109588ddcfSespie PTR
ternary_search(const ternary_node * p,const char * s)111*20fce977Smiod ternary_search (const ternary_node *p, const char *s)
1129588ddcfSespie {
1139588ddcfSespie   const ternary_node *curr;
1149588ddcfSespie   int diff, spchar;
1159588ddcfSespie   spchar = *s;
1169588ddcfSespie   curr = p;
1179588ddcfSespie   /* Loop while we haven't hit a NULL node or returned */
1189588ddcfSespie   while (curr)
1199588ddcfSespie     {
1209588ddcfSespie       /* Calculate the difference */
1219588ddcfSespie       diff = spchar - curr->splitchar;
1229588ddcfSespie       /* Handle the equal case */
1239588ddcfSespie       if (diff == 0)
1249588ddcfSespie 	{
1259588ddcfSespie 	  if (spchar == 0)
1269588ddcfSespie 	    return (PTR) curr->eqkid;
1279588ddcfSespie 	  spchar = *++s;
1289588ddcfSespie 	  curr = curr->eqkid;
1299588ddcfSespie 	}
1309588ddcfSespie       /* Handle the less than case */
1319588ddcfSespie       else if (diff < 0)
1329588ddcfSespie 	curr = curr->lokid;
1339588ddcfSespie       /* All that's left is greater than */
1349588ddcfSespie       else
1359588ddcfSespie 	curr = curr->hikid;
1369588ddcfSespie     }
1379588ddcfSespie   return NULL;
1389588ddcfSespie }
1399588ddcfSespie 
1409588ddcfSespie /* For those who care, the recursive version of the search. Useful if
1419588ddcfSespie    you want a starting point for pmsearch or nearsearch. */
1429588ddcfSespie static PTR
ternary_recursivesearch(const ternary_node * p,const char * s)143*20fce977Smiod ternary_recursivesearch (const ternary_node *p, const char *s)
1449588ddcfSespie {
1459588ddcfSespie   if (!p)
1469588ddcfSespie     return 0;
1479588ddcfSespie   if (*s < p->splitchar)
1489588ddcfSespie     return ternary_recursivesearch (p->lokid, s);
1499588ddcfSespie   else if (*s > p->splitchar)
1509588ddcfSespie     return ternary_recursivesearch (p->hikid, s);
1519588ddcfSespie   else
1529588ddcfSespie     {
1539588ddcfSespie       if (*s == 0)
1549588ddcfSespie 	return (PTR) p->eqkid;
1559588ddcfSespie       return ternary_recursivesearch (p->eqkid, ++s);
1569588ddcfSespie     }
1579588ddcfSespie }
158