1 /* hash.c: hash table operations.
3 Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2002, 2005, 2008
4 Karl Berry & Olaf Weber.
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with this library; if not, see <http://www.gnu.org/licenses/>. */
19 #include <kpathsea/config.h>
20 #include <kpathsea/c-ctype.h>
22 #include <kpathsea/hash.h>
23 #include <kpathsea/str-list.h>
26 /* The hash function. We go for simplicity here. */
28 /* All our hash tables are related to filenames. */
29 #ifdef MONOCASE_FILENAMES
30 #if defined(WIN32) && !defined(__i386_pc_gnu__)
31 /* This is way faster under Win32. */
32 #define TRANSFORM(x) ((unsigned)CharLower((LPTSTR)(BYTE)(x)))
34 #define TRANSFORM(x) (tolower(x))
37 #define TRANSFORM(x) (x)
41 hash P2C(hash_table_type, table, const_string, key)
45 /* Our keys aren't often anagrams of each other, so no point in
46 weighting the characters. */
48 n = (n + n + TRANSFORM (*key++)) % table.size;
53 /* Identical has function as above, but does not normalize keys. */
55 hash_normalized P2C(hash_table_type, table, const_string, key)
59 /* Our keys aren't often anagrams of each other, so no point in
60 weighting the characters. */
62 n = (n + n + (*key++)) % table.size;
68 hash_create P1C(unsigned, size)
70 /* hash_table_type ret; changed into "static ..." to work around gcc
71 optimizer bug for Alpha. */
72 static hash_table_type ret;
74 ret.buckets = XTALLOC (size, hash_element_type *);
77 /* calloc's zeroes aren't necessarily NULL, so be safe. */
78 for (b = 0; b <ret.size; b++)
79 ret.buckets[b] = NULL;
84 /* Whether or not KEY is already in MAP, insert it and VALUE. Do not
85 duplicate the strings, in case they're being purposefully shared. */
88 hash_insert P3C(hash_table_type *, table,
92 unsigned n = hash (*table, key);
93 hash_element_type *new_elt = XTALLOC1 (hash_element_type);
96 new_elt->value = value;
99 /* Insert the new element at the end of the list. */
100 if (!table->buckets[n])
101 /* first element in bucket is a special case. */
102 table->buckets[n] = new_elt;
105 hash_element_type *loc = table->buckets[n];
106 while (loc->next) /* Find the last element. */
108 loc->next = new_elt; /* Insert the new one after. */
112 /* Same as above, for normalized keys. */
114 hash_insert_normalized P3C(hash_table_type *, table,
118 unsigned n = hash_normalized (*table, key);
119 hash_element_type *new_elt = XTALLOC1 (hash_element_type);
122 new_elt->value = value;
123 new_elt->next = NULL;
125 /* Insert the new element at the end of the list. */
126 if (!table->buckets[n])
127 /* first element in bucket is a special case. */
128 table->buckets[n] = new_elt;
131 hash_element_type *loc = table->buckets[n];
132 while (loc->next) /* Find the last element. */
134 loc->next = new_elt; /* Insert the new one after. */
138 /* Remove a (KEY, VALUE) pair. */
141 hash_remove P3C(hash_table_type *, table, const_string, key,
144 hash_element_type *p;
145 hash_element_type *q;
146 unsigned n = hash (*table, key);
149 for (q = NULL, p = table->buckets[n]; p != NULL; q = p, p = p->next)
150 if (FILESTRCASEEQ (key, p->key) && STREQ (value, p->value))
153 /* We found something, remove it from the chain. */
154 if (q) q->next = p->next; else table->buckets[n] = p->next;
155 /* We cannot dispose of the contents. */
160 /* Look up STR in MAP. Return a (dynamically-allocated) list of the
161 corresponding strings or NULL if no match. */
164 /* Print the hash values as integers if this is nonzero. */
165 boolean kpse_debug_hash_lookup_int = false;
169 hash_lookup P2C(hash_table_type, table, const_string, key)
171 hash_element_type *p;
173 unsigned n = hash (table, key);
174 ret = str_list_init ();
176 /* Look at everything in this bucket. */
177 for (p = table.buckets[n]; p != NULL; p = p->next)
178 if (FILESTRCASEEQ (key, p->key))
179 /* Cast because the general str_list_type shouldn't force const data. */
180 str_list_add (&ret, (string) p->value);
182 /* If we found anything, mark end of list with null. */
184 str_list_add (&ret, NULL);
187 if (KPSE_DEBUG_P (KPSE_DEBUG_HASH))
189 DEBUGF1 ("hash_lookup(%s) =>", key);
191 fputs (" (nil)\n", stderr);
195 for (r = STR_LIST (ret); *r; r++)
198 if (kpse_debug_hash_lookup_int)
199 fprintf (stderr, "%ld", (long) *r);
209 return STR_LIST (ret);
212 /* We only print nonempty buckets, to decrease output volume. */
215 hash_print P2C(hash_table_type, table, boolean, summary_only)
218 unsigned total_elements = 0, total_buckets = 0;
220 for (b = 0; b < table.size; b++) {
221 hash_element_type *bucket = table.buckets[b];
225 hash_element_type *tb;
228 if (!summary_only) fprintf (stderr, "%4d ", b);
230 for (tb = bucket->next; tb != NULL; tb = tb->next)
232 if (!summary_only) fprintf (stderr, ":%-5d", len);
233 total_elements += len;
236 for (tb = bucket; tb != NULL; tb = tb->next)
237 fprintf (stderr, " %s=>%s", tb->key, tb->value);
244 "%u buckets, %u nonempty (%u%%); %u entries, average chain %.1f.\n",
247 100 * total_buckets / table.size,
249 total_buckets ? total_elements / (double) total_buckets : 0.0);