1*4d9fdb46SRobert Mustacchi /* Copyright (c) 2013-2019, David Anderson
2*4d9fdb46SRobert Mustacchi All rights reserved.
3*4d9fdb46SRobert Mustacchi 
4*4d9fdb46SRobert Mustacchi Redistribution and use in source and binary forms, with
5*4d9fdb46SRobert Mustacchi or without modification, are permitted provided that the
6*4d9fdb46SRobert Mustacchi following conditions are met:
7*4d9fdb46SRobert Mustacchi 
8*4d9fdb46SRobert Mustacchi     Redistributions of source code must retain the above
9*4d9fdb46SRobert Mustacchi     copyright notice, this list of conditions and the following
10*4d9fdb46SRobert Mustacchi     disclaimer.
11*4d9fdb46SRobert Mustacchi 
12*4d9fdb46SRobert Mustacchi     Redistributions in binary form must reproduce the above
13*4d9fdb46SRobert Mustacchi     copyright notice, this list of conditions and the following
14*4d9fdb46SRobert Mustacchi     disclaimer in the documentation and/or other materials
15*4d9fdb46SRobert Mustacchi     provided with the distribution.
16*4d9fdb46SRobert Mustacchi 
17*4d9fdb46SRobert Mustacchi THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
18*4d9fdb46SRobert Mustacchi CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
19*4d9fdb46SRobert Mustacchi INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20*4d9fdb46SRobert Mustacchi OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21*4d9fdb46SRobert Mustacchi ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
22*4d9fdb46SRobert Mustacchi CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23*4d9fdb46SRobert Mustacchi SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24*4d9fdb46SRobert Mustacchi NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25*4d9fdb46SRobert Mustacchi LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26*4d9fdb46SRobert Mustacchi HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27*4d9fdb46SRobert Mustacchi CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28*4d9fdb46SRobert Mustacchi OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
29*4d9fdb46SRobert Mustacchi EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30*4d9fdb46SRobert Mustacchi 
31*4d9fdb46SRobert Mustacchi */
32*4d9fdb46SRobert Mustacchi 
33*4d9fdb46SRobert Mustacchi 
34*4d9fdb46SRobert Mustacchi /*  The interfaces follow tsearch (See the Single
35*4d9fdb46SRobert Mustacchi     Unix Specification) but the implementation is
36*4d9fdb46SRobert Mustacchi     written without reference to the source of any
37*4d9fdb46SRobert Mustacchi     version of tsearch or any hashing code.
38*4d9fdb46SRobert Mustacchi 
39*4d9fdb46SRobert Mustacchi     An additional interface is added (compared to
40*4d9fdb46SRobert Mustacchi     a real tsearch) to let the caller identify a
41*4d9fdb46SRobert Mustacchi     'hash' function with each hash table (called
42*4d9fdb46SRobert Mustacchi     a tree below, but that is a misnomer).
43*4d9fdb46SRobert Mustacchi 
44*4d9fdb46SRobert Mustacchi     So read 'tree' below as hash table.
45*4d9fdb46SRobert Mustacchi 
46*4d9fdb46SRobert Mustacchi     See http://www.prevanders.net/tsearch.html
47*4d9fdb46SRobert Mustacchi     for information and an example of use.
48*4d9fdb46SRobert Mustacchi 
49*4d9fdb46SRobert Mustacchi     Based on Knuth, chapter 6.4
50*4d9fdb46SRobert Mustacchi 
51*4d9fdb46SRobert Mustacchi     This uses a hash based on the key.
52*4d9fdb46SRobert Mustacchi     Collision resolution is by chaining.
53*4d9fdb46SRobert Mustacchi 
54*4d9fdb46SRobert Mustacchi     twalk() and tdestroy() walk in a random order.
55*4d9fdb46SRobert Mustacchi     The 'preorder' etc labels mean nothing in a hash, so everything
56*4d9fdb46SRobert Mustacchi     is called a leaf.
57*4d9fdb46SRobert Mustacchi 
58*4d9fdb46SRobert Mustacchi */
59*4d9fdb46SRobert Mustacchi 
60*4d9fdb46SRobert Mustacchi 
61*4d9fdb46SRobert Mustacchi #include "config.h"
62*4d9fdb46SRobert Mustacchi #ifdef HAVE_UNUSED_ATTRIBUTE
63*4d9fdb46SRobert Mustacchi #define  UNUSEDARG __attribute__ ((unused))
64*4d9fdb46SRobert Mustacchi #else
65*4d9fdb46SRobert Mustacchi #define  UNUSEDARG
66*4d9fdb46SRobert Mustacchi #endif
67*4d9fdb46SRobert Mustacchi #ifdef HAVE_STDLIB_H
68*4d9fdb46SRobert Mustacchi #include "stdlib.h" /* for malloc, free() etc */
69*4d9fdb46SRobert Mustacchi #endif /* HAVE_STDLIB_H */
70*4d9fdb46SRobert Mustacchi #ifdef HAVE_MALLOC_H
71*4d9fdb46SRobert Mustacchi /* Useful include for some Windows compilers. */
72*4d9fdb46SRobert Mustacchi #include <malloc.h>
73*4d9fdb46SRobert Mustacchi #endif /* HAVE_MALLOC_H */
74*4d9fdb46SRobert Mustacchi #include <stdio.h>  /* for printf() */
75*4d9fdb46SRobert Mustacchi #ifdef HAVE_STDINT_H
76*4d9fdb46SRobert Mustacchi #include <stdint.h> /* for uintptr_t */
77*4d9fdb46SRobert Mustacchi #endif /* HAVE_STDINT_H */
78*4d9fdb46SRobert Mustacchi /*  This must match the types and print options
79*4d9fdb46SRobert Mustacchi     found in libdwarf.h.  */
80*4d9fdb46SRobert Mustacchi #define Dwarf_Unsigned unsigned long long
81*4d9fdb46SRobert Mustacchi #if defined(_WIN32) && defined(HAVE_NONSTANDARD_PRINTF_64_FORMAT)
82*4d9fdb46SRobert Mustacchi #define DW_PR_DUx "I64x"
83*4d9fdb46SRobert Mustacchi #define DW_PR_DUu "I64u"
84*4d9fdb46SRobert Mustacchi #else
85*4d9fdb46SRobert Mustacchi #define DW_PR_DUx "llx"
86*4d9fdb46SRobert Mustacchi #define DW_PR_DUu "llu"
87*4d9fdb46SRobert Mustacchi #endif /* DW_PR defines */
88*4d9fdb46SRobert Mustacchi #include "dwarf_tsearch.h"
89*4d9fdb46SRobert Mustacchi 
90*4d9fdb46SRobert Mustacchi /*  A table of primes used to size  and resize the hash table.
91*4d9fdb46SRobert Mustacchi     From public sources of prime numbers, arbitrarily chosen
92*4d9fdb46SRobert Mustacchi     to approximately double in size at each step.
93*4d9fdb46SRobert Mustacchi */
94*4d9fdb46SRobert Mustacchi static unsigned long primes[] =
95*4d9fdb46SRobert Mustacchi {
96*4d9fdb46SRobert Mustacchi #if 0 /* for testing only */
97*4d9fdb46SRobert Mustacchi 5,11, 17,23, 31, 47, 53,
98*4d9fdb46SRobert Mustacchi #endif
99*4d9fdb46SRobert Mustacchi 79,
100*4d9fdb46SRobert Mustacchi 1009,
101*4d9fdb46SRobert Mustacchi 5591,
102*4d9fdb46SRobert Mustacchi 10007,
103*4d9fdb46SRobert Mustacchi 21839,
104*4d9fdb46SRobert Mustacchi 41413,
105*4d9fdb46SRobert Mustacchi 99907,
106*4d9fdb46SRobert Mustacchi 199967,
107*4d9fdb46SRobert Mustacchi 400009,
108*4d9fdb46SRobert Mustacchi 800029,
109*4d9fdb46SRobert Mustacchi 1600141,
110*4d9fdb46SRobert Mustacchi 3000089,
111*4d9fdb46SRobert Mustacchi 6000121,
112*4d9fdb46SRobert Mustacchi 12000257,
113*4d9fdb46SRobert Mustacchi 24000143,
114*4d9fdb46SRobert Mustacchi 48000203,
115*4d9fdb46SRobert Mustacchi 100000127,
116*4d9fdb46SRobert Mustacchi 200001611,
117*4d9fdb46SRobert Mustacchi 400000669,
118*4d9fdb46SRobert Mustacchi 800000573,
119*4d9fdb46SRobert Mustacchi 0 /* Here we are giving up */
120*4d9fdb46SRobert Mustacchi };
121*4d9fdb46SRobert Mustacchi 
122*4d9fdb46SRobert Mustacchi static unsigned long allowed_fill_percent = 90;
123*4d9fdb46SRobert Mustacchi 
124*4d9fdb46SRobert Mustacchi 
125*4d9fdb46SRobert Mustacchi struct hs_base {
126*4d9fdb46SRobert Mustacchi     unsigned long tablesize_;
127*4d9fdb46SRobert Mustacchi     unsigned long tablesize_entry_index_;
128*4d9fdb46SRobert Mustacchi     unsigned long allowed_fill_;
129*4d9fdb46SRobert Mustacchi     /* Record_count means number of active records,
130*4d9fdb46SRobert Mustacchi         counting all records on chains.
131*4d9fdb46SRobert Mustacchi         When the record_count is > 90% of a full
132*4d9fdb46SRobert Mustacchi         tablesize_ we redo the table before adding
133*4d9fdb46SRobert Mustacchi         a new entry.  */
134*4d9fdb46SRobert Mustacchi     unsigned long record_count_;
135*4d9fdb46SRobert Mustacchi     /*  hashtab_ is an array of hs_entry,
136*4d9fdb46SRobert Mustacchi         indexes 0 through tablesize_ -1. */
137*4d9fdb46SRobert Mustacchi     struct ts_entry * hashtab_;
138*4d9fdb46SRobert Mustacchi     DW_TSHASHTYPE (*hashfunc_)(const void *key);
139*4d9fdb46SRobert Mustacchi };
140*4d9fdb46SRobert Mustacchi 
141*4d9fdb46SRobert Mustacchi struct ts_entry {
142*4d9fdb46SRobert Mustacchi     const void * keyptr;
143*4d9fdb46SRobert Mustacchi     /*  So that a keyptr of 0 (if added) is
144*4d9fdb46SRobert Mustacchi         not confused with an empty hash slot,
145*4d9fdb46SRobert Mustacchi         we must mark used slots as used in the hash tab */
146*4d9fdb46SRobert Mustacchi     unsigned char entryused;
147*4d9fdb46SRobert Mustacchi     struct ts_entry *next;
148*4d9fdb46SRobert Mustacchi };
149*4d9fdb46SRobert Mustacchi 
150*4d9fdb46SRobert Mustacchi enum search_intent_t
151*4d9fdb46SRobert Mustacchi {
152*4d9fdb46SRobert Mustacchi     want_insert,
153*4d9fdb46SRobert Mustacchi     only_find,
154*4d9fdb46SRobert Mustacchi     want_delete
155*4d9fdb46SRobert Mustacchi };
156*4d9fdb46SRobert Mustacchi 
157*4d9fdb46SRobert Mustacchi static struct ts_entry *
158*4d9fdb46SRobert Mustacchi tsearch_inner( const void *key, struct hs_base* head,
159*4d9fdb46SRobert Mustacchi     int (*compar)(const void *, const void *),
160*4d9fdb46SRobert Mustacchi     const enum search_intent_t intent, int*inserted,
161*4d9fdb46SRobert Mustacchi     struct ts_entry **parent_ptr);
162*4d9fdb46SRobert Mustacchi static void
163*4d9fdb46SRobert Mustacchi dwarf_tdestroy_inner(struct hs_base*h,
164*4d9fdb46SRobert Mustacchi     void (*free_node)(void *nodep),
165*4d9fdb46SRobert Mustacchi     int depth);
166*4d9fdb46SRobert Mustacchi 
167*4d9fdb46SRobert Mustacchi 
168*4d9fdb46SRobert Mustacchi /*  A trivial integer-based percentage calculation.
169*4d9fdb46SRobert Mustacchi     Percents >100 are reasonable for a hash-with-chains
170*4d9fdb46SRobert Mustacchi     situation (even if they might not be the best choice
171*4d9fdb46SRobert Mustacchi     for performance). */
172*4d9fdb46SRobert Mustacchi static unsigned long
calculate_allowed_fill(unsigned long fill_percent,unsigned long ct)173*4d9fdb46SRobert Mustacchi calculate_allowed_fill(unsigned long fill_percent, unsigned long ct)
174*4d9fdb46SRobert Mustacchi {
175*4d9fdb46SRobert Mustacchi     unsigned long v = 0;
176*4d9fdb46SRobert Mustacchi     if(ct < 100000) {
177*4d9fdb46SRobert Mustacchi         unsigned long v2 = (ct *fill_percent)/100;
178*4d9fdb46SRobert Mustacchi         return v2;
179*4d9fdb46SRobert Mustacchi     }
180*4d9fdb46SRobert Mustacchi     v = (ct /100)*fill_percent;
181*4d9fdb46SRobert Mustacchi     return v;
182*4d9fdb46SRobert Mustacchi }
183*4d9fdb46SRobert Mustacchi 
184*4d9fdb46SRobert Mustacchi /* Initialize the hash and pass in the hash function.
185*4d9fdb46SRobert Mustacchi    If the entry count needed is unknown, pass in  0 as a count estimate,
186*4d9fdb46SRobert Mustacchi    but if the number of hash entries needed can be estimated,
187*4d9fdb46SRobert Mustacchi    pass in the estimate (which need not be prime, we actually use
188*4d9fdb46SRobert Mustacchi    the nearest higher prime from the above table).
189*4d9fdb46SRobert Mustacchi    If the estimated count is
190*4d9fdb46SRobert Mustacchi    Return the tree base, or return NULL if insufficient memory. */
191*4d9fdb46SRobert Mustacchi void *
dwarf_initialize_search_hash(void ** treeptr,DW_TSHASHTYPE (* hashfunc)(const void * key),unsigned long size_estimate)192*4d9fdb46SRobert Mustacchi dwarf_initialize_search_hash( void **treeptr,
193*4d9fdb46SRobert Mustacchi     DW_TSHASHTYPE(*hashfunc)(const void *key),
194*4d9fdb46SRobert Mustacchi     unsigned long size_estimate)
195*4d9fdb46SRobert Mustacchi {
196*4d9fdb46SRobert Mustacchi     unsigned long prime_to_use = primes[0];
197*4d9fdb46SRobert Mustacchi     unsigned entry_index = 0;
198*4d9fdb46SRobert Mustacchi     unsigned k = 0;
199*4d9fdb46SRobert Mustacchi     struct hs_base *base = 0;
200*4d9fdb46SRobert Mustacchi 
201*4d9fdb46SRobert Mustacchi     base = *(struct hs_base **)treeptr;
202*4d9fdb46SRobert Mustacchi     if(base) {
203*4d9fdb46SRobert Mustacchi         /* initalized already. */
204*4d9fdb46SRobert Mustacchi         return base ;
205*4d9fdb46SRobert Mustacchi     }
206*4d9fdb46SRobert Mustacchi     base = calloc(sizeof(struct hs_base),1);
207*4d9fdb46SRobert Mustacchi     if(!base) {
208*4d9fdb46SRobert Mustacchi         /* Out of memory. */
209*4d9fdb46SRobert Mustacchi         return NULL ;
210*4d9fdb46SRobert Mustacchi     }
211*4d9fdb46SRobert Mustacchi     prime_to_use = primes[0];
212*4d9fdb46SRobert Mustacchi     while(size_estimate && (size_estimate > prime_to_use)) {
213*4d9fdb46SRobert Mustacchi         k = k +1;
214*4d9fdb46SRobert Mustacchi         prime_to_use = primes[k];
215*4d9fdb46SRobert Mustacchi         if(prime_to_use == 0) {
216*4d9fdb46SRobert Mustacchi             /* Oops. Too large. */
217*4d9fdb46SRobert Mustacchi             free(base);
218*4d9fdb46SRobert Mustacchi             return NULL;
219*4d9fdb46SRobert Mustacchi         }
220*4d9fdb46SRobert Mustacchi         entry_index = k;
221*4d9fdb46SRobert Mustacchi     }
222*4d9fdb46SRobert Mustacchi     base->tablesize_ = prime_to_use;
223*4d9fdb46SRobert Mustacchi     base->allowed_fill_ = calculate_allowed_fill(allowed_fill_percent,
224*4d9fdb46SRobert Mustacchi         prime_to_use);
225*4d9fdb46SRobert Mustacchi     if( base->allowed_fill_< (base->tablesize_/2)) {
226*4d9fdb46SRobert Mustacchi         free(base);
227*4d9fdb46SRobert Mustacchi         /* Oops. We are in trouble. Coding mistake here.  */
228*4d9fdb46SRobert Mustacchi         return NULL;
229*4d9fdb46SRobert Mustacchi     }
230*4d9fdb46SRobert Mustacchi     base->record_count_ = 0;
231*4d9fdb46SRobert Mustacchi     base->tablesize_entry_index_ = entry_index;
232*4d9fdb46SRobert Mustacchi     /*  hashtab_ is an array of hs_entry,
233*4d9fdb46SRobert Mustacchi         indexes 0 through tablesize_ -1. */
234*4d9fdb46SRobert Mustacchi     base->hashfunc_ = hashfunc;
235*4d9fdb46SRobert Mustacchi     base->hashtab_ = calloc(sizeof(struct ts_entry),base->tablesize_);
236*4d9fdb46SRobert Mustacchi     if(!base->hashtab_) {
237*4d9fdb46SRobert Mustacchi         free(base);
238*4d9fdb46SRobert Mustacchi         return NULL;
239*4d9fdb46SRobert Mustacchi     }
240*4d9fdb46SRobert Mustacchi     *treeptr = base;
241*4d9fdb46SRobert Mustacchi     return base;
242*4d9fdb46SRobert Mustacchi }
243*4d9fdb46SRobert Mustacchi 
244*4d9fdb46SRobert Mustacchi 
245*4d9fdb46SRobert Mustacchi /*  We don't really care whether hashpos or chainpos
246*4d9fdb46SRobert Mustacchi     are 32 or 64 bits. 32 suffices. */
print_entry(struct ts_entry * t,const char * descr,char * (* keyprint)(const void *),unsigned long hashpos,unsigned long chainpos)247*4d9fdb46SRobert Mustacchi static void print_entry(struct ts_entry *t,const char *descr,
248*4d9fdb46SRobert Mustacchi     char *(* keyprint)(const void *),
249*4d9fdb46SRobert Mustacchi     unsigned long hashpos,
250*4d9fdb46SRobert Mustacchi     unsigned long chainpos)
251*4d9fdb46SRobert Mustacchi {
252*4d9fdb46SRobert Mustacchi     char *v = 0;
253*4d9fdb46SRobert Mustacchi     if(!t->entryused) {
254*4d9fdb46SRobert Mustacchi         return;
255*4d9fdb46SRobert Mustacchi     }
256*4d9fdb46SRobert Mustacchi     v = keyprint(t->keyptr);
257*4d9fdb46SRobert Mustacchi     printf(
258*4d9fdb46SRobert Mustacchi         "[%4lu.%02lu] 0x%08" DW_PR_DUx
259*4d9fdb46SRobert Mustacchi         " <keyptr 0x%08" DW_PR_DUx
260*4d9fdb46SRobert Mustacchi         "> <key %s> %s\n",
261*4d9fdb46SRobert Mustacchi         hashpos,chainpos,
262*4d9fdb46SRobert Mustacchi         (Dwarf_Unsigned)(uintptr_t)t,
263*4d9fdb46SRobert Mustacchi         (Dwarf_Unsigned)(uintptr_t)t->keyptr,
264*4d9fdb46SRobert Mustacchi         v,
265*4d9fdb46SRobert Mustacchi         descr);
266*4d9fdb46SRobert Mustacchi }
267*4d9fdb46SRobert Mustacchi 
268*4d9fdb46SRobert Mustacchi /* For debugging */
269*4d9fdb46SRobert Mustacchi static void
dumptree_inner(const struct hs_base * h,char * (* keyprint)(const void *),const char * descr,int printdetails)270*4d9fdb46SRobert Mustacchi dumptree_inner(const struct hs_base *h,
271*4d9fdb46SRobert Mustacchi     char *(* keyprint)(const void *),
272*4d9fdb46SRobert Mustacchi     const char *descr, int printdetails)
273*4d9fdb46SRobert Mustacchi {
274*4d9fdb46SRobert Mustacchi     unsigned long ix = 0;
275*4d9fdb46SRobert Mustacchi     unsigned long tsize = h->tablesize_;
276*4d9fdb46SRobert Mustacchi     struct ts_entry *p = &h->hashtab_[0];
277*4d9fdb46SRobert Mustacchi     unsigned long hashused = 0;
278*4d9fdb46SRobert Mustacchi     unsigned long maxchainlength = 0;
279*4d9fdb46SRobert Mustacchi     unsigned long chainsgt1 = 0;
280*4d9fdb46SRobert Mustacchi     printf("dumptree head ptr : 0x%08" DW_PR_DUx
281*4d9fdb46SRobert Mustacchi         " size %"    DW_PR_DUu
282*4d9fdb46SRobert Mustacchi         " entries %" DW_PR_DUu
283*4d9fdb46SRobert Mustacchi         " allowed %" DW_PR_DUu " %s\n",
284*4d9fdb46SRobert Mustacchi         (Dwarf_Unsigned)(uintptr_t)h,
285*4d9fdb46SRobert Mustacchi         (Dwarf_Unsigned)h->tablesize_,
286*4d9fdb46SRobert Mustacchi         (Dwarf_Unsigned)h->record_count_,
287*4d9fdb46SRobert Mustacchi         (Dwarf_Unsigned)h->allowed_fill_,
288*4d9fdb46SRobert Mustacchi         descr);
289*4d9fdb46SRobert Mustacchi     for(  ; ix < tsize; ix++,p++) {
290*4d9fdb46SRobert Mustacchi         unsigned long chainlength = 0;
291*4d9fdb46SRobert Mustacchi         struct ts_entry*n = 0;
292*4d9fdb46SRobert Mustacchi         int chainpos = 0;
293*4d9fdb46SRobert Mustacchi         if(p->entryused) {
294*4d9fdb46SRobert Mustacchi             ++hashused;
295*4d9fdb46SRobert Mustacchi             chainlength = 1;
296*4d9fdb46SRobert Mustacchi             if(printdetails) {
297*4d9fdb46SRobert Mustacchi                 print_entry(p,"head",keyprint,ix,chainpos);
298*4d9fdb46SRobert Mustacchi             }
299*4d9fdb46SRobert Mustacchi         }
300*4d9fdb46SRobert Mustacchi         chainpos++;
301*4d9fdb46SRobert Mustacchi         for(n = p->next; n ; n = n->next) {
302*4d9fdb46SRobert Mustacchi             chainlength++;
303*4d9fdb46SRobert Mustacchi             if(printdetails) {
304*4d9fdb46SRobert Mustacchi                 print_entry(n,"chain",keyprint,ix,chainpos);
305*4d9fdb46SRobert Mustacchi             }
306*4d9fdb46SRobert Mustacchi         }
307*4d9fdb46SRobert Mustacchi         if(chainlength > maxchainlength) {
308*4d9fdb46SRobert Mustacchi             maxchainlength = chainlength;
309*4d9fdb46SRobert Mustacchi         }
310*4d9fdb46SRobert Mustacchi         if (chainlength > 1) {
311*4d9fdb46SRobert Mustacchi             chainsgt1++;
312*4d9fdb46SRobert Mustacchi         }
313*4d9fdb46SRobert Mustacchi     }
314*4d9fdb46SRobert Mustacchi     printf("Hashtable: %lu of %lu hash entries used.\n",hashused,tsize);
315*4d9fdb46SRobert Mustacchi     printf("Hashtable: %lu chains length longer than 1. \n",chainsgt1);
316*4d9fdb46SRobert Mustacchi     printf("Hashtable: %lu is maximum chain length.\n",maxchainlength);
317*4d9fdb46SRobert Mustacchi }
318*4d9fdb46SRobert Mustacchi 
319*4d9fdb46SRobert Mustacchi /*  Dumping the tree.
320*4d9fdb46SRobert Mustacchi     */
321*4d9fdb46SRobert Mustacchi void
dwarf_tdump(const void * headp_in,char * (* keyprint)(const void *),const char * msg)322*4d9fdb46SRobert Mustacchi dwarf_tdump(const void*headp_in,
323*4d9fdb46SRobert Mustacchi     char *(* keyprint)(const void *),
324*4d9fdb46SRobert Mustacchi     const char *msg)
325*4d9fdb46SRobert Mustacchi {
326*4d9fdb46SRobert Mustacchi     const struct hs_base *head = (const struct hs_base *)headp_in;
327*4d9fdb46SRobert Mustacchi     if(!head) {
328*4d9fdb46SRobert Mustacchi         printf("dumptree null tree ptr : %s\n",msg);
329*4d9fdb46SRobert Mustacchi         return;
330*4d9fdb46SRobert Mustacchi     }
331*4d9fdb46SRobert Mustacchi     dumptree_inner(head,keyprint,msg,1);
332*4d9fdb46SRobert Mustacchi }
333*4d9fdb46SRobert Mustacchi 
334*4d9fdb46SRobert Mustacchi static struct ts_entry *
allocate_ts_entry(const void * key)335*4d9fdb46SRobert Mustacchi allocate_ts_entry(const void *key)
336*4d9fdb46SRobert Mustacchi {
337*4d9fdb46SRobert Mustacchi     struct ts_entry *e =  0;
338*4d9fdb46SRobert Mustacchi 
339*4d9fdb46SRobert Mustacchi     e = (struct ts_entry *) malloc(sizeof(struct ts_entry));
340*4d9fdb46SRobert Mustacchi     if(!e) {
341*4d9fdb46SRobert Mustacchi         return NULL;
342*4d9fdb46SRobert Mustacchi     }
343*4d9fdb46SRobert Mustacchi     e->keyptr = key;
344*4d9fdb46SRobert Mustacchi     e->entryused = 1;
345*4d9fdb46SRobert Mustacchi     e->next = 0;
346*4d9fdb46SRobert Mustacchi     return e;
347*4d9fdb46SRobert Mustacchi }
348*4d9fdb46SRobert Mustacchi 
349*4d9fdb46SRobert Mustacchi static void
resize_table(struct hs_base * head,int (* compar)(const void *,const void *))350*4d9fdb46SRobert Mustacchi resize_table(struct hs_base *head,
351*4d9fdb46SRobert Mustacchi     int (*compar)(const void *, const void *))
352*4d9fdb46SRobert Mustacchi {
353*4d9fdb46SRobert Mustacchi     struct hs_base newhead;
354*4d9fdb46SRobert Mustacchi     unsigned new_entry_index = 0;
355*4d9fdb46SRobert Mustacchi     unsigned long prime_to_use = 0;
356*4d9fdb46SRobert Mustacchi 
357*4d9fdb46SRobert Mustacchi     /* Copy the values we have. */
358*4d9fdb46SRobert Mustacchi     newhead = *head;
359*4d9fdb46SRobert Mustacchi     /* But drop the hashtab_ from new. calloc below. */
360*4d9fdb46SRobert Mustacchi     newhead.hashtab_ = 0;
361*4d9fdb46SRobert Mustacchi     newhead.record_count_ = 0;
362*4d9fdb46SRobert Mustacchi     new_entry_index = head->tablesize_entry_index_ +1;
363*4d9fdb46SRobert Mustacchi     prime_to_use = primes[new_entry_index];
364*4d9fdb46SRobert Mustacchi     if(prime_to_use == 0) {
365*4d9fdb46SRobert Mustacchi         /*  Oops, too large. Leave table size as is, though
366*4d9fdb46SRobert Mustacchi             it will get slow as it overfills. */
367*4d9fdb46SRobert Mustacchi         return;
368*4d9fdb46SRobert Mustacchi     }
369*4d9fdb46SRobert Mustacchi     newhead.tablesize_ = prime_to_use;
370*4d9fdb46SRobert Mustacchi     newhead.allowed_fill_ = calculate_allowed_fill(allowed_fill_percent,
371*4d9fdb46SRobert Mustacchi         prime_to_use);
372*4d9fdb46SRobert Mustacchi     if( newhead.allowed_fill_< (newhead.tablesize_/2)) {
373*4d9fdb46SRobert Mustacchi         /* Oops. We are in trouble.  */
374*4d9fdb46SRobert Mustacchi         return;
375*4d9fdb46SRobert Mustacchi     }
376*4d9fdb46SRobert Mustacchi     newhead.tablesize_entry_index_ = new_entry_index;
377*4d9fdb46SRobert Mustacchi     newhead.hashtab_ = calloc(sizeof(struct ts_entry),newhead.tablesize_);
378*4d9fdb46SRobert Mustacchi     if(!newhead.hashtab_) {
379*4d9fdb46SRobert Mustacchi         /*  Oops, too large. Leave table size as is, though
380*4d9fdb46SRobert Mustacchi             things will get slow as it overfills. */
381*4d9fdb46SRobert Mustacchi         free(newhead.hashtab_);
382*4d9fdb46SRobert Mustacchi         return;
383*4d9fdb46SRobert Mustacchi     }
384*4d9fdb46SRobert Mustacchi     {
385*4d9fdb46SRobert Mustacchi         /*  Insert all the records from the old table into
386*4d9fdb46SRobert Mustacchi             the new table. */
387*4d9fdb46SRobert Mustacchi         int fillnewfail = 0;
388*4d9fdb46SRobert Mustacchi         unsigned long ix = 0;
389*4d9fdb46SRobert Mustacchi         unsigned long tsize = head->tablesize_;
390*4d9fdb46SRobert Mustacchi         struct ts_entry *p = &head->hashtab_[0];
391*4d9fdb46SRobert Mustacchi         for(  ; ix < tsize; ix++,p++) {
392*4d9fdb46SRobert Mustacchi             int inserted = 0;
393*4d9fdb46SRobert Mustacchi             struct ts_entry*n = 0;
394*4d9fdb46SRobert Mustacchi             if(fillnewfail) {
395*4d9fdb46SRobert Mustacchi                 break;
396*4d9fdb46SRobert Mustacchi             }
397*4d9fdb46SRobert Mustacchi             if(p->keyptr) {
398*4d9fdb46SRobert Mustacchi                 tsearch_inner(p->keyptr,
399*4d9fdb46SRobert Mustacchi                     &newhead,compar,
400*4d9fdb46SRobert Mustacchi                     want_insert,
401*4d9fdb46SRobert Mustacchi                     &inserted,
402*4d9fdb46SRobert Mustacchi                     0);
403*4d9fdb46SRobert Mustacchi                 if(!inserted) {
404*4d9fdb46SRobert Mustacchi                     fillnewfail = 1;
405*4d9fdb46SRobert Mustacchi                     break;
406*4d9fdb46SRobert Mustacchi                 }
407*4d9fdb46SRobert Mustacchi             }
408*4d9fdb46SRobert Mustacchi             for(n = p->next; n ; n = n->next) {
409*4d9fdb46SRobert Mustacchi                 inserted = 0;
410*4d9fdb46SRobert Mustacchi                 tsearch_inner(n->keyptr,
411*4d9fdb46SRobert Mustacchi                     &newhead,compar,
412*4d9fdb46SRobert Mustacchi                     want_insert,
413*4d9fdb46SRobert Mustacchi                     &inserted,
414*4d9fdb46SRobert Mustacchi                     0);
415*4d9fdb46SRobert Mustacchi                 if(!inserted) {
416*4d9fdb46SRobert Mustacchi                     fillnewfail = 1;
417*4d9fdb46SRobert Mustacchi                     break;
418*4d9fdb46SRobert Mustacchi                 }
419*4d9fdb46SRobert Mustacchi             }
420*4d9fdb46SRobert Mustacchi         }
421*4d9fdb46SRobert Mustacchi         if(fillnewfail) {
422*4d9fdb46SRobert Mustacchi             free(newhead.hashtab_);
423*4d9fdb46SRobert Mustacchi             return;
424*4d9fdb46SRobert Mustacchi         }
425*4d9fdb46SRobert Mustacchi     }
426*4d9fdb46SRobert Mustacchi     /* Now get rid of the chain entries of the old table. */
427*4d9fdb46SRobert Mustacchi     dwarf_tdestroy_inner(head,0,0);
428*4d9fdb46SRobert Mustacchi     /* Now get rid of the old table itself. */
429*4d9fdb46SRobert Mustacchi     free(head->hashtab_);
430*4d9fdb46SRobert Mustacchi     head->hashtab_ = 0;
431*4d9fdb46SRobert Mustacchi     *head = newhead;
432*4d9fdb46SRobert Mustacchi     return;
433*4d9fdb46SRobert Mustacchi }
434*4d9fdb46SRobert Mustacchi 
435*4d9fdb46SRobert Mustacchi /*   Inner search of the hash and synonym chains.
436*4d9fdb46SRobert Mustacchi   */
437*4d9fdb46SRobert Mustacchi static struct ts_entry *
tsearch_inner(const void * key,struct hs_base * head,int (* compar)(const void *,const void *),const enum search_intent_t intent,int * inserted,struct ts_entry ** owner_ptr)438*4d9fdb46SRobert Mustacchi tsearch_inner( const void *key, struct hs_base* head,
439*4d9fdb46SRobert Mustacchi     int (*compar)(const void *, const void *),
440*4d9fdb46SRobert Mustacchi     const enum search_intent_t intent, int*inserted,
441*4d9fdb46SRobert Mustacchi     /* owner_ptr used for delete.  Only set
442*4d9fdb46SRobert Mustacchi         if the to-be-deleted item is on a chain,
443*4d9fdb46SRobert Mustacchi         not in the hashtab. Points to the item
444*4d9fdb46SRobert Mustacchi         pointing to the to-be-deleted-item.*/
445*4d9fdb46SRobert Mustacchi     struct ts_entry **owner_ptr)
446*4d9fdb46SRobert Mustacchi {
447*4d9fdb46SRobert Mustacchi     struct ts_entry *s =0;
448*4d9fdb46SRobert Mustacchi     struct ts_entry *c =0;
449*4d9fdb46SRobert Mustacchi     struct ts_entry *q =0;
450*4d9fdb46SRobert Mustacchi     int kc = 0;
451*4d9fdb46SRobert Mustacchi     DW_TSHASHTYPE keyhash =  0;
452*4d9fdb46SRobert Mustacchi     DW_TSHASHTYPE hindx = 0;
453*4d9fdb46SRobert Mustacchi     struct ts_entry *chain_parent = 0;
454*4d9fdb46SRobert Mustacchi 
455*4d9fdb46SRobert Mustacchi     if(! head->hashfunc_) {
456*4d9fdb46SRobert Mustacchi         /* Not fully initialized. */
457*4d9fdb46SRobert Mustacchi         return NULL;
458*4d9fdb46SRobert Mustacchi     }
459*4d9fdb46SRobert Mustacchi     keyhash =  head->hashfunc_(key);
460*4d9fdb46SRobert Mustacchi     if (intent == want_insert) {
461*4d9fdb46SRobert Mustacchi         if( head->record_count_ > head->allowed_fill_) {
462*4d9fdb46SRobert Mustacchi             resize_table(head,compar);
463*4d9fdb46SRobert Mustacchi         }
464*4d9fdb46SRobert Mustacchi     }
465*4d9fdb46SRobert Mustacchi     hindx = keyhash%head->tablesize_;
466*4d9fdb46SRobert Mustacchi     s = &head->hashtab_[hindx];
467*4d9fdb46SRobert Mustacchi     if(!s->entryused) {
468*4d9fdb46SRobert Mustacchi         /* Not found. */
469*4d9fdb46SRobert Mustacchi         if(intent != want_insert) {
470*4d9fdb46SRobert Mustacchi             return NULL;
471*4d9fdb46SRobert Mustacchi         }
472*4d9fdb46SRobert Mustacchi         /*  Insert in the base hash table in an
473*4d9fdb46SRobert Mustacchi             empty slot. */
474*4d9fdb46SRobert Mustacchi         *inserted = 1;
475*4d9fdb46SRobert Mustacchi         head->record_count_++;
476*4d9fdb46SRobert Mustacchi         s->keyptr = (const void *)key;
477*4d9fdb46SRobert Mustacchi         s->entryused = 1;
478*4d9fdb46SRobert Mustacchi         s->next = 0;
479*4d9fdb46SRobert Mustacchi         return s;
480*4d9fdb46SRobert Mustacchi     }
481*4d9fdb46SRobert Mustacchi     kc = compar(key,s->keyptr);
482*4d9fdb46SRobert Mustacchi     if(kc == 0 ) {
483*4d9fdb46SRobert Mustacchi         /* found! */
484*4d9fdb46SRobert Mustacchi         if(want_delete) {
485*4d9fdb46SRobert Mustacchi             *owner_ptr = 0;
486*4d9fdb46SRobert Mustacchi         }
487*4d9fdb46SRobert Mustacchi         return (void *)&(s->keyptr);
488*4d9fdb46SRobert Mustacchi     }
489*4d9fdb46SRobert Mustacchi     chain_parent = s;
490*4d9fdb46SRobert Mustacchi     for(c = s->next; c; c = c->next)  {
491*4d9fdb46SRobert Mustacchi         kc = compar(key,c->keyptr);
492*4d9fdb46SRobert Mustacchi         if(kc == 0 ) {
493*4d9fdb46SRobert Mustacchi             /* found! */
494*4d9fdb46SRobert Mustacchi             if(want_delete) {
495*4d9fdb46SRobert Mustacchi                 *owner_ptr = chain_parent;
496*4d9fdb46SRobert Mustacchi             }
497*4d9fdb46SRobert Mustacchi             return (void *)&(c->keyptr);
498*4d9fdb46SRobert Mustacchi         }
499*4d9fdb46SRobert Mustacchi         chain_parent = c;
500*4d9fdb46SRobert Mustacchi     }
501*4d9fdb46SRobert Mustacchi     if(intent != want_insert) {
502*4d9fdb46SRobert Mustacchi         return NULL;
503*4d9fdb46SRobert Mustacchi     }
504*4d9fdb46SRobert Mustacchi     /* Insert following head record of the chain. */
505*4d9fdb46SRobert Mustacchi     q = allocate_ts_entry(key);
506*4d9fdb46SRobert Mustacchi     if (!q) {
507*4d9fdb46SRobert Mustacchi         return q;
508*4d9fdb46SRobert Mustacchi     }
509*4d9fdb46SRobert Mustacchi     q->next = s->next;
510*4d9fdb46SRobert Mustacchi     s->next = q;
511*4d9fdb46SRobert Mustacchi     head->record_count_++;
512*4d9fdb46SRobert Mustacchi     *inserted = 1;
513*4d9fdb46SRobert Mustacchi     return q;
514*4d9fdb46SRobert Mustacchi }
515*4d9fdb46SRobert Mustacchi /* Search and, if missing, insert. */
516*4d9fdb46SRobert Mustacchi void *
dwarf_tsearch(const void * key,void ** headin,int (* compar)(const void *,const void *))517*4d9fdb46SRobert Mustacchi dwarf_tsearch(const void *key, void **headin,
518*4d9fdb46SRobert Mustacchi     int (*compar)(const void *, const void *))
519*4d9fdb46SRobert Mustacchi {
520*4d9fdb46SRobert Mustacchi     struct hs_base **rootp = (struct hs_base **)headin;
521*4d9fdb46SRobert Mustacchi     struct hs_base *head = *rootp;
522*4d9fdb46SRobert Mustacchi     struct ts_entry *r = 0;
523*4d9fdb46SRobert Mustacchi     int inserted = 0;
524*4d9fdb46SRobert Mustacchi     /* nullme won't be set. */
525*4d9fdb46SRobert Mustacchi     struct ts_entry *nullme = 0;
526*4d9fdb46SRobert Mustacchi 
527*4d9fdb46SRobert Mustacchi     if (!head) {
528*4d9fdb46SRobert Mustacchi         /* something is wrong here, not initialized. */
529*4d9fdb46SRobert Mustacchi         return NULL;
530*4d9fdb46SRobert Mustacchi     }
531*4d9fdb46SRobert Mustacchi     r = tsearch_inner(key,head,compar,want_insert,&inserted,&nullme);
532*4d9fdb46SRobert Mustacchi     if (!r) {
533*4d9fdb46SRobert Mustacchi         return NULL;
534*4d9fdb46SRobert Mustacchi     }
535*4d9fdb46SRobert Mustacchi     return (void *)&(r->keyptr);
536*4d9fdb46SRobert Mustacchi }
537*4d9fdb46SRobert Mustacchi 
538*4d9fdb46SRobert Mustacchi 
539*4d9fdb46SRobert Mustacchi /* Search. */
540*4d9fdb46SRobert Mustacchi void *
dwarf_tfind(const void * key,void * const * rootp,int (* compar)(const void *,const void *))541*4d9fdb46SRobert Mustacchi dwarf_tfind(const void *key, void *const *rootp,
542*4d9fdb46SRobert Mustacchi     int (*compar)(const void *, const void *))
543*4d9fdb46SRobert Mustacchi {
544*4d9fdb46SRobert Mustacchi     /*  Nothing will change, but we discard const
545*4d9fdb46SRobert Mustacchi         so we can use tsearch_inner(). */
546*4d9fdb46SRobert Mustacchi     struct hs_base **proot = (struct hs_base **)rootp;
547*4d9fdb46SRobert Mustacchi     struct hs_base *head = *proot;
548*4d9fdb46SRobert Mustacchi     struct ts_entry *r = 0;
549*4d9fdb46SRobert Mustacchi     /* inserted flag won't be set. */
550*4d9fdb46SRobert Mustacchi     int inserted = 0;
551*4d9fdb46SRobert Mustacchi     /* nullme won't be set. */
552*4d9fdb46SRobert Mustacchi     struct ts_entry * nullme = 0;
553*4d9fdb46SRobert Mustacchi     /* Get to actual tree. */
554*4d9fdb46SRobert Mustacchi 
555*4d9fdb46SRobert Mustacchi     if (!head) {
556*4d9fdb46SRobert Mustacchi         return NULL;
557*4d9fdb46SRobert Mustacchi     }
558*4d9fdb46SRobert Mustacchi 
559*4d9fdb46SRobert Mustacchi     r = tsearch_inner(key,head,compar,only_find,&inserted,&nullme);
560*4d9fdb46SRobert Mustacchi     if(!r) {
561*4d9fdb46SRobert Mustacchi         return NULL;
562*4d9fdb46SRobert Mustacchi     }
563*4d9fdb46SRobert Mustacchi     return (void *)(&(r->keyptr));
564*4d9fdb46SRobert Mustacchi }
565*4d9fdb46SRobert Mustacchi 
566*4d9fdb46SRobert Mustacchi /*  Unlike the simple binary tree case,
567*4d9fdb46SRobert Mustacchi     a fully-empty hash situation does not null the *rootp
568*4d9fdb46SRobert Mustacchi */
569*4d9fdb46SRobert Mustacchi void *
dwarf_tdelete(const void * key,void ** rootp,int (* compar)(const void *,const void *))570*4d9fdb46SRobert Mustacchi dwarf_tdelete(const void *key, void **rootp,
571*4d9fdb46SRobert Mustacchi     int (*compar)(const void *, const void *))
572*4d9fdb46SRobert Mustacchi {
573*4d9fdb46SRobert Mustacchi     struct hs_base **proot = (struct hs_base **)rootp;
574*4d9fdb46SRobert Mustacchi     struct hs_base *head = *proot;
575*4d9fdb46SRobert Mustacchi     struct ts_entry *found = 0;
576*4d9fdb46SRobert Mustacchi     /* inserted flag won't be set. */
577*4d9fdb46SRobert Mustacchi     int inserted = 0;
578*4d9fdb46SRobert Mustacchi     struct ts_entry * parentp = 0;
579*4d9fdb46SRobert Mustacchi 
580*4d9fdb46SRobert Mustacchi     if (!head) {
581*4d9fdb46SRobert Mustacchi         return NULL;
582*4d9fdb46SRobert Mustacchi     }
583*4d9fdb46SRobert Mustacchi 
584*4d9fdb46SRobert Mustacchi     found = tsearch_inner(key,head,compar,want_delete,&inserted,
585*4d9fdb46SRobert Mustacchi         &parentp);
586*4d9fdb46SRobert Mustacchi     if(found) {
587*4d9fdb46SRobert Mustacchi         if(parentp) {
588*4d9fdb46SRobert Mustacchi             /* Delete a chain entry. */
589*4d9fdb46SRobert Mustacchi             head->record_count_--;
590*4d9fdb46SRobert Mustacchi             parentp->next = found->next;
591*4d9fdb46SRobert Mustacchi             /*  We free our storage. It would be up
592*4d9fdb46SRobert Mustacchi                 to caller to do a tfind to find
593*4d9fdb46SRobert Mustacchi                 a record and delete content if necessary. */
594*4d9fdb46SRobert Mustacchi             free(found);
595*4d9fdb46SRobert Mustacchi             return (void *)&(parentp->keyptr);
596*4d9fdb46SRobert Mustacchi         }
597*4d9fdb46SRobert Mustacchi         /* So found is the head of a chain. */
598*4d9fdb46SRobert Mustacchi         if(found->next) {
599*4d9fdb46SRobert Mustacchi             /*  Delete a chain entry, pull up to hash tab, freeing
600*4d9fdb46SRobert Mustacchi                 up the chain entry. */
601*4d9fdb46SRobert Mustacchi             struct ts_entry *pullup = found->next;
602*4d9fdb46SRobert Mustacchi             *found = *pullup;
603*4d9fdb46SRobert Mustacchi             free(pullup);
604*4d9fdb46SRobert Mustacchi             head->record_count_--;
605*4d9fdb46SRobert Mustacchi             return (void *)&(found->keyptr);
606*4d9fdb46SRobert Mustacchi         } else {
607*4d9fdb46SRobert Mustacchi             /*  Delete a main hash table entry.
608*4d9fdb46SRobert Mustacchi                 Problem: what the heck to return as a keyptr pointer?
609*4d9fdb46SRobert Mustacchi                 Well, we return NULL. As in the standard
610*4d9fdb46SRobert Mustacchi                 tsearch, returning NULL does not mean
611*4d9fdb46SRobert Mustacchi                 failure! Here it just means 'empty chain somewhere'.
612*4d9fdb46SRobert Mustacchi             */
613*4d9fdb46SRobert Mustacchi             head->record_count_--;
614*4d9fdb46SRobert Mustacchi             found->next = 0;
615*4d9fdb46SRobert Mustacchi             found->keyptr = 0;
616*4d9fdb46SRobert Mustacchi             found->entryused = 0;
617*4d9fdb46SRobert Mustacchi             return NULL;
618*4d9fdb46SRobert Mustacchi         }
619*4d9fdb46SRobert Mustacchi     }
620*4d9fdb46SRobert Mustacchi     return NULL;
621*4d9fdb46SRobert Mustacchi }
622*4d9fdb46SRobert Mustacchi 
623*4d9fdb46SRobert Mustacchi static void
dwarf_twalk_inner(const struct hs_base * h,struct ts_entry * p,void (* action)(const void * nodep,const DW_VISIT which,UNUSEDARG const int depth),UNUSEDARG unsigned level)624*4d9fdb46SRobert Mustacchi dwarf_twalk_inner(const struct hs_base *h,
625*4d9fdb46SRobert Mustacchi     struct ts_entry *p,
626*4d9fdb46SRobert Mustacchi     void (*action)(const void *nodep, const DW_VISIT which,
627*4d9fdb46SRobert Mustacchi         UNUSEDARG const int depth),
628*4d9fdb46SRobert Mustacchi     UNUSEDARG unsigned level)
629*4d9fdb46SRobert Mustacchi {
630*4d9fdb46SRobert Mustacchi     unsigned long ix = 0;
631*4d9fdb46SRobert Mustacchi     unsigned long tsize = h->tablesize_;
632*4d9fdb46SRobert Mustacchi     for(  ; ix < tsize; ix++,p++) {
633*4d9fdb46SRobert Mustacchi         struct ts_entry*n = 0;
634*4d9fdb46SRobert Mustacchi         if(p->keyptr) {
635*4d9fdb46SRobert Mustacchi             action((void *)(&(p->keyptr)),dwarf_leaf,level);
636*4d9fdb46SRobert Mustacchi         }
637*4d9fdb46SRobert Mustacchi         for(n = p->next; n ; n = n->next) {
638*4d9fdb46SRobert Mustacchi             action((void *)(&(n->keyptr)),dwarf_leaf,level);
639*4d9fdb46SRobert Mustacchi         }
640*4d9fdb46SRobert Mustacchi     }
641*4d9fdb46SRobert Mustacchi }
642*4d9fdb46SRobert Mustacchi 
643*4d9fdb46SRobert Mustacchi void
dwarf_twalk(const void * rootp,void (* action)(const void * nodep,const DW_VISIT which,UNUSEDARG const int depth))644*4d9fdb46SRobert Mustacchi dwarf_twalk(const void *rootp,
645*4d9fdb46SRobert Mustacchi     void (*action)(const void *nodep, const DW_VISIT which,
646*4d9fdb46SRobert Mustacchi         UNUSEDARG const int depth))
647*4d9fdb46SRobert Mustacchi {
648*4d9fdb46SRobert Mustacchi     const struct hs_base *head = (const struct hs_base *)rootp;
649*4d9fdb46SRobert Mustacchi     struct ts_entry *root = 0;
650*4d9fdb46SRobert Mustacchi     if(!head) {
651*4d9fdb46SRobert Mustacchi         return;
652*4d9fdb46SRobert Mustacchi     }
653*4d9fdb46SRobert Mustacchi     root = head->hashtab_;
654*4d9fdb46SRobert Mustacchi     /* Get to actual tree. */
655*4d9fdb46SRobert Mustacchi     dwarf_twalk_inner(head,root,action,0);
656*4d9fdb46SRobert Mustacchi }
657*4d9fdb46SRobert Mustacchi 
658*4d9fdb46SRobert Mustacchi static void
dwarf_tdestroy_inner(struct hs_base * h,void (* free_node)(void * nodep),UNUSEDARG int depth)659*4d9fdb46SRobert Mustacchi dwarf_tdestroy_inner(struct hs_base*h,
660*4d9fdb46SRobert Mustacchi     void (*free_node)(void *nodep),
661*4d9fdb46SRobert Mustacchi     UNUSEDARG int depth)
662*4d9fdb46SRobert Mustacchi {
663*4d9fdb46SRobert Mustacchi     unsigned long ix = 0;
664*4d9fdb46SRobert Mustacchi     unsigned long tsize = h->tablesize_;
665*4d9fdb46SRobert Mustacchi     struct ts_entry *p = &h->hashtab_[0];
666*4d9fdb46SRobert Mustacchi     for(  ; ix < tsize; ix++,p++) {
667*4d9fdb46SRobert Mustacchi         struct ts_entry*n = 0;
668*4d9fdb46SRobert Mustacchi         struct ts_entry*prev = 0;
669*4d9fdb46SRobert Mustacchi         if(p->keyptr && p->entryused) {
670*4d9fdb46SRobert Mustacchi             if(free_node) {
671*4d9fdb46SRobert Mustacchi                 free_node((void *)(p->keyptr));
672*4d9fdb46SRobert Mustacchi             }
673*4d9fdb46SRobert Mustacchi             --h->record_count_;
674*4d9fdb46SRobert Mustacchi         }
675*4d9fdb46SRobert Mustacchi         /* Now walk and free up the chain entries. */
676*4d9fdb46SRobert Mustacchi         for(n = p->next; n ; ) {
677*4d9fdb46SRobert Mustacchi             if(free_node) {
678*4d9fdb46SRobert Mustacchi                 free_node((void *)(n->keyptr));
679*4d9fdb46SRobert Mustacchi             }
680*4d9fdb46SRobert Mustacchi             --h->record_count_;
681*4d9fdb46SRobert Mustacchi             prev = n;
682*4d9fdb46SRobert Mustacchi             n = n->next;
683*4d9fdb46SRobert Mustacchi             free(prev);
684*4d9fdb46SRobert Mustacchi         }
685*4d9fdb46SRobert Mustacchi     }
686*4d9fdb46SRobert Mustacchi }
687*4d9fdb46SRobert Mustacchi 
688*4d9fdb46SRobert Mustacchi /*  Walk the tree, freeing all space in the tree
689*4d9fdb46SRobert Mustacchi     and calling the user's callback function on each node.
690*4d9fdb46SRobert Mustacchi 
691*4d9fdb46SRobert Mustacchi     It is up to the caller to zero out anything pointing to
692*4d9fdb46SRobert Mustacchi     head (ie, that has the value rootp holds) after this
693*4d9fdb46SRobert Mustacchi     returns.
694*4d9fdb46SRobert Mustacchi */
695*4d9fdb46SRobert Mustacchi void
dwarf_tdestroy(void * rootp,void (* free_node)(void * nodep))696*4d9fdb46SRobert Mustacchi dwarf_tdestroy(void *rootp, void (*free_node)(void *nodep))
697*4d9fdb46SRobert Mustacchi {
698*4d9fdb46SRobert Mustacchi     struct hs_base *head = (struct hs_base *)rootp;
699*4d9fdb46SRobert Mustacchi     struct ts_entry *root = 0;
700*4d9fdb46SRobert Mustacchi     if(!head) {
701*4d9fdb46SRobert Mustacchi         return;
702*4d9fdb46SRobert Mustacchi     }
703*4d9fdb46SRobert Mustacchi     root = head->hashtab_;
704*4d9fdb46SRobert Mustacchi     dwarf_tdestroy_inner(head,free_node,0);
705*4d9fdb46SRobert Mustacchi     free(root);
706*4d9fdb46SRobert Mustacchi     free(head);
707*4d9fdb46SRobert Mustacchi }
708