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