Home | History | Annotate | Line # | Download | only in common
hash.c revision 1.6
      1  1.1    gwr /************************************************************************
      2  1.1    gwr           Copyright 1988, 1991 by Carnegie Mellon University
      3  1.1    gwr 
      4  1.1    gwr                           All Rights Reserved
      5  1.1    gwr 
      6  1.1    gwr Permission to use, copy, modify, and distribute this software and its
      7  1.1    gwr documentation for any purpose and without fee is hereby granted, provided
      8  1.1    gwr that the above copyright notice appear in all copies and that both that
      9  1.1    gwr copyright notice and this permission notice appear in supporting
     10  1.1    gwr documentation, and that the name of Carnegie Mellon University not be used
     11  1.1    gwr in advertising or publicity pertaining to distribution of the software
     12  1.1    gwr without specific, written prior permission.
     13  1.1    gwr 
     14  1.1    gwr CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
     15  1.1    gwr SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
     16  1.1    gwr IN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
     17  1.1    gwr DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
     18  1.1    gwr PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
     19  1.1    gwr ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
     20  1.1    gwr SOFTWARE.
     21  1.1    gwr ************************************************************************/
     22  1.1    gwr 
     23  1.4  lukem #include <sys/cdefs.h>
     24  1.1    gwr #ifndef lint
     25  1.6    wiz __RCSID("$NetBSD: hash.c,v 1.6 2002/07/14 00:30:02 wiz Exp $");
     26  1.1    gwr #endif
     27  1.1    gwr 
     28  1.1    gwr 
     29  1.1    gwr /*
     30  1.1    gwr  * Generalized hash table ADT
     31  1.1    gwr  *
     32  1.1    gwr  * Provides multiple, dynamically-allocated, variable-sized hash tables on
     33  1.1    gwr  * various data and keys.
     34  1.1    gwr  *
     35  1.1    gwr  * This package attempts to follow some of the coding conventions suggested
     36  1.1    gwr  * by Bob Sidebotham and the AFS Clean Code Committee of the
     37  1.1    gwr  * Information Technology Center at Carnegie Mellon.
     38  1.1    gwr  */
     39  1.1    gwr 
     40  1.1    gwr 
     41  1.1    gwr #include <sys/types.h>
     42  1.1    gwr #include <stdlib.h>
     43  1.1    gwr 
     44  1.1    gwr #ifndef USE_BFUNCS
     45  1.1    gwr #include <memory.h>
     46  1.1    gwr /* Yes, memcpy is OK here (no overlapped copies). */
     47  1.1    gwr #define bcopy(a,b,c)    memcpy(b,a,c)
     48  1.1    gwr #define bzero(p,l)      memset(p,0,l)
     49  1.1    gwr #define bcmp(a,b,c)     memcmp(a,b,c)
     50  1.1    gwr #endif
     51  1.1    gwr 
     52  1.1    gwr #include "hash.h"
     53  1.1    gwr 
     54  1.1    gwr #define TRUE		1
     55  1.1    gwr #define FALSE		0
     56  1.1    gwr #ifndef	NULL
     57  1.1    gwr #define NULL		0
     58  1.1    gwr #endif
     59  1.1    gwr 
     60  1.1    gwr /*
     61  1.1    gwr  * This can be changed to make internal routines visible to debuggers, etc.
     62  1.1    gwr  */
     63  1.1    gwr #ifndef PRIVATE
     64  1.1    gwr #define PRIVATE static
     65  1.1    gwr #endif
     66  1.1    gwr 
     67  1.5    wiz PRIVATE void hashi_FreeMembers(hash_member *, hash_freefp);
     68  1.1    gwr 
     69  1.1    gwr 
     70  1.1    gwr 
     72  1.1    gwr 
     73  1.1    gwr /*
     74  1.1    gwr  * Hash table initialization routine.
     75  1.1    gwr  *
     76  1.1    gwr  * This routine creates and intializes a hash table of size "tablesize"
     77  1.1    gwr  * entries.  Successful calls return a pointer to the hash table (which must
     78  1.1    gwr  * be passed to other hash routines to identify the hash table).  Failed
     79  1.1    gwr  * calls return NULL.
     80  1.1    gwr  */
     81  1.1    gwr 
     82  1.5    wiz hash_tbl *
     83  1.1    gwr hash_Init(unsigned int tablesize)
     84  1.6    wiz {
     85  1.6    wiz 	hash_tbl *hashtblptr;
     86  1.1    gwr 	unsigned totalsize;
     87  1.1    gwr 
     88  1.1    gwr 	if (tablesize > 0) {
     89  1.1    gwr 		totalsize = sizeof(hash_tbl)
     90  1.1    gwr 			+ sizeof(hash_member *) * (tablesize - 1);
     91  1.1    gwr 		hashtblptr = (hash_tbl *) malloc(totalsize);
     92  1.1    gwr 		if (hashtblptr) {
     93  1.1    gwr 			bzero((char *) hashtblptr, totalsize);
     94  1.1    gwr 			hashtblptr->size = tablesize;	/* Success! */
     95  1.1    gwr 			hashtblptr->bucketnum = 0;
     96  1.1    gwr 			hashtblptr->member = (hashtblptr->table)[0];
     97  1.1    gwr 		}
     98  1.1    gwr 	} else {
     99  1.1    gwr 		hashtblptr = NULL;		/* Disallow zero-length tables */
    100  1.1    gwr 	}
    101  1.1    gwr 	return hashtblptr;			/* NULL if failure */
    102  1.1    gwr }
    103  1.1    gwr 
    104  1.1    gwr 
    106  1.1    gwr 
    107  1.1    gwr /*
    108  1.1    gwr  * Frees an entire linked list of bucket members (used in the open
    109  1.1    gwr  * hashing scheme).  Does nothing if the passed pointer is NULL.
    110  1.1    gwr  */
    111  1.5    wiz 
    112  1.1    gwr PRIVATE void
    113  1.1    gwr hashi_FreeMembers(hash_member *bucketptr, hash_freefp free_data)
    114  1.1    gwr {
    115  1.1    gwr 	hash_member *nextbucket;
    116  1.1    gwr 	while (bucketptr) {
    117  1.1    gwr 		nextbucket = bucketptr->next;
    118  1.1    gwr 		(*free_data) (bucketptr->data);
    119  1.1    gwr 		free((char *) bucketptr);
    120  1.1    gwr 		bucketptr = nextbucket;
    121  1.1    gwr 	}
    122  1.1    gwr }
    123  1.1    gwr 
    124  1.1    gwr 
    125  1.1    gwr 
    126  1.1    gwr 
    127  1.1    gwr /*
    128  1.1    gwr  * This routine re-initializes the hash table.  It frees all the allocated
    129  1.1    gwr  * memory and resets all bucket pointers to NULL.
    130  1.1    gwr  */
    131  1.5    wiz 
    132  1.1    gwr void
    133  1.1    gwr hash_Reset(hash_tbl *hashtable, hash_freefp free_data)
    134  1.1    gwr {
    135  1.1    gwr 	hash_member **bucketptr;
    136  1.1    gwr 	unsigned i;
    137  1.1    gwr 
    138  1.1    gwr 	bucketptr = hashtable->table;
    139  1.1    gwr 	for (i = 0; i < hashtable->size; i++) {
    140  1.1    gwr 		hashi_FreeMembers(*bucketptr, free_data);
    141  1.1    gwr 		*bucketptr++ = NULL;
    142  1.1    gwr 	}
    143  1.1    gwr 	hashtable->bucketnum = 0;
    144  1.1    gwr 	hashtable->member = (hashtable->table)[0];
    145  1.1    gwr }
    146  1.1    gwr 
    147  1.1    gwr 
    149  1.1    gwr 
    150  1.1    gwr /*
    151  1.1    gwr  * Generic hash function to calculate a hash code from the given string.
    152  1.1    gwr  *
    153  1.1    gwr  * For each byte of the string, this function left-shifts the value in an
    154  1.1    gwr  * accumulator and then adds the byte into the accumulator.  The contents of
    155  1.1    gwr  * the accumulator is returned after the entire string has been processed.
    156  1.1    gwr  * It is assumed that this result will be used as the "hashcode" parameter in
    157  1.1    gwr  * calls to other functions in this package.  These functions automatically
    158  1.1    gwr  * adjust the hashcode for the size of each hashtable.
    159  1.1    gwr  *
    160  1.1    gwr  * This algorithm probably works best when the hash table size is a prime
    161  1.1    gwr  * number.
    162  1.1    gwr  *
    163  1.1    gwr  * Hopefully, this function is better than the previous one which returned
    164  1.1    gwr  * the sum of the squares of all the bytes.  I'm still open to other
    165  1.1    gwr  * suggestions for a default hash function.  The programmer is more than
    166  1.1    gwr  * welcome to supply his/her own hash function as that is one of the design
    167  1.1    gwr  * features of this package.
    168  1.6    wiz  */
    169  1.1    gwr 
    170  1.6    wiz unsigned
    171  1.1    gwr hash_HashFunction(unsigned char *string, unsigned int len)
    172  1.1    gwr {
    173  1.1    gwr 	unsigned accum;
    174  1.1    gwr 
    175  1.1    gwr 	accum = 0;
    176  1.1    gwr 	for (; len > 0; len--) {
    177  1.1    gwr 		accum <<= 1;
    178  1.1    gwr 		accum += (unsigned) (*string++ & 0xFF);
    179  1.1    gwr 	}
    180  1.1    gwr 	return accum;
    181  1.1    gwr }
    182  1.1    gwr 
    183  1.1    gwr 
    185  1.1    gwr 
    186  1.1    gwr /*
    187  1.1    gwr  * Returns TRUE if at least one entry for the given key exists; FALSE
    188  1.5    wiz  * otherwise.
    189  1.5    wiz  */
    190  1.1    gwr 
    191  1.6    wiz int
    192  1.1    gwr hash_Exists(hash_tbl *hashtable, unsigned int hashcode, hash_cmpfp compare,
    193  1.1    gwr 	    hash_datum *key)
    194  1.1    gwr {
    195  1.1    gwr 	hash_member *memberptr;
    196  1.1    gwr 
    197  1.1    gwr 	memberptr = (hashtable->table)[hashcode % (hashtable->size)];
    198  1.1    gwr 	while (memberptr) {
    199  1.1    gwr 		if ((*compare) (key, memberptr->data)) {
    200  1.1    gwr 			return TRUE;		/* Entry does exist */
    201  1.1    gwr 		}
    202  1.1    gwr 		memberptr = memberptr->next;
    203  1.1    gwr 	}
    204  1.1    gwr 	return FALSE;				/* Entry does not exist */
    205  1.1    gwr }
    206  1.1    gwr 
    207  1.1    gwr 
    209  1.1    gwr 
    210  1.1    gwr /*
    211  1.1    gwr  * Insert the data item "element" into the hash table using "hashcode"
    212  1.1    gwr  * to determine the bucket number, and "compare" and "key" to determine
    213  1.1    gwr  * its uniqueness.
    214  1.1    gwr  *
    215  1.1    gwr  * If the insertion is successful 0 is returned.  If a matching entry
    216  1.5    wiz  * already exists in the given bucket of the hash table, or some other error
    217  1.5    wiz  * occurs, -1 is returned and the insertion is not done.
    218  1.1    gwr  */
    219  1.1    gwr 
    220  1.1    gwr int
    221  1.1    gwr hash_Insert(hash_tbl *hashtable, unsigned int hashcode, hash_cmpfp compare,
    222  1.1    gwr 	    hash_datum *key, hash_datum *element)
    223  1.1    gwr {
    224  1.1    gwr 	hash_member *temp;
    225  1.1    gwr 
    226  1.1    gwr 	hashcode %= hashtable->size;
    227  1.1    gwr 	if (hash_Exists(hashtable, hashcode, compare, key)) {
    228  1.1    gwr 		return -1;				/* At least one entry already exists */
    229  1.1    gwr 	}
    230  1.1    gwr 	temp = (hash_member *) malloc(sizeof(hash_member));
    231  1.1    gwr 	if (!temp)
    232  1.1    gwr 		return -1;				/* malloc failed! */
    233  1.1    gwr 
    234  1.1    gwr 	temp->data = element;
    235  1.1    gwr 	temp->next = (hashtable->table)[hashcode];
    236  1.1    gwr 	(hashtable->table)[hashcode] = temp;
    237  1.1    gwr 	return 0;					/* Success */
    238  1.1    gwr }
    239  1.1    gwr 
    240  1.1    gwr 
    242  1.1    gwr 
    243  1.1    gwr /*
    244  1.5    wiz  * Delete all data elements which match the given key.  If at least one
    245  1.5    wiz  * element is found and the deletion is successful, 0 is returned.
    246  1.1    gwr  * If no matching elements can be found in the hash table, -1 is returned.
    247  1.1    gwr  */
    248  1.1    gwr 
    249  1.1    gwr int
    250  1.1    gwr hash_Delete(hash_tbl *hashtable, unsigned int hashcode, hash_cmpfp compare,
    251  1.1    gwr 	    hash_datum *key, hash_freefp free_data)
    252  1.1    gwr {
    253  1.1    gwr 	hash_member *memberptr, *tempptr;
    254  1.1    gwr 	hash_member *previous = NULL;
    255  1.1    gwr 	int retval;
    256  1.1    gwr 
    257  1.1    gwr 	retval = -1;
    258  1.1    gwr 	hashcode %= hashtable->size;
    259  1.1    gwr 
    260  1.1    gwr 	/*
    261  1.1    gwr 	 * Delete the first member of the list if it matches.  Since this moves
    262  1.1    gwr 	 * the second member into the first position we have to keep doing this
    263  1.1    gwr 	 * over and over until it no longer matches.
    264  1.1    gwr 	 */
    265  1.1    gwr 	memberptr = (hashtable->table)[hashcode];
    266  1.1    gwr 	while (memberptr && (*compare) (key, memberptr->data)) {
    267  1.1    gwr 		(hashtable->table)[hashcode] = memberptr->next;
    268  1.1    gwr 		/*
    269  1.1    gwr 		 * Stop hashi_FreeMembers() from deleting the whole list!
    270  1.1    gwr 		 */
    271  1.1    gwr 		memberptr->next = NULL;
    272  1.1    gwr 		hashi_FreeMembers(memberptr, free_data);
    273  1.1    gwr 		memberptr = (hashtable->table)[hashcode];
    274  1.1    gwr 		retval = 0;
    275  1.1    gwr 	}
    276  1.1    gwr 
    277  1.1    gwr 	/*
    278  1.1    gwr 	 * Now traverse the rest of the list
    279  1.1    gwr 	 */
    280  1.1    gwr 	if (memberptr) {
    281  1.1    gwr 		previous = memberptr;
    282  1.1    gwr 		memberptr = memberptr->next;
    283  1.1    gwr 	}
    284  1.1    gwr 	while (memberptr) {
    285  1.1    gwr 		if ((*compare) (key, memberptr->data)) {
    286  1.1    gwr 			tempptr = memberptr;
    287  1.1    gwr 			previous->next = memberptr = memberptr->next;
    288  1.1    gwr 			/*
    289  1.1    gwr 			 * Put the brakes on hashi_FreeMembers(). . . .
    290  1.1    gwr 			 */
    291  1.1    gwr 			tempptr->next = NULL;
    292  1.1    gwr 			hashi_FreeMembers(tempptr, free_data);
    293  1.1    gwr 			retval = 0;
    294  1.1    gwr 		} else {
    295  1.1    gwr 			previous = memberptr;
    296  1.1    gwr 			memberptr = memberptr->next;
    297  1.1    gwr 		}
    298  1.1    gwr 	}
    299  1.1    gwr 	return retval;
    300  1.1    gwr }
    301  1.1    gwr 
    302  1.1    gwr 
    304  1.1    gwr 
    305  1.1    gwr /*
    306  1.5    wiz  * Locate and return the data entry associated with the given key.
    307  1.5    wiz  *
    308  1.1    gwr  * If the data entry is found, a pointer to it is returned.  Otherwise,
    309  1.1    gwr  * NULL is returned.
    310  1.1    gwr  */
    311  1.1    gwr 
    312  1.1    gwr hash_datum *
    313  1.1    gwr hash_Lookup(hash_tbl *hashtable, unsigned int hashcode, hash_cmpfp compare,
    314  1.1    gwr 	    hash_datum *key)
    315  1.1    gwr {
    316  1.1    gwr 	hash_member *memberptr;
    317  1.1    gwr 
    318  1.1    gwr 	memberptr = (hashtable->table)[hashcode % (hashtable->size)];
    319  1.1    gwr 	while (memberptr) {
    320  1.1    gwr 		if ((*compare) (key, memberptr->data)) {
    321  1.1    gwr 			return (memberptr->data);
    322  1.1    gwr 		}
    323  1.1    gwr 		memberptr = memberptr->next;
    324  1.1    gwr 	}
    325  1.1    gwr 	return NULL;
    326  1.1    gwr }
    327  1.1    gwr 
    328  1.5    wiz 
    330  1.6    wiz 
    331  1.6    wiz /*
    332  1.1    gwr  * Return the next available entry in the hashtable for a linear search
    333  1.1    gwr  */
    334  1.1    gwr 
    335  1.1    gwr hash_datum *
    336  1.1    gwr hash_NextEntry(hash_tbl *hashtable)
    337  1.1    gwr {
    338  1.1    gwr 	unsigned bucket;
    339  1.1    gwr 	hash_member *memberptr;
    340  1.1    gwr 
    341  1.1    gwr 	/*
    342  1.1    gwr 	 * First try to pick up where we left off.
    343  1.1    gwr 	 */
    344  1.1    gwr 	memberptr = hashtable->member;
    345  1.1    gwr 	if (memberptr) {
    346  1.1    gwr 		hashtable->member = memberptr->next;	/* Set up for next call */
    347  1.1    gwr 		return memberptr->data;	/* Return the data */
    348  1.1    gwr 	}
    349  1.1    gwr 	/*
    350  1.1    gwr 	 * We hit the end of a chain, so look through the array of buckets
    351  1.1    gwr 	 * until we find a new chain (non-empty bucket) or run out of buckets.
    352  1.1    gwr 	 */
    353  1.1    gwr 	bucket = hashtable->bucketnum + 1;
    354  1.1    gwr 	while ((bucket < hashtable->size) &&
    355  1.1    gwr 		   !(memberptr = (hashtable->table)[bucket])) {
    356  1.1    gwr 		bucket++;
    357  1.1    gwr 	}
    358  1.1    gwr 
    359  1.1    gwr 	/*
    360  1.1    gwr 	 * Check to see if we ran out of buckets.
    361  1.1    gwr 	 */
    362  1.1    gwr 	if (bucket >= hashtable->size) {
    363  1.1    gwr 		/*
    364  1.1    gwr 		 * Reset to top of table for next call.
    365  1.1    gwr 		 */
    366  1.1    gwr 		hashtable->bucketnum = 0;
    367  1.1    gwr 		hashtable->member = (hashtable->table)[0];
    368  1.1    gwr 		/*
    369  1.1    gwr 		 * But return end-of-table indication to the caller this time.
    370  1.1    gwr 		 */
    371  1.1    gwr 		return NULL;
    372  1.1    gwr 	}
    373  1.1    gwr 	/*
    374  1.1    gwr 	 * Must have found a non-empty bucket.
    375  1.1    gwr 	 */
    376  1.1    gwr 	hashtable->bucketnum = bucket;
    377  1.1    gwr 	hashtable->member = memberptr->next;	/* Set up for next call */
    378  1.1    gwr 	return memberptr->data;		/* Return the data */
    379  1.1    gwr }
    380  1.5    wiz 
    381  1.1    gwr 
    383  1.1    gwr 
    384  1.1    gwr /*
    385  1.1    gwr  * Return the first entry in a hash table for a linear search
    386  1.1    gwr  */
    387  1.1    gwr 
    388  1.1    gwr hash_datum *
    389  1.1    gwr hash_FirstEntry(hash_tbl *hashtable)
    390  1.1    gwr {
    391  1.1    gwr 	hashtable->bucketnum = 0;
    392  1.1    gwr 	hashtable->member = (hashtable->table)[0];
    393  1.1    gwr 	return hash_NextEntry(hashtable);
    394  1.1    gwr }
    395  1.1    gwr 
    396  1.1    gwr /*
    397  1.1    gwr  * Local Variables:
    398              * tab-width: 4
    399              * c-indent-level: 4
    400              * c-argdecl-indent: 4
    401              * c-continued-statement-offset: 4
    402              * c-continued-brace-offset: -4
    403              * c-label-offset: -4
    404              * c-brace-offset: 0
    405              * End:
    406              */
    407