xref: /freebsd-src/cddl/contrib/opensolaris/tools/ctf/cvt/hash.c (revision 1673e4046da975ab0e2bf67d45499930ebab0dbe)
1*1673e404SJohn Birrell /*
2*1673e404SJohn Birrell  * CDDL HEADER START
3*1673e404SJohn Birrell  *
4*1673e404SJohn Birrell  * The contents of this file are subject to the terms of the
5*1673e404SJohn Birrell  * Common Development and Distribution License, Version 1.0 only
6*1673e404SJohn Birrell  * (the "License").  You may not use this file except in compliance
7*1673e404SJohn Birrell  * with the License.
8*1673e404SJohn Birrell  *
9*1673e404SJohn Birrell  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*1673e404SJohn Birrell  * or http://www.opensolaris.org/os/licensing.
11*1673e404SJohn Birrell  * See the License for the specific language governing permissions
12*1673e404SJohn Birrell  * and limitations under the License.
13*1673e404SJohn Birrell  *
14*1673e404SJohn Birrell  * When distributing Covered Code, include this CDDL HEADER in each
15*1673e404SJohn Birrell  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*1673e404SJohn Birrell  * If applicable, add the following below this CDDL HEADER, with the
17*1673e404SJohn Birrell  * fields enclosed by brackets "[]" replaced with your own identifying
18*1673e404SJohn Birrell  * information: Portions Copyright [yyyy] [name of copyright owner]
19*1673e404SJohn Birrell  *
20*1673e404SJohn Birrell  * CDDL HEADER END
21*1673e404SJohn Birrell  */
22*1673e404SJohn Birrell /*
23*1673e404SJohn Birrell  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*1673e404SJohn Birrell  * Use is subject to license terms.
25*1673e404SJohn Birrell  */
26*1673e404SJohn Birrell 
27*1673e404SJohn Birrell #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*1673e404SJohn Birrell 
29*1673e404SJohn Birrell /*
30*1673e404SJohn Birrell  * Routines for manipulating hash tables
31*1673e404SJohn Birrell  */
32*1673e404SJohn Birrell 
33*1673e404SJohn Birrell #include <stdio.h>
34*1673e404SJohn Birrell #include <stdlib.h>
35*1673e404SJohn Birrell #include <strings.h>
36*1673e404SJohn Birrell #include <sys/types.h>
37*1673e404SJohn Birrell #include <sys/sysmacros.h>
38*1673e404SJohn Birrell 
39*1673e404SJohn Birrell #include "hash.h"
40*1673e404SJohn Birrell #include "memory.h"
41*1673e404SJohn Birrell #include "list.h"
42*1673e404SJohn Birrell 
43*1673e404SJohn Birrell struct hash {
44*1673e404SJohn Birrell 	int h_nbuckets;
45*1673e404SJohn Birrell 	list_t **h_buckets;
46*1673e404SJohn Birrell 
47*1673e404SJohn Birrell 	int (*h_hashfn)(int, void *);
48*1673e404SJohn Birrell 	int (*h_cmp)(void *, void *);
49*1673e404SJohn Birrell };
50*1673e404SJohn Birrell 
51*1673e404SJohn Birrell struct hash_data {
52*1673e404SJohn Birrell 	hash_t *hd_hash;
53*1673e404SJohn Birrell 	int (*hd_fun)(void *, void *);
54*1673e404SJohn Birrell 	void *hd_key;
55*1673e404SJohn Birrell 	void *hd_private;
56*1673e404SJohn Birrell 
57*1673e404SJohn Birrell 	void *hd_ret;
58*1673e404SJohn Birrell };
59*1673e404SJohn Birrell 
60*1673e404SJohn Birrell static int
61*1673e404SJohn Birrell hash_def_hash(int nbuckets, void *arg)
62*1673e404SJohn Birrell {
63*1673e404SJohn Birrell 	uintptr_t data = (uintptr_t) arg;
64*1673e404SJohn Birrell 	return (data % nbuckets);
65*1673e404SJohn Birrell }
66*1673e404SJohn Birrell 
67*1673e404SJohn Birrell static int
68*1673e404SJohn Birrell hash_def_cmp(void *d1, void *d2)
69*1673e404SJohn Birrell {
70*1673e404SJohn Birrell 	return (d1 != d2);
71*1673e404SJohn Birrell }
72*1673e404SJohn Birrell 
73*1673e404SJohn Birrell 
74*1673e404SJohn Birrell int
75*1673e404SJohn Birrell hash_name(int nbuckets, const char *name)
76*1673e404SJohn Birrell {
77*1673e404SJohn Birrell 	const char *c;
78*1673e404SJohn Birrell 	ulong_t g;
79*1673e404SJohn Birrell 	int h = 0;
80*1673e404SJohn Birrell 
81*1673e404SJohn Birrell 	for (c = name; *c; c++) {
82*1673e404SJohn Birrell 		h = (h << 4) + *c;
83*1673e404SJohn Birrell 		if ((g = (h & 0xf0000000)) != 0) {
84*1673e404SJohn Birrell 			h ^= (g >> 24);
85*1673e404SJohn Birrell 			h ^= g;
86*1673e404SJohn Birrell 		}
87*1673e404SJohn Birrell 	}
88*1673e404SJohn Birrell 
89*1673e404SJohn Birrell 	return (h % nbuckets);
90*1673e404SJohn Birrell }
91*1673e404SJohn Birrell 
92*1673e404SJohn Birrell hash_t *
93*1673e404SJohn Birrell hash_new(int nbuckets, int (*hashfn)(int, void *), int (*cmp)(void *, void *))
94*1673e404SJohn Birrell {
95*1673e404SJohn Birrell 	hash_t *hash;
96*1673e404SJohn Birrell 
97*1673e404SJohn Birrell 	hash = xmalloc(sizeof (hash_t));
98*1673e404SJohn Birrell 	hash->h_buckets = xcalloc(sizeof (list_t *) * nbuckets);
99*1673e404SJohn Birrell 	hash->h_nbuckets = nbuckets;
100*1673e404SJohn Birrell 	hash->h_hashfn = hashfn ? hashfn : hash_def_hash;
101*1673e404SJohn Birrell 	hash->h_cmp = cmp ? cmp : hash_def_cmp;
102*1673e404SJohn Birrell 
103*1673e404SJohn Birrell 	return (hash);
104*1673e404SJohn Birrell }
105*1673e404SJohn Birrell 
106*1673e404SJohn Birrell void
107*1673e404SJohn Birrell hash_add(hash_t *hash, void *key)
108*1673e404SJohn Birrell {
109*1673e404SJohn Birrell 	int bucket = hash->h_hashfn(hash->h_nbuckets, key);
110*1673e404SJohn Birrell 
111*1673e404SJohn Birrell 	list_add(&hash->h_buckets[bucket], key);
112*1673e404SJohn Birrell }
113*1673e404SJohn Birrell 
114*1673e404SJohn Birrell static int
115*1673e404SJohn Birrell hash_add_cb(void *node, void *private)
116*1673e404SJohn Birrell {
117*1673e404SJohn Birrell 	hash_add((hash_t *)private, node);
118*1673e404SJohn Birrell 	return (0);
119*1673e404SJohn Birrell }
120*1673e404SJohn Birrell 
121*1673e404SJohn Birrell void
122*1673e404SJohn Birrell hash_merge(hash_t *to, hash_t *from)
123*1673e404SJohn Birrell {
124*1673e404SJohn Birrell 	(void) hash_iter(from, hash_add_cb, to);
125*1673e404SJohn Birrell }
126*1673e404SJohn Birrell 
127*1673e404SJohn Birrell static int
128*1673e404SJohn Birrell hash_remove_cb(void *key1, void *key2, void *arg)
129*1673e404SJohn Birrell {
130*1673e404SJohn Birrell 	hash_t *hash = arg;
131*1673e404SJohn Birrell 	return (hash->h_cmp(key1, key2));
132*1673e404SJohn Birrell }
133*1673e404SJohn Birrell 
134*1673e404SJohn Birrell void
135*1673e404SJohn Birrell hash_remove(hash_t *hash, void *key)
136*1673e404SJohn Birrell {
137*1673e404SJohn Birrell 	int bucket = hash->h_hashfn(hash->h_nbuckets, key);
138*1673e404SJohn Birrell 
139*1673e404SJohn Birrell 	(void) list_remove(&hash->h_buckets[bucket], key,
140*1673e404SJohn Birrell 	    hash_remove_cb, hash);
141*1673e404SJohn Birrell }
142*1673e404SJohn Birrell 
143*1673e404SJohn Birrell int
144*1673e404SJohn Birrell hash_match(hash_t *hash, void *key, int (*fun)(void *, void *),
145*1673e404SJohn Birrell     void *private)
146*1673e404SJohn Birrell {
147*1673e404SJohn Birrell 	int bucket = hash->h_hashfn(hash->h_nbuckets, key);
148*1673e404SJohn Birrell 
149*1673e404SJohn Birrell 	return (list_iter(hash->h_buckets[bucket], fun, private) < 0);
150*1673e404SJohn Birrell }
151*1673e404SJohn Birrell 
152*1673e404SJohn Birrell static int
153*1673e404SJohn Birrell hash_find_list_cb(void *node, void *arg)
154*1673e404SJohn Birrell {
155*1673e404SJohn Birrell 	struct hash_data *hd = arg;
156*1673e404SJohn Birrell 	int cbrc;
157*1673e404SJohn Birrell 	int rc = 0;
158*1673e404SJohn Birrell 
159*1673e404SJohn Birrell 	if (hd->hd_hash->h_cmp(hd->hd_key, node) == 0) {
160*1673e404SJohn Birrell 		if ((cbrc = hd->hd_fun(node, hd->hd_private)) < 0)
161*1673e404SJohn Birrell 			return (cbrc);
162*1673e404SJohn Birrell 		rc += cbrc;
163*1673e404SJohn Birrell 	}
164*1673e404SJohn Birrell 
165*1673e404SJohn Birrell 	return (rc);
166*1673e404SJohn Birrell }
167*1673e404SJohn Birrell 
168*1673e404SJohn Birrell int
169*1673e404SJohn Birrell hash_find_iter(hash_t *hash, void *key, int (*fun)(void *, void *),
170*1673e404SJohn Birrell     void *private)
171*1673e404SJohn Birrell {
172*1673e404SJohn Birrell 	int bucket = hash->h_hashfn(hash->h_nbuckets, key);
173*1673e404SJohn Birrell 	struct hash_data hd;
174*1673e404SJohn Birrell 
175*1673e404SJohn Birrell 	hd.hd_hash = hash;
176*1673e404SJohn Birrell 	hd.hd_fun = fun;
177*1673e404SJohn Birrell 	hd.hd_key = key;
178*1673e404SJohn Birrell 	hd.hd_private = private;
179*1673e404SJohn Birrell 
180*1673e404SJohn Birrell 	return (list_iter(hash->h_buckets[bucket], hash_find_list_cb,
181*1673e404SJohn Birrell 	    &hd));
182*1673e404SJohn Birrell }
183*1673e404SJohn Birrell 
184*1673e404SJohn Birrell /* stop on first match */
185*1673e404SJohn Birrell static int
186*1673e404SJohn Birrell hash_find_first_cb(void *node, void *arg)
187*1673e404SJohn Birrell {
188*1673e404SJohn Birrell 	struct hash_data *hd = arg;
189*1673e404SJohn Birrell 	if (hd->hd_hash->h_cmp(hd->hd_key, node) == 0) {
190*1673e404SJohn Birrell 		hd->hd_ret = node;
191*1673e404SJohn Birrell 		return (-1);
192*1673e404SJohn Birrell 	}
193*1673e404SJohn Birrell 
194*1673e404SJohn Birrell 	return (0);
195*1673e404SJohn Birrell }
196*1673e404SJohn Birrell 
197*1673e404SJohn Birrell int
198*1673e404SJohn Birrell hash_find(hash_t *hash, void *key, void **value)
199*1673e404SJohn Birrell {
200*1673e404SJohn Birrell 	int ret;
201*1673e404SJohn Birrell 	struct hash_data hd;
202*1673e404SJohn Birrell 
203*1673e404SJohn Birrell 	hd.hd_hash = hash;
204*1673e404SJohn Birrell 	hd.hd_fun = hash_find_first_cb;
205*1673e404SJohn Birrell 	hd.hd_key = key;
206*1673e404SJohn Birrell 
207*1673e404SJohn Birrell 	ret = hash_match(hash, key, hash_find_first_cb, &hd);
208*1673e404SJohn Birrell 	if (ret && value)
209*1673e404SJohn Birrell 		*value = hd.hd_ret;
210*1673e404SJohn Birrell 
211*1673e404SJohn Birrell 	return (ret);
212*1673e404SJohn Birrell }
213*1673e404SJohn Birrell 
214*1673e404SJohn Birrell int
215*1673e404SJohn Birrell hash_iter(hash_t *hash, int (*fun)(void *, void *), void *private)
216*1673e404SJohn Birrell {
217*1673e404SJohn Birrell 	int cumrc = 0;
218*1673e404SJohn Birrell 	int cbrc;
219*1673e404SJohn Birrell 	int i;
220*1673e404SJohn Birrell 
221*1673e404SJohn Birrell 	for (i = 0; i < hash->h_nbuckets; i++) {
222*1673e404SJohn Birrell 		if (hash->h_buckets[i] != NULL) {
223*1673e404SJohn Birrell 			if ((cbrc = list_iter(hash->h_buckets[i], fun,
224*1673e404SJohn Birrell 			    private)) < 0)
225*1673e404SJohn Birrell 				return (cbrc);
226*1673e404SJohn Birrell 			cumrc += cbrc;
227*1673e404SJohn Birrell 		}
228*1673e404SJohn Birrell 	}
229*1673e404SJohn Birrell 
230*1673e404SJohn Birrell 	return (cumrc);
231*1673e404SJohn Birrell }
232*1673e404SJohn Birrell 
233*1673e404SJohn Birrell int
234*1673e404SJohn Birrell hash_count(hash_t *hash)
235*1673e404SJohn Birrell {
236*1673e404SJohn Birrell 	int num, i;
237*1673e404SJohn Birrell 
238*1673e404SJohn Birrell 	for (num = 0, i = 0; i < hash->h_nbuckets; i++)
239*1673e404SJohn Birrell 		num += list_count(hash->h_buckets[i]);
240*1673e404SJohn Birrell 
241*1673e404SJohn Birrell 	return (num);
242*1673e404SJohn Birrell }
243*1673e404SJohn Birrell 
244*1673e404SJohn Birrell void
245*1673e404SJohn Birrell hash_free(hash_t *hash, void (*datafree)(void *, void *), void *private)
246*1673e404SJohn Birrell {
247*1673e404SJohn Birrell 	int i;
248*1673e404SJohn Birrell 
249*1673e404SJohn Birrell 	if (hash == NULL)
250*1673e404SJohn Birrell 		return;
251*1673e404SJohn Birrell 
252*1673e404SJohn Birrell 	for (i = 0; i < hash->h_nbuckets; i++)
253*1673e404SJohn Birrell 		list_free(hash->h_buckets[i], datafree, private);
254*1673e404SJohn Birrell 	free(hash->h_buckets);
255*1673e404SJohn Birrell 	free(hash);
256*1673e404SJohn Birrell }
257*1673e404SJohn Birrell 
258*1673e404SJohn Birrell void
259*1673e404SJohn Birrell hash_stats(hash_t *hash, int verbose)
260*1673e404SJohn Birrell {
261*1673e404SJohn Birrell 	int min = list_count(hash->h_buckets[0]);
262*1673e404SJohn Birrell 	int minidx = 0;
263*1673e404SJohn Birrell 	int max = min;
264*1673e404SJohn Birrell 	int maxidx = 0;
265*1673e404SJohn Birrell 	int tot = min;
266*1673e404SJohn Birrell 	int count;
267*1673e404SJohn Birrell 	int i;
268*1673e404SJohn Birrell 
269*1673e404SJohn Birrell 	if (min && verbose)
270*1673e404SJohn Birrell 		printf("%3d: %d\n", 0, min);
271*1673e404SJohn Birrell 	for (i = 1; i < hash->h_nbuckets; i++) {
272*1673e404SJohn Birrell 		count = list_count(hash->h_buckets[i]);
273*1673e404SJohn Birrell 		if (min > count) {
274*1673e404SJohn Birrell 			min = count;
275*1673e404SJohn Birrell 			minidx = i;
276*1673e404SJohn Birrell 		}
277*1673e404SJohn Birrell 		if (max < count) {
278*1673e404SJohn Birrell 			max = count;
279*1673e404SJohn Birrell 			maxidx = i;
280*1673e404SJohn Birrell 		}
281*1673e404SJohn Birrell 		if (count && verbose)
282*1673e404SJohn Birrell 			printf("%3d: %d\n", i, count);
283*1673e404SJohn Birrell 		tot += count;
284*1673e404SJohn Birrell 	}
285*1673e404SJohn Birrell 
286*1673e404SJohn Birrell 	printf("Hash statistics:\n");
287*1673e404SJohn Birrell 	printf(" Buckets: %d\n", hash->h_nbuckets);
288*1673e404SJohn Birrell 	printf(" Items  : %d\n", tot);
289*1673e404SJohn Birrell 	printf(" Min/Max: %d in #%d, %d in #%d\n", min, minidx, max, maxidx);
290*1673e404SJohn Birrell 	printf(" Average: %5.2f\n", (float)tot / (float)hash->h_nbuckets);
291*1673e404SJohn Birrell }
292