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