Freeciv21
Develop your civilization from humble roots to a global empire
genhash.cpp
Go to the documentation of this file.
1 /*__ ___ ***************************************
2 / \ / \ Copyright (c) 1996-2020 Freeciv21 and Freeciv
3 \_ \ / __/ contributors. This file is part of Freeciv21.
4  _\ \ / /__ Freeciv21 is free software: you can redistribute it
5  \___ \____/ __/ and/or modify it under the terms of the GNU General
6  \_ _/ Public License as published by the Free Software
7  | @ @ \_ Foundation, either version 3 of the License,
8  | or (at your option) any later version.
9  _/ /\ You should have received a copy of the GNU
10  /o) (o/\ \_ General Public License along with Freeciv21.
11  \_____/ / If not, see https://www.gnu.org/licenses/.
12  \____/ ********************************************************/
13 
59 #include "genhash.h"
60 
61 // utility
62 #include "log.h"
63 #include "shared.h" // ARRAY_SIZE
64 #include "support.h"
65 
66 #include <cstring>
67 
68 #define FULL_RATIO 0.75 // consider expanding when above this
69 #define MIN_RATIO 0.24 // shrink when below this
70 
71 struct genhash_entry {
72  void *key;
73  void *data;
76 };
77 
78 // Contents of the opaque type:
79 struct genhash {
87  size_t num_buckets;
88  size_t num_entries;
89  bool no_shrink; // Do not auto-shrink when set.
90 };
91 
92 struct genhash_iter {
93  struct iterator vtable;
94  struct genhash_entry *const *bucket, *const *end;
95  const struct genhash_entry *iterator;
96 };
97 
98 #define GENHASH_ITER(p) ((struct genhash_iter *) (p))
99 
105 {
106  unsigned long result = 0;
107 
108  for (; *vkey != '\0'; vkey++) {
109  result *= 5;
110  result += *vkey;
111  }
112  result &= 0xFFFFFFFF; // To make results independent of sizeof(long)
113  return result;
114 }
115 
119 bool genhash_str_comp_func(const char *vkey1, const char *vkey2)
120 {
121  return 0 == strcmp(vkey1, vkey2);
122 }
123 
127 char *genhash_str_copy_func(const char *vkey)
128 {
129  return fc_strdup(nullptr != vkey ? vkey : "");
130 }
131 
135 void genhash_str_free_func(char *vkey)
136 {
137 #ifdef FREECIV_DEBUG
138  fc_assert_ret(nullptr != vkey);
139 #endif
140  delete[] vkey;
141 }
142 
156 #define MIN_BUCKETS 29 // Historical purposes.
157 static size_t genhash_calc_num_buckets(size_t num_entries)
158 {
159  /* A bunch of prime numbers close to successive elements of the sequence
160  * A_n = 3 * 2 ^ n; to be used for table sizes. */
161  static const size_t sizes[] = {
162  MIN_BUCKETS, 53, 97, 193, 389,
163  769, 1543, 3079, 6151, 12289,
164  24593, 49157, 98317, 196613, 393241,
165  786433, 1572869, 3145739, 6291469, 12582917,
166  25165843, 50331653, 100663319, 201326611, 402653189,
167  805306457, 1610612741, 3221225473ul, 4294967291ul};
168  const size_t *pframe = sizes, *pmid;
169  int fsize = ARRAY_SIZE(sizes) - 1, lpart;
170 
171  num_entries <<= 1; // breathing room
172 
173  while (fsize > 0) {
174  lpart = fsize >> 1;
175  pmid = pframe + lpart;
176  if (*pmid < num_entries) {
177  pframe = pmid + 1;
178  fsize = fsize - lpart - 1;
179  } else {
180  fsize = lpart;
181  }
182  }
183  return *pframe;
184 }
185 
201  size_t num_buckets)
202 {
203  genhash *pgenhash = new genhash;
204 
205  log_debug("New genhash table with %lu buckets",
206  (long unsigned) num_buckets);
207 
208  pgenhash->buckets = new genhash_entry *[num_buckets]();
209  pgenhash->key_val_func = key_val_func;
210  pgenhash->key_comp_func = key_comp_func;
211  pgenhash->key_copy_func = key_copy_func;
212  pgenhash->key_free_func = key_free_func;
213  pgenhash->data_copy_func = data_copy_func;
214  pgenhash->data_free_func = data_free_func;
215  pgenhash->num_buckets = num_buckets;
216  pgenhash->num_entries = 0;
217  pgenhash->no_shrink = false;
218 
219  return pgenhash;
220 }
221 
234  size_t nentries)
235 {
238  genhash_calc_num_buckets(nentries));
239 }
240 
246  size_t nentries)
247 {
248  return genhash_new_nbuckets(key_val_func, key_comp_func, nullptr, nullptr,
249  nullptr, nullptr,
250  genhash_calc_num_buckets(nentries));
251 }
252 
265 {
268  MIN_BUCKETS);
269 }
270 
276 {
277  return genhash_new_nbuckets(key_val_func, key_comp_func, nullptr, nullptr,
278  nullptr, nullptr, MIN_BUCKETS);
279 }
280 
284 void genhash_destroy(struct genhash *pgenhash)
285 {
286  fc_assert_ret(nullptr != pgenhash);
287  pgenhash->no_shrink = true;
288  genhash_clear(pgenhash);
289  delete[] pgenhash->buckets;
290  delete pgenhash;
291  pgenhash = nullptr;
292 }
293 
297 static void genhash_resize_table(struct genhash *pgenhash,
298  size_t new_nbuckets)
299 {
300  struct genhash_entry **new_buckets, **bucket, **end, **slot;
301  struct genhash_entry *iter, *next;
302 
303  fc_assert(new_nbuckets >= pgenhash->num_entries);
304 
305  new_buckets = new genhash_entry *[new_nbuckets]();
306  bucket = pgenhash->buckets;
307  end = bucket + pgenhash->num_buckets;
308  for (; bucket < end; bucket++) {
309  for (iter = *bucket; nullptr != iter; iter = next) {
310  slot = new_buckets + (iter->hash_val % new_nbuckets);
311  next = iter->next;
312  iter->next = *slot;
313  *slot = iter;
314  }
315  }
316 
317  delete[] pgenhash->buckets;
318  pgenhash->buckets = new_buckets;
319  pgenhash->num_buckets = new_nbuckets;
320 }
321 
329 #define genhash_maybe_expand(htab) genhash_maybe_resize((htab), true)
330 #define genhash_maybe_shrink(htab) genhash_maybe_resize((htab), false)
331 static bool genhash_maybe_resize(struct genhash *pgenhash, bool expandingp)
332 {
333  size_t limit, new_nbuckets;
334 
335  if (!expandingp && pgenhash->no_shrink) {
336  return false;
337  }
338  if (expandingp) {
339  limit = FULL_RATIO * pgenhash->num_buckets;
340  if (pgenhash->num_entries < limit) {
341  return false;
342  }
343  } else {
344  if (pgenhash->num_buckets <= MIN_BUCKETS) {
345  return false;
346  }
347  limit = MIN_RATIO * pgenhash->num_buckets;
348  if (pgenhash->num_entries > limit) {
349  return false;
350  }
351  }
352 
353  new_nbuckets = genhash_calc_num_buckets(pgenhash->num_entries);
354 
355  log_debug("%s genhash (entries = %lu, buckets = %lu, new = %lu, "
356  "%s limit = %lu)",
357  (new_nbuckets < pgenhash->num_buckets
358  ? "Shrinking"
359  : (new_nbuckets > pgenhash->num_buckets ? "Expanding"
360  : "Rehashing")),
361  (long unsigned) pgenhash->num_entries,
362  (long unsigned) pgenhash->num_buckets,
363  (long unsigned) new_nbuckets, expandingp ? "up" : "down",
364  (long unsigned) limit);
365  genhash_resize_table(pgenhash, new_nbuckets);
366  return true;
367 }
368 
372 static inline genhash_val_t genhash_val_calc(const struct genhash *pgenhash,
373  const void *key)
374 {
375  if (nullptr != pgenhash->key_val_func) {
376  return pgenhash->key_val_func(key);
377  } else {
378  return ((intptr_t) key);
379  }
380 }
381 
386 static inline struct genhash_entry **
387 genhash_slot_lookup(const struct genhash *pgenhash, const void *key,
389 {
390  struct genhash_entry **slot;
391  genhash_comp_fn_t key_comp_func = pgenhash->key_comp_func;
392 
393  slot = pgenhash->buckets + (hash_val % pgenhash->num_buckets);
394  if (nullptr != key_comp_func) {
395  for (; nullptr != *slot; slot = &(*slot)->next) {
396  if (hash_val == (*slot)->hash_val
397  && key_comp_func((*slot)->key, key)) {
398  return slot;
399  }
400  }
401  } else {
402  for (; nullptr != *slot; slot = &(*slot)->next) {
403  if (key == (*slot)->key) {
404  return slot;
405  }
406  }
407  }
408  return slot;
409 }
410 
414 static inline void genhash_default_get(void **pkey, void **data)
415 {
416  if (nullptr != pkey) {
417  *pkey = nullptr;
418  }
419  if (nullptr != data) {
420  *data = nullptr;
421  }
422 }
423 
427 static inline void genhash_slot_get(struct genhash_entry *const *slot,
428  void **pkey, void **data)
429 {
430  const struct genhash_entry *entry = *slot;
431 
432  if (nullptr != pkey) {
433  *pkey = entry->key;
434  }
435  if (nullptr != data) {
436  *data = entry->data;
437  }
438 }
439 
443 static inline void genhash_slot_create(struct genhash *pgenhash,
444  struct genhash_entry **slot,
445  const void *key, const void *data,
447 {
449 
450  entry->key =
451  (nullptr != pgenhash->key_copy_func ? pgenhash->key_copy_func(key)
452  : const_cast<void *>(key));
453  entry->data =
454  (nullptr != pgenhash->data_copy_func ? pgenhash->data_copy_func(data)
455  : const_cast<void *>(data));
456  entry->hash_val = hash_val;
457  entry->next = *slot;
458  *slot = entry;
459 }
460 
464 static inline void genhash_slot_free(struct genhash *pgenhash,
465  struct genhash_entry **slot)
466 {
467  struct genhash_entry *entry = *slot;
468 
469  if (nullptr != pgenhash->key_free_func) {
470  ::operator delete[](entry->key);
471  }
472  if (nullptr != pgenhash->data_free_func) {
473  ::operator delete(entry->data);
474  }
475  *slot = entry->next;
476  delete entry;
477 }
478 
482 static inline void genhash_slot_set(struct genhash *pgenhash,
483  struct genhash_entry **slot,
484  const void *key, const void *data)
485 {
486  struct genhash_entry *entry = *slot;
487 
488  if (nullptr != pgenhash->key_free_func) {
489  pgenhash->key_free_func(entry->key);
490  }
491  if (nullptr != pgenhash->data_free_func) {
492  pgenhash->data_free_func(entry->data);
493  }
494  entry->key =
495  (nullptr != pgenhash->key_copy_func ? pgenhash->key_copy_func(key)
496  : const_cast<void *>(key));
497  entry->data =
498  (nullptr != pgenhash->data_copy_func ? pgenhash->data_copy_func(data)
499  : const_cast<void *>(data));
500 }
501 
506 bool genhash_set_no_shrink(struct genhash *pgenhash, bool no_shrink)
507 {
508  bool old;
509 
510  fc_assert_ret_val(nullptr != pgenhash, false);
511  old = pgenhash->no_shrink;
512  pgenhash->no_shrink = no_shrink;
513  return old;
514 }
515 
519 size_t genhash_size(const struct genhash *pgenhash)
520 {
521  fc_assert_ret_val(nullptr != pgenhash, 0);
522  return pgenhash->num_entries;
523 }
524 
528 size_t genhash_capacity(const struct genhash *pgenhash)
529 {
530  fc_assert_ret_val(nullptr != pgenhash, 0);
531  return pgenhash->num_buckets;
532 }
533 
537 struct genhash *genhash_copy(const struct genhash *pgenhash)
538 {
539  struct genhash *new_genhash;
540  struct genhash_entry *const *src_bucket, *const *end;
541  const struct genhash_entry *src_iter;
542  struct genhash_entry **dest_slot, **dest_bucket;
543 
544  fc_assert_ret_val(nullptr != pgenhash, nullptr);
545 
546  new_genhash = new genhash;
547 
548  // Copy fields.
549  *new_genhash = *pgenhash;
550 
551  // But make fresh buckets.
552  new_genhash->buckets = new genhash_entry *[new_genhash->num_buckets]();
553 
554  // Let's re-insert all data
555  src_bucket = pgenhash->buckets;
556  end = src_bucket + pgenhash->num_buckets;
557  dest_bucket = new_genhash->buckets;
558 
559  for (; src_bucket < end; src_bucket++, dest_bucket++) {
560  dest_slot = dest_bucket;
561  for (src_iter = *src_bucket; nullptr != src_iter;
562  src_iter = src_iter->next) {
563  genhash_slot_create(new_genhash, dest_slot, src_iter->key,
564  src_iter->data, src_iter->hash_val);
565  dest_slot = &(*dest_slot)->next;
566  }
567  }
568 
569  return new_genhash;
570 }
571 
575 void genhash_clear(struct genhash *pgenhash)
576 {
577  struct genhash_entry **bucket, **end;
578 
579  fc_assert_ret(nullptr != pgenhash);
580 
581  bucket = pgenhash->buckets;
582  end = bucket + pgenhash->num_buckets;
583  for (; bucket < end; bucket++) {
584  while (nullptr != *bucket) {
585  genhash_slot_free(pgenhash, bucket);
586  }
587  }
588 
589  pgenhash->num_entries = 0;
590  genhash_maybe_shrink(pgenhash);
591 }
592 
597 bool genhash_insert(struct genhash *pgenhash, const void *key,
598  const void *data)
599 {
600  struct genhash_entry **slot;
602 
603  fc_assert_ret_val(nullptr != pgenhash, false);
604 
605  hash_val = genhash_val_calc(pgenhash, key);
606  slot = genhash_slot_lookup(pgenhash, key, hash_val);
607  if (nullptr != *slot) {
608  return false;
609  } else {
610  if (genhash_maybe_expand(pgenhash)) {
611  // Recalculate slot.
612  slot = pgenhash->buckets + (hash_val % pgenhash->num_buckets);
613  }
614  genhash_slot_create(pgenhash, slot, key, data, hash_val);
615  pgenhash->num_entries++;
616  return true;
617  }
618 }
619 
625 bool genhash_replace(struct genhash *pgenhash, const void *key,
626  const void *data)
627 {
628  return genhash_replace_full(pgenhash, key, data, nullptr, nullptr);
629 }
630 
640 bool genhash_replace_full(struct genhash *pgenhash, const void *key,
641  const void *data, void **old_pkey,
642  void **old_pdata)
643 {
644  struct genhash_entry **slot;
646 
647  fc_assert_action(nullptr != pgenhash,
648  genhash_default_get(old_pkey, old_pdata);
649  return false);
650 
651  hash_val = genhash_val_calc(pgenhash, key);
652  slot = genhash_slot_lookup(pgenhash, key, hash_val);
653  if (nullptr != *slot) {
654  // Replace.
655  genhash_slot_get(slot, old_pkey, old_pdata);
656  genhash_slot_set(pgenhash, slot, key, data);
657  return true;
658  } else {
659  // Insert.
660  if (genhash_maybe_expand(pgenhash)) {
661  // Recalculate slot.
662  slot = pgenhash->buckets + (hash_val % pgenhash->num_buckets);
663  }
664  genhash_default_get(old_pkey, old_pdata);
665  genhash_slot_create(pgenhash, slot, key, data, hash_val);
666  pgenhash->num_entries++;
667  return false;
668  }
669 }
670 
675 bool genhash_lookup(const struct genhash *pgenhash, const void *key,
676  void **pdata)
677 {
678  struct genhash_entry **slot;
679 
680  fc_assert_action(nullptr != pgenhash, genhash_default_get(nullptr, pdata);
681  return false);
682 
683  slot = genhash_slot_lookup(pgenhash, key, genhash_val_calc(pgenhash, key));
684  if (nullptr != *slot) {
685  genhash_slot_get(slot, nullptr, pdata);
686  return true;
687  } else {
688  genhash_default_get(nullptr, pdata);
689  return false;
690  }
691 }
692 
696 bool genhash_remove(struct genhash *pgenhash, const void *key)
697 {
698  return genhash_remove_full(pgenhash, key, nullptr, nullptr);
699 }
700 
708 bool genhash_remove_full(struct genhash *pgenhash, const void *key,
709  void **deleted_pkey, void **deleted_pdata)
710 {
711  struct genhash_entry **slot;
712 
713  fc_assert_action(nullptr != pgenhash,
714  genhash_default_get(deleted_pkey, deleted_pdata);
715  return false);
716 
717  slot = genhash_slot_lookup(pgenhash, key, genhash_val_calc(pgenhash, key));
718  if (nullptr != *slot) {
719  genhash_slot_get(slot, deleted_pkey, deleted_pdata);
720  genhash_slot_free(pgenhash, slot);
721  genhash_maybe_shrink(pgenhash);
722  fc_assert(0 < pgenhash->num_entries);
723  pgenhash->num_entries--;
724  return true;
725  } else {
726  genhash_default_get(deleted_pkey, deleted_pdata);
727  return false;
728  }
729 }
730 
734 bool genhashs_are_equal(const struct genhash *pgenhash1,
735  const struct genhash *pgenhash2)
736 {
737  return genhashs_are_equal_full(pgenhash1, pgenhash2, nullptr);
738 }
739 
743 bool genhashs_are_equal_full(const struct genhash *pgenhash1,
744  const struct genhash *pgenhash2,
745  genhash_comp_fn_t data_comp_func)
746 {
747  struct genhash_entry *const *bucket1, *const *max1, *const *slot2;
748  const struct genhash_entry *iter1;
749 
750  // Check pointers.
751  if (pgenhash1 == pgenhash2) {
752  return true;
753  } else if (nullptr == pgenhash1 || nullptr == pgenhash2) {
754  return false;
755  }
756 
757  // General check.
758  if (pgenhash1->num_entries != pgenhash2->num_entries
759  /* If the key functions is not the same, we cannot know if the
760  * keys are equals. */
761  || pgenhash1->key_val_func != pgenhash2->key_val_func
762  || pgenhash1->key_comp_func != pgenhash2->key_comp_func) {
763  return false;
764  }
765 
766  // Compare buckets.
767  bucket1 = pgenhash1->buckets;
768  max1 = bucket1 + pgenhash1->num_buckets;
769  for (; bucket1 < max1; bucket1++) {
770  for (iter1 = *bucket1; nullptr != iter1; iter1 = iter1->next) {
771  slot2 = genhash_slot_lookup(pgenhash2, iter1->key, iter1->hash_val);
772  if (nullptr == *slot2
773  || (iter1->data != (*slot2)->data
774  && (nullptr == data_comp_func
775  || !data_comp_func(iter1->data, (*slot2)->data)))) {
776  return false;
777  }
778  }
779  }
780 
781  return true;
782 }
783 
787 size_t genhash_iter_sizeof() { return sizeof(struct genhash_iter); }
788 
793 {
794  struct genhash_iter *iter = GENHASH_ITER(genhash_iter);
795  return iter->iterator->key;
796 }
797 
802 {
803  struct genhash_iter *iter = GENHASH_ITER(genhash_iter);
804  return iter->iterator->data;
805 }
806 
811 {
812  struct genhash_iter *iter = GENHASH_ITER(genhash_iter);
813 
814  iter->iterator = iter->iterator->next;
815  if (nullptr != iter->iterator) {
816  return;
817  }
818 
819  for (iter->bucket++; iter->bucket < iter->end; iter->bucket++) {
820  if (nullptr != *iter->bucket) {
821  iter->iterator = *iter->bucket;
822  return;
823  }
824  }
825 }
826 
832 static void *genhash_iter_get(const struct iterator *genhash_iter)
833 {
834  return (void *) genhash_iter;
835 }
836 
840 static bool genhash_iter_valid(const struct iterator *genhash_iter)
841 {
842  struct genhash_iter *iter = GENHASH_ITER(genhash_iter);
843  return iter->bucket < iter->end;
844 }
845 
849 static inline struct iterator *
851  const struct genhash *pgenhash,
852  void *(*get)(const struct iterator *) )
853 {
854  if (nullptr == pgenhash) {
855  return invalid_iter_init(ITERATOR(iter));
856  }
857 
858  iter->vtable.next = genhash_iter_next;
859  iter->vtable.get = get;
861  iter->bucket = pgenhash->buckets;
862  iter->end = pgenhash->buckets + pgenhash->num_buckets;
863 
864  // Seek to the first used bucket.
865  for (; iter->bucket < iter->end; iter->bucket++) {
866  if (nullptr != *iter->bucket) {
867  iter->iterator = *iter->bucket;
868  break;
869  }
870  }
871 
872  return ITERATOR(iter);
873 }
874 
881  const struct genhash *pgenhash)
882 {
883  return genhash_iter_init_common(iter, pgenhash, genhash_iter_get);
884 }
885 
890  const struct genhash *pgenhash)
891 {
892  return genhash_iter_init_common(iter, pgenhash, genhash_iter_key);
893 }
894 
899  const struct genhash *pgenhash)
900 {
901  return genhash_iter_init_common(iter, pgenhash, genhash_iter_value);
902 }
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)
Internal constructor, specifying exact number of buckets.
Definition: genhash.cpp:195
#define genhash_maybe_expand(htab)
Call this when an entry might be added or deleted: resizes the genhash table if seems like a good ide...
Definition: genhash.cpp:329
size_t genhash_iter_sizeof()
"Sizeof" function implementation for generic_iterate genhash iterators.
Definition: genhash.cpp:787
static void genhash_iter_next(struct iterator *genhash_iter)
Iterator interface 'next' function implementation.
Definition: genhash.cpp:810
bool genhashs_are_equal(const struct genhash *pgenhash1, const struct genhash *pgenhash2)
Returns TRUE iff the hash tables contains the same pairs of key/data.
Definition: genhash.cpp:734
bool genhash_insert(struct genhash *pgenhash, const void *key, const void *data)
Insert entry: returns TRUE if inserted, or FALSE if there was already an entry with the same key,...
Definition: genhash.cpp:597
bool genhash_str_comp_func(const char *vkey1, const char *vkey2)
A supplied function for comparison of nul-terminated strings:
Definition: genhash.cpp:119
bool genhashs_are_equal_full(const struct genhash *pgenhash1, const struct genhash *pgenhash2, genhash_comp_fn_t data_comp_func)
Returns TRUE iff the hash tables contains the same pairs of key/data.
Definition: genhash.cpp:743
#define genhash_maybe_shrink(htab)
Definition: genhash.cpp:330
static void genhash_slot_free(struct genhash *pgenhash, struct genhash_entry **slot)
Free the entry slot and call the free callbacks.
Definition: genhash.cpp:464
static size_t genhash_calc_num_buckets(size_t num_entries)
Definition: genhash.cpp:157
static bool genhash_maybe_resize(struct genhash *pgenhash, bool expandingp)
Definition: genhash.cpp:331
bool genhash_set_no_shrink(struct genhash *pgenhash, bool no_shrink)
Prevent or allow the genhash table automatically shrinking.
Definition: genhash.cpp:506
static struct iterator * genhash_iter_init_common(struct genhash_iter *iter, const struct genhash *pgenhash, void *(*get)(const struct iterator *))
Common genhash iterator initializer.
Definition: genhash.cpp:850
size_t genhash_size(const struct genhash *pgenhash)
Returns the number of entries in the genhash table.
Definition: genhash.cpp:519
static bool genhash_iter_valid(const struct iterator *genhash_iter)
Iterator interface 'valid' function implementation.
Definition: genhash.cpp:840
static struct genhash_entry ** genhash_slot_lookup(const struct genhash *pgenhash, const void *key, genhash_val_t hash_val)
Return slot (entry pointer) in genhash table where key resides, or where it should go if it is to be ...
Definition: genhash.cpp:387
struct genhash * genhash_copy(const struct genhash *pgenhash)
Returns a newly allocated mostly deep copy of the given genhash table.
Definition: genhash.cpp:537
void genhash_destroy(struct genhash *pgenhash)
Destructor: free internal memory.
Definition: genhash.cpp:284
struct genhash * 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)
Constructor with unspecified number of entries.
Definition: genhash.cpp:259
static void genhash_slot_get(struct genhash_entry *const *slot, void **pkey, void **data)
Function to store data.
Definition: genhash.cpp:427
size_t genhash_capacity(const struct genhash *pgenhash)
Returns the number of buckets in the genhash table.
Definition: genhash.cpp:528
void genhash_clear(struct genhash *pgenhash)
Remove all entries of the genhash table.
Definition: genhash.cpp:575
struct genhash * genhash_new(genhash_val_fn_t key_val_func, genhash_comp_fn_t key_comp_func)
Constructor with unspecified number of entries.
Definition: genhash.cpp:274
#define MIN_RATIO
Definition: genhash.cpp:69
static void genhash_default_get(void **pkey, void **data)
Function to store from invalid data.
Definition: genhash.cpp:414
bool genhash_lookup(const struct genhash *pgenhash, const void *key, void **pdata)
Lookup data.
Definition: genhash.cpp:675
static genhash_val_t genhash_val_calc(const struct genhash *pgenhash, const void *key)
Calculate genhash value given hash table and key.
Definition: genhash.cpp:372
#define FULL_RATIO
Definition: genhash.cpp:68
static void genhash_slot_create(struct genhash *pgenhash, struct genhash_entry **slot, const void *key, const void *data, genhash_val_t hash_val)
Create the entry and call the copy callbacks.
Definition: genhash.cpp:443
void * genhash_iter_key(const struct iterator *genhash_iter)
Helper function for genhash (key, value) pair iteration.
Definition: genhash.cpp:792
struct iterator * genhash_key_iter_init(struct genhash_iter *iter, const struct genhash *pgenhash)
Returns an iterator over the genhash table's k genhashgenhashenhashys.
Definition: genhash.cpp:889
bool genhash_remove(struct genhash *pgenhash, const void *key)
Delete an entry from the genhash table.
Definition: genhash.cpp:696
#define MIN_BUCKETS
Calculate a "reasonable" number of buckets for a given number of entries.
Definition: genhash.cpp:156
static void genhash_slot_set(struct genhash *pgenhash, struct genhash_entry **slot, const void *key, const void *data)
Clear previous values (with free callback) and call the copy callbacks.
Definition: genhash.cpp:482
bool genhash_replace_full(struct genhash *pgenhash, const void *key, const void *data, void **old_pkey, void **old_pdata)
Insert entry, replacing any existing entry which has the same key.
Definition: genhash.cpp:640
char * genhash_str_copy_func(const char *vkey)
Copy function for string allocation.
Definition: genhash.cpp:127
struct genhash * genhash_new_nentries(genhash_val_fn_t key_val_func, genhash_comp_fn_t key_comp_func, size_t nentries)
Constructor specifying number of entries.
Definition: genhash.cpp:244
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)
Constructor specifying number of entries.
Definition: genhash.cpp:228
void * genhash_iter_value(const struct iterator *genhash_iter)
Helper function for genhash (key, value) pair iteration.
Definition: genhash.cpp:801
struct iterator * genhash_iter_init(struct genhash_iter *iter, const struct genhash *pgenhash)
Returns an iterator that iterates over both keys and values of the genhash table.
Definition: genhash.cpp:880
static void genhash_resize_table(struct genhash *pgenhash, size_t new_nbuckets)
Resize the genhash table: relink entries.
Definition: genhash.cpp:297
void genhash_str_free_func(char *vkey)
Free function for string allocation.
Definition: genhash.cpp:135
bool genhash_replace(struct genhash *pgenhash, const void *key, const void *data)
Insert entry, replacing any existing entry which has the same key.
Definition: genhash.cpp:625
genhash_val_t genhash_str_val_func(const char *vkey)
A supplied genhash function appropriate to nul-terminated strings.
Definition: genhash.cpp:104
static void * genhash_iter_get(const struct iterator *genhash_iter)
Iterator interface 'get' function implementation.
Definition: genhash.cpp:832
struct iterator * genhash_value_iter_init(struct genhash_iter *iter, const struct genhash *pgenhash)
Returns an iterator over the hash table's values.
Definition: genhash.cpp:898
#define GENHASH_ITER(p)
Definition: genhash.cpp:98
bool genhash_remove_full(struct genhash *pgenhash, const void *key, void **deleted_pkey, void **deleted_pdata)
Delete an entry from the genhash table.
Definition: genhash.cpp:708
genhash_val_t(* genhash_val_fn_t)(const void *)
Definition: genhash.h:30
void *(* genhash_copy_fn_t)(const void *)
Definition: genhash.h:32
bool(* genhash_comp_fn_t)(const void *, const void *)
Definition: genhash.h:31
void(* genhash_free_fn_t)(void *)
Definition: genhash.h:33
unsigned int genhash_val_t
Definition: genhash.h:24
struct iterator * invalid_iter_init(struct iterator *it)
Initializes the iterator vtable so that generic_iterate assumes that the iterator is invalid.
Definition: iterator.cpp:37
#define ITERATOR(p)
Definition: iterator.h:26
#define fc_assert_ret(condition)
Definition: log.h:112
#define fc_assert(condition)
Definition: log.h:89
#define fc_assert_ret_val(condition, val)
Definition: log.h:114
#define fc_assert_action(condition, action)
Definition: log.h:104
#define log_debug(message,...)
Definition: log.h:65
#define ARRAY_SIZE(x)
Definition: shared.h:79
Definition: genhash.cpp:71
genhash_val_t hash_val
Definition: genhash.cpp:74
struct genhash_entry * next
Definition: genhash.cpp:75
void * key
Definition: genhash.cpp:72
void * data
Definition: genhash.cpp:73
const struct genhash_entry * iterator
Definition: genhash.cpp:95
struct genhash_entry *const *const * end
Definition: genhash.cpp:94
struct genhash_entry *const * bucket
Definition: genhash.cpp:94
struct iterator vtable
Definition: genhash.cpp:93
struct genhash_entry ** buckets
Definition: genhash.cpp:80
genhash_comp_fn_t key_comp_func
Definition: genhash.cpp:82
genhash_val_fn_t key_val_func
Definition: genhash.cpp:81
genhash_free_fn_t key_free_func
Definition: genhash.cpp:84
bool no_shrink
Definition: genhash.cpp:89
genhash_copy_fn_t data_copy_func
Definition: genhash.cpp:85
size_t num_buckets
Definition: genhash.cpp:87
size_t num_entries
Definition: genhash.cpp:88
genhash_free_fn_t data_free_func
Definition: genhash.cpp:86
genhash_copy_fn_t key_copy_func
Definition: genhash.cpp:83
bool(* valid)(const struct iterator *it)
Definition: iterator.h:23
void *(* get)(const struct iterator *it)
Definition: iterator.h:22
void(* next)(struct iterator *it)
Definition: iterator.h:21
#define fc_strdup(str)
Definition: support.h:111