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