added preprocessor macros to improve code readability
[rocksndiamonds.git] / src / libgame / hash.h
1 // ============================================================================
2 // Artsoft Retro-Game Library
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
5 //                  Holger Schemel
6 //                  info@artsoft.org
7 //                  https://www.artsoft.org/
8 // ----------------------------------------------------------------------------
9 // hash.h
10 // ============================================================================
11
12 /*
13  * Copyright (C) 2002 Christopher Clark <firstname.lastname@cl.cam.ac.uk>
14  *
15  * Permission is hereby granted, free of charge, to any person obtaining a copy
16  * of this software and associated documentation files (the "Software"), to
17  * deal in the Software without restriction, including without limitation the
18  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
19  * sell copies of the Software, and to permit persons to whom the Software is
20  * furnished to do so, subject to the following conditions:
21  *
22  * The above copyright notice and this permission notice shall be included in
23  * all copies of the Software and its documentation and acknowledgment shall be
24  * given in the documentation and software packages that this Software was
25  * used.
26  *
27  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
30  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
31  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
32  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33  * */
34
35 #ifndef HASH_H
36 #define HASH_H
37
38
39 /* Example of use:
40  *
41  *      struct hashtable  *h;
42  *      struct some_key   *k;
43  *      struct some_value *v;
44  *
45  *      static unsigned int         hash_from_key_fn( void *k );
46  *      static int                  keys_equal_fn ( void *key1, void *key2 );
47  *
48  *      h = create_hashtable(16, 0.75, hash_from_key_fn, keys_equal_fn, free, free);
49  *      k = (struct some_key *)     malloc(sizeof(struct some_key));
50  *      v = (struct some_value *)   malloc(sizeof(struct some_value));
51  *
52  *      (initialise k and v to suitable values)
53  * 
54  *      if (! hashtable_insert(h,k,v) )
55  *      {     exit(-1);               }
56  *
57  *      if (NULL == (found = hashtable_search(h,k) ))
58  *      {    printf("not found!");                  }
59  *
60  *      if (NULL == (found = hashtable_remove(h,k) ))
61  *      {    printf("Not found\n");                 }
62  *
63  */
64
65 /* Macros may be used to define type-safe(r) hashtable access functions, with
66  * methods specialized to take known key and value types as parameters.
67  * 
68  * Example:
69  *
70  * Insert this at the start of your file:
71  *
72  * DEFINE_HASHTABLE_INSERT(insert_some, struct some_key, struct some_value);
73  * DEFINE_HASHTABLE_SEARCH(search_some, struct some_key, struct some_value);
74  * DEFINE_HASHTABLE_REMOVE(remove_some, struct some_key, struct some_value);
75  *
76  * This defines the functions 'insert_some', 'search_some' and 'remove_some'.
77  * These operate just like hashtable_insert etc., with the same parameters,
78  * but their function signatures have 'struct some_key *' rather than
79  * 'void *', and hence can generate compile time errors if your program is
80  * supplying incorrect data as a key (and similarly for value).
81  *
82  * Note that the hash and key equality functions passed to create_hashtable
83  * still take 'void *' parameters instead of 'some key *'. This shouldn't be
84  * a difficult issue as they're only defined and passed once, and the other
85  * functions will ensure that only valid keys are supplied to them.
86  *
87  * The cost for this checking is increased code size and runtime overhead
88  * - if performance is important, it may be worth switching back to the
89  * unsafe methods once your program has been debugged with the safe methods.
90  * This just requires switching to some simple alternative defines - eg:
91  * #define insert_some hashtable_insert
92  *
93  */
94
95
96 /*****************************************************************************/
97 struct entry
98 {
99   void *k, *v;
100   unsigned int h;
101   struct entry *next;
102 };
103
104 struct hashtable
105 {
106   unsigned int tablelength;
107   struct entry **table;
108   unsigned int entrycount;
109   unsigned int loadlimit;
110   unsigned int (*hashfn) (void *k);
111   int (*eqfn) (void *k1, void *k2);
112   void (*freekfn) (void *k);
113   void (*freevfn) (void *v);
114 };
115
116 /*****************************************************************************/
117 struct hashtable_itr
118 {
119   struct hashtable *h;
120   struct entry *e;
121   unsigned int index;
122 };
123
124 typedef struct hashtable HashTable;
125
126
127 /*****************************************************************************
128  * create_hashtable_ext
129    
130  * @name                    create_hashtable
131  * @param   minsize         minimum initial size of hashtable
132  * @param   maxloadfactor   maximum ratio entries / tablesize
133  * @param   hashfunction    function for hashing keys
134  * @param   key_eq_fn       function for determining key equality
135  * @param   key_free_fn     function for freeing keys
136  * @param   value_free_fn   function for freeing values
137  * @return                  newly created hashtable or NULL on failure
138  */
139
140 struct hashtable *
141 create_hashtable_ext(unsigned int minsize, float maxloadfactor,
142                      unsigned int (*hashfunction) (void*),
143                      int (*key_eq_fn) (void*, void*),
144                      void (*key_free_fn) (void*),
145                      void (*value_free_fn) (void*));
146
147 /* wrapper function using reasonable default values for some parameters */
148 struct hashtable *
149 create_hashtable(unsigned int (*hashfunction) (void*),
150                  int (*key_eq_fn) (void*, void*),
151                  void (*key_free_fn) (void*),
152                  void (*value_free_fn) (void*));
153
154 /*****************************************************************************
155  * hashtable_insert
156    
157  * @name        hashtable_insert
158  * @param   h   the hashtable to insert into
159  * @param   k   the key   - will be freed on removal if free function defined
160  * @param   v   the value - will be freed on removal if free function defined
161  * @return      non-zero for successful insertion
162  *
163  * This function will cause the table to expand if the insertion would take
164  * the ratio of entries to table size over the maximum load factor.
165  *
166  * This function does not check for repeated insertions with a duplicate key.
167  * The value returned when using a duplicate key is undefined -- when
168  * the hashtable changes size, the order of retrieval of duplicate key
169  * entries is reversed.
170  * If in doubt, remove before insert.
171  */
172
173 int 
174 hashtable_insert(struct hashtable *h, void *k, void *v);
175
176 #define DEFINE_HASHTABLE_INSERT(fnname, keytype, valuetype) \
177 static int fnname (struct hashtable *h, keytype *k, valuetype *v) \
178 { \
179   return hashtable_insert(h, k, v); \
180 }
181
182 /*****************************************************************************
183  * hashtable_change
184    
185  * @name        hashtable_change
186  * @param   h   the hashtable to search
187  * @param   k   the key of the entry to change
188  * @param   v   the new value
189  * @return      non-zero for successful change
190  */
191
192 int 
193 hashtable_change(struct hashtable *h, void *k, void *v);
194
195 #define DEFINE_HASHTABLE_CHANGE(fnname, keytype, valuetype) \
196 static int fnname (struct hashtable *h, keytype *k, valuetype *v) \
197 { \
198   return hashtable_change(h, k, v); \
199 }
200
201 /*****************************************************************************
202  * hashtable_exists
203    
204  * @name        hashtable_exists
205  * @param   h   the hashtable to search
206  * @param   k   the key to search for
207  * @return      non-zero if key exists, else zero
208  */
209
210 int
211 hashtable_exists(struct hashtable *h, void *k);
212
213 #define DEFINE_HASHTABLE_EXISTS(fnname, keytype, valuetype) \
214 static int fnname (struct hashtable *h, keytype *k) \
215 { \
216   return hashtable_exists(h, k); \
217 }
218
219 /*****************************************************************************
220  * hashtable_search
221    
222  * @name        hashtable_search
223  * @param   h   the hashtable to search
224  * @param   k   the key to search for
225  * @return      the value associated with the key, or NULL if none found
226  */
227
228 void *
229 hashtable_search(struct hashtable *h, void *k);
230
231 #define DEFINE_HASHTABLE_SEARCH(fnname, keytype, valuetype) \
232 static valuetype * fnname (struct hashtable *h, keytype *k) \
233 { \
234   return (valuetype *) (hashtable_search(h, k)); \
235 }
236
237 /*****************************************************************************
238  * hashtable_remove
239    
240  * @name        hashtable_remove
241  * @param   h   the hashtable to remove the item from
242  * @param   k   the key to search for
243  * @return      the value associated with the key, or NULL if none found
244  */
245
246 void * /* returns value */
247 hashtable_remove(struct hashtable *h, void *k);
248
249 #define DEFINE_HASHTABLE_REMOVE(fnname, keytype, valuetype) \
250 static valuetype * fnname (struct hashtable *h, keytype *k) \
251 { \
252   return (valuetype *) (hashtable_remove(h, k)); \
253 }
254
255
256 /*****************************************************************************
257  * hashtable_count
258    
259  * @name        hashtable_count
260  * @return      the number of items stored in the hashtable
261  */
262 unsigned int
263 hashtable_count(struct hashtable *h);
264
265
266 /*****************************************************************************
267  * hashtable_destroy
268    
269  * @name        hashtable_destroy
270  */
271
272 void
273 hashtable_destroy(struct hashtable *h);
274
275
276 /*****************************************************************************/
277 /* hashtable_iterator
278  */
279
280 struct hashtable_itr *
281 hashtable_iterator(struct hashtable *h);
282
283 /*****************************************************************************/
284 /* key - return the key of the (key, value) pair at the current position */
285
286 void *
287 hashtable_iterator_key(struct hashtable_itr *i);
288
289 /*****************************************************************************/
290 /* value - return the value of the (key, value) pair at the current position */
291
292 void *
293 hashtable_iterator_value(struct hashtable_itr *i);
294
295 /*****************************************************************************/
296 /* advance - advance the iterator to the next element
297  *           returns zero if advanced to end of table */
298
299 int
300 hashtable_iterator_advance(struct hashtable_itr *itr);
301
302
303 /*****************************************************************************/
304 /* hashtable_fn - prototype of function to call for hashtable entry
305
306  * @name        hashtable_fn
307  * @param   k   the key of the current hash entry
308  * @param   v   the value of the current hash entry
309  * @param   u   additional user data
310  */
311
312 typedef void (*hashtable_fn) (void *k, void *v, void *u);
313
314 /*****************************************************************************/
315 /* hashtable_foreach - call function for all hashtable entries
316
317  * @name        hashtable_foreach
318  * @param   h   the hashtable to iterate through
319  * @param   fn  the function to call for each entry
320  */
321
322 void
323 hashtable_foreach(struct hashtable *h, hashtable_fn fn, void *userdata);
324
325 /*****************************************************************************/
326 /* hashtable_remove_fn - prototype of function to call for hashtable entry
327
328  * @name        hashtable_remove_fn
329  * @param   k   the key of the current hash entry
330  * @param   v   the value of the current hash entry
331  * @param   u   additional user data
332  * @return      non-zero if entry should be removed, else zero
333  */
334
335 typedef int (*hashtable_remove_fn) (void *k, void *v, void *u);
336
337 /*****************************************************************************/
338 /* hashtable_foreach_remove - call function for all hashtable entries and remove them,
339  *                            if function returned 1
340  *                            returns the number of removed entries
341
342  * @name        hashtable_foreach_remove
343  * @param   h   the hashtable to iterate through
344  * @param   fn  the function to call for each entry
345  * @return      the number of removed entries
346  */
347
348 unsigned int
349 hashtable_foreach_remove(struct hashtable *h, hashtable_remove_fn fn, void *userdata);
350
351 /*****************************************************************************/
352 /* hashtable_remove_all - remove_all hashtable entries
353
354  * @name        hashtable_remove
355  * @param   h   the hashtable to remove all entries from
356  * @return      the number of removed entries
357  */
358
359 unsigned int
360 hashtable_remove_all(struct hashtable *h);
361
362 #endif