├── 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 |
--------------------------------------------------------------------------------