1 /**********************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12 ***********************************************************************/
13
14 /****************************************************************************
15 A general-purpose generic hash table implementation.
16
17 Based on implementation previous included in registry.c, but separated
18 out so that can be used more generally. Maybe we should just use glib?
19
20 Original author: David Pfitzner dwp@mso.anu.edu.au
21
22 A hash table maps keys to user data values, using a user-supplied hash
23 function to do this efficiently. Here both keys and values are general
24 data represented by (void*) pointers. Memory management of both keys
25 and data is the responsibility of the caller: that is, the caller must
26 ensure that the memory (especially for keys) remains valid (allocated)
27 for as long as required (typically, the life of the genhash table).
28 (Otherwise, to allocate keys internally would either have to restrict
29 key type (e.g., strings), or have user-supplied function to duplicate
30 a key type. See further comments below.)
31
32 User-supplied functions required are:
33 key_val_func: map key to bucket number given number of buckets; should
34 map keys fairly evenly to range 0 to (num_buckets - 1)
35 inclusive.
36
37 key_comp_func: compare keys for equality, necessary for lookups for keys
38 which map to the same genhash value. Keys which compare
39 equal should map to the same hash value. Returns 0 for
40 equality, so can use qsort-type comparison function (but
41 the hash table does not make use of the ordering
42 information if the return value is non-zero).
43
44 Some constructors also accept following functions to be registered:
45 key_copy_func: This is called when assigning a new value to a bucket.
46 key_free_func: This is called when genhash no longer needs key construct.
47 Note that one key construct gets freed even when it is
48 replaced with another that is considered identical by
49 key_comp_func().
50 data_copy_func: same as 'key_copy_func', but for data.
51 data_free_func: same as 'key_free_func', but for data.
52
53 Implementation uses open hashing. Collision resolution is done by
54 separate chaining with linked lists. Resize hash table when deemed
55 necessary by making and populating a new table.
56 ****************************************************************************/
57
58 #ifdef HAVE_CONFIG_H
59 #include <fc_config.h>
60 #endif
61
62 #include <string.h>
63
64 /* utility */
65 #include "log.h"
66 #include "mem.h"
67 #include "shared.h" /* ARRAY_SIZE */
68 #include "support.h"
69
70 #include "genhash.h"
71
72 #define FULL_RATIO 0.75 /* consider expanding when above this */
73 #define MIN_RATIO 0.24 /* shrink when below this */
74
75 struct genhash_entry {
76 void *key;
77 void *data;
78 genhash_val_t hash_val;
79 struct genhash_entry *next;
80 };
81
82 /* Contents of the opaque type: */
83 struct genhash {
84 struct genhash_entry **buckets;
85 genhash_val_fn_t key_val_func;
86 genhash_comp_fn_t key_comp_func;
87 genhash_copy_fn_t key_copy_func;
88 genhash_free_fn_t key_free_func;
89 genhash_copy_fn_t data_copy_func;
90 genhash_free_fn_t data_free_func;
91 size_t num_buckets;
92 size_t num_entries;
93 bool no_shrink; /* Do not auto-shrink when set. */
94 };
95
96 struct genhash_iter {
97 struct iterator vtable;
98 struct genhash_entry *const *bucket, *const *end;
99 const struct genhash_entry *iterator;
100 };
101
102 #define GENHASH_ITER(p) ((struct genhash_iter *) (p))
103
104
105 /****************************************************************************
106 A supplied genhash function appropriate to nul-terminated strings.
107 Prefers table sizes that are prime numbers.
108 ****************************************************************************/
genhash_str_val_func(const char * vkey)109 genhash_val_t genhash_str_val_func(const char *vkey)
110 {
111 unsigned long result = 0;
112
113 for (; *vkey != '\0'; vkey++) {
114 result *= 5;
115 result += *vkey;
116 }
117 result &= 0xFFFFFFFF; /* To make results independent of sizeof(long) */
118 return result;
119 }
120
121 /****************************************************************************
122 A supplied function for comparison of nul-terminated strings:
123 ****************************************************************************/
genhash_str_comp_func(const char * vkey1,const char * vkey2)124 bool genhash_str_comp_func(const char *vkey1, const char *vkey2)
125 {
126 return 0 == strcmp(vkey1, vkey2);
127 }
128
129 /****************************************************************************
130 Copy function for string allocation.
131 ****************************************************************************/
genhash_str_copy_func(const char * vkey)132 char *genhash_str_copy_func(const char *vkey)
133 {
134 return fc_strdup(NULL != vkey ? vkey : "");
135 }
136
137 /****************************************************************************
138 Free function for string allocation.
139 ****************************************************************************/
genhash_str_free_func(char * vkey)140 void genhash_str_free_func(char *vkey)
141 {
142 #ifdef DEBUG
143 fc_assert_ret(NULL != vkey);
144 #endif
145 free(vkey);
146 }
147
148
149 /****************************************************************************
150 Calculate a "reasonable" number of buckets for a given number of entries.
151 Gives a prime number far from powers of 2, allowing at least a factor of
152 2 from the given number of entries for breathing room.
153
154 Generalized restrictions on the behavior of this function:
155 * MIN_BUCKETS <= genhash_calc_num_buckets(x)
156 * genhash_calc_num_buckets(x) * MIN_RATIO < x whenever
157 x > MIN_BUCKETS * MIN_RATIO.
158 * genhash_calc_num_buckets(x) * FULL_RATIO > x.
159 This one is more of a recommendation, to ensure enough free space:
160 * genhash_calc_num_buckets(x) >= 2 * x.
161 ****************************************************************************/
162 #define MIN_BUCKETS 29 /* Historical purposes. */
genhash_calc_num_buckets(size_t num_entries)163 static size_t genhash_calc_num_buckets(size_t num_entries)
164 {
165 /* A bunch of prime numbers close to successive elements of the sequence
166 * A_n = 3 * 2 ^ n; to be used for table sizes. */
167 static const size_t sizes[] = {
168 MIN_BUCKETS, 53, 97, 193,
169 389, 769, 1543, 3079, 6151,
170 12289, 24593, 49157, 98317, 196613,
171 393241, 786433, 1572869, 3145739, 6291469,
172 12582917, 25165843, 50331653, 100663319, 201326611,
173 402653189, 805306457, 1610612741, 3221225473ul, 4294967291ul
174 };
175 const size_t *pframe = sizes, *pmid;
176 int fsize = ARRAY_SIZE(sizes) - 1, lpart;
177
178 num_entries <<= 1; /* breathing room */
179
180 while (fsize > 0) {
181 lpart = fsize >> 1;
182 pmid = pframe + lpart;
183 if (*pmid < num_entries) {
184 pframe = pmid + 1;
185 fsize = fsize - lpart - 1;
186 } else {
187 fsize = lpart;
188 }
189 }
190 return *pframe;
191 }
192
193 /****************************************************************************
194 Internal constructor, specifying exact number of buckets.
195 Allows to specify functions to free the memory allocated for the key and
196 user-data that get called when removing the bucket from the hash table or
197 changing key/user-data values.
198
199 NB: Be sure to check the "copy constructor" genhash_copy() if you change
200 this function significantly.
201 ****************************************************************************/
202 static struct genhash *
genhash_new_nbuckets(genhash_val_fn_t key_val_func,genhash_comp_fn_t key_comp_func,genhash_copy_fn_t key_copy_func,genhash_free_fn_t key_free_func,genhash_copy_fn_t data_copy_func,genhash_free_fn_t data_free_func,size_t num_buckets)203 genhash_new_nbuckets(genhash_val_fn_t key_val_func,
204 genhash_comp_fn_t key_comp_func,
205 genhash_copy_fn_t key_copy_func,
206 genhash_free_fn_t key_free_func,
207 genhash_copy_fn_t data_copy_func,
208 genhash_free_fn_t data_free_func,
209 size_t num_buckets)
210 {
211 struct genhash *pgenhash = fc_malloc(sizeof(*pgenhash));
212
213 log_debug("New genhash table with %lu buckets",
214 (long unsigned) num_buckets);
215
216 pgenhash->buckets = fc_calloc(num_buckets, sizeof(*pgenhash->buckets));
217 pgenhash->key_val_func = key_val_func;
218 pgenhash->key_comp_func = key_comp_func;
219 pgenhash->key_copy_func = key_copy_func;
220 pgenhash->key_free_func = key_free_func;
221 pgenhash->data_copy_func = data_copy_func;
222 pgenhash->data_free_func = data_free_func;
223 pgenhash->num_buckets = num_buckets;
224 pgenhash->num_entries = 0;
225 pgenhash->no_shrink = FALSE;
226
227 return pgenhash;
228 }
229
230 /****************************************************************************
231 Constructor specifying number of entries.
232 Allows to specify functions to free the memory allocated for the key and
233 user-data that get called when removing the bucket from the hash table or
234 changing key/user-data values.
235 ****************************************************************************/
236 struct genhash *
genhash_new_nentries_full(genhash_val_fn_t key_val_func,genhash_comp_fn_t key_comp_func,genhash_copy_fn_t key_copy_func,genhash_free_fn_t key_free_func,genhash_copy_fn_t data_copy_func,genhash_free_fn_t data_free_func,size_t nentries)237 genhash_new_nentries_full(genhash_val_fn_t key_val_func,
238 genhash_comp_fn_t key_comp_func,
239 genhash_copy_fn_t key_copy_func,
240 genhash_free_fn_t key_free_func,
241 genhash_copy_fn_t data_copy_func,
242 genhash_free_fn_t data_free_func,
243 size_t nentries)
244 {
245 return genhash_new_nbuckets(key_val_func, key_comp_func,
246 key_copy_func, key_free_func,
247 data_copy_func, data_free_func,
248 genhash_calc_num_buckets(nentries));
249 }
250
251 /****************************************************************************
252 Constructor specifying number of entries.
253 ****************************************************************************/
genhash_new_nentries(genhash_val_fn_t key_val_func,genhash_comp_fn_t key_comp_func,size_t nentries)254 struct genhash *genhash_new_nentries(genhash_val_fn_t key_val_func,
255 genhash_comp_fn_t key_comp_func,
256 size_t nentries)
257 {
258 return genhash_new_nbuckets(key_val_func, key_comp_func,
259 NULL, NULL, NULL, NULL,
260 genhash_calc_num_buckets(nentries));
261 }
262
263 /****************************************************************************
264 Constructor with unspecified number of entries.
265 Allows to specify functions to free the memory allocated for the key and
266 user-data that get called when removing the bucket from the hash table or
267 changing key/user-data values.
268 ****************************************************************************/
genhash_new_full(genhash_val_fn_t key_val_func,genhash_comp_fn_t key_comp_func,genhash_copy_fn_t key_copy_func,genhash_free_fn_t key_free_func,genhash_copy_fn_t data_copy_func,genhash_free_fn_t data_free_func)269 struct genhash *genhash_new_full(genhash_val_fn_t key_val_func,
270 genhash_comp_fn_t key_comp_func,
271 genhash_copy_fn_t key_copy_func,
272 genhash_free_fn_t key_free_func,
273 genhash_copy_fn_t data_copy_func,
274 genhash_free_fn_t data_free_func)
275 {
276 return genhash_new_nbuckets(key_val_func, key_comp_func,
277 key_copy_func, key_free_func,
278 data_copy_func, data_free_func, MIN_BUCKETS);
279 }
280
281 /****************************************************************************
282 Constructor with unspecified number of entries.
283 ****************************************************************************/
genhash_new(genhash_val_fn_t key_val_func,genhash_comp_fn_t key_comp_func)284 struct genhash *genhash_new(genhash_val_fn_t key_val_func,
285 genhash_comp_fn_t key_comp_func)
286 {
287 return genhash_new_nbuckets(key_val_func, key_comp_func,
288 NULL, NULL, NULL, NULL, MIN_BUCKETS);
289 }
290
291 /**************************************************************************
292 Destructor: free internal memory.
293 **************************************************************************/
genhash_destroy(struct genhash * pgenhash)294 void genhash_destroy(struct genhash *pgenhash)
295 {
296 fc_assert_ret(NULL != pgenhash);
297 pgenhash->no_shrink = TRUE;
298 genhash_clear(pgenhash);
299 free(pgenhash->buckets);
300 free(pgenhash);
301 }
302
303
304 /****************************************************************************
305 Resize the genhash table: relink entries.
306 ****************************************************************************/
genhash_resize_table(struct genhash * pgenhash,size_t new_nbuckets)307 static void genhash_resize_table(struct genhash *pgenhash,
308 size_t new_nbuckets)
309 {
310 struct genhash_entry **new_buckets, **bucket, **end, **slot;
311 struct genhash_entry *iter, *next;
312
313 fc_assert(new_nbuckets >= pgenhash->num_entries);
314
315 new_buckets = fc_calloc(new_nbuckets, sizeof(*pgenhash->buckets));
316
317 bucket = pgenhash->buckets;
318 end = bucket + pgenhash->num_buckets;
319 for (; bucket < end; bucket++) {
320 for (iter = *bucket; NULL != iter; iter = next) {
321 slot = new_buckets + (iter->hash_val % new_nbuckets);
322 next = iter->next;
323 iter->next = *slot;
324 *slot = iter;
325 }
326 }
327
328 free(pgenhash->buckets);
329 pgenhash->buckets = new_buckets;
330 pgenhash->num_buckets = new_nbuckets;
331 }
332
333 /****************************************************************************
334 Call this when an entry might be added or deleted: resizes the genhash
335 table if seems like a good idea. Count deleted entries in check
336 because efficiency may be degraded if there are too many deleted
337 entries. But for determining new size, ignore deleted entries,
338 since they'll be removed by rehashing.
339 ****************************************************************************/
340 #define genhash_maybe_expand(htab) genhash_maybe_resize((htab), TRUE)
341 #define genhash_maybe_shrink(htab) genhash_maybe_resize((htab), FALSE)
genhash_maybe_resize(struct genhash * pgenhash,bool expandingp)342 static bool genhash_maybe_resize(struct genhash *pgenhash, bool expandingp)
343 {
344 size_t limit, new_nbuckets;
345
346 if (!expandingp && pgenhash->no_shrink) {
347 return FALSE;
348 }
349 if (expandingp) {
350 limit = FULL_RATIO * pgenhash->num_buckets;
351 if (pgenhash->num_entries < limit) {
352 return FALSE;
353 }
354 } else {
355 if (pgenhash->num_buckets <= MIN_BUCKETS) {
356 return FALSE;
357 }
358 limit = MIN_RATIO * pgenhash->num_buckets;
359 if (pgenhash->num_entries > limit) {
360 return FALSE;
361 }
362 }
363
364 new_nbuckets = genhash_calc_num_buckets(pgenhash->num_entries);
365
366 log_debug("%s genhash (entries = %lu, buckets = %lu, new = %lu, "
367 "%s limit = %lu)",
368 (new_nbuckets < pgenhash->num_buckets ? "Shrinking"
369 : (new_nbuckets > pgenhash->num_buckets
370 ? "Expanding" : "Rehashing")),
371 (long unsigned) pgenhash->num_entries,
372 (long unsigned) pgenhash->num_buckets,
373 (long unsigned) new_nbuckets,
374 expandingp ? "up": "down", (long unsigned) limit);
375 genhash_resize_table(pgenhash, new_nbuckets);
376 return TRUE;
377 }
378
379
380 /****************************************************************************
381 Calculate genhash value given hash table and key.
382 ****************************************************************************/
genhash_val_calc(const struct genhash * pgenhash,const void * key)383 static inline genhash_val_t genhash_val_calc(const struct genhash *pgenhash,
384 const void *key)
385 {
386 if (NULL != pgenhash->key_val_func) {
387 return pgenhash->key_val_func(key);
388 } else {
389 return ((intptr_t) key);
390 }
391 }
392
393 /****************************************************************************
394 Return slot (entry pointer) in genhash table where key resides, or where
395 it should go if it is to be a new key.
396 ****************************************************************************/
397 static inline struct genhash_entry **
genhash_slot_lookup(const struct genhash * pgenhash,const void * key,genhash_val_t hash_val)398 genhash_slot_lookup(const struct genhash *pgenhash,
399 const void *key,
400 genhash_val_t hash_val)
401 {
402 struct genhash_entry **slot;
403 genhash_comp_fn_t key_comp_func = pgenhash->key_comp_func;
404
405 slot = pgenhash->buckets + (hash_val % pgenhash->num_buckets);
406 if (NULL != key_comp_func) {
407 for (; NULL != *slot; slot = &(*slot)->next) {
408 if (hash_val == (*slot)->hash_val
409 && key_comp_func((*slot)->key, key)) {
410 return slot;
411 }
412 }
413 } else {
414 for (; NULL != *slot; slot = &(*slot)->next) {
415 if (key == (*slot)->key) {
416 return slot;
417 }
418 }
419 }
420 return slot;
421 }
422
423 /****************************************************************************
424 Function to store from invalid data.
425 ****************************************************************************/
genhash_default_get(void ** pkey,void ** data)426 static inline void genhash_default_get(void **pkey, void **data)
427 {
428 if (NULL != pkey) {
429 *pkey = NULL;
430 }
431 if (NULL != data) {
432 *data = NULL;
433 }
434 }
435
436 /****************************************************************************
437 Function to store data.
438 ****************************************************************************/
genhash_slot_get(struct genhash_entry * const * slot,void ** pkey,void ** data)439 static inline void genhash_slot_get(struct genhash_entry *const *slot,
440 void **pkey, void **data)
441 {
442 const struct genhash_entry *entry = *slot;
443
444 if (NULL != pkey) {
445 *pkey = entry->key;
446 }
447 if (NULL != data) {
448 *data = entry->data;
449 }
450 }
451
452 /****************************************************************************
453 Create the entry and call the copy callbacks.
454 ****************************************************************************/
genhash_slot_create(struct genhash * pgenhash,struct genhash_entry ** slot,const void * key,const void * data,genhash_val_t hash_val)455 static inline void genhash_slot_create(struct genhash *pgenhash,
456 struct genhash_entry **slot,
457 const void *key, const void *data,
458 genhash_val_t hash_val)
459 {
460 struct genhash_entry *entry = fc_malloc(sizeof(*entry));
461
462 entry->key = (NULL != pgenhash->key_copy_func
463 ? pgenhash->key_copy_func(key) : (void *) key);
464 entry->data = (NULL != pgenhash->data_copy_func
465 ? pgenhash->data_copy_func(data) : (void *) data);
466 entry->hash_val = hash_val;
467 entry->next = *slot;
468 *slot = entry;
469 }
470
471 /****************************************************************************
472 Free the entry slot and call the free callbacks.
473 ****************************************************************************/
genhash_slot_free(struct genhash * pgenhash,struct genhash_entry ** slot)474 static inline void genhash_slot_free(struct genhash *pgenhash,
475 struct genhash_entry **slot)
476 {
477 struct genhash_entry *entry = *slot;
478
479 if (NULL != pgenhash->key_free_func) {
480 pgenhash->key_free_func(entry->key);
481 }
482 if (NULL != pgenhash->data_free_func) {
483 pgenhash->data_free_func(entry->data);
484 }
485 *slot = entry->next;
486 free(entry);
487 }
488
489 /****************************************************************************
490 Clear previous values (with free callback) and call the copy callbacks.
491 ****************************************************************************/
genhash_slot_set(struct genhash * pgenhash,struct genhash_entry ** slot,const void * key,const void * data)492 static inline void genhash_slot_set(struct genhash *pgenhash,
493 struct genhash_entry **slot,
494 const void *key, const void *data)
495 {
496 struct genhash_entry *entry = *slot;
497
498 if (NULL != pgenhash->key_free_func) {
499 pgenhash->key_free_func(entry->key);
500 }
501 if (NULL != pgenhash->data_free_func) {
502 pgenhash->data_free_func(entry->data);
503 }
504 entry->key = (NULL != pgenhash->key_copy_func
505 ? pgenhash->key_copy_func(key) : (void *) key);
506 entry->data = (NULL != pgenhash->data_copy_func
507 ? pgenhash->data_copy_func(data) : (void *) data);
508 }
509
510
511 /****************************************************************************
512 Prevent or allow the genhash table automatically shrinking. Returns the
513 old value of the setting.
514 ****************************************************************************/
genhash_set_no_shrink(struct genhash * pgenhash,bool no_shrink)515 bool genhash_set_no_shrink(struct genhash *pgenhash, bool no_shrink)
516 {
517 bool old;
518
519 fc_assert_ret_val(NULL != pgenhash, FALSE);
520 old = pgenhash->no_shrink;
521 pgenhash->no_shrink = no_shrink;
522 return old;
523 }
524
525 /****************************************************************************
526 Returns the number of entries in the genhash table.
527 ****************************************************************************/
genhash_size(const struct genhash * pgenhash)528 size_t genhash_size(const struct genhash *pgenhash)
529 {
530 fc_assert_ret_val(NULL != pgenhash, 0);
531 return pgenhash->num_entries;
532 }
533
534 /****************************************************************************
535 Returns the number of buckets in the genhash table.
536 ****************************************************************************/
genhash_capacity(const struct genhash * pgenhash)537 size_t genhash_capacity(const struct genhash *pgenhash)
538 {
539 fc_assert_ret_val(NULL != pgenhash, 0);
540 return pgenhash->num_buckets;
541 }
542
543 /****************************************************************************
544 Returns a newly allocated mostly deep copy of the given genhash table.
545 ****************************************************************************/
genhash_copy(const struct genhash * pgenhash)546 struct genhash *genhash_copy(const struct genhash *pgenhash)
547 {
548 struct genhash *new_genhash;
549 struct genhash_entry *const *src_bucket, *const *end;
550 const struct genhash_entry *src_iter;
551 struct genhash_entry **dest_slot, **dest_bucket;
552
553 fc_assert_ret_val(NULL != pgenhash, NULL);
554
555 new_genhash = fc_malloc(sizeof(*new_genhash));
556
557 /* Copy fields. */
558 *new_genhash = *pgenhash;
559
560 /* But make fresh buckets. */
561 new_genhash->buckets = fc_calloc(new_genhash->num_buckets,
562 sizeof(*new_genhash->buckets));
563
564 /* Let's re-insert all data */
565 src_bucket = pgenhash->buckets;
566 end = src_bucket + pgenhash->num_buckets;
567 dest_bucket = new_genhash->buckets;
568
569 for (; src_bucket < end; src_bucket++, dest_bucket++) {
570 dest_slot = dest_bucket;
571 for (src_iter = *src_bucket; NULL != src_iter;
572 src_iter = src_iter->next) {
573 genhash_slot_create(new_genhash, dest_slot, src_iter->key,
574 src_iter->data, src_iter->hash_val);
575 dest_slot = &(*dest_slot)->next;
576 }
577 }
578
579 return new_genhash;
580 }
581
582 /****************************************************************************
583 Remove all entries of the genhash table.
584 ****************************************************************************/
genhash_clear(struct genhash * pgenhash)585 void genhash_clear(struct genhash *pgenhash)
586 {
587 struct genhash_entry **bucket, **end;
588
589 fc_assert_ret(NULL != pgenhash);
590
591 bucket = pgenhash->buckets;
592 end = bucket + pgenhash->num_buckets;
593 for (; bucket < end; bucket++) {
594 while (NULL != *bucket) {
595 genhash_slot_free(pgenhash, bucket);
596 }
597 }
598
599 pgenhash->num_entries = 0;
600 genhash_maybe_shrink(pgenhash);
601 }
602
603 /****************************************************************************
604 Insert entry: returns TRUE if inserted, or FALSE if there was already an
605 entry with the same key, in which case the entry was not inserted.
606 ****************************************************************************/
genhash_insert(struct genhash * pgenhash,const void * key,const void * data)607 bool genhash_insert(struct genhash *pgenhash, const void *key,
608 const void *data)
609 {
610 struct genhash_entry **slot;
611 genhash_val_t hash_val;
612
613 fc_assert_ret_val(NULL != pgenhash, FALSE);
614
615 hash_val = genhash_val_calc(pgenhash, key);
616 slot = genhash_slot_lookup(pgenhash, key, hash_val);
617 if (NULL != *slot) {
618 return FALSE;
619 } else {
620 if (genhash_maybe_expand(pgenhash)) {
621 /* Recalculate slot. */
622 slot = pgenhash->buckets + (hash_val % pgenhash->num_buckets);
623 }
624 genhash_slot_create(pgenhash, slot, key, data, hash_val);
625 pgenhash->num_entries++;
626 return TRUE;
627 }
628 }
629
630 /****************************************************************************
631 Insert entry, replacing any existing entry which has the same key.
632 Returns TRUE if a data have been replaced, FALSE if it was a simple
633 insertion.
634 ****************************************************************************/
genhash_replace(struct genhash * pgenhash,const void * key,const void * data)635 bool genhash_replace(struct genhash *pgenhash, const void *key,
636 const void *data)
637 {
638 return genhash_replace_full(pgenhash, key, data, NULL, NULL);
639 }
640
641 /****************************************************************************
642 Insert entry, replacing any existing entry which has the same key.
643 Returns TRUE if a data have been replaced, FALSE if it was a simple
644 insertion.
645
646 Returns in 'old_pkey' and 'old_pdata' the old content of the bucket if
647 they are not NULL. NB: It can returns freed pointers if free functions
648 were supplied to the genhash table.
649 ****************************************************************************/
genhash_replace_full(struct genhash * pgenhash,const void * key,const void * data,void ** old_pkey,void ** old_pdata)650 bool genhash_replace_full(struct genhash *pgenhash, const void *key,
651 const void *data, void **old_pkey,
652 void **old_pdata)
653 {
654 struct genhash_entry **slot;
655 genhash_val_t hash_val;
656
657 fc_assert_action(NULL != pgenhash,
658 genhash_default_get(old_pkey, old_pdata); return FALSE);
659
660 hash_val = genhash_val_calc(pgenhash, key);
661 slot = genhash_slot_lookup(pgenhash, key, hash_val);
662 if (NULL != *slot) {
663 /* Replace. */
664 genhash_slot_get(slot, old_pkey, old_pdata);
665 genhash_slot_set(pgenhash, slot, key, data);
666 return TRUE;
667 } else {
668 /* Insert. */
669 if (genhash_maybe_expand(pgenhash)) {
670 /* Recalculate slot. */
671 slot = pgenhash->buckets + (hash_val % pgenhash->num_buckets);
672 }
673 genhash_default_get(old_pkey, old_pdata);
674 genhash_slot_create(pgenhash, slot, key, data, hash_val);
675 pgenhash->num_entries++;
676 return FALSE;
677 }
678 }
679
680 /****************************************************************************
681 Lookup data. Return TRUE on success, then pdata - if not NULL will be set
682 to the data value.
683 ****************************************************************************/
genhash_lookup(const struct genhash * pgenhash,const void * key,void ** pdata)684 bool genhash_lookup(const struct genhash *pgenhash, const void *key,
685 void **pdata)
686 {
687 struct genhash_entry **slot;
688
689 fc_assert_action(NULL != pgenhash,
690 genhash_default_get(NULL, pdata); return FALSE);
691
692 slot = genhash_slot_lookup(pgenhash, key, genhash_val_calc(pgenhash, key));
693 if (NULL != *slot) {
694 genhash_slot_get(slot, NULL, pdata);
695 return TRUE;
696 } else {
697 genhash_default_get(NULL, pdata);
698 return FALSE;
699 }
700 }
701
702 /****************************************************************************
703 Delete an entry from the genhash table. Returns TRUE on success.
704 ****************************************************************************/
genhash_remove(struct genhash * pgenhash,const void * key)705 bool genhash_remove(struct genhash *pgenhash, const void *key)
706 {
707 return genhash_remove_full(pgenhash, key, NULL, NULL);
708 }
709
710 /****************************************************************************
711 Delete an entry from the genhash table. Returns TRUE on success.
712
713 Returns in 'deleted_pkey' and 'deleted_pdata' the old contents of the
714 deleted entry if not NULL. NB: It can returns freed pointers if free
715 functions were supplied to the genhash table.
716 ****************************************************************************/
genhash_remove_full(struct genhash * pgenhash,const void * key,void ** deleted_pkey,void ** deleted_pdata)717 bool genhash_remove_full(struct genhash *pgenhash, const void *key,
718 void **deleted_pkey, void **deleted_pdata)
719 {
720 struct genhash_entry **slot;
721
722 fc_assert_action(NULL != pgenhash,
723 genhash_default_get(deleted_pkey, deleted_pdata);
724 return FALSE);
725
726 slot = genhash_slot_lookup(pgenhash, key, genhash_val_calc(pgenhash, key));
727 if (NULL != *slot) {
728 genhash_slot_get(slot, deleted_pkey, deleted_pdata);
729 genhash_slot_free(pgenhash, slot);
730 genhash_maybe_shrink(pgenhash);
731 fc_assert(0 < pgenhash->num_entries);
732 pgenhash->num_entries--;
733 return TRUE;
734 } else {
735 genhash_default_get(deleted_pkey, deleted_pdata);
736 return FALSE;
737 }
738 }
739
740
741 /****************************************************************************
742 Returns TRUE iff the hash tables contains the same pairs of key/data.
743 ****************************************************************************/
genhashs_are_equal(const struct genhash * pgenhash1,const struct genhash * pgenhash2)744 bool genhashs_are_equal(const struct genhash *pgenhash1,
745 const struct genhash *pgenhash2)
746 {
747 return genhashs_are_equal_full(pgenhash1, pgenhash2, NULL);
748 }
749
750 /****************************************************************************
751 Returns TRUE iff the hash tables contains the same pairs of key/data.
752 ****************************************************************************/
genhashs_are_equal_full(const struct genhash * pgenhash1,const struct genhash * pgenhash2,genhash_comp_fn_t data_comp_func)753 bool genhashs_are_equal_full(const struct genhash *pgenhash1,
754 const struct genhash *pgenhash2,
755 genhash_comp_fn_t data_comp_func)
756 {
757 struct genhash_entry *const *bucket1, *const *max1, *const *slot2;
758 const struct genhash_entry *iter1;
759
760 /* Check pointers. */
761 if (pgenhash1 == pgenhash2) {
762 return TRUE;
763 } else if (NULL == pgenhash1 || NULL == pgenhash2) {
764 return FALSE;
765 }
766
767 /* General check. */
768 if (pgenhash1->num_entries != pgenhash2->num_entries
769 /* If the key functions is not the same, we cannot know if the
770 * keys are equals. */
771 || pgenhash1->key_val_func != pgenhash2->key_val_func
772 || pgenhash1->key_comp_func != pgenhash2->key_comp_func) {
773 return FALSE;
774 }
775
776 /* Compare buckets. */
777 bucket1 = pgenhash1->buckets;
778 max1 = bucket1 + pgenhash1->num_buckets;
779 for (; bucket1 < max1; bucket1++) {
780 for (iter1 = *bucket1; NULL != iter1; iter1 = iter1->next) {
781 slot2 = genhash_slot_lookup(pgenhash2, iter1->key, iter1->hash_val);
782 if (NULL == *slot2
783 || (iter1->data != (*slot2)->data
784 && (NULL == data_comp_func
785 || !data_comp_func(iter1->data, (*slot2)->data)))) {
786 return FALSE;
787 }
788 }
789 }
790
791 return TRUE;
792 }
793
794
795 /****************************************************************************
796 "Sizeof" function implementation for generic_iterate genhash iterators.
797 ****************************************************************************/
genhash_iter_sizeof(void)798 size_t genhash_iter_sizeof(void)
799 {
800 return sizeof(struct genhash_iter);
801 }
802
803 /****************************************************************************
804 Helper function for genhash (key, value) pair iteration.
805 ****************************************************************************/
genhash_iter_key(const struct iterator * genhash_iter)806 void *genhash_iter_key(const struct iterator *genhash_iter)
807 {
808 struct genhash_iter *iter = GENHASH_ITER(genhash_iter);
809 return (void *) iter->iterator->key;
810 }
811
812 /****************************************************************************
813 Helper function for genhash (key, value) pair iteration.
814 ****************************************************************************/
genhash_iter_value(const struct iterator * genhash_iter)815 void *genhash_iter_value(const struct iterator *genhash_iter)
816 {
817 struct genhash_iter *iter = GENHASH_ITER(genhash_iter);
818 return (void *) iter->iterator->data;
819 }
820
821 /****************************************************************************
822 Iterator interface 'next' function implementation.
823 ****************************************************************************/
genhash_iter_next(struct iterator * genhash_iter)824 static void genhash_iter_next(struct iterator *genhash_iter)
825 {
826 struct genhash_iter *iter = GENHASH_ITER(genhash_iter);
827
828 iter->iterator = iter->iterator->next;
829 if (NULL != iter->iterator) {
830 return;
831 }
832
833 for (iter->bucket++; iter->bucket < iter->end; iter->bucket++) {
834 if (NULL != *iter->bucket) {
835 iter->iterator = *iter->bucket;
836 return;
837 }
838 }
839 }
840
841 /****************************************************************************
842 Iterator interface 'get' function implementation. This just returns the
843 iterator itself, so you would need to use genhash_iter_get_key/value to
844 get the actual keys and values.
845 ****************************************************************************/
genhash_iter_get(const struct iterator * genhash_iter)846 static void *genhash_iter_get(const struct iterator *genhash_iter)
847 {
848 return (void *) genhash_iter;
849 }
850
851 /****************************************************************************
852 Iterator interface 'valid' function implementation.
853 ****************************************************************************/
genhash_iter_valid(const struct iterator * genhash_iter)854 static bool genhash_iter_valid(const struct iterator *genhash_iter)
855 {
856 struct genhash_iter *iter = GENHASH_ITER(genhash_iter);
857 return iter->bucket < iter->end;
858 }
859
860 /****************************************************************************
861 Common genhash iterator initializer.
862 ****************************************************************************/
863 static inline struct iterator *
genhash_iter_init_common(struct genhash_iter * iter,const struct genhash * pgenhash,void * (* get)(const struct iterator *))864 genhash_iter_init_common(struct genhash_iter *iter,
865 const struct genhash *pgenhash,
866 void * (*get) (const struct iterator *))
867 {
868 if (NULL == pgenhash) {
869 return invalid_iter_init(ITERATOR(iter));
870 }
871
872 iter->vtable.next = genhash_iter_next;
873 iter->vtable.get = get;
874 iter->vtable.valid = genhash_iter_valid;
875 iter->bucket = pgenhash->buckets;
876 iter->end = pgenhash->buckets + pgenhash->num_buckets;
877
878 /* Seek to the first used bucket. */
879 for (; iter->bucket < iter->end; iter->bucket++) {
880 if (NULL != *iter->bucket) {
881 iter->iterator = *iter->bucket;
882 break;
883 }
884 }
885
886 return ITERATOR(iter);
887 }
888
889 /****************************************************************************
890 Returns an iterator that iterates over both keys and values of the genhash
891 table. NB: iterator_get() returns an iterator pointer, so use the helper
892 functions genhash_iter_get_{key,value} to access the key and value.
893 ****************************************************************************/
genhash_iter_init(struct genhash_iter * iter,const struct genhash * pgenhash)894 struct iterator *genhash_iter_init(struct genhash_iter *iter,
895 const struct genhash *pgenhash)
896 {
897 return genhash_iter_init_common(iter, pgenhash, genhash_iter_get);
898 }
899
900 /****************************************************************************
901 Returns an iterator over the genhash table's k genhashgenhashenhashys.
902 ****************************************************************************/
genhash_key_iter_init(struct genhash_iter * iter,const struct genhash * pgenhash)903 struct iterator *genhash_key_iter_init(struct genhash_iter *iter,
904 const struct genhash *pgenhash)
905 {
906 return genhash_iter_init_common(iter, pgenhash, genhash_iter_key);
907 }
908
909 /****************************************************************************
910 Returns an iterator over the hash table's values.
911 ****************************************************************************/
genhash_value_iter_init(struct genhash_iter * iter,const struct genhash * pgenhash)912 struct iterator *genhash_value_iter_init(struct genhash_iter *iter,
913 const struct genhash *pgenhash)
914 {
915 return genhash_iter_init_common(iter, pgenhash, genhash_iter_value);
916 }
917