Path: blob/main/cddl/contrib/opensolaris/tools/ctf/cvt/hash.c
39586 views
/*1* CDDL HEADER START2*3* The contents of this file are subject to the terms of the4* Common Development and Distribution License, Version 1.0 only5* (the "License"). You may not use this file except in compliance6* with the License.7*8* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE9* or http://www.opensolaris.org/os/licensing.10* See the License for the specific language governing permissions11* and limitations under the License.12*13* When distributing Covered Code, include this CDDL HEADER in each14* file and include the License file at usr/src/OPENSOLARIS.LICENSE.15* If applicable, add the following below this CDDL HEADER, with the16* fields enclosed by brackets "[]" replaced with your own identifying17* information: Portions Copyright [yyyy] [name of copyright owner]18*19* CDDL HEADER END20*/21/*22* Copyright 2004 Sun Microsystems, Inc. All rights reserved.23* Use is subject to license terms.24*/2526#pragma ident "%Z%%M% %I% %E% SMI"2728/*29* Routines for manipulating hash tables30*/3132#include <stdio.h>33#include <stdlib.h>34#include <strings.h>35#include <sys/types.h>36#include <sys/sysmacros.h>3738#include "hash.h"39#include "memory.h"40#include "list.h"4142struct hash {43int h_nbuckets;44list_t **h_buckets;4546int (*h_hashfn)(int, void *);47int (*h_cmp)(void *, void *);48};4950struct hash_data {51hash_t *hd_hash;52int (*hd_fun)(void *, void *);53void *hd_key;54void *hd_private;5556void *hd_ret;57};5859static int60hash_def_hash(int nbuckets, void *arg)61{62uintptr_t data = (uintptr_t) arg;63return (data % nbuckets);64}6566static int67hash_def_cmp(void *d1, void *d2)68{69return (d1 != d2);70}717273int74hash_name(int nbuckets, const char *name)75{76const char *c;77ulong_t g;78int h = 0;7980for (c = name; *c; c++) {81h = (h << 4) + *c;82if ((g = (h & 0xf0000000)) != 0) {83h ^= (g >> 24);84h ^= g;85}86}8788return (h % nbuckets);89}9091hash_t *92hash_new(int nbuckets, int (*hashfn)(int, void *), int (*cmp)(void *, void *))93{94hash_t *hash;9596hash = xmalloc(sizeof (hash_t));97hash->h_buckets = xcalloc(sizeof (list_t *) * nbuckets);98hash->h_nbuckets = nbuckets;99hash->h_hashfn = hashfn ? hashfn : hash_def_hash;100hash->h_cmp = cmp ? cmp : hash_def_cmp;101102return (hash);103}104105void106hash_add(hash_t *hash, void *key)107{108int bucket = hash->h_hashfn(hash->h_nbuckets, key);109110list_add(&hash->h_buckets[bucket], key);111}112113static int114hash_add_cb(void *node, void *private)115{116hash_add((hash_t *)private, node);117return (0);118}119120void121hash_merge(hash_t *to, hash_t *from)122{123(void) hash_iter(from, hash_add_cb, to);124}125126static int127hash_remove_cb(void *key1, void *key2, void *arg)128{129hash_t *hash = arg;130return (hash->h_cmp(key1, key2));131}132133void134hash_remove(hash_t *hash, void *key)135{136int bucket = hash->h_hashfn(hash->h_nbuckets, key);137138(void) list_remove(&hash->h_buckets[bucket], key,139hash_remove_cb, hash);140}141142int143hash_match(hash_t *hash, void *key, int (*fun)(void *, void *),144void *private)145{146int bucket = hash->h_hashfn(hash->h_nbuckets, key);147148return (list_iter(hash->h_buckets[bucket], fun, private) < 0);149}150151static int152hash_find_list_cb(void *node, void *arg)153{154struct hash_data *hd = arg;155int cbrc;156int rc = 0;157158if (hd->hd_hash->h_cmp(hd->hd_key, node) == 0) {159if ((cbrc = hd->hd_fun(node, hd->hd_private)) < 0)160return (cbrc);161rc += cbrc;162}163164return (rc);165}166167int168hash_find_iter(hash_t *hash, void *key, int (*fun)(void *, void *),169void *private)170{171int bucket = hash->h_hashfn(hash->h_nbuckets, key);172struct hash_data hd;173174hd.hd_hash = hash;175hd.hd_fun = fun;176hd.hd_key = key;177hd.hd_private = private;178179return (list_iter(hash->h_buckets[bucket], hash_find_list_cb,180&hd));181}182183/* stop on first match */184static int185hash_find_first_cb(void *node, void *arg)186{187struct hash_data *hd = arg;188if (hd->hd_hash->h_cmp(hd->hd_key, node) == 0) {189hd->hd_ret = node;190return (-1);191}192193return (0);194}195196int197hash_find(hash_t *hash, void *key, void **value)198{199int ret;200struct hash_data hd;201202hd.hd_hash = hash;203hd.hd_fun = hash_find_first_cb;204hd.hd_key = key;205206ret = hash_match(hash, key, hash_find_first_cb, &hd);207if (ret && value)208*value = hd.hd_ret;209210return (ret);211}212213int214hash_iter(hash_t *hash, int (*fun)(void *, void *), void *private)215{216int cumrc = 0;217int cbrc;218int i;219220for (i = 0; i < hash->h_nbuckets; i++) {221if (hash->h_buckets[i] != NULL) {222if ((cbrc = list_iter(hash->h_buckets[i], fun,223private)) < 0)224return (cbrc);225cumrc += cbrc;226}227}228229return (cumrc);230}231232int233hash_count(hash_t *hash)234{235int num, i;236237for (num = 0, i = 0; i < hash->h_nbuckets; i++)238num += list_count(hash->h_buckets[i]);239240return (num);241}242243void244hash_free(hash_t *hash, void (*datafree)(void *, void *), void *private)245{246int i;247248if (hash == NULL)249return;250251for (i = 0; i < hash->h_nbuckets; i++)252list_free(hash->h_buckets[i], datafree, private);253free(hash->h_buckets);254free(hash);255}256257void258hash_stats(hash_t *hash, int verbose)259{260int min = list_count(hash->h_buckets[0]);261int minidx = 0;262int max = min;263int maxidx = 0;264int tot = min;265int count;266int i;267268if (min && verbose)269printf("%3d: %d\n", 0, min);270for (i = 1; i < hash->h_nbuckets; i++) {271count = list_count(hash->h_buckets[i]);272if (min > count) {273min = count;274minidx = i;275}276if (max < count) {277max = count;278maxidx = i;279}280if (count && verbose)281printf("%3d: %d\n", i, count);282tot += count;283}284285printf("Hash statistics:\n");286printf(" Buckets: %d\n", hash->h_nbuckets);287printf(" Items : %d\n", tot);288printf(" Min/Max: %d in #%d, %d in #%d\n", min, minidx, max, maxidx);289printf(" Average: %5.2f\n", (float)tot / (float)hash->h_nbuckets);290}291292293