xref: /freebsd/cddl/contrib/opensolaris/tools/ctf/cvt/hash.c (revision 4cc75139b96639698b4e96da3b60cd3d81e9a959)
11673e404SJohn Birrell /*
21673e404SJohn Birrell  * CDDL HEADER START
31673e404SJohn Birrell  *
41673e404SJohn Birrell  * The contents of this file are subject to the terms of the
51673e404SJohn Birrell  * Common Development and Distribution License, Version 1.0 only
61673e404SJohn Birrell  * (the "License").  You may not use this file except in compliance
71673e404SJohn Birrell  * with the License.
81673e404SJohn Birrell  *
91673e404SJohn Birrell  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
101673e404SJohn Birrell  * or http://www.opensolaris.org/os/licensing.
111673e404SJohn Birrell  * See the License for the specific language governing permissions
121673e404SJohn Birrell  * and limitations under the License.
131673e404SJohn Birrell  *
141673e404SJohn Birrell  * When distributing Covered Code, include this CDDL HEADER in each
151673e404SJohn Birrell  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
161673e404SJohn Birrell  * If applicable, add the following below this CDDL HEADER, with the
171673e404SJohn Birrell  * fields enclosed by brackets "[]" replaced with your own identifying
181673e404SJohn Birrell  * information: Portions Copyright [yyyy] [name of copyright owner]
191673e404SJohn Birrell  *
201673e404SJohn Birrell  * CDDL HEADER END
211673e404SJohn Birrell  */
221673e404SJohn Birrell /*
231673e404SJohn Birrell  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
241673e404SJohn Birrell  * Use is subject to license terms.
251673e404SJohn Birrell  */
261673e404SJohn Birrell 
271673e404SJohn Birrell #pragma ident	"%Z%%M%	%I%	%E% SMI"
281673e404SJohn Birrell 
291673e404SJohn Birrell /*
301673e404SJohn Birrell  * Routines for manipulating hash tables
311673e404SJohn Birrell  */
321673e404SJohn Birrell 
331673e404SJohn Birrell #include <stdio.h>
341673e404SJohn Birrell #include <stdlib.h>
351673e404SJohn Birrell #include <strings.h>
361673e404SJohn Birrell #include <sys/types.h>
371673e404SJohn Birrell #include <sys/sysmacros.h>
381673e404SJohn Birrell 
391673e404SJohn Birrell #include "hash.h"
401673e404SJohn Birrell #include "memory.h"
411673e404SJohn Birrell #include "list.h"
421673e404SJohn Birrell 
431673e404SJohn Birrell struct hash {
441673e404SJohn Birrell 	int h_nbuckets;
451673e404SJohn Birrell 	list_t **h_buckets;
461673e404SJohn Birrell 
471673e404SJohn Birrell 	int (*h_hashfn)(int, void *);
481673e404SJohn Birrell 	int (*h_cmp)(void *, void *);
491673e404SJohn Birrell };
501673e404SJohn Birrell 
511673e404SJohn Birrell struct hash_data {
521673e404SJohn Birrell 	hash_t *hd_hash;
534cc75139SJohn Birrell 	int (*hd_fun)(void *, void *);
541673e404SJohn Birrell 	void *hd_key;
551673e404SJohn Birrell 	void *hd_private;
561673e404SJohn Birrell 
571673e404SJohn Birrell 	void *hd_ret;
581673e404SJohn Birrell };
591673e404SJohn Birrell 
601673e404SJohn Birrell static int
hash_def_hash(int nbuckets,void * arg)614cc75139SJohn Birrell hash_def_hash(int nbuckets, void *arg)
621673e404SJohn Birrell {
634cc75139SJohn Birrell 	uintptr_t data = (uintptr_t) arg;
641673e404SJohn Birrell 	return (data % nbuckets);
651673e404SJohn Birrell }
661673e404SJohn Birrell 
671673e404SJohn Birrell static int
hash_def_cmp(void * d1,void * d2)684cc75139SJohn Birrell hash_def_cmp(void *d1, void *d2)
691673e404SJohn Birrell {
701673e404SJohn Birrell 	return (d1 != d2);
711673e404SJohn Birrell }
721673e404SJohn Birrell 
731673e404SJohn Birrell 
741673e404SJohn Birrell int
hash_name(int nbuckets,const char * name)751673e404SJohn Birrell hash_name(int nbuckets, const char *name)
761673e404SJohn Birrell {
771673e404SJohn Birrell 	const char *c;
781673e404SJohn Birrell 	ulong_t g;
791673e404SJohn Birrell 	int h = 0;
801673e404SJohn Birrell 
811673e404SJohn Birrell 	for (c = name; *c; c++) {
821673e404SJohn Birrell 		h = (h << 4) + *c;
831673e404SJohn Birrell 		if ((g = (h & 0xf0000000)) != 0) {
841673e404SJohn Birrell 			h ^= (g >> 24);
851673e404SJohn Birrell 			h ^= g;
861673e404SJohn Birrell 		}
871673e404SJohn Birrell 	}
881673e404SJohn Birrell 
891673e404SJohn Birrell 	return (h % nbuckets);
901673e404SJohn Birrell }
911673e404SJohn Birrell 
921673e404SJohn Birrell hash_t *
hash_new(int nbuckets,int (* hashfn)(int,void *),int (* cmp)(void *,void *))931673e404SJohn Birrell hash_new(int nbuckets, int (*hashfn)(int, void *), int (*cmp)(void *, void *))
941673e404SJohn Birrell {
951673e404SJohn Birrell 	hash_t *hash;
961673e404SJohn Birrell 
971673e404SJohn Birrell 	hash = xmalloc(sizeof (hash_t));
981673e404SJohn Birrell 	hash->h_buckets = xcalloc(sizeof (list_t *) * nbuckets);
991673e404SJohn Birrell 	hash->h_nbuckets = nbuckets;
1004cc75139SJohn Birrell 	hash->h_hashfn = hashfn ? hashfn : hash_def_hash;
1014cc75139SJohn Birrell 	hash->h_cmp = cmp ? cmp : hash_def_cmp;
1021673e404SJohn Birrell 
1031673e404SJohn Birrell 	return (hash);
1041673e404SJohn Birrell }
1051673e404SJohn Birrell 
1061673e404SJohn Birrell void
hash_add(hash_t * hash,void * key)1071673e404SJohn Birrell hash_add(hash_t *hash, void *key)
1081673e404SJohn Birrell {
1091673e404SJohn Birrell 	int bucket = hash->h_hashfn(hash->h_nbuckets, key);
1101673e404SJohn Birrell 
1111673e404SJohn Birrell 	list_add(&hash->h_buckets[bucket], key);
1121673e404SJohn Birrell }
1131673e404SJohn Birrell 
1141673e404SJohn Birrell static int
hash_add_cb(void * node,void * private)1151673e404SJohn Birrell hash_add_cb(void *node, void *private)
1161673e404SJohn Birrell {
1171673e404SJohn Birrell 	hash_add((hash_t *)private, node);
1181673e404SJohn Birrell 	return (0);
1191673e404SJohn Birrell }
1201673e404SJohn Birrell 
1211673e404SJohn Birrell void
hash_merge(hash_t * to,hash_t * from)1221673e404SJohn Birrell hash_merge(hash_t *to, hash_t *from)
1231673e404SJohn Birrell {
1241673e404SJohn Birrell 	(void) hash_iter(from, hash_add_cb, to);
1251673e404SJohn Birrell }
1261673e404SJohn Birrell 
1271673e404SJohn Birrell static int
hash_remove_cb(void * key1,void * key2,void * arg)1284cc75139SJohn Birrell hash_remove_cb(void *key1, void *key2, void *arg)
1291673e404SJohn Birrell {
1304cc75139SJohn Birrell 	hash_t *hash = arg;
1311673e404SJohn Birrell 	return (hash->h_cmp(key1, key2));
1321673e404SJohn Birrell }
1331673e404SJohn Birrell 
1341673e404SJohn Birrell void
hash_remove(hash_t * hash,void * key)1351673e404SJohn Birrell hash_remove(hash_t *hash, void *key)
1361673e404SJohn Birrell {
1371673e404SJohn Birrell 	int bucket = hash->h_hashfn(hash->h_nbuckets, key);
1381673e404SJohn Birrell 
1391673e404SJohn Birrell 	(void) list_remove(&hash->h_buckets[bucket], key,
1404cc75139SJohn Birrell 	    hash_remove_cb, hash);
1411673e404SJohn Birrell }
1421673e404SJohn Birrell 
1431673e404SJohn Birrell int
hash_match(hash_t * hash,void * key,int (* fun)(void *,void *),void * private)1441673e404SJohn Birrell hash_match(hash_t *hash, void *key, int (*fun)(void *, void *),
1451673e404SJohn Birrell     void *private)
1461673e404SJohn Birrell {
1471673e404SJohn Birrell 	int bucket = hash->h_hashfn(hash->h_nbuckets, key);
1481673e404SJohn Birrell 
1491673e404SJohn Birrell 	return (list_iter(hash->h_buckets[bucket], fun, private) < 0);
1501673e404SJohn Birrell }
1511673e404SJohn Birrell 
1521673e404SJohn Birrell static int
hash_find_list_cb(void * node,void * arg)1534cc75139SJohn Birrell hash_find_list_cb(void *node, void *arg)
1541673e404SJohn Birrell {
1554cc75139SJohn Birrell 	struct hash_data *hd = arg;
1561673e404SJohn Birrell 	int cbrc;
1571673e404SJohn Birrell 	int rc = 0;
1581673e404SJohn Birrell 
1591673e404SJohn Birrell 	if (hd->hd_hash->h_cmp(hd->hd_key, node) == 0) {
1601673e404SJohn Birrell 		if ((cbrc = hd->hd_fun(node, hd->hd_private)) < 0)
1611673e404SJohn Birrell 			return (cbrc);
1621673e404SJohn Birrell 		rc += cbrc;
1631673e404SJohn Birrell 	}
1641673e404SJohn Birrell 
1651673e404SJohn Birrell 	return (rc);
1661673e404SJohn Birrell }
1671673e404SJohn Birrell 
1681673e404SJohn Birrell int
hash_find_iter(hash_t * hash,void * key,int (* fun)(void *,void *),void * private)1691673e404SJohn Birrell hash_find_iter(hash_t *hash, void *key, int (*fun)(void *, void *),
1701673e404SJohn Birrell     void *private)
1711673e404SJohn Birrell {
1721673e404SJohn Birrell 	int bucket = hash->h_hashfn(hash->h_nbuckets, key);
1731673e404SJohn Birrell 	struct hash_data hd;
1741673e404SJohn Birrell 
1751673e404SJohn Birrell 	hd.hd_hash = hash;
1761673e404SJohn Birrell 	hd.hd_fun = fun;
1771673e404SJohn Birrell 	hd.hd_key = key;
1781673e404SJohn Birrell 	hd.hd_private = private;
1791673e404SJohn Birrell 
1804cc75139SJohn Birrell 	return (list_iter(hash->h_buckets[bucket], hash_find_list_cb,
1811673e404SJohn Birrell 	    &hd));
1821673e404SJohn Birrell }
1831673e404SJohn Birrell 
1841673e404SJohn Birrell /* stop on first match */
1851673e404SJohn Birrell static int
hash_find_first_cb(void * node,void * arg)1864cc75139SJohn Birrell hash_find_first_cb(void *node, void *arg)
1871673e404SJohn Birrell {
1884cc75139SJohn Birrell 	struct hash_data *hd = arg;
1891673e404SJohn Birrell 	if (hd->hd_hash->h_cmp(hd->hd_key, node) == 0) {
1901673e404SJohn Birrell 		hd->hd_ret = node;
1911673e404SJohn Birrell 		return (-1);
1921673e404SJohn Birrell 	}
1931673e404SJohn Birrell 
1941673e404SJohn Birrell 	return (0);
1951673e404SJohn Birrell }
1961673e404SJohn Birrell 
1971673e404SJohn Birrell int
hash_find(hash_t * hash,void * key,void ** value)1981673e404SJohn Birrell hash_find(hash_t *hash, void *key, void **value)
1991673e404SJohn Birrell {
2001673e404SJohn Birrell 	int ret;
2011673e404SJohn Birrell 	struct hash_data hd;
2021673e404SJohn Birrell 
2031673e404SJohn Birrell 	hd.hd_hash = hash;
2041673e404SJohn Birrell 	hd.hd_fun = hash_find_first_cb;
2051673e404SJohn Birrell 	hd.hd_key = key;
2061673e404SJohn Birrell 
2074cc75139SJohn Birrell 	ret = hash_match(hash, key, hash_find_first_cb, &hd);
2081673e404SJohn Birrell 	if (ret && value)
2091673e404SJohn Birrell 		*value = hd.hd_ret;
2101673e404SJohn Birrell 
2111673e404SJohn Birrell 	return (ret);
2121673e404SJohn Birrell }
2131673e404SJohn Birrell 
2141673e404SJohn Birrell int
hash_iter(hash_t * hash,int (* fun)(void *,void *),void * private)2151673e404SJohn Birrell hash_iter(hash_t *hash, int (*fun)(void *, void *), void *private)
2161673e404SJohn Birrell {
2171673e404SJohn Birrell 	int cumrc = 0;
2181673e404SJohn Birrell 	int cbrc;
2191673e404SJohn Birrell 	int i;
2201673e404SJohn Birrell 
2211673e404SJohn Birrell 	for (i = 0; i < hash->h_nbuckets; i++) {
2221673e404SJohn Birrell 		if (hash->h_buckets[i] != NULL) {
2231673e404SJohn Birrell 			if ((cbrc = list_iter(hash->h_buckets[i], fun,
2241673e404SJohn Birrell 			    private)) < 0)
2251673e404SJohn Birrell 				return (cbrc);
2261673e404SJohn Birrell 			cumrc += cbrc;
2271673e404SJohn Birrell 		}
2281673e404SJohn Birrell 	}
2291673e404SJohn Birrell 
2301673e404SJohn Birrell 	return (cumrc);
2311673e404SJohn Birrell }
2321673e404SJohn Birrell 
2331673e404SJohn Birrell int
hash_count(hash_t * hash)2341673e404SJohn Birrell hash_count(hash_t *hash)
2351673e404SJohn Birrell {
2361673e404SJohn Birrell 	int num, i;
2371673e404SJohn Birrell 
2381673e404SJohn Birrell 	for (num = 0, i = 0; i < hash->h_nbuckets; i++)
2391673e404SJohn Birrell 		num += list_count(hash->h_buckets[i]);
2401673e404SJohn Birrell 
2411673e404SJohn Birrell 	return (num);
2421673e404SJohn Birrell }
2431673e404SJohn Birrell 
2441673e404SJohn Birrell void
hash_free(hash_t * hash,void (* datafree)(void *,void *),void * private)2451673e404SJohn Birrell hash_free(hash_t *hash, void (*datafree)(void *, void *), void *private)
2461673e404SJohn Birrell {
2471673e404SJohn Birrell 	int i;
2481673e404SJohn Birrell 
2491673e404SJohn Birrell 	if (hash == NULL)
2501673e404SJohn Birrell 		return;
2511673e404SJohn Birrell 
2521673e404SJohn Birrell 	for (i = 0; i < hash->h_nbuckets; i++)
2531673e404SJohn Birrell 		list_free(hash->h_buckets[i], datafree, private);
2541673e404SJohn Birrell 	free(hash->h_buckets);
2551673e404SJohn Birrell 	free(hash);
2561673e404SJohn Birrell }
2571673e404SJohn Birrell 
2581673e404SJohn Birrell void
hash_stats(hash_t * hash,int verbose)2591673e404SJohn Birrell hash_stats(hash_t *hash, int verbose)
2601673e404SJohn Birrell {
2611673e404SJohn Birrell 	int min = list_count(hash->h_buckets[0]);
2621673e404SJohn Birrell 	int minidx = 0;
2631673e404SJohn Birrell 	int max = min;
2641673e404SJohn Birrell 	int maxidx = 0;
2651673e404SJohn Birrell 	int tot = min;
2661673e404SJohn Birrell 	int count;
2671673e404SJohn Birrell 	int i;
2681673e404SJohn Birrell 
2691673e404SJohn Birrell 	if (min && verbose)
2701673e404SJohn Birrell 		printf("%3d: %d\n", 0, min);
2711673e404SJohn Birrell 	for (i = 1; i < hash->h_nbuckets; i++) {
2721673e404SJohn Birrell 		count = list_count(hash->h_buckets[i]);
2731673e404SJohn Birrell 		if (min > count) {
2741673e404SJohn Birrell 			min = count;
2751673e404SJohn Birrell 			minidx = i;
2761673e404SJohn Birrell 		}
2771673e404SJohn Birrell 		if (max < count) {
2781673e404SJohn Birrell 			max = count;
2791673e404SJohn Birrell 			maxidx = i;
2801673e404SJohn Birrell 		}
2811673e404SJohn Birrell 		if (count && verbose)
2821673e404SJohn Birrell 			printf("%3d: %d\n", i, count);
2831673e404SJohn Birrell 		tot += count;
2841673e404SJohn Birrell 	}
2851673e404SJohn Birrell 
2861673e404SJohn Birrell 	printf("Hash statistics:\n");
2871673e404SJohn Birrell 	printf(" Buckets: %d\n", hash->h_nbuckets);
2881673e404SJohn Birrell 	printf(" Items  : %d\n", tot);
2891673e404SJohn Birrell 	printf(" Min/Max: %d in #%d, %d in #%d\n", min, minidx, max, maxidx);
2901673e404SJohn Birrell 	printf(" Average: %5.2f\n", (float)tot / (float)hash->h_nbuckets);
2911673e404SJohn Birrell }
292