├── COPYING ├── CREDITS ├── Makefile ├── README.md ├── hashtable.c ├── hashtable.h ├── hashtable_itr.c ├── hashtable_itr.h ├── hashtable_powers.c ├── hashtable_private.h ├── hashtable_utility.c ├── hashtable_utility.h └── tester.c /COPYING: -------------------------------------------------------------------------------- 1 | Copyright (c) 2002, 2004, Christopher Clark 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright 12 | notice, this list of conditions and the following disclaimer in the 13 | documentation and/or other materials provided with the distribution. 14 | 15 | * Neither the name of the original author; nor the names of any contributors 16 | may be used to endorse or promote products derived from this software 17 | without specific prior written permission. 18 | 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 24 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /CREDITS: -------------------------------------------------------------------------------- 1 | Thanks to Glenn Lawyer for pointing out a Makefile fix for the tester example 2 | code. 3 | 4 | Thanks to Holger Schemel for reminding me to actually free the hashtable in the 5 | destroy function... 6 | Also for the hashtable_change function, now found in the hashtable utility 7 | source. 8 | 9 | Thanks to John Muehlhausen for the iterator bug report - fixed 2003-03-19. 10 | 11 | Thanks to Leonid Nilva for feedback. 12 | 13 | Thanks to Mark Seneski for thoroughly reviewing my code, catching some of my 14 | slips from best practice, and prompting me to finally get around to sizing the 15 | table using prime numbers. 16 | Thanks due to Aaron Krowne for his table of prime numbers used to do this. 17 | http://planetmath.org/encyclopedia/GoodHashTablePrimes.html 18 | 19 | Thanks to A. B. M. Omar Faruk for spotting the bug in the sample code on the 20 | web page, where the same key struct was used for insertion into the hashtable, 21 | and then also for retrieval. Ownership of the key is claimed when it is 22 | inserted. 23 | 24 | Christopher Clark 25 | Updated 29th April, 2007. 26 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | tester: hashtable.o tester.o hashtable_itr.o 3 | gcc -g -Wall -O -lm -o tester hashtable.o hashtable_itr.o tester.o 4 | 5 | all: tester old_tester 6 | 7 | tester.o: tester.c 8 | gcc -g -Wall -O -c tester.c -o tester.o 9 | 10 | old_tester: hashtable_powers.o tester.o hashtable_itr.o 11 | gcc -g -Wall -O -o old_tester hashtable_powers.o hashtable_itr.o tester.o 12 | 13 | hashtable_powers.o: hashtable_powers.c 14 | gcc -g -Wall -O -c hashtable_powers.c -o hashtable_powers.o 15 | 16 | hashtable.o: hashtable.c 17 | gcc -g -Wall -O -c hashtable.c -o hashtable.o 18 | 19 | hashtable_itr.o: hashtable_itr.c 20 | gcc -g -Wall -O -c hashtable_itr.c -o hashtable_itr.o 21 | 22 | tidy: 23 | rm *.o 24 | 25 | clean: tidy 26 | rm -f tester old_tester 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # C Hash Table 2 | 3 | ## Source code for a hash table data structure in C 4 | 5 | This code is made available under the terms of the new BSD license. 6 | 7 | If you use this code, drop me an email. It's nice to feel useful occasionally. 8 | I promise not to sell your email address to Nigerian spam bandits. Thanks. 9 | Christopher Clark (firstname.lastname @ cl.cam.ac.uk), January 2005. 10 | 11 | 12 | ## Defined functions 13 | 14 | * create_hashtable 15 | * hashtable_insert 16 | * hashtable_search 17 | * hashtable_remove 18 | * hashtable_count 19 | * hashtable_destroy 20 | 21 | 22 | ## Example of use 23 | 24 | 25 | struct hashtable *h; 26 | struct some_key *k; 27 | struct some_value *v; 28 | 29 | static unsigned int hash_from_key_fn( void *k ); 30 | static int keys_equal_fn ( void *key1, void *key2 ); 31 | 32 | h = create_hashtable(16, hash_from_key_fn, keys_equal_fn); 33 | 34 | insert_key = (struct some_key *) malloc(sizeof(struct some_key)); 35 | retrieve_key = (struct some_key *) malloc(sizeof(struct some_key)); 36 | 37 | v = (struct some_value *) malloc(sizeof(struct some_value)); 38 | 39 | (You should initialise insert_key, retrieve_key and v here) 40 | 41 | if (! hashtable_insert(h,insert_key,v) ) 42 | { exit(-1); } 43 | 44 | if (NULL == (found = hashtable_search(h,retrieve_key) )) 45 | { printf("not found!"); } 46 | 47 | if (NULL == (found = hashtable_remove(h,retrieve_key) )) 48 | { printf("Not found\n"); } 49 | 50 | hashtable_destroy(h,1); /* second arg indicates "free(value)" */ 51 | 52 | 53 | 54 | ## Description 55 | 56 | The table will increase in size as elements are added, to keep the ratio of elements to table size below a threshold. The table is sized by selecting a prime number of appropriate magnitude, to ensure best distribution of the contents. 57 | 58 | For improved type safety, macros have been defined and may be used to define type-safe(r) hashtable access functions, with methods specialized to take known key and value types as parameters. Example: Insert this at the start of your file: 59 | 60 | 61 | DEFINE_HASHTABLE_INSERT(insert_some, struct some_key, struct some_value); 62 | DEFINE_HASHTABLE_SEARCH(search_some, struct some_key, struct some_value); 63 | DEFINE_HASHTABLE_REMOVE(remove_some, struct some_key, struct some_value); 64 | 65 | 66 | This defines the functions `insert_some`, `search_some` and `remove_some`. These operate just like hashtable_insert etc., with the same parameters, but their function signatures have `struct some_key *` rather than `void *`, and hence can generate compile time errors if your program is supplying incorrect data as a key (and similarly for value). 67 | 68 | Note that the hash and key equality functions passed to create_hashtable still take `void *` parameters instead of `some key *`. This shouldn't be a serious issue as they're only defined and passed once, and the other functions will ensure that only valid keys are supplied to them. 69 | 70 | The cost for this checking is increased code size and runtime overhead - if performance is important, it may be worth switching back to the unsafe methods once your program has been debugged with the safe methods. 71 | 72 | 73 | ## Iterator 74 | 75 | The iterator is a simple one-way iterator over the hashtable contents, providing accessors for the the key and value at the current element. 76 | 77 | 78 | /* Iterator constructor only returns a valid iterator if 79 | * the hashtable is not empty */ 80 | 81 | if (hashtable_count(h) > 0) 82 | { 83 | itr = hashtable_iterator(h); 84 | do { 85 | k = hashtable_iterator_key(itr); 86 | v = hashtable_iterator_value(itr); 87 | 88 | /* here (k,v) are a valid (key, value) pair */ 89 | /* We could call 'hashtable_remove(h,k)' - and this operation 90 | * 'free's k and returns v. 91 | * However, after the operation, the iterator is broken. 92 | */ 93 | 94 | } while (hashtable_iterator_advance(itr)); 95 | } 96 | free(itr); 97 | 98 | 99 | 100 | 101 | ## Notes 102 | 103 | You may find this (external) page of [hash functions for strings][1] helpful. Note that the hashtable includes a small section of code to protect against poor hash functions - it may be worthwhile removing this if you are sure you are using a good hash function. 104 | 105 | If hashing strings, remember that `strcmp` is not a boolean comparison function directly suitable for `keys_equal_fn`. 106 | 107 | 108 | Archived copy of the original hashtable implementation, where table size is a power of two, rather than prime. [ hashtable_powers.c ] 109 | 110 | 111 | [Christopher Clark][2] 112 | Updated 11th January, 2005. 113 | 114 | [1]: http://www.cs.yorku.ca/~oz/hash.html 115 | [2]: http://www.cl.cam.ac.uk/~cwc22/ 116 | 117 | -------------------------------------------------------------------------------- /hashtable.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2004 Christopher Clark */ 2 | 3 | #include "hashtable.h" 4 | #include "hashtable_private.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | /* 11 | Credit for primes table: Aaron Krowne 12 | http://br.endernet.org/~akrowne/ 13 | http://planetmath.org/encyclopedia/GoodHashTablePrimes.html 14 | */ 15 | static const unsigned int primes[] = { 16 | 53, 97, 193, 389, 17 | 769, 1543, 3079, 6151, 18 | 12289, 24593, 49157, 98317, 19 | 196613, 393241, 786433, 1572869, 20 | 3145739, 6291469, 12582917, 25165843, 21 | 50331653, 100663319, 201326611, 402653189, 22 | 805306457, 1610612741 23 | }; 24 | const unsigned int prime_table_length = sizeof(primes)/sizeof(primes[0]); 25 | const float max_load_factor = 0.65; 26 | 27 | /*****************************************************************************/ 28 | struct hashtable * 29 | create_hashtable(unsigned int minsize, 30 | unsigned int (*hashf) (void*), 31 | int (*eqf) (void*,void*)) 32 | { 33 | struct hashtable *h; 34 | unsigned int pindex, size = primes[0]; 35 | /* Check requested hashtable isn't too large */ 36 | if (minsize > (1u << 30)) return NULL; 37 | /* Enforce size as prime */ 38 | for (pindex=0; pindex < prime_table_length; pindex++) { 39 | if (primes[pindex] > minsize) { size = primes[pindex]; break; } 40 | } 41 | h = (struct hashtable *)malloc(sizeof(struct hashtable)); 42 | if (NULL == h) return NULL; /*oom*/ 43 | h->table = (struct entry **)malloc(sizeof(struct entry*) * size); 44 | if (NULL == h->table) { free(h); return NULL; } /*oom*/ 45 | memset(h->table, 0, size * sizeof(struct entry *)); 46 | h->tablelength = size; 47 | h->primeindex = pindex; 48 | h->entrycount = 0; 49 | h->hashfn = hashf; 50 | h->eqfn = eqf; 51 | h->loadlimit = (unsigned int) ceil(size * max_load_factor); 52 | return h; 53 | } 54 | 55 | /*****************************************************************************/ 56 | unsigned int 57 | hash(struct hashtable *h, void *k) 58 | { 59 | /* Aim to protect against poor hash functions by adding logic here 60 | * - logic taken from java 1.4 hashtable source */ 61 | unsigned int i = h->hashfn(k); 62 | i += ~(i << 9); 63 | i ^= ((i >> 14) | (i << 18)); /* >>> */ 64 | i += (i << 4); 65 | i ^= ((i >> 10) | (i << 22)); /* >>> */ 66 | return i; 67 | } 68 | 69 | /*****************************************************************************/ 70 | static int 71 | hashtable_expand(struct hashtable *h) 72 | { 73 | /* Double the size of the table to accomodate more entries */ 74 | struct entry **newtable; 75 | struct entry *e; 76 | struct entry **pE; 77 | unsigned int newsize, i, index; 78 | /* Check we're not hitting max capacity */ 79 | if (h->primeindex == (prime_table_length - 1)) return 0; 80 | newsize = primes[++(h->primeindex)]; 81 | 82 | newtable = (struct entry **)malloc(sizeof(struct entry*) * newsize); 83 | if (NULL != newtable) 84 | { 85 | memset(newtable, 0, newsize * sizeof(struct entry *)); 86 | /* This algorithm is not 'stable'. ie. it reverses the list 87 | * when it transfers entries between the tables */ 88 | for (i = 0; i < h->tablelength; i++) { 89 | while (NULL != (e = h->table[i])) { 90 | h->table[i] = e->next; 91 | index = indexFor(newsize,e->h); 92 | e->next = newtable[index]; 93 | newtable[index] = e; 94 | } 95 | } 96 | free(h->table); 97 | h->table = newtable; 98 | } 99 | /* Plan B: realloc instead */ 100 | else 101 | { 102 | newtable = (struct entry **) 103 | realloc(h->table, newsize * sizeof(struct entry *)); 104 | if (NULL == newtable) { (h->primeindex)--; return 0; } 105 | h->table = newtable; 106 | memset(newtable[h->tablelength], 0, newsize - h->tablelength); 107 | for (i = 0; i < h->tablelength; i++) { 108 | for (pE = &(newtable[i]), e = *pE; e != NULL; e = *pE) { 109 | index = indexFor(newsize,e->h); 110 | if (index == i) 111 | { 112 | pE = &(e->next); 113 | } 114 | else 115 | { 116 | *pE = e->next; 117 | e->next = newtable[index]; 118 | newtable[index] = e; 119 | } 120 | } 121 | } 122 | } 123 | h->tablelength = newsize; 124 | h->loadlimit = (unsigned int) ceil(newsize * max_load_factor); 125 | return -1; 126 | } 127 | 128 | /*****************************************************************************/ 129 | unsigned int 130 | hashtable_count(struct hashtable *h) 131 | { 132 | return h->entrycount; 133 | } 134 | 135 | /*****************************************************************************/ 136 | int 137 | hashtable_insert(struct hashtable *h, void *k, void *v) 138 | { 139 | /* This method allows duplicate keys - but they shouldn't be used */ 140 | unsigned int index; 141 | struct entry *e; 142 | if (++(h->entrycount) > h->loadlimit) 143 | { 144 | /* Ignore the return value. If expand fails, we should 145 | * still try cramming just this value into the existing table 146 | * -- we may not have memory for a larger table, but one more 147 | * element may be ok. Next time we insert, we'll try expanding again.*/ 148 | hashtable_expand(h); 149 | } 150 | e = (struct entry *)malloc(sizeof(struct entry)); 151 | if (NULL == e) { --(h->entrycount); return 0; } /*oom*/ 152 | e->h = hash(h,k); 153 | index = indexFor(h->tablelength,e->h); 154 | e->k = k; 155 | e->v = v; 156 | e->next = h->table[index]; 157 | h->table[index] = e; 158 | return -1; 159 | } 160 | 161 | /*****************************************************************************/ 162 | void * /* returns value associated with key */ 163 | hashtable_search(struct hashtable *h, void *k) 164 | { 165 | struct entry *e; 166 | unsigned int hashvalue, index; 167 | hashvalue = hash(h,k); 168 | index = indexFor(h->tablelength,hashvalue); 169 | e = h->table[index]; 170 | while (NULL != e) 171 | { 172 | /* Check hash value to short circuit heavier comparison */ 173 | if ((hashvalue == e->h) && (h->eqfn(k, e->k))) return e->v; 174 | e = e->next; 175 | } 176 | return NULL; 177 | } 178 | 179 | /*****************************************************************************/ 180 | void * /* returns value associated with key */ 181 | hashtable_remove(struct hashtable *h, void *k) 182 | { 183 | /* TODO: consider compacting the table when the load factor drops enough, 184 | * or provide a 'compact' method. */ 185 | 186 | struct entry *e; 187 | struct entry **pE; 188 | void *v; 189 | unsigned int hashvalue, index; 190 | 191 | hashvalue = hash(h,k); 192 | index = indexFor(h->tablelength,hash(h,k)); 193 | pE = &(h->table[index]); 194 | e = *pE; 195 | while (NULL != e) 196 | { 197 | /* Check hash value to short circuit heavier comparison */ 198 | if ((hashvalue == e->h) && (h->eqfn(k, e->k))) 199 | { 200 | *pE = e->next; 201 | h->entrycount--; 202 | v = e->v; 203 | freekey(e->k); 204 | free(e); 205 | return v; 206 | } 207 | pE = &(e->next); 208 | e = e->next; 209 | } 210 | return NULL; 211 | } 212 | 213 | /*****************************************************************************/ 214 | /* destroy */ 215 | void 216 | hashtable_destroy(struct hashtable *h, int free_values) 217 | { 218 | unsigned int i; 219 | struct entry *e, *f; 220 | struct entry **table = h->table; 221 | if (free_values) 222 | { 223 | for (i = 0; i < h->tablelength; i++) 224 | { 225 | e = table[i]; 226 | while (NULL != e) 227 | { f = e; e = e->next; freekey(f->k); free(f->v); free(f); } 228 | } 229 | } 230 | else 231 | { 232 | for (i = 0; i < h->tablelength; i++) 233 | { 234 | e = table[i]; 235 | while (NULL != e) 236 | { f = e; e = e->next; freekey(f->k); free(f); } 237 | } 238 | } 239 | free(h->table); 240 | free(h); 241 | } 242 | 243 | /* 244 | * Copyright (c) 2002, Christopher Clark 245 | * All rights reserved. 246 | * 247 | * Redistribution and use in source and binary forms, with or without 248 | * modification, are permitted provided that the following conditions 249 | * are met: 250 | * 251 | * * Redistributions of source code must retain the above copyright 252 | * notice, this list of conditions and the following disclaimer. 253 | * 254 | * * Redistributions in binary form must reproduce the above copyright 255 | * notice, this list of conditions and the following disclaimer in the 256 | * documentation and/or other materials provided with the distribution. 257 | * 258 | * * Neither the name of the original author; nor the names of any contributors 259 | * may be used to endorse or promote products derived from this software 260 | * without specific prior written permission. 261 | * 262 | * 263 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 264 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 265 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 266 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 267 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 268 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 269 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 270 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 271 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 272 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 273 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 274 | */ 275 | -------------------------------------------------------------------------------- /hashtable.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2002 Christopher Clark */ 2 | 3 | #ifndef __HASHTABLE_CWC22_H__ 4 | #define __HASHTABLE_CWC22_H__ 5 | 6 | struct hashtable; 7 | 8 | /* Example of use: 9 | * 10 | * struct hashtable *h; 11 | * struct some_key *k; 12 | * struct some_value *v; 13 | * 14 | * static unsigned int hash_from_key_fn( void *k ); 15 | * static int keys_equal_fn ( void *key1, void *key2 ); 16 | * 17 | * h = create_hashtable(16, hash_from_key_fn, keys_equal_fn); 18 | * k = (struct some_key *) malloc(sizeof(struct some_key)); 19 | * v = (struct some_value *) malloc(sizeof(struct some_value)); 20 | * 21 | * (initialise k and v to suitable values) 22 | * 23 | * if (! hashtable_insert(h,k,v) ) 24 | * { exit(-1); } 25 | * 26 | * if (NULL == (found = hashtable_search(h,k) )) 27 | * { printf("not found!"); } 28 | * 29 | * if (NULL == (found = hashtable_remove(h,k) )) 30 | * { printf("Not found\n"); } 31 | * 32 | */ 33 | 34 | /* Macros may be used to define type-safe(r) hashtable access functions, with 35 | * methods specialized to take known key and value types as parameters. 36 | * 37 | * Example: 38 | * 39 | * Insert this at the start of your file: 40 | * 41 | * DEFINE_HASHTABLE_INSERT(insert_some, struct some_key, struct some_value); 42 | * DEFINE_HASHTABLE_SEARCH(search_some, struct some_key, struct some_value); 43 | * DEFINE_HASHTABLE_REMOVE(remove_some, struct some_key, struct some_value); 44 | * 45 | * This defines the functions 'insert_some', 'search_some' and 'remove_some'. 46 | * These operate just like hashtable_insert etc., with the same parameters, 47 | * but their function signatures have 'struct some_key *' rather than 48 | * 'void *', and hence can generate compile time errors if your program is 49 | * supplying incorrect data as a key (and similarly for value). 50 | * 51 | * Note that the hash and key equality functions passed to create_hashtable 52 | * still take 'void *' parameters instead of 'some key *'. This shouldn't be 53 | * a difficult issue as they're only defined and passed once, and the other 54 | * functions will ensure that only valid keys are supplied to them. 55 | * 56 | * The cost for this checking is increased code size and runtime overhead 57 | * - if performance is important, it may be worth switching back to the 58 | * unsafe methods once your program has been debugged with the safe methods. 59 | * This just requires switching to some simple alternative defines - eg: 60 | * #define insert_some hashtable_insert 61 | * 62 | */ 63 | 64 | /***************************************************************************** 65 | * create_hashtable 66 | 67 | * @name create_hashtable 68 | * @param minsize minimum initial size of hashtable 69 | * @param hashfunction function for hashing keys 70 | * @param key_eq_fn function for determining key equality 71 | * @return newly created hashtable or NULL on failure 72 | */ 73 | 74 | struct hashtable * 75 | create_hashtable(unsigned int minsize, 76 | unsigned int (*hashfunction) (void*), 77 | int (*key_eq_fn) (void*,void*)); 78 | 79 | /***************************************************************************** 80 | * hashtable_insert 81 | 82 | * @name hashtable_insert 83 | * @param h the hashtable to insert into 84 | * @param k the key - hashtable claims ownership and will free on removal 85 | * @param v the value - does not claim ownership 86 | * @return non-zero for successful insertion 87 | * 88 | * This function will cause the table to expand if the insertion would take 89 | * the ratio of entries to table size over the maximum load factor. 90 | * 91 | * This function does not check for repeated insertions with a duplicate key. 92 | * The value returned when using a duplicate key is undefined -- when 93 | * the hashtable changes size, the order of retrieval of duplicate key 94 | * entries is reversed. 95 | * If in doubt, remove before insert. 96 | */ 97 | 98 | int 99 | hashtable_insert(struct hashtable *h, void *k, void *v); 100 | 101 | #define DEFINE_HASHTABLE_INSERT(fnname, keytype, valuetype) \ 102 | int fnname (struct hashtable *h, keytype *k, valuetype *v) \ 103 | { \ 104 | return hashtable_insert(h,k,v); \ 105 | } 106 | 107 | /***************************************************************************** 108 | * hashtable_search 109 | 110 | * @name hashtable_search 111 | * @param h the hashtable to search 112 | * @param k the key to search for - does not claim ownership 113 | * @return the value associated with the key, or NULL if none found 114 | */ 115 | 116 | void * 117 | hashtable_search(struct hashtable *h, void *k); 118 | 119 | #define DEFINE_HASHTABLE_SEARCH(fnname, keytype, valuetype) \ 120 | valuetype * fnname (struct hashtable *h, keytype *k) \ 121 | { \ 122 | return (valuetype *) (hashtable_search(h,k)); \ 123 | } 124 | 125 | /***************************************************************************** 126 | * hashtable_remove 127 | 128 | * @name hashtable_remove 129 | * @param h the hashtable to remove the item from 130 | * @param k the key to search for - does not claim ownership 131 | * @return the value associated with the key, or NULL if none found 132 | */ 133 | 134 | void * /* returns value */ 135 | hashtable_remove(struct hashtable *h, void *k); 136 | 137 | #define DEFINE_HASHTABLE_REMOVE(fnname, keytype, valuetype) \ 138 | valuetype * fnname (struct hashtable *h, keytype *k) \ 139 | { \ 140 | return (valuetype *) (hashtable_remove(h,k)); \ 141 | } 142 | 143 | 144 | /***************************************************************************** 145 | * hashtable_count 146 | 147 | * @name hashtable_count 148 | * @param h the hashtable 149 | * @return the number of items stored in the hashtable 150 | */ 151 | unsigned int 152 | hashtable_count(struct hashtable *h); 153 | 154 | 155 | /***************************************************************************** 156 | * hashtable_destroy 157 | 158 | * @name hashtable_destroy 159 | * @param h the hashtable 160 | * @param free_values whether to call 'free' on the remaining values 161 | */ 162 | 163 | void 164 | hashtable_destroy(struct hashtable *h, int free_values); 165 | 166 | #endif /* __HASHTABLE_CWC22_H__ */ 167 | 168 | /* 169 | * Copyright (c) 2002, Christopher Clark 170 | * All rights reserved. 171 | * 172 | * Redistribution and use in source and binary forms, with or without 173 | * modification, are permitted provided that the following conditions 174 | * are met: 175 | * 176 | * * Redistributions of source code must retain the above copyright 177 | * notice, this list of conditions and the following disclaimer. 178 | * 179 | * * Redistributions in binary form must reproduce the above copyright 180 | * notice, this list of conditions and the following disclaimer in the 181 | * documentation and/or other materials provided with the distribution. 182 | * 183 | * * Neither the name of the original author; nor the names of any contributors 184 | * may be used to endorse or promote products derived from this software 185 | * without specific prior written permission. 186 | * 187 | * 188 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 189 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 190 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 191 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 192 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 193 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 194 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 195 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 196 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 197 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 198 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 199 | */ 200 | -------------------------------------------------------------------------------- /hashtable_itr.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2002, 2004 Christopher Clark */ 2 | 3 | #include "hashtable.h" 4 | #include "hashtable_private.h" 5 | #include "hashtable_itr.h" 6 | #include /* defines NULL */ 7 | 8 | /*****************************************************************************/ 9 | /* hashtable_iterator - iterator constructor */ 10 | 11 | struct hashtable_itr * 12 | hashtable_iterator(struct hashtable *h) 13 | { 14 | unsigned int i, tablelength; 15 | struct hashtable_itr *itr = (struct hashtable_itr *) 16 | malloc(sizeof(struct hashtable_itr)); 17 | if (NULL == itr) return NULL; 18 | itr->h = h; 19 | itr->e = NULL; 20 | itr->parent = NULL; 21 | tablelength = h->tablelength; 22 | itr->index = tablelength; 23 | if (0 == h->entrycount) return itr; 24 | 25 | for (i = 0; i < tablelength; i++) 26 | { 27 | if (NULL != h->table[i]) 28 | { 29 | itr->e = h->table[i]; 30 | itr->index = i; 31 | break; 32 | } 33 | } 34 | return itr; 35 | } 36 | 37 | /*****************************************************************************/ 38 | /* key - return the key of the (key,value) pair at the current position */ 39 | /* value - return the value of the (key,value) pair at the current position */ 40 | 41 | void * 42 | hashtable_iterator_key(struct hashtable_itr *i) 43 | { return i->e->k; } 44 | 45 | void * 46 | hashtable_iterator_value(struct hashtable_itr *i) 47 | { return i->e->v; } 48 | 49 | /*****************************************************************************/ 50 | /* advance - advance the iterator to the next element 51 | * returns zero if advanced to end of table */ 52 | 53 | int 54 | hashtable_iterator_advance(struct hashtable_itr *itr) 55 | { 56 | unsigned int j,tablelength; 57 | struct entry **table; 58 | struct entry *next; 59 | if (NULL == itr->e) return 0; /* stupidity check */ 60 | 61 | next = itr->e->next; 62 | if (NULL != next) 63 | { 64 | itr->parent = itr->e; 65 | itr->e = next; 66 | return -1; 67 | } 68 | tablelength = itr->h->tablelength; 69 | itr->parent = NULL; 70 | if (tablelength <= (j = ++(itr->index))) 71 | { 72 | itr->e = NULL; 73 | return 0; 74 | } 75 | table = itr->h->table; 76 | while (NULL == (next = table[j])) 77 | { 78 | if (++j >= tablelength) 79 | { 80 | itr->index = tablelength; 81 | itr->e = NULL; 82 | return 0; 83 | } 84 | } 85 | itr->index = j; 86 | itr->e = next; 87 | return -1; 88 | } 89 | 90 | /*****************************************************************************/ 91 | /* remove - remove the entry at the current iterator position 92 | * and advance the iterator, if there is a successive 93 | * element. 94 | * If you want the value, read it before you remove: 95 | * beware memory leaks if you don't. 96 | * Returns zero if end of iteration. */ 97 | 98 | int 99 | hashtable_iterator_remove(struct hashtable_itr *itr) 100 | { 101 | struct entry *remember_e, *remember_parent; 102 | int ret; 103 | 104 | /* Do the removal */ 105 | if (NULL == (itr->parent)) 106 | { 107 | /* element is head of a chain */ 108 | itr->h->table[itr->index] = itr->e->next; 109 | } else { 110 | /* element is mid-chain */ 111 | itr->parent->next = itr->e->next; 112 | } 113 | /* itr->e is now outside the hashtable */ 114 | remember_e = itr->e; 115 | itr->h->entrycount--; 116 | freekey(remember_e->k); 117 | 118 | /* Advance the iterator, correcting the parent */ 119 | remember_parent = itr->parent; 120 | ret = hashtable_iterator_advance(itr); 121 | if (itr->parent == remember_e) { itr->parent = remember_parent; } 122 | free(remember_e); 123 | return ret; 124 | } 125 | 126 | /*****************************************************************************/ 127 | int /* returns zero if not found */ 128 | hashtable_iterator_search(struct hashtable_itr *itr, 129 | struct hashtable *h, void *k) 130 | { 131 | struct entry *e, *parent; 132 | unsigned int hashvalue, index; 133 | 134 | hashvalue = hash(h,k); 135 | index = indexFor(h->tablelength,hashvalue); 136 | 137 | e = h->table[index]; 138 | parent = NULL; 139 | while (NULL != e) 140 | { 141 | /* Check hash value to short circuit heavier comparison */ 142 | if ((hashvalue == e->h) && (h->eqfn(k, e->k))) 143 | { 144 | itr->index = index; 145 | itr->e = e; 146 | itr->parent = parent; 147 | itr->h = h; 148 | return -1; 149 | } 150 | parent = e; 151 | e = e->next; 152 | } 153 | return 0; 154 | } 155 | 156 | 157 | /* 158 | * Copyright (c) 2002, 2004, Christopher Clark 159 | * All rights reserved. 160 | * 161 | * Redistribution and use in source and binary forms, with or without 162 | * modification, are permitted provided that the following conditions 163 | * are met: 164 | * 165 | * * Redistributions of source code must retain the above copyright 166 | * notice, this list of conditions and the following disclaimer. 167 | * 168 | * * Redistributions in binary form must reproduce the above copyright 169 | * notice, this list of conditions and the following disclaimer in the 170 | * documentation and/or other materials provided with the distribution. 171 | * 172 | * * Neither the name of the original author; nor the names of any contributors 173 | * may be used to endorse or promote products derived from this software 174 | * without specific prior written permission. 175 | * 176 | * 177 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 178 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 179 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 180 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 181 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 182 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 183 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 184 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 185 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 186 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 187 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 188 | */ 189 | -------------------------------------------------------------------------------- /hashtable_itr.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2002, 2004 Christopher Clark */ 2 | 3 | #ifndef __HASHTABLE_ITR_CWC22__ 4 | #define __HASHTABLE_ITR_CWC22__ 5 | #include "hashtable.h" 6 | #include "hashtable_private.h" /* needed to enable inlining */ 7 | 8 | /*****************************************************************************/ 9 | /* This struct is only concrete here to allow the inlining of two of the 10 | * accessor functions. */ 11 | struct hashtable_itr 12 | { 13 | struct hashtable *h; 14 | struct entry *e; 15 | struct entry *parent; 16 | unsigned int index; 17 | }; 18 | 19 | 20 | /*****************************************************************************/ 21 | /* hashtable_iterator 22 | */ 23 | 24 | struct hashtable_itr * 25 | hashtable_iterator(struct hashtable *h); 26 | 27 | /*****************************************************************************/ 28 | /* hashtable_iterator_key 29 | * - return the value of the (key,value) pair at the current position */ 30 | 31 | extern inline void * 32 | hashtable_iterator_key(struct hashtable_itr *i) 33 | { 34 | return i->e->k; 35 | } 36 | 37 | /*****************************************************************************/ 38 | /* value - return the value of the (key,value) pair at the current position */ 39 | 40 | extern inline void * 41 | hashtable_iterator_value(struct hashtable_itr *i) 42 | { 43 | return i->e->v; 44 | } 45 | 46 | /*****************************************************************************/ 47 | /* advance - advance the iterator to the next element 48 | * returns zero if advanced to end of table */ 49 | 50 | int 51 | hashtable_iterator_advance(struct hashtable_itr *itr); 52 | 53 | /*****************************************************************************/ 54 | /* remove - remove current element and advance the iterator to the next element 55 | * NB: if you need the value to free it, read it before 56 | * removing. ie: beware memory leaks! 57 | * returns zero if advanced to end of table */ 58 | 59 | int 60 | hashtable_iterator_remove(struct hashtable_itr *itr); 61 | 62 | /*****************************************************************************/ 63 | /* search - overwrite the supplied iterator, to point to the entry 64 | * matching the supplied key. 65 | h points to the hashtable to be searched. 66 | * returns zero if not found. */ 67 | int 68 | hashtable_iterator_search(struct hashtable_itr *itr, 69 | struct hashtable *h, void *k); 70 | 71 | #define DEFINE_HASHTABLE_ITERATOR_SEARCH(fnname, keytype) \ 72 | int fnname (struct hashtable_itr *i, struct hashtable *h, keytype *k) \ 73 | { \ 74 | return (hashtable_iterator_search(i,h,k)); \ 75 | } 76 | 77 | 78 | 79 | #endif /* __HASHTABLE_ITR_CWC22__*/ 80 | 81 | /* 82 | * Copyright (c) 2002, 2004, Christopher Clark 83 | * All rights reserved. 84 | * 85 | * Redistribution and use in source and binary forms, with or without 86 | * modification, are permitted provided that the following conditions 87 | * are met: 88 | * 89 | * * Redistributions of source code must retain the above copyright 90 | * notice, this list of conditions and the following disclaimer. 91 | * 92 | * * Redistributions in binary form must reproduce the above copyright 93 | * notice, this list of conditions and the following disclaimer in the 94 | * documentation and/or other materials provided with the distribution. 95 | * 96 | * * Neither the name of the original author; nor the names of any contributors 97 | * may be used to endorse or promote products derived from this software 98 | * without specific prior written permission. 99 | * 100 | * 101 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 102 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 103 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 104 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 105 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 106 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 107 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 108 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 109 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 110 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 111 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 112 | */ 113 | -------------------------------------------------------------------------------- /hashtable_powers.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2002 Christopher Clark * */ 2 | 3 | #include "hashtable.h" 4 | #include "hashtable_private.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | const float max_load_factor = 0.65; 11 | 12 | /*****************************************************************************/ 13 | struct hashtable * 14 | create_hashtable(unsigned int minsize, 15 | unsigned int (*hashf) (void*), 16 | int (*eqf) (void*,void*)) 17 | { 18 | struct hashtable *h; 19 | unsigned int i, size = 1u; 20 | /* Check requested hashtable isn't too large */ 21 | if (minsize > (1u << 31)) return NULL; 22 | /* Enforce size as power of 2 */ 23 | while (size < minsize) size <<= 1; 24 | h = (struct hashtable *)malloc(sizeof(struct hashtable)); 25 | if (NULL == h) return NULL; /*oom*/ 26 | h->table = (struct entry **)malloc(sizeof(struct entry*) * size); 27 | if (NULL == h->table) { free(h); return NULL; } /*oom*/ 28 | for (i=0;itable[i] = NULL; } 29 | h->tablelength = size; 30 | h->entrycount = 0; 31 | h->hashfn = hashf; 32 | h->eqfn = eqf; 33 | h->loadlimit = (unsigned int) ceil(size * max_load_factor); 34 | return h; 35 | } 36 | 37 | /*****************************************************************************/ 38 | unsigned int 39 | hash(struct hashtable *h, void *k) 40 | { 41 | /* Aim to protect against poor hash functions by adding logic here 42 | * - logic taken from java 1.4 hashtable source */ 43 | unsigned int i = h->hashfn(k); 44 | i += ~(i << 9); 45 | i ^= ((i >> 14) | (i << 18)); /* >>> */ 46 | i += (i << 4); 47 | i ^= ((i >> 10) | (i << 22)); /* >>> */ 48 | return i; 49 | } 50 | 51 | /*****************************************************************************/ 52 | static int 53 | hashtable_expand(struct hashtable *h) 54 | { 55 | /* Double the size of the table to accomodate more entries */ 56 | struct entry **newtable; 57 | struct entry *e; 58 | struct entry **pE; 59 | unsigned int newsize, i, index; 60 | /* Check we're not hitting max capacity */ 61 | if (0 == (newsize = (h->tablelength << 1))) return 0; 62 | 63 | newtable = (struct entry **)malloc(sizeof(struct entry*) * newsize); 64 | if (NULL != newtable) 65 | { 66 | memset(newtable, 0, newsize * sizeof(struct entry *)); 67 | /* This algorithm is not 'stable'. ie. it reverses the list 68 | * when it transfers entries between the tables */ 69 | for (i = 0; i < h->tablelength; i++) { 70 | while (NULL != (e = h->table[i])) { 71 | h->table[i] = e->next; 72 | index = indexFor(newsize,e->h); 73 | e->next = newtable[index]; 74 | newtable[index] = e; 75 | } 76 | } 77 | free(h->table); 78 | h->table = newtable; 79 | } 80 | /* Plan B: realloc instead */ 81 | else 82 | { 83 | newtable = (struct entry **) 84 | realloc(h->table, newsize * sizeof(struct entry *)); 85 | if (NULL == newtable) return 0; 86 | h->table = newtable; 87 | for (i = h->tablelength; i < newsize; i++) { 88 | newtable[i] = NULL; 89 | } 90 | for (i = 0; i < h->tablelength; i++) { 91 | for (pE = &(newtable[i]), e = *pE; e != NULL; e = *pE) { 92 | index = indexFor(newsize,e->h); 93 | if (index == i) 94 | { 95 | pE = &(e->next); 96 | } 97 | else 98 | { 99 | *pE = e->next; 100 | e->next = newtable[index]; 101 | newtable[index] = e; 102 | } 103 | } 104 | } 105 | } 106 | h->tablelength = newsize; 107 | h->loadlimit = (unsigned int) ceil(newsize * max_load_factor); 108 | return -1; 109 | } 110 | 111 | /*****************************************************************************/ 112 | unsigned int 113 | hashtable_count(struct hashtable *h) 114 | { 115 | return h->entrycount; 116 | } 117 | 118 | /*****************************************************************************/ 119 | int 120 | hashtable_insert(struct hashtable *h, void *k, void *v) 121 | { 122 | /* This method allows duplicate keys - but they shouldn't be used */ 123 | unsigned int index; 124 | struct entry *e; 125 | if (++(h->entrycount) > h->loadlimit) 126 | { 127 | /* Ignore the return value. If expand fails, we should 128 | * still try cramming just this value into the existing table 129 | * -- we may not have memory for a larger table, but one more 130 | * element may be ok. Next time we insert, we'll try expanding again.*/ 131 | hashtable_expand(h); 132 | } 133 | e = (struct entry *)malloc(sizeof(struct entry)); 134 | if (NULL == e) { --(h->entrycount); return 0; } /*oom*/ 135 | e->h = hash(h,k); 136 | index = indexFor(h->tablelength,e->h); 137 | e->k = k; 138 | e->v = v; 139 | e->next = h->table[index]; 140 | h->table[index] = e; 141 | return -1; 142 | } 143 | 144 | /*****************************************************************************/ 145 | void * /* returns value associated with key */ 146 | hashtable_search(struct hashtable *h, void *k) 147 | { 148 | struct entry *e; 149 | unsigned int hashvalue, index; 150 | hashvalue = hash(h,k); 151 | index = indexFor(h->tablelength,hashvalue); 152 | e = h->table[index]; 153 | while (NULL != e) 154 | { 155 | /* Check hash value to short circuit heavier comparison */ 156 | if ((hashvalue == e->h) && (h->eqfn(k, e->k))) return e->v; 157 | e = e->next; 158 | } 159 | return NULL; 160 | } 161 | 162 | /*****************************************************************************/ 163 | void * /* returns value associated with key */ 164 | hashtable_remove(struct hashtable *h, void *k) 165 | { 166 | /* TODO: consider compacting the table when the load factor drops enough, 167 | * or provide a 'compact' method. */ 168 | 169 | struct entry *e; 170 | struct entry **pE; 171 | void *v; 172 | 173 | unsigned int index = indexFor(h->tablelength,hash(h,k)); 174 | pE = &(h->table[index]); 175 | e = *pE; 176 | while (NULL != e) 177 | { 178 | if (h->eqfn(k, e->k)) 179 | { 180 | *pE = e->next; 181 | h->entrycount--; 182 | v = e->v; 183 | freekey(e->k); 184 | free(e); 185 | return v; 186 | } 187 | pE = &(e->next); 188 | e = e->next; 189 | } 190 | return NULL; 191 | } 192 | 193 | /*****************************************************************************/ 194 | /* destroy */ 195 | void 196 | hashtable_destroy(struct hashtable *h, int free_values) 197 | { 198 | unsigned int i; 199 | struct entry *e, *f; 200 | struct entry **table = h->table; 201 | if (free_values) 202 | { 203 | for (i = 0; i < h->tablelength; i++) 204 | { 205 | e = table[i]; 206 | while (NULL != e) 207 | { f = e; e = e->next; freekey(f->k); free(f->v); free(f); } 208 | } 209 | } 210 | else 211 | { 212 | for (i = 0; i < h->tablelength; i++) 213 | { 214 | e = table[i]; 215 | while (NULL != e) 216 | { f = e; e = e->next; freekey(f->k); free(f); } 217 | } 218 | } 219 | free(h->table); 220 | free(h); 221 | } 222 | 223 | /* 224 | * Copyright (c) 2002, Christopher Clark 225 | * All rights reserved. 226 | * 227 | * Redistribution and use in source and binary forms, with or without 228 | * modification, are permitted provided that the following conditions 229 | * are met: 230 | * 231 | * * Redistributions of source code must retain the above copyright 232 | * notice, this list of conditions and the following disclaimer. 233 | * 234 | * * Redistributions in binary form must reproduce the above copyright 235 | * notice, this list of conditions and the following disclaimer in the 236 | * documentation and/or other materials provided with the distribution. 237 | * 238 | * * Neither the name of the original author; nor the names of any contributors 239 | * may be used to endorse or promote products derived from this software 240 | * without specific prior written permission. 241 | * 242 | * 243 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 244 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 245 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 246 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 247 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 248 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 249 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 250 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 251 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 252 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 253 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 254 | */ 255 | -------------------------------------------------------------------------------- /hashtable_private.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2002, 2004 Christopher Clark */ 2 | 3 | #ifndef __HASHTABLE_PRIVATE_CWC22_H__ 4 | #define __HASHTABLE_PRIVATE_CWC22_H__ 5 | 6 | #include "hashtable.h" 7 | 8 | /*****************************************************************************/ 9 | struct entry 10 | { 11 | void *k, *v; 12 | unsigned int h; 13 | struct entry *next; 14 | }; 15 | 16 | struct hashtable { 17 | unsigned int tablelength; 18 | struct entry **table; 19 | unsigned int entrycount; 20 | unsigned int loadlimit; 21 | unsigned int primeindex; 22 | unsigned int (*hashfn) (void *k); 23 | int (*eqfn) (void *k1, void *k2); 24 | }; 25 | 26 | /*****************************************************************************/ 27 | unsigned int 28 | hash(struct hashtable *h, void *k); 29 | 30 | /*****************************************************************************/ 31 | /* indexFor */ 32 | static inline unsigned int 33 | indexFor(unsigned int tablelength, unsigned int hashvalue) { 34 | return (hashvalue % tablelength); 35 | }; 36 | 37 | /* Only works if tablelength == 2^N */ 38 | /*static inline unsigned int 39 | indexFor(unsigned int tablelength, unsigned int hashvalue) 40 | { 41 | return (hashvalue & (tablelength - 1u)); 42 | } 43 | */ 44 | 45 | /*****************************************************************************/ 46 | #define freekey(X) free(X) 47 | /*define freekey(X) ; */ 48 | 49 | 50 | /*****************************************************************************/ 51 | 52 | #endif /* __HASHTABLE_PRIVATE_CWC22_H__*/ 53 | 54 | /* 55 | * Copyright (c) 2002, Christopher Clark 56 | * All rights reserved. 57 | * 58 | * Redistribution and use in source and binary forms, with or without 59 | * modification, are permitted provided that the following conditions 60 | * are met: 61 | * 62 | * * Redistributions of source code must retain the above copyright 63 | * notice, this list of conditions and the following disclaimer. 64 | * 65 | * * Redistributions in binary form must reproduce the above copyright 66 | * notice, this list of conditions and the following disclaimer in the 67 | * documentation and/or other materials provided with the distribution. 68 | * 69 | * * Neither the name of the original author; nor the names of any contributors 70 | * may be used to endorse or promote products derived from this software 71 | * without specific prior written permission. 72 | * 73 | * 74 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 75 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 76 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 77 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 78 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 79 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 80 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 81 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 82 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 83 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 84 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 85 | */ 86 | -------------------------------------------------------------------------------- /hashtable_utility.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2002 Christopher Clark */ 2 | 3 | #include "hashtable.h" 4 | #include "hashtable_private.h" 5 | #include "hashtable_utility.h" 6 | #include 7 | #include 8 | #include 9 | 10 | /*****************************************************************************/ 11 | /* hashtable_change 12 | * 13 | * function to change the value associated with a key, where there already 14 | * exists a value bound to the key in the hashtable. 15 | * Source due to Holger Schemel. 16 | * 17 | * */ 18 | int 19 | hashtable_change(struct hashtable *h, void *k, void *v) 20 | { 21 | struct entry *e; 22 | unsigned int hashvalue, index; 23 | hashvalue = hash(h,k); 24 | index = indexFor(h->tablelength,hashvalue); 25 | e = h->table[index]; 26 | while (NULL != e) 27 | { 28 | /* Check hash value to short circuit heavier comparison */ 29 | if ((hashvalue == e->h) && (h->eqfn(k, e->k))) 30 | { 31 | free(e->v); 32 | e->v = v; 33 | return -1; 34 | } 35 | e = e->next; 36 | } 37 | return 0; 38 | } 39 | 40 | /* 41 | * Copyright (c) 2002, Christopher Clark 42 | * All rights reserved. 43 | * 44 | * Redistribution and use in source and binary forms, with or without 45 | * modification, are permitted provided that the following conditions 46 | * are met: 47 | * 48 | * * Redistributions of source code must retain the above copyright 49 | * notice, this list of conditions and the following disclaimer. 50 | * 51 | * * Redistributions in binary form must reproduce the above copyright 52 | * notice, this list of conditions and the following disclaimer in the 53 | * documentation and/or other materials provided with the distribution. 54 | * 55 | * * Neither the name of the original author; nor the names of any contributors 56 | * may be used to endorse or promote products derived from this software 57 | * without specific prior written permission. 58 | * 59 | * 60 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 61 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 62 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 63 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 64 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 65 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 66 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 67 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 68 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 69 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 70 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 71 | */ 72 | -------------------------------------------------------------------------------- /hashtable_utility.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2002 Christopher Clark */ 2 | 3 | #ifndef __HASHTABLE_CWC22_UTILITY_H__ 4 | #define __HASHTABLE_CWC22_UTILITY_H__ 5 | 6 | /***************************************************************************** 7 | * hashtable_change 8 | * 9 | * function to change the value associated with a key, where there already 10 | * exists a value bound to the key in the hashtable. 11 | * Source due to Holger Schemel. 12 | * 13 | * @name hashtable_change 14 | * @param h the hashtable 15 | * @param key 16 | * @param value 17 | * 18 | */ 19 | int 20 | hashtable_change(struct hashtable *h, void *k, void *v); 21 | 22 | #endif /* __HASHTABLE_CWC22_H__ */ 23 | 24 | /* 25 | * Copyright (c) 2002, Christopher Clark 26 | * All rights reserved. 27 | * 28 | * Redistribution and use in source and binary forms, with or without 29 | * modification, are permitted provided that the following conditions 30 | * are met: 31 | * 32 | * * Redistributions of source code must retain the above copyright 33 | * notice, this list of conditions and the following disclaimer. 34 | * 35 | * * Redistributions in binary form must reproduce the above copyright 36 | * notice, this list of conditions and the following disclaimer in the 37 | * documentation and/or other materials provided with the distribution. 38 | * 39 | * * Neither the name of the original author; nor the names of any contributors 40 | * may be used to endorse or promote products derived from this software 41 | * without specific prior written permission. 42 | * 43 | * 44 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 45 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 46 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 47 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 48 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 49 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 50 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 51 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 52 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 53 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 54 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 55 | */ 56 | -------------------------------------------------------------------------------- /tester.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2002, 2004 Christopher Clark */ 2 | 3 | #include "hashtable.h" 4 | #include "hashtable_itr.h" 5 | #include 6 | #include 7 | #include /* for memcmp */ 8 | 9 | static const int ITEM_COUNT = 4000; 10 | 11 | typedef unsigned int uint32_t; 12 | typedef unsigned short uint16_t; 13 | 14 | /*****************************************************************************/ 15 | struct key 16 | { 17 | uint32_t one_ip; uint32_t two_ip; uint16_t one_port; uint16_t two_port; 18 | }; 19 | 20 | struct value 21 | { 22 | char *id; 23 | }; 24 | 25 | DEFINE_HASHTABLE_INSERT(insert_some, struct key, struct value); 26 | DEFINE_HASHTABLE_SEARCH(search_some, struct key, struct value); 27 | DEFINE_HASHTABLE_REMOVE(remove_some, struct key, struct value); 28 | DEFINE_HASHTABLE_ITERATOR_SEARCH(search_itr_some, struct key); 29 | 30 | 31 | /*****************************************************************************/ 32 | static unsigned int 33 | hashfromkey(void *ky) 34 | { 35 | struct key *k = (struct key *)ky; 36 | return (((k->one_ip << 17) | (k->one_ip >> 15)) ^ k->two_ip) + 37 | (k->one_port * 17) + (k->two_port * 13 * 29); 38 | } 39 | 40 | static int 41 | equalkeys(void *k1, void *k2) 42 | { 43 | return (0 == memcmp(k1,k2,sizeof(struct key))); 44 | } 45 | 46 | /*****************************************************************************/ 47 | int 48 | main(int argc, char **argv) 49 | { 50 | struct key *k, *kk; 51 | struct value *v, *found; 52 | struct hashtable *h; 53 | struct hashtable_itr *itr; 54 | int i; 55 | 56 | h = create_hashtable(16, hashfromkey, equalkeys); 57 | if (NULL == h) exit(-1); /*oom*/ 58 | 59 | 60 | /*****************************************************************************/ 61 | /* Insertion */ 62 | for (i = 0; i < ITEM_COUNT; i++) 63 | { 64 | k = (struct key *)malloc(sizeof(struct key)); 65 | if (NULL == k) { 66 | printf("ran out of memory allocating a key\n"); 67 | return 1; 68 | } 69 | k->one_ip = 0xcfccee40 + i; 70 | k->two_ip = 0xcf0cee67 - (5 * i); 71 | k->one_port = 22 + (7 * i); 72 | k->two_port = 5522 - (3 * i); 73 | 74 | v = (struct value *)malloc(sizeof(struct value)); 75 | v->id = "a value"; 76 | 77 | if (!insert_some(h,k,v)) exit(-1); /*oom*/ 78 | } 79 | printf("After insertion, hashtable contains %u items.\n", 80 | hashtable_count(h)); 81 | 82 | /*****************************************************************************/ 83 | /* Hashtable search */ 84 | k = (struct key *)malloc(sizeof(struct key)); 85 | if (NULL == k) { 86 | printf("ran out of memory allocating a key\n"); 87 | return 1; 88 | } 89 | 90 | for (i = 0; i < ITEM_COUNT; i++) 91 | { 92 | k->one_ip = 0xcfccee40 + i; 93 | k->two_ip = 0xcf0cee67 - (5 * i); 94 | k->one_port = 22 + (7 * i); 95 | k->two_port = 5522 - (3 * i); 96 | 97 | if (NULL == (found = search_some(h,k))) { 98 | printf("BUG: key not found\n"); 99 | } 100 | } 101 | 102 | /*****************************************************************************/ 103 | /* Hashtable iteration */ 104 | /* Iterator constructor only returns a valid iterator if 105 | * the hashtable is not empty */ 106 | itr = hashtable_iterator(h); 107 | i = 0; 108 | if (hashtable_count(h) > 0) 109 | { 110 | do { 111 | kk = hashtable_iterator_key(itr); 112 | v = hashtable_iterator_value(itr); 113 | /* here (kk,v) are a valid (key, value) pair */ 114 | /* We could call 'hashtable_remove(h,kk)' - and this operation 115 | * 'free's kk. However, the iterator is then broken. 116 | * This is why hashtable_iterator_remove exists - see below. 117 | */ 118 | i++; 119 | 120 | } while (hashtable_iterator_advance(itr)); 121 | } 122 | printf("Iterated through %u entries.\n", i); 123 | 124 | /*****************************************************************************/ 125 | /* Hashtable iterator search */ 126 | 127 | /* Try the search some method */ 128 | for (i = 0; i < ITEM_COUNT; i++) 129 | { 130 | k->one_ip = 0xcfccee40 + i; 131 | k->two_ip = 0xcf0cee67 - (5 * i); 132 | k->one_port = 22 + (7 * i); 133 | k->two_port = 5522 - (3 * i); 134 | 135 | if (0 == search_itr_some(itr,h,k)) { 136 | printf("BUG: key not found searching with iterator"); 137 | } 138 | } 139 | 140 | /*****************************************************************************/ 141 | /* Hashtable removal */ 142 | 143 | for (i = 0; i < ITEM_COUNT; i++) 144 | { 145 | k->one_ip = 0xcfccee40 + i; 146 | k->two_ip = 0xcf0cee67 - (5 * i); 147 | k->one_port = 22 + (7 * i); 148 | k->two_port = 5522 - (3 * i); 149 | 150 | if (NULL == (found = remove_some(h,k))) { 151 | printf("BUG: key not found for removal\n"); 152 | } 153 | } 154 | printf("After removal, hashtable contains %u items.\n", 155 | hashtable_count(h)); 156 | 157 | /*****************************************************************************/ 158 | /* Hashtable destroy and create */ 159 | 160 | hashtable_destroy(h, 1); 161 | h = NULL; 162 | free(k); 163 | 164 | h = create_hashtable(160, hashfromkey, equalkeys); 165 | if (NULL == h) { 166 | printf("out of memory allocating second hashtable\n"); 167 | return 1; 168 | } 169 | 170 | /*****************************************************************************/ 171 | /* Hashtable insertion */ 172 | 173 | for (i = 0; i < ITEM_COUNT; i++) 174 | { 175 | k = (struct key *)malloc(sizeof(struct key)); 176 | k->one_ip = 0xcfccee40 + i; 177 | k->two_ip = 0xcf0cee67 - (5 * i); 178 | k->one_port = 22 + (7 * i); 179 | k->two_port = 5522 - (3 * i); 180 | 181 | v = (struct value *)malloc(sizeof(struct value)); 182 | v->id = "a value"; 183 | 184 | if (!insert_some(h,k,v)) 185 | { 186 | printf("out of memory inserting into second hashtable\n"); 187 | return 1; 188 | } 189 | } 190 | printf("After insertion, hashtable contains %u items.\n", 191 | hashtable_count(h)); 192 | 193 | /*****************************************************************************/ 194 | /* Hashtable iterator search and iterator remove */ 195 | 196 | k = (struct key *)malloc(sizeof(struct key)); 197 | if (NULL == k) { 198 | printf("ran out of memory allocating a key\n"); 199 | return 1; 200 | } 201 | 202 | for (i = ITEM_COUNT - 1; i >= 0; i = i - 7) 203 | { 204 | k->one_ip = 0xcfccee40 + i; 205 | k->two_ip = 0xcf0cee67 - (5 * i); 206 | k->one_port = 22 + (7 * i); 207 | k->two_port = 5522 - (3 * i); 208 | 209 | if (0 == search_itr_some(itr, h, k)) { 210 | printf("BUG: key %u not found for search preremoval using iterator\n", i); 211 | return 1; 212 | } 213 | if (0 == hashtable_iterator_remove(itr)) { 214 | printf("BUG: key not found for removal using iterator\n"); 215 | return 1; 216 | } 217 | } 218 | free(itr); 219 | 220 | /*****************************************************************************/ 221 | /* Hashtable iterator remove and advance */ 222 | 223 | for (itr = hashtable_iterator(h); 224 | hashtable_iterator_remove(itr) != 0; ) { 225 | ; 226 | } 227 | free(itr); 228 | printf("After removal, hashtable contains %u items.\n", 229 | hashtable_count(h)); 230 | 231 | /*****************************************************************************/ 232 | /* Hashtable destroy */ 233 | 234 | hashtable_destroy(h, 1); 235 | free(k); 236 | return 0; 237 | } 238 | 239 | /* 240 | * Copyright (c) 2002, 2004, Christopher Clark 241 | * All rights reserved. 242 | * 243 | * Redistribution and use in source and binary forms, with or without 244 | * modification, are permitted provided that the following conditions 245 | * are met: 246 | * 247 | * * Redistributions of source code must retain the above copyright 248 | * notice, this list of conditions and the following disclaimer. 249 | * 250 | * * Redistributions in binary form must reproduce the above copyright 251 | * notice, this list of conditions and the following disclaimer in the 252 | * documentation and/or other materials provided with the distribution. 253 | * 254 | * * Neither the name of the original author; nor the names of any contributors 255 | * may be used to endorse or promote products derived from this software 256 | * without specific prior written permission. 257 | * 258 | * 259 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 260 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 261 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 262 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 263 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 264 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 265 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 266 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 267 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 268 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 269 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 270 | */ 271 | --------------------------------------------------------------------------------