📄 hash.c
字号:
/* $Id: hash.c,v 3.0 1992/12/14 00:14:13 davison Trn $*//* This file is an altered version of a set of hash routines by** Geoffrey Collyer. See the end of the file for his copyright.*/#include "EXTERN.h"#include "common.h"#include "util.h"#include "INTERN.h"#include "hash.h"/* tunable parameters */#define RETAIN 600 /* retain & recycle this many HASHENTs */static HASHENT *hereuse = NULL;static int reusables = 0;static HASHENT **hashfind _((HASHTABLE*,char*,int));static unsigned hash _((char*,int));static int default_cmp _((char*,int,HASHDATUM));static HASHENT *healloc _((void));static void hefree _((HASHENT*));HASHTABLE *hashcreate(size, cmpfunc)unsigned size; /* a crude guide to size */int (*cmpfunc)();{ register HASHTABLE *tbl; /* allocate HASHTABLE and (HASHENT*) array together to reduce the ** number of malloc calls. */ register struct alignalloc { HASHTABLE ht; HASHENT *hepa[1]; /* longer than it looks */ } *aap; aap = (struct alignalloc*) safemalloc(sizeof *aap + (size-1)*sizeof (HASHENT*)); bzero((char*)aap, sizeof *aap + (size-1)*sizeof (HASHENT*)); tbl = &aap->ht; tbl->ht_size = (size == 0? 1: size); /* size of 0 is nonsense */ tbl->ht_magic = HASHMAG; tbl->ht_cmp = (cmpfunc == NULL? default_cmp: cmpfunc); tbl->ht_addr = aap->hepa; return tbl;}/* Free all the memory associated with tbl, erase the pointers to it, and** invalidate tbl to prevent further use via other pointers to it.*/voidhashdestroy(tbl)register HASHTABLE *tbl;{ register unsigned idx; register HASHENT *hp, *next; register HASHENT **hepp; register int tblsize; if (tbl == NULL || BADTBL(tbl)) return; tblsize = tbl->ht_size; hepp = tbl->ht_addr; for (idx = 0; idx < tblsize; idx++) { for (hp = hepp[idx]; hp != NULL; hp = next) { next = hp->he_next; hp->he_next = NULL; hefree(hp); } hepp[idx] = NULL; } tbl->ht_magic = 0; /* de-certify this table */ tbl->ht_addr = NULL; free((char*)tbl);}voidhashstore(tbl, key, keylen, data)register HASHTABLE *tbl;char *key;int keylen;HASHDATUM data;{ register HASHENT *hp; register HASHENT **nextp; nextp = hashfind(tbl, key, keylen); hp = *nextp; if (hp == NULL) { /* absent; allocate an entry */ hp = healloc(); hp->he_next = NULL; hp->he_keylen = keylen; *nextp = hp; /* append to hash chain */ } hp->he_data = data; /* supersede any old data for this key */}voidhashdelete(tbl, key, keylen)register HASHTABLE *tbl;char *key;int keylen;{ register HASHENT *hp; register HASHENT **nextp; nextp = hashfind(tbl, key, keylen); hp = *nextp; if (hp == NULL) /* absent */ return; *nextp = hp->he_next; /* skip this entry */ hp->he_next = NULL; hp->he_data.dat_ptr = NULL; hefree(hp);}HASHENT **slast_nextp;int slast_keylen;HASHDATUM /* data corresponding to key */hashfetch(tbl, key, keylen)register HASHTABLE *tbl;char *key;int keylen;{ register HASHENT *hp; register HASHENT **nextp; static HASHDATUM errdatum = { NULL, 0 }; nextp = hashfind(tbl, key, keylen); slast_nextp = nextp; slast_keylen = keylen; hp = *nextp; if (hp == NULL) /* absent */ return errdatum; else return hp->he_data;}voidhashstorelast(data)HASHDATUM data;{ register HASHENT *hp; hp = *slast_nextp; if (hp == NULL) { /* absent; allocate an entry */ hp = healloc(); hp->he_next = NULL; hp->he_keylen = slast_keylen; *slast_nextp = hp; /* append to hash chain */ } hp->he_data = data; /* supersede any old data for this key */}/* Visit each entry by calling nodefunc at each, with key, data and extra as** arguments.*/voidhashwalk(tbl, nodefunc, extra)HASHTABLE *tbl;register void (*nodefunc)();register int extra;{ register unsigned idx; register HASHENT *hp; register HASHENT **hepp; register int tblsize; if (BADTBL(tbl)) return; hepp = tbl->ht_addr; tblsize = tbl->ht_size; for (idx = 0; idx < tblsize; idx++) for (hp = hepp[idx]; hp != NULL; hp = hp->he_next) (*nodefunc)(&hp->he_data, extra);}/* The returned value is the address of the pointer that refers to the** found object. Said pointer may be NULL if the object was not found;** if so, this pointer should be updated with the address of the object** to be inserted, if insertion is desired.*/static HASHENT **hashfind(tbl, key, keylen)register HASHTABLE *tbl;char *key;register int keylen;{ register HASHENT *hp, *prevhp = NULL; register HASHENT **hepp; register unsigned size; if (BADTBL(tbl)) fatal_error("Hash table is invalid."); size = tbl->ht_size; hepp = &tbl->ht_addr[hash(key,keylen) % size]; for (hp = *hepp; hp != NULL; prevhp = hp, hp = hp->he_next) { if (hp->he_keylen == keylen && !(*tbl->ht_cmp)(key, keylen, hp->he_data)) break; } /* assert: *(returned value) == hp */ return (prevhp == NULL? hepp: &prevhp->he_next);}static unsigned /* not yet taken modulus table size */hash(key, keylen)register char *key;register int keylen;{ register unsigned hash = 0; while (keylen--) hash += *key++; return hash;}static intdefault_cmp(key, keylen, data)char *key;int keylen;HASHDATUM data;{ /* We already know that the lengths are equal, just compare the strings */ return bcmp(key, data.dat_ptr, keylen);}static HASHENT *healloc() /* allocate a hash entry */{ register HASHENT *hp; if (hereuse == NULL) return (HASHENT*)safemalloc(sizeof (HASHENT)); /* pull the first reusable one off the pile */ hp = hereuse; hereuse = hereuse->he_next; hp->he_next = NULL; /* prevent accidents */ reusables--; return hp;}static voidhefree(hp) /* free a hash entry */register HASHENT *hp;{ if (reusables >= RETAIN) /* compost heap is full? */ free((char*)hp); /* yup, just pitch this one */ else { /* no, just stash for reuse */ ++reusables; hp->he_next = hereuse; hereuse = hp; }}/* * Copyright (c) 1992 Geoffrey Collyer * All rights reserved. * Written by Geoffrey Collyer. * * This software is not subject to any license of the American Telephone * and Telegraph Company, the Regents of the University of California, or * the Free Software Foundation. * * Permission is granted to anyone to use this software for any purpose on * any computer system, and to alter it and redistribute it freely, subject * to the following restrictions: * * 1. The author is not responsible for the consequences of use of this * software, no matter how awful, even if they arise from flaws in it. * * 2. The origin of this software must not be misrepresented, either by * explicit claim or by omission. Since few users ever read sources, * credits must appear in the documentation. * * 3. Altered versions must be plainly marked as such, and must not be * misrepresented as being the original software. Since few users * ever read sources, credits must appear in the documentation. * * 4. This notice may not be removed or altered. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -