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