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; 531673e404SJohn 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 611673e404SJohn Birrell hash_def_hash(int nbuckets, void *arg) 621673e404SJohn Birrell { 631673e404SJohn Birrell uintptr_t data = (uintptr_t) arg; 641673e404SJohn Birrell return (data % nbuckets); 651673e404SJohn Birrell } 661673e404SJohn Birrell 671673e404SJohn Birrell static int 681673e404SJohn Birrell hash_def_cmp(void *d1, void *d2) 691673e404SJohn Birrell { 701673e404SJohn Birrell return (d1 != d2); 711673e404SJohn Birrell } 721673e404SJohn Birrell 731673e404SJohn Birrell 741673e404SJohn Birrell int 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 * 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; 1001673e404SJohn Birrell hash->h_hashfn = hashfn ? hashfn : hash_def_hash; 1011673e404SJohn Birrell hash->h_cmp = cmp ? cmp : hash_def_cmp; 1021673e404SJohn Birrell 1031673e404SJohn Birrell return (hash); 1041673e404SJohn Birrell } 1051673e404SJohn Birrell 1061673e404SJohn Birrell void 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 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 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 1281673e404SJohn Birrell hash_remove_cb(void *key1, void *key2, void *arg) 1291673e404SJohn Birrell { 1301673e404SJohn Birrell hash_t *hash = arg; 1311673e404SJohn Birrell return (hash->h_cmp(key1, key2)); 1321673e404SJohn Birrell } 1331673e404SJohn Birrell 1341673e404SJohn Birrell void 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, 1401673e404SJohn Birrell hash_remove_cb, hash); 1411673e404SJohn Birrell } 1421673e404SJohn Birrell 1431673e404SJohn Birrell int 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 1531673e404SJohn Birrell hash_find_list_cb(void *node, void *arg) 1541673e404SJohn Birrell { 1551673e404SJohn 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 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 1801673e404SJohn 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 1861673e404SJohn Birrell hash_find_first_cb(void *node, void *arg) 1871673e404SJohn Birrell { 1881673e404SJohn 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 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 2071673e404SJohn 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 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 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 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 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