1 /* hash.c: hash table operations.
3 Copyright 1994-2000, 2002, 2005, 2008, 2012
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. */
31 hash (hash_table_type table
, const_string key
)
35 /* Our keys aren't often anagrams of each other, so no point in
36 weighting the characters. */
40 n
= (n
+ n
+ (unsigned)(*key
++)) % table
.size
;
41 n
= (n
+ n
+ (unsigned)(*key
++)) % table
.size
;
44 n
= (n
+ n
+ TRANSFORM (*key
++)) % table
.size
;
49 /* Identical has function as above, but does not normalize keys. */
51 hash_normalized (hash_table_type table
, const_string key
)
55 /* Our keys aren't often anagrams of each other, so no point in
56 weighting the characters. */
58 n
= (n
+ n
+ (*key
++)) % table
.size
;
64 hash_create (unsigned size
)
66 /* The was "static ..." since Oct3, 1997 to work around a gcc
67 optimizer bug for Alpha. That particular optimization bug
68 should be gone by now (Mar4, 2009).
72 ret
.buckets
= XTALLOC (size
, hash_element_type
*);
75 /* calloc's zeroes aren't necessarily NULL, so be safe. */
76 for (b
= 0; b
<ret
.size
; b
++)
77 ret
.buckets
[b
] = NULL
;
82 /* Whether or not KEY is already in TABLE, insert it and VALUE. Do not
83 duplicate the strings, in case they're being purposefully shared. */
86 hash_insert (hash_table_type
*table
,
90 unsigned n
= hash (*table
, key
);
91 hash_element_type
*new_elt
= XTALLOC1 (hash_element_type
);
94 new_elt
->value
= value
;
97 /* Insert the new element at the end of the list. */
98 if (!table
->buckets
[n
])
99 /* first element in bucket is a special case. */
100 table
->buckets
[n
] = new_elt
;
103 hash_element_type
*loc
= table
->buckets
[n
];
104 while (loc
->next
) /* Find the last element. */
106 loc
->next
= new_elt
; /* Insert the new one after. */
110 /* Same as above, for normalized keys. */
112 hash_insert_normalized (hash_table_type
*table
,
116 unsigned n
= hash_normalized (*table
, key
);
117 hash_element_type
*new_elt
= XTALLOC1 (hash_element_type
);
120 new_elt
->value
= value
;
121 new_elt
->next
= NULL
;
123 /* Insert the new element at the end of the list. */
124 if (!table
->buckets
[n
])
125 /* first element in bucket is a special case. */
126 table
->buckets
[n
] = new_elt
;
129 hash_element_type
*loc
= table
->buckets
[n
];
130 while (loc
->next
) /* Find the last element. */
132 loc
->next
= new_elt
; /* Insert the new one after. */
136 /* Remove a (KEY, VALUE) pair. */
139 hash_remove (hash_table_type
*table
, const_string key
,
142 hash_element_type
*p
;
143 hash_element_type
*q
;
144 unsigned n
= hash (*table
, key
);
147 for (q
= NULL
, p
= table
->buckets
[n
]; p
!= NULL
; q
= p
, p
= p
->next
)
148 if (FILESTRCASEEQ (key
, p
->key
) && STREQ (value
, p
->value
))
151 /* We found something, remove it from the chain. */
152 if (q
) q
->next
= p
->next
; else table
->buckets
[n
] = p
->next
;
153 /* We cannot dispose of the contents. */
158 /* Look up KEY in TABLE, and return NULL-terminated list of all matching
159 values (not copies), in insertion order. If none, return NULL. */
162 hash_lookup (hash_table_type table
, const_string key
)
164 hash_element_type
*p
;
166 unsigned n
= hash (table
, key
);
167 ret
= cstr_list_init ();
169 /* Look at everything in this bucket. */
170 for (p
= table
.buckets
[n
]; p
!= NULL
; p
= p
->next
)
171 if (FILESTRCASEEQ (key
, p
->key
))
172 cstr_list_add (&ret
, p
->value
);
174 /* If we found anything, mark end of list with null. */
176 cstr_list_add (&ret
, NULL
);
179 #if defined (KPSE_COMPAT_API)
181 kpathsea kpse
= kpse_def
;
182 if (KPATHSEA_DEBUG_P (KPSE_DEBUG_HASH
))
184 DEBUGF1 ("hash_lookup(%s) =>", key
);
186 fputs (" (nil)\n", stderr
);
190 for (r
= STR_LIST (ret
); *r
; r
++)
193 if (kpse
->debug_hash_lookup_int
)
195 fprintf (stderr
, "%I64d", (__int64
) *r
);
197 fprintf (stderr
, "%ld", (long) *r
);
210 return STR_LIST (ret
);
214 /* We only print nonempty buckets, to decrease output volume. */
217 hash_print (hash_table_type table
, boolean summary_only
)
220 unsigned total_elements
= 0, total_buckets
= 0;
222 for (b
= 0; b
< table
.size
; b
++) {
223 hash_element_type
*bucket
= table
.buckets
[b
];
227 hash_element_type
*tb
;
230 if (!summary_only
) fprintf (stderr
, "%4d ", b
);
232 for (tb
= bucket
->next
; tb
!= NULL
; tb
= tb
->next
)
234 if (!summary_only
) fprintf (stderr
, ":%-5d", len
);
235 total_elements
+= len
;
238 for (tb
= bucket
; tb
!= NULL
; tb
= tb
->next
)
239 fprintf (stderr
, " %s=>%s", tb
->key
, tb
->value
);
246 "%u buckets, %u nonempty (%u%%); %u entries, average chain %.1f.\n",
249 100 * total_buckets
/ table
.size
,
251 total_buckets
? total_elements
/ (double) total_buckets
: 0.0);
255 #if KPATHSEA_CAN_FREE
257 hash_free (hash_table_type table
)
259 struct hash_element_struct
*p
, *q
;
260 p
= (struct hash_element_struct
*)table
.buckets
;
263 free ((char *)p
->key
);
264 free ((char *)p
->value
);