Blender V4.3
BLI_ghash.c
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
12#include <limits.h>
13#include <stdarg.h>
14#include <stdlib.h>
15#include <string.h>
16
17#include "MEM_guardedalloc.h"
18
19#include "BLI_math_base.h"
20#include "BLI_mempool.h"
21#include "BLI_sys_types.h" /* for intptr_t support */
22#include "BLI_utildefines.h"
23
24#define GHASH_INTERNAL_API
25#include "BLI_ghash.h" /* own include */
26
27#include "BLI_strict_flags.h" /* Keep last. */
28
29/* -------------------------------------------------------------------- */
33#define GHASH_USE_MODULO_BUCKETS
34
38static const uint hashsizes[] = {
39 5, 11, 17, 37, 67, 131, 257, 521, 1031,
40 2053, 4099, 8209, 16411, 32771, 65537, 131101, 262147, 524309,
41 1048583, 2097169, 4194319, 8388617, 16777259, 33554467, 67108879, 134217757, 268435459,
42};
43
44#ifdef GHASH_USE_MODULO_BUCKETS
45# define GHASH_MAX_SIZE 27
46BLI_STATIC_ASSERT(ARRAY_SIZE(hashsizes) == GHASH_MAX_SIZE, "Invalid 'hashsizes' size");
47#else
48# define GHASH_BUCKET_BIT_MIN 2
49# define GHASH_BUCKET_BIT_MAX 28 /* About 268M of buckets... */
50#endif
51
60#define GHASH_LIMIT_GROW(_nbkt) (((_nbkt) * 3) / 4)
61#define GHASH_LIMIT_SHRINK(_nbkt) (((_nbkt) * 3) / 16)
62
63/* WARNING! Keep in sync with ugly _gh_Entry in header!!! */
64typedef struct Entry {
65 struct Entry *next;
66
67 void *key;
69
70typedef struct GHashEntry {
72
73 void *val;
75
77
78#define GHASH_ENTRY_SIZE(_is_gset) ((_is_gset) ? sizeof(GSetEntry) : sizeof(GHashEntry))
79
80struct GHash {
83
88#ifdef GHASH_USE_MODULO_BUCKETS
90#else
91 uint bucket_mask, bucket_bit, bucket_bit_min;
92#endif
93
96};
97
100/* -------------------------------------------------------------------- */
105 Entry *dst,
106 const GHash *gh_src,
107 const Entry *src,
108 GHashKeyCopyFP keycopyfp,
109 GHashValCopyFP valcopyfp)
110{
111 dst->key = (keycopyfp) ? keycopyfp(src->key) : src->key;
112
113 if ((gh_dst->flag & GHASH_FLAG_IS_GSET) == 0) {
114 if ((gh_src->flag & GHASH_FLAG_IS_GSET) == 0) {
115 ((GHashEntry *)dst)->val = (valcopyfp) ? valcopyfp(((GHashEntry *)src)->val) :
116 ((GHashEntry *)src)->val;
117 }
118 else {
119 ((GHashEntry *)dst)->val = NULL;
120 }
121 }
122}
123
127BLI_INLINE uint ghash_keyhash(const GHash *gh, const void *key)
128{
129 return gh->hashfp(key);
130}
131
136{
137 return gh->hashfp(e->key);
138}
139
144{
145#ifdef GHASH_USE_MODULO_BUCKETS
146 return hash % gh->nbuckets;
147#else
148 return hash & gh->bucket_mask;
149#endif
150}
151
156{
157 if (curr_bucket >= gh->nbuckets) {
158 curr_bucket = 0;
159 }
160 if (gh->buckets[curr_bucket]) {
161 return curr_bucket;
162 }
163 for (; curr_bucket < gh->nbuckets; curr_bucket++) {
164 if (gh->buckets[curr_bucket]) {
165 return curr_bucket;
166 }
167 }
168 for (curr_bucket = 0; curr_bucket < gh->nbuckets; curr_bucket++) {
169 if (gh->buckets[curr_bucket]) {
170 return curr_bucket;
171 }
172 }
174 return 0;
175}
176
180static void ghash_buckets_resize(GHash *gh, const uint nbuckets)
181{
182 Entry **buckets_old = gh->buckets;
183 Entry **buckets_new;
184 const uint nbuckets_old = gh->nbuckets;
185 uint i;
186
187 BLI_assert((gh->nbuckets != nbuckets) || !gh->buckets);
188 // printf("%s: %d -> %d\n", __func__, nbuckets_old, nbuckets);
189
190 gh->nbuckets = nbuckets;
191#ifdef GHASH_USE_MODULO_BUCKETS
192#else
193 gh->bucket_mask = nbuckets - 1;
194#endif
195
196 buckets_new = (Entry **)MEM_callocN(sizeof(*gh->buckets) * gh->nbuckets, __func__);
197
198 if (buckets_old) {
199 if (nbuckets > nbuckets_old) {
200 for (i = 0; i < nbuckets_old; i++) {
201 for (Entry *e = buckets_old[i], *e_next; e; e = e_next) {
202 const uint hash = ghash_entryhash(gh, e);
203 const uint bucket_index = ghash_bucket_index(gh, hash);
204 e_next = e->next;
205 e->next = buckets_new[bucket_index];
206 buckets_new[bucket_index] = e;
207 }
208 }
209 }
210 else {
211 for (i = 0; i < nbuckets_old; i++) {
212#ifdef GHASH_USE_MODULO_BUCKETS
213 for (Entry *e = buckets_old[i], *e_next; e; e = e_next) {
214 const uint hash = ghash_entryhash(gh, e);
215 const uint bucket_index = ghash_bucket_index(gh, hash);
216 e_next = e->next;
217 e->next = buckets_new[bucket_index];
218 buckets_new[bucket_index] = e;
219 }
220#else
221 /* No need to recompute hashes in this case, since our mask is just smaller,
222 * all items in old bucket 'i' will go in same new bucket (i & new_mask)! */
223 const uint bucket_index = ghash_bucket_index(gh, i);
224 BLI_assert(!buckets_old[i] ||
225 (bucket_index == ghash_bucket_index(gh, ghash_entryhash(gh, buckets_old[i]))));
226 Entry *e;
227 for (e = buckets_old[i]; e && e->next; e = e->next) {
228 /* pass */
229 }
230 if (e) {
231 e->next = buckets_new[bucket_index];
232 buckets_new[bucket_index] = buckets_old[i];
233 }
234#endif
235 }
236 }
237 }
238
239 gh->buckets = buckets_new;
240 if (buckets_old) {
241 MEM_freeN(buckets_old);
242 }
243}
244
249static void ghash_buckets_expand(GHash *gh, const uint nentries, const bool user_defined)
250{
251 uint new_nbuckets;
252
253 if (LIKELY(gh->buckets && (nentries < gh->limit_grow))) {
254 return;
255 }
256
257 new_nbuckets = gh->nbuckets;
258
259#ifdef GHASH_USE_MODULO_BUCKETS
260 while ((nentries > gh->limit_grow) && (gh->cursize < GHASH_MAX_SIZE - 1)) {
261 new_nbuckets = hashsizes[++gh->cursize];
262 gh->limit_grow = GHASH_LIMIT_GROW(new_nbuckets);
263 }
264#else
265 while ((nentries > gh->limit_grow) && (gh->bucket_bit < GHASH_BUCKET_BIT_MAX)) {
266 new_nbuckets = 1u << ++gh->bucket_bit;
267 gh->limit_grow = GHASH_LIMIT_GROW(new_nbuckets);
268 }
269#endif
270
271 if (user_defined) {
272#ifdef GHASH_USE_MODULO_BUCKETS
273 gh->size_min = gh->cursize;
274#else
275 gh->bucket_bit_min = gh->bucket_bit;
276#endif
277 }
278
279 if ((new_nbuckets == gh->nbuckets) && gh->buckets) {
280 return;
281 }
282
283 gh->limit_grow = GHASH_LIMIT_GROW(new_nbuckets);
284 gh->limit_shrink = GHASH_LIMIT_SHRINK(new_nbuckets);
285 ghash_buckets_resize(gh, new_nbuckets);
286}
287
289 const uint nentries,
290 const bool user_defined,
291 const bool force_shrink)
292{
293 uint new_nbuckets;
294
295 if (!(force_shrink || (gh->flag & GHASH_FLAG_ALLOW_SHRINK))) {
296 return;
297 }
298
299 if (LIKELY(gh->buckets && (nentries > gh->limit_shrink))) {
300 return;
301 }
302
303 new_nbuckets = gh->nbuckets;
304
305#ifdef GHASH_USE_MODULO_BUCKETS
306 while ((nentries < gh->limit_shrink) && (gh->cursize > gh->size_min)) {
307 new_nbuckets = hashsizes[--gh->cursize];
308 gh->limit_shrink = GHASH_LIMIT_SHRINK(new_nbuckets);
309 }
310#else
311 while ((nentries < gh->limit_shrink) && (gh->bucket_bit > gh->bucket_bit_min)) {
312 new_nbuckets = 1u << --gh->bucket_bit;
313 gh->limit_shrink = GHASH_LIMIT_SHRINK(new_nbuckets);
314 }
315#endif
316
317 if (user_defined) {
318#ifdef GHASH_USE_MODULO_BUCKETS
319 gh->size_min = gh->cursize;
320#else
321 gh->bucket_bit_min = gh->bucket_bit;
322#endif
323 }
324
325 if ((new_nbuckets == gh->nbuckets) && gh->buckets) {
326 return;
327 }
328
329 gh->limit_grow = GHASH_LIMIT_GROW(new_nbuckets);
330 gh->limit_shrink = GHASH_LIMIT_SHRINK(new_nbuckets);
331 ghash_buckets_resize(gh, new_nbuckets);
332}
333
337BLI_INLINE void ghash_buckets_reset(GHash *gh, const uint nentries)
338{
340
341#ifdef GHASH_USE_MODULO_BUCKETS
342 gh->cursize = 0;
343 gh->size_min = 0;
344 gh->nbuckets = hashsizes[gh->cursize];
345#else
346 gh->bucket_bit = GHASH_BUCKET_BIT_MIN;
347 gh->bucket_bit_min = GHASH_BUCKET_BIT_MIN;
348 gh->nbuckets = 1u << gh->bucket_bit;
349 gh->bucket_mask = gh->nbuckets - 1;
350#endif
351
354
355 gh->nentries = 0;
356
357 ghash_buckets_expand(gh, nentries, (nentries != 0));
358}
359
365BLI_INLINE Entry *ghash_lookup_entry_ex(const GHash *gh, const void *key, const uint bucket_index)
366{
367 Entry *e;
368 /* If we do not store GHash, not worth computing it for each entry here!
369 * Typically, comparison function will be quicker, and since it's needed in the end anyway... */
370 for (e = gh->buckets[bucket_index]; e; e = e->next) {
371 if (UNLIKELY(gh->cmpfp(key, e->key) == false)) {
372 return e;
373 }
374 }
375
376 return NULL;
377}
378
386 const void *key,
387 Entry **r_e_prev,
388 const uint bucket_index)
389{
390 /* If we do not store GHash, not worth computing it for each entry here!
391 * Typically, comparison function will be quicker, and since it's needed in the end anyway... */
392 for (Entry *e_prev = NULL, *e = gh->buckets[bucket_index]; e; e_prev = e, e = e->next) {
393 if (UNLIKELY(gh->cmpfp(key, e->key) == false)) {
394 *r_e_prev = e_prev;
395 return e;
396 }
397 }
398
399 *r_e_prev = NULL;
400 return NULL;
401}
402
406BLI_INLINE Entry *ghash_lookup_entry(const GHash *gh, const void *key)
407{
408 const uint hash = ghash_keyhash(gh, key);
409 const uint bucket_index = ghash_bucket_index(gh, hash);
410 return ghash_lookup_entry_ex(gh, key, bucket_index);
411}
412
414 GHashCmpFP cmpfp,
415 const char *info,
416 const uint nentries_reserve,
417 const uint flag)
418{
419 GHash *gh = MEM_mallocN(sizeof(*gh), info);
420
421 gh->hashfp = hashfp;
422 gh->cmpfp = cmpfp;
423
424 gh->buckets = NULL;
425 gh->flag = flag;
426
427 ghash_buckets_reset(gh, nentries_reserve);
429 GHASH_ENTRY_SIZE(flag & GHASH_FLAG_IS_GSET), 64, 64, BLI_MEMPOOL_NOP);
430
431 return gh;
432}
433
439BLI_INLINE void ghash_insert_ex(GHash *gh, void *key, void *val, const uint bucket_index)
440{
442
443 BLI_assert((gh->flag & GHASH_FLAG_ALLOW_DUPES) || (BLI_ghash_haskey(gh, key) == 0));
444 BLI_assert(!(gh->flag & GHASH_FLAG_IS_GSET));
445
446 e->e.next = gh->buckets[bucket_index];
447 e->e.key = key;
448 e->val = val;
449 gh->buckets[bucket_index] = (Entry *)e;
450
451 ghash_buckets_expand(gh, ++gh->nentries, false);
452}
453
458 void *key,
459 const uint bucket_index,
460 Entry *e)
461{
462 BLI_assert((gh->flag & GHASH_FLAG_ALLOW_DUPES) || (BLI_ghash_haskey(gh, key) == 0));
463
464 e->next = gh->buckets[bucket_index];
465 e->key = key;
466 gh->buckets[bucket_index] = e;
467
468 ghash_buckets_expand(gh, ++gh->nentries, false);
469}
470
474BLI_INLINE void ghash_insert_ex_keyonly(GHash *gh, void *key, const uint bucket_index)
475{
477
478 BLI_assert((gh->flag & GHASH_FLAG_ALLOW_DUPES) || (BLI_ghash_haskey(gh, key) == 0));
479 BLI_assert((gh->flag & GHASH_FLAG_IS_GSET) != 0);
480
481 e->next = gh->buckets[bucket_index];
482 e->key = key;
483 gh->buckets[bucket_index] = e;
484
485 ghash_buckets_expand(gh, ++gh->nentries, false);
486}
487
488BLI_INLINE void ghash_insert(GHash *gh, void *key, void *val)
489{
490 const uint hash = ghash_keyhash(gh, key);
491 const uint bucket_index = ghash_bucket_index(gh, hash);
492
493 ghash_insert_ex(gh, key, val, bucket_index);
494}
495
497 void *key,
498 void *val,
499 const bool override,
500 GHashKeyFreeFP keyfreefp,
501 GHashValFreeFP valfreefp)
502{
503 const uint hash = ghash_keyhash(gh, key);
504 const uint bucket_index = ghash_bucket_index(gh, hash);
505 GHashEntry *e = (GHashEntry *)ghash_lookup_entry_ex(gh, key, bucket_index);
506
507 BLI_assert(!(gh->flag & GHASH_FLAG_IS_GSET));
508
509 if (e) {
510 if (override) {
511 if (keyfreefp) {
512 keyfreefp(e->e.key);
513 }
514 if (valfreefp) {
515 valfreefp(e->val);
516 }
517 e->e.key = key;
518 e->val = val;
519 }
520 return false;
521 }
522 ghash_insert_ex(gh, key, val, bucket_index);
523 return true;
524}
525
527 void *key,
528 const bool override,
529 GHashKeyFreeFP keyfreefp)
530{
531 const uint hash = ghash_keyhash(gh, key);
532 const uint bucket_index = ghash_bucket_index(gh, hash);
533 Entry *e = ghash_lookup_entry_ex(gh, key, bucket_index);
534
535 BLI_assert((gh->flag & GHASH_FLAG_IS_GSET) != 0);
536
537 if (e) {
538 if (override) {
539 if (keyfreefp) {
540 keyfreefp(e->key);
541 }
542 e->key = key;
543 }
544 return false;
545 }
546 ghash_insert_ex_keyonly(gh, key, bucket_index);
547 return true;
548}
549
554 const void *key,
555 GHashKeyFreeFP keyfreefp,
556 GHashValFreeFP valfreefp,
557 const uint bucket_index)
558{
559 Entry *e_prev;
560 Entry *e = ghash_lookup_entry_prev_ex(gh, key, &e_prev, bucket_index);
561
562 BLI_assert(!valfreefp || !(gh->flag & GHASH_FLAG_IS_GSET));
563
564 if (e) {
565 if (keyfreefp) {
566 keyfreefp(e->key);
567 }
568 if (valfreefp) {
569 valfreefp(((GHashEntry *)e)->val);
570 }
571
572 if (e_prev) {
573 e_prev->next = e->next;
574 }
575 else {
576 gh->buckets[bucket_index] = e->next;
577 }
578
579 ghash_buckets_contract(gh, --gh->nentries, false, false);
580 }
581
582 return e;
583}
584
589{
590 uint curr_bucket = state->curr_bucket;
591 if (gh->nentries == 0) {
592 return NULL;
593 }
594
595 /* NOTE: using first_bucket_index here allows us to avoid potential
596 * huge number of loops over buckets,
597 * in case we are popping from a large ghash with few items in it... */
598 curr_bucket = ghash_find_next_bucket_index(gh, curr_bucket);
599
600 Entry *e = gh->buckets[curr_bucket];
601 BLI_assert(e);
602
603 ghash_remove_ex(gh, e->key, NULL, NULL, curr_bucket);
604
605 state->curr_bucket = curr_bucket;
606 return e;
607}
608
612static void ghash_free_cb(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
613{
614 uint i;
615
616 BLI_assert(keyfreefp || valfreefp);
617 BLI_assert(!valfreefp || !(gh->flag & GHASH_FLAG_IS_GSET));
618
619 for (i = 0; i < gh->nbuckets; i++) {
620 Entry *e;
621
622 for (e = gh->buckets[i]; e; e = e->next) {
623 if (keyfreefp) {
624 keyfreefp(e->key);
625 }
626 if (valfreefp) {
627 valfreefp(((GHashEntry *)e)->val);
628 }
629 }
630 }
631}
632
636static GHash *ghash_copy(const GHash *gh, GHashKeyCopyFP keycopyfp, GHashValCopyFP valcopyfp)
637{
638 GHash *gh_new;
639 uint i;
640 /* This allows us to be sure to get the same number of buckets in gh_new as in ghash. */
641 const uint reserve_nentries_new = MAX2(GHASH_LIMIT_GROW(gh->nbuckets) - 1, gh->nentries);
642
643 BLI_assert(!valcopyfp || !(gh->flag & GHASH_FLAG_IS_GSET));
644
645 gh_new = ghash_new(gh->hashfp, gh->cmpfp, __func__, 0, gh->flag);
646 ghash_buckets_expand(gh_new, reserve_nentries_new, false);
647
648 BLI_assert(gh_new->nbuckets == gh->nbuckets);
649
650 for (i = 0; i < gh->nbuckets; i++) {
651 Entry *e;
652
653 for (e = gh->buckets[i]; e; e = e->next) {
654 Entry *e_new = BLI_mempool_alloc(gh_new->entrypool);
655 ghash_entry_copy(gh_new, e_new, gh, e, keycopyfp, valcopyfp);
656
657 /* Warning!
658 * This means entries in buckets in new copy will be in reversed order!
659 * This shall not be an issue though, since order should never be assumed in ghash. */
660
661 /* NOTE: We can use 'i' here, since we are sure that
662 * 'gh' and 'gh_new' have the same number of buckets! */
663 e_new->next = gh_new->buckets[i];
664 gh_new->buckets[i] = e_new;
665 }
666 }
667 gh_new->nentries = gh->nentries;
668
669 return gh_new;
670}
671
674/* -------------------------------------------------------------------- */
679 GHashCmpFP cmpfp,
680 const char *info,
681 const uint nentries_reserve)
682{
683 return ghash_new(hashfp, cmpfp, info, nentries_reserve, 0);
684}
685
686GHash *BLI_ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info)
687{
688 return BLI_ghash_new_ex(hashfp, cmpfp, info, 0);
689}
690
691GHash *BLI_ghash_copy(const GHash *gh, GHashKeyCopyFP keycopyfp, GHashValCopyFP valcopyfp)
692{
693 return ghash_copy(gh, keycopyfp, valcopyfp);
694}
695
696void BLI_ghash_reserve(GHash *gh, const uint nentries_reserve)
697{
698 ghash_buckets_expand(gh, nentries_reserve, true);
699 ghash_buckets_contract(gh, nentries_reserve, true, false);
700}
701
703{
704 return gh->nentries;
705}
706
707void BLI_ghash_insert(GHash *gh, void *key, void *val)
708{
709 ghash_insert(gh, key, val);
710}
711
713 GHash *gh, void *key, void *val, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
714{
715 return ghash_insert_safe(gh, key, val, true, keyfreefp, valfreefp);
716}
717
718void *BLI_ghash_replace_key(GHash *gh, void *key)
719{
720 const uint hash = ghash_keyhash(gh, key);
721 const uint bucket_index = ghash_bucket_index(gh, hash);
722 GHashEntry *e = (GHashEntry *)ghash_lookup_entry_ex(gh, key, bucket_index);
723 if (e != NULL) {
724 void *key_prev = e->e.key;
725 e->e.key = key;
726 return key_prev;
727 }
728 return NULL;
729}
730
731void *BLI_ghash_lookup(const GHash *gh, const void *key)
732{
734 BLI_assert(!(gh->flag & GHASH_FLAG_IS_GSET));
735 return e ? e->val : NULL;
736}
737
738void *BLI_ghash_lookup_default(const GHash *gh, const void *key, void *val_default)
739{
741 BLI_assert(!(gh->flag & GHASH_FLAG_IS_GSET));
742 return e ? e->val : val_default;
743}
744
745void **BLI_ghash_lookup_p(GHash *gh, const void *key)
746{
748 BLI_assert(!(gh->flag & GHASH_FLAG_IS_GSET));
749 return e ? &e->val : NULL;
750}
751
752bool BLI_ghash_ensure_p(GHash *gh, void *key, void ***r_val)
753{
754 const uint hash = ghash_keyhash(gh, key);
755 const uint bucket_index = ghash_bucket_index(gh, hash);
756 GHashEntry *e = (GHashEntry *)ghash_lookup_entry_ex(gh, key, bucket_index);
757 const bool haskey = (e != NULL);
758
759 if (!haskey) {
761 ghash_insert_ex_keyonly_entry(gh, key, bucket_index, (Entry *)e);
762 }
763
764 *r_val = &e->val;
765 return haskey;
766}
767
768bool BLI_ghash_ensure_p_ex(GHash *gh, const void *key, void ***r_key, void ***r_val)
769{
770 const uint hash = ghash_keyhash(gh, key);
771 const uint bucket_index = ghash_bucket_index(gh, hash);
772 GHashEntry *e = (GHashEntry *)ghash_lookup_entry_ex(gh, key, bucket_index);
773 const bool haskey = (e != NULL);
774
775 if (!haskey) {
776 /* Pass 'key' in case we resize. */
778 ghash_insert_ex_keyonly_entry(gh, (void *)key, bucket_index, (Entry *)e);
779 e->e.key = NULL; /* caller must re-assign */
780 }
781
782 *r_key = &e->e.key;
783 *r_val = &e->val;
784 return haskey;
785}
786
788 const void *key,
789 GHashKeyFreeFP keyfreefp,
790 GHashValFreeFP valfreefp)
791{
792 const uint hash = ghash_keyhash(gh, key);
793 const uint bucket_index = ghash_bucket_index(gh, hash);
794 Entry *e = ghash_remove_ex(gh, key, keyfreefp, valfreefp, bucket_index);
795 if (e) {
797 return true;
798 }
799 return false;
800}
801
802void *BLI_ghash_popkey(GHash *gh, const void *key, GHashKeyFreeFP keyfreefp)
803{
804 /* Same as #BLI_ghash_remove but return the value,
805 * no free value argument since it will be returned. */
806
807 const uint hash = ghash_keyhash(gh, key);
808 const uint bucket_index = ghash_bucket_index(gh, hash);
809 GHashEntry *e = (GHashEntry *)ghash_remove_ex(gh, key, keyfreefp, NULL, bucket_index);
810 BLI_assert(!(gh->flag & GHASH_FLAG_IS_GSET));
811 if (e) {
812 void *val = e->val;
814 return val;
815 }
816 return NULL;
817}
818
819bool BLI_ghash_haskey(const GHash *gh, const void *key)
820{
821 return (ghash_lookup_entry(gh, key) != NULL);
822}
823
824bool BLI_ghash_pop(GHash *gh, GHashIterState *state, void **r_key, void **r_val)
825{
827
828 BLI_assert(!(gh->flag & GHASH_FLAG_IS_GSET));
829
830 if (e) {
831 *r_key = e->e.key;
832 *r_val = e->val;
833
835 return true;
836 }
837
838 *r_key = *r_val = NULL;
839 return false;
840}
841
843 GHashKeyFreeFP keyfreefp,
844 GHashValFreeFP valfreefp,
845 const uint nentries_reserve)
846{
847 if (keyfreefp || valfreefp) {
848 ghash_free_cb(gh, keyfreefp, valfreefp);
849 }
850
851 ghash_buckets_reset(gh, nentries_reserve);
852 BLI_mempool_clear_ex(gh->entrypool, nentries_reserve ? (int)nentries_reserve : -1);
853}
854
855void BLI_ghash_clear(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
856{
857 BLI_ghash_clear_ex(gh, keyfreefp, valfreefp, 0);
858}
859
860void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
861{
863 if (keyfreefp || valfreefp) {
864 ghash_free_cb(gh, keyfreefp, valfreefp);
865 }
866
867 MEM_freeN(gh->buckets);
869 MEM_freeN(gh);
870}
871
873{
874 gh->flag |= flag;
875}
876
878{
879 gh->flag &= ~flag;
880}
881
884/* -------------------------------------------------------------------- */
889{
890 GHashIterator *ghi = MEM_mallocN(sizeof(*ghi), "ghash iterator");
891 BLI_ghashIterator_init(ghi, gh);
892 return ghi;
893}
894
896{
897 ghi->gh = gh;
898 ghi->curEntry = NULL;
899 ghi->curBucket = UINT_MAX; /* wraps to zero */
900 if (gh->nentries) {
901 do {
902 ghi->curBucket++;
903 if (UNLIKELY(ghi->curBucket == ghi->gh->nbuckets)) {
904 break;
905 }
906 ghi->curEntry = ghi->gh->buckets[ghi->curBucket];
907 } while (!ghi->curEntry);
908 }
909}
910
912{
913 if (ghi->curEntry) {
914 ghi->curEntry = ghi->curEntry->next;
915 while (!ghi->curEntry) {
916 ghi->curBucket++;
917 if (ghi->curBucket == ghi->gh->nbuckets) {
918 break;
919 }
920 ghi->curEntry = ghi->gh->buckets[ghi->curBucket];
921 }
922 }
923}
924
926{
927 MEM_freeN(ghi);
928}
929
932/* -------------------------------------------------------------------- */
937 GSetCmpFP cmpfp,
938 const char *info,
939 const uint nentries_reserve)
940{
941 return (GSet *)ghash_new(hashfp, cmpfp, info, nentries_reserve, GHASH_FLAG_IS_GSET);
942}
943
944GSet *BLI_gset_new(GSetHashFP hashfp, GSetCmpFP cmpfp, const char *info)
945{
946 return BLI_gset_new_ex(hashfp, cmpfp, info, 0);
947}
948
949GSet *BLI_gset_copy(const GSet *gs, GHashKeyCopyFP keycopyfp)
950{
951 return (GSet *)ghash_copy((const GHash *)gs, keycopyfp, NULL);
952}
953
955{
956 return ((GHash *)gs)->nentries;
957}
958
959void BLI_gset_insert(GSet *gs, void *key)
960{
961 const uint hash = ghash_keyhash((GHash *)gs, key);
962 const uint bucket_index = ghash_bucket_index((GHash *)gs, hash);
963 ghash_insert_ex_keyonly((GHash *)gs, key, bucket_index);
964}
965
966bool BLI_gset_add(GSet *gs, void *key)
967{
968 return ghash_insert_safe_keyonly((GHash *)gs, key, false, NULL);
969}
970
971bool BLI_gset_ensure_p_ex(GSet *gs, const void *key, void ***r_key)
972{
973 const uint hash = ghash_keyhash((GHash *)gs, key);
974 const uint bucket_index = ghash_bucket_index((GHash *)gs, hash);
975 GSetEntry *e = (GSetEntry *)ghash_lookup_entry_ex((const GHash *)gs, key, bucket_index);
976 const bool haskey = (e != NULL);
977
978 if (!haskey) {
979 /* Pass 'key' in case we resize */
980 e = BLI_mempool_alloc(((GHash *)gs)->entrypool);
981 ghash_insert_ex_keyonly_entry((GHash *)gs, (void *)key, bucket_index, (Entry *)e);
982 e->key = NULL; /* caller must re-assign */
983 }
984
985 *r_key = &e->key;
986 return haskey;
987}
988
989bool BLI_gset_reinsert(GSet *gs, void *key, GSetKeyFreeFP keyfreefp)
990{
991 return ghash_insert_safe_keyonly((GHash *)gs, key, true, keyfreefp);
992}
993
994void *BLI_gset_replace_key(GSet *gs, void *key)
995{
996 return BLI_ghash_replace_key((GHash *)gs, key);
997}
998
999bool BLI_gset_remove(GSet *gs, const void *key, GSetKeyFreeFP keyfreefp)
1000{
1001 return BLI_ghash_remove((GHash *)gs, key, keyfreefp, NULL);
1002}
1003
1004bool BLI_gset_haskey(const GSet *gs, const void *key)
1005{
1006 return (ghash_lookup_entry((const GHash *)gs, key) != NULL);
1007}
1008
1009bool BLI_gset_pop(GSet *gs, GSetIterState *state, void **r_key)
1010{
1012
1013 if (e) {
1014 *r_key = e->key;
1015
1016 BLI_mempool_free(((GHash *)gs)->entrypool, e);
1017 return true;
1018 }
1019
1020 *r_key = NULL;
1021 return false;
1022}
1023
1024void BLI_gset_clear_ex(GSet *gs, GSetKeyFreeFP keyfreefp, const uint nentries_reserve)
1025{
1026 BLI_ghash_clear_ex((GHash *)gs, keyfreefp, NULL, nentries_reserve);
1027}
1028
1030{
1031 BLI_ghash_clear((GHash *)gs, keyfreefp, NULL);
1032}
1033
1035{
1036 BLI_ghash_free((GHash *)gs, keyfreefp, NULL);
1037}
1038
1040{
1041 ((GHash *)gs)->flag |= flag;
1042}
1043
1045{
1046 ((GHash *)gs)->flag &= ~flag;
1047}
1048
1051/* -------------------------------------------------------------------- */
1058void *BLI_gset_lookup(const GSet *gs, const void *key)
1059{
1060 Entry *e = ghash_lookup_entry((const GHash *)gs, key);
1061 return e ? e->key : NULL;
1062}
1063
1064void *BLI_gset_pop_key(GSet *gs, const void *key)
1065{
1066 const uint hash = ghash_keyhash((GHash *)gs, key);
1067 const uint bucket_index = ghash_bucket_index((GHash *)gs, hash);
1068 Entry *e = ghash_remove_ex((GHash *)gs, key, NULL, NULL, bucket_index);
1069 if (e) {
1070 void *key_ret = e->key;
1071 BLI_mempool_free(((GHash *)gs)->entrypool, e);
1072 return key_ret;
1073 }
1074 return NULL;
1075}
1076
1079/* -------------------------------------------------------------------- */
1084{
1085 return (int)gh->nbuckets;
1086}
1088{
1089 return BLI_ghash_buckets_len((const GHash *)gs);
1090}
1091
1093 double *r_load,
1094 double *r_variance,
1095 double *r_prop_empty_buckets,
1096 double *r_prop_overloaded_buckets,
1097 int *r_biggest_bucket)
1098{
1099 double mean;
1100 uint i;
1101
1102 if (gh->nentries == 0) {
1103 if (r_load) {
1104 *r_load = 0.0;
1105 }
1106 if (r_variance) {
1107 *r_variance = 0.0;
1108 }
1109 if (r_prop_empty_buckets) {
1110 *r_prop_empty_buckets = 1.0;
1111 }
1112 if (r_prop_overloaded_buckets) {
1113 *r_prop_overloaded_buckets = 0.0;
1114 }
1115 if (r_biggest_bucket) {
1116 *r_biggest_bucket = 0;
1117 }
1118
1119 return 0.0;
1120 }
1121
1122 mean = (double)gh->nentries / (double)gh->nbuckets;
1123 if (r_load) {
1124 *r_load = mean;
1125 }
1126 if (r_biggest_bucket) {
1127 *r_biggest_bucket = 0;
1128 }
1129
1130 if (r_variance) {
1131 /* We already know our mean (i.e. load factor), easy to compute variance.
1132 * See https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Two-pass_algorithm
1133 */
1134 double sum = 0.0;
1135 for (i = 0; i < gh->nbuckets; i++) {
1136 int count = 0;
1137 Entry *e;
1138 for (e = gh->buckets[i]; e; e = e->next) {
1139 count++;
1140 }
1141 sum += ((double)count - mean) * ((double)count - mean);
1142 }
1143 *r_variance = sum / (double)(gh->nbuckets - 1);
1144 }
1145
1146 {
1147 uint64_t sum = 0;
1148 uint64_t overloaded_buckets_threshold = (uint64_t)max_ii(GHASH_LIMIT_GROW(1), 1);
1149 uint64_t sum_overloaded = 0;
1150 uint64_t sum_empty = 0;
1151
1152 for (i = 0; i < gh->nbuckets; i++) {
1153 uint64_t count = 0;
1154 Entry *e;
1155 for (e = gh->buckets[i]; e; e = e->next) {
1156 count++;
1157 }
1158 if (r_biggest_bucket) {
1159 *r_biggest_bucket = max_ii(*r_biggest_bucket, (int)count);
1160 }
1161 if (r_prop_overloaded_buckets && (count > overloaded_buckets_threshold)) {
1162 sum_overloaded++;
1163 }
1164 if (r_prop_empty_buckets && !count) {
1165 sum_empty++;
1166 }
1167 sum += count * (count + 1);
1168 }
1169 if (r_prop_overloaded_buckets) {
1170 *r_prop_overloaded_buckets = (double)sum_overloaded / (double)gh->nbuckets;
1171 }
1172 if (r_prop_empty_buckets) {
1173 *r_prop_empty_buckets = (double)sum_empty / (double)gh->nbuckets;
1174 }
1175 return ((double)sum * (double)gh->nbuckets /
1176 ((double)gh->nentries * (gh->nentries + 2 * gh->nbuckets - 1)));
1177 }
1178}
1180 double *r_load,
1181 double *r_variance,
1182 double *r_prop_empty_buckets,
1183 double *r_prop_overloaded_buckets,
1184 int *r_biggest_bucket)
1185{
1186 return BLI_ghash_calc_quality_ex((const GHash *)gs,
1187 r_load,
1188 r_variance,
1189 r_prop_empty_buckets,
1190 r_prop_overloaded_buckets,
1191 r_biggest_bucket);
1192}
1193
1195{
1197}
1199{
1201}
1202
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_STATIC_ASSERT(a, msg)
Definition BLI_assert.h:87
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_INLINE
#define GHASH_MAX_SIZE
Definition BLI_ghash.c:45
BLI_INLINE void ghash_entry_copy(GHash *gh_dst, Entry *dst, const GHash *gh_src, const Entry *src, GHashKeyCopyFP keycopyfp, GHashValCopyFP valcopyfp)
Definition BLI_ghash.c:104
BLI_INLINE Entry * ghash_lookup_entry_prev_ex(GHash *gh, const void *key, Entry **r_e_prev, const uint bucket_index)
Definition BLI_ghash.c:385
GHashIterator * BLI_ghashIterator_new(GHash *gh)
Definition BLI_ghash.c:888
BLI_INLINE Entry * ghash_lookup_entry(const GHash *gh, const void *key)
Definition BLI_ghash.c:406
bool BLI_ghash_pop(GHash *gh, GHashIterState *state, void **r_key, void **r_val)
Definition BLI_ghash.c:824
static Entry * ghash_pop(GHash *gh, GHashIterState *state)
Definition BLI_ghash.c:588
static void ghash_buckets_resize(GHash *gh, const uint nbuckets)
Definition BLI_ghash.c:180
bool BLI_gset_ensure_p_ex(GSet *gs, const void *key, void ***r_key)
Definition BLI_ghash.c:971
bool BLI_ghash_reinsert(GHash *gh, void *key, void *val, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.c:712
void BLI_ghashIterator_step(GHashIterator *ghi)
Definition BLI_ghash.c:911
bool BLI_ghash_ensure_p_ex(GHash *gh, const void *key, void ***r_key, void ***r_val)
Definition BLI_ghash.c:768
void BLI_ghash_clear(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.c:855
BLI_INLINE bool ghash_insert_safe_keyonly(GHash *gh, void *key, const bool override, GHashKeyFreeFP keyfreefp)
Definition BLI_ghash.c:526
void BLI_ghashIterator_free(GHashIterator *ghi)
Definition BLI_ghash.c:925
uint BLI_gset_len(const GSet *gs)
Definition BLI_ghash.c:954
double BLI_gset_calc_quality(const GSet *gs)
Definition BLI_ghash.c:1198
static void ghash_buckets_contract(GHash *gh, const uint nentries, const bool user_defined, const bool force_shrink)
Definition BLI_ghash.c:288
void * BLI_gset_replace_key(GSet *gs, void *key)
Definition BLI_ghash.c:994
void BLI_ghash_clear_ex(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp, const uint nentries_reserve)
Definition BLI_ghash.c:842
#define GHASH_ENTRY_SIZE(_is_gset)
Definition BLI_ghash.c:78
int BLI_ghash_buckets_len(const GHash *gh)
Definition BLI_ghash.c:1083
struct GHashEntry GHashEntry
BLI_INLINE void ghash_insert(GHash *gh, void *key, void *val)
Definition BLI_ghash.c:488
BLI_INLINE void ghash_buckets_reset(GHash *gh, const uint nentries)
Definition BLI_ghash.c:337
void BLI_ghash_reserve(GHash *gh, const uint nentries_reserve)
Definition BLI_ghash.c:696
void BLI_gset_clear(GSet *gs, GSetKeyFreeFP keyfreefp)
Definition BLI_ghash.c:1029
void BLI_gset_flag_clear(GSet *gs, uint flag)
Definition BLI_ghash.c:1044
struct Entry Entry
BLI_INLINE void ghash_insert_ex_keyonly(GHash *gh, void *key, const uint bucket_index)
Definition BLI_ghash.c:474
void * BLI_ghash_popkey(GHash *gh, const void *key, GHashKeyFreeFP keyfreefp)
Definition BLI_ghash.c:802
void BLI_gset_clear_ex(GSet *gs, GSetKeyFreeFP keyfreefp, const uint nentries_reserve)
Definition BLI_ghash.c:1024
double BLI_ghash_calc_quality_ex(const GHash *gh, double *r_load, double *r_variance, double *r_prop_empty_buckets, double *r_prop_overloaded_buckets, int *r_biggest_bucket)
Definition BLI_ghash.c:1092
BLI_INLINE Entry * ghash_lookup_entry_ex(const GHash *gh, const void *key, const uint bucket_index)
Definition BLI_ghash.c:365
BLI_INLINE uint ghash_find_next_bucket_index(const GHash *gh, uint curr_bucket)
Definition BLI_ghash.c:155
void * BLI_gset_pop_key(GSet *gs, const void *key)
Definition BLI_ghash.c:1064
GHash * BLI_ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info)
Definition BLI_ghash.c:686
void BLI_gset_flag_set(GSet *gs, uint flag)
Definition BLI_ghash.c:1039
GHash * BLI_ghash_copy(const GHash *gh, GHashKeyCopyFP keycopyfp, GHashValCopyFP valcopyfp)
Definition BLI_ghash.c:691
BLI_INLINE bool ghash_insert_safe(GHash *gh, void *key, void *val, const bool override, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.c:496
void BLI_ghash_flag_clear(GHash *gh, uint flag)
Definition BLI_ghash.c:877
static Entry * ghash_remove_ex(GHash *gh, const void *key, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp, const uint bucket_index)
Definition BLI_ghash.c:553
bool BLI_gset_haskey(const GSet *gs, const void *key)
Definition BLI_ghash.c:1004
void BLI_gset_insert(GSet *gs, void *key)
Definition BLI_ghash.c:959
BLI_INLINE uint ghash_keyhash(const GHash *gh, const void *key)
Definition BLI_ghash.c:127
static GHash * ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info, const uint nentries_reserve, const uint flag)
Definition BLI_ghash.c:413
double BLI_ghash_calc_quality(const GHash *gh)
Definition BLI_ghash.c:1194
#define GHASH_LIMIT_SHRINK(_nbkt)
Definition BLI_ghash.c:61
bool BLI_ghash_haskey(const GHash *gh, const void *key)
Definition BLI_ghash.c:819
static const uint hashsizes[]
Definition BLI_ghash.c:38
bool BLI_gset_reinsert(GSet *gs, void *key, GSetKeyFreeFP keyfreefp)
Definition BLI_ghash.c:989
GSet * BLI_gset_new_ex(GSetHashFP hashfp, GSetCmpFP cmpfp, const char *info, const uint nentries_reserve)
Definition BLI_ghash.c:936
uint BLI_ghash_len(const GHash *gh)
Definition BLI_ghash.c:702
BLI_INLINE uint ghash_bucket_index(const GHash *gh, const uint hash)
Definition BLI_ghash.c:143
int BLI_gset_buckets_len(const GSet *gs)
Definition BLI_ghash.c:1087
void * BLI_ghash_lookup(const GHash *gh, const void *key)
Definition BLI_ghash.c:731
void * BLI_gset_lookup(const GSet *gs, const void *key)
Definition BLI_ghash.c:1058
GSet * BLI_gset_new(GSetHashFP hashfp, GSetCmpFP cmpfp, const char *info)
Definition BLI_ghash.c:944
BLI_INLINE void ghash_insert_ex(GHash *gh, void *key, void *val, const uint bucket_index)
Definition BLI_ghash.c:439
void ** BLI_ghash_lookup_p(GHash *gh, const void *key)
Definition BLI_ghash.c:745
#define GHASH_LIMIT_GROW(_nbkt)
Definition BLI_ghash.c:60
void BLI_ghash_flag_set(GHash *gh, uint flag)
Definition BLI_ghash.c:872
bool BLI_ghash_remove(GHash *gh, const void *key, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.c:787
double BLI_gset_calc_quality_ex(const GSet *gs, double *r_load, double *r_variance, double *r_prop_empty_buckets, double *r_prop_overloaded_buckets, int *r_biggest_bucket)
Definition BLI_ghash.c:1179
Entry GSetEntry
Definition BLI_ghash.c:76
BLI_INLINE void ghash_insert_ex_keyonly_entry(GHash *gh, void *key, const uint bucket_index, Entry *e)
Definition BLI_ghash.c:457
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition BLI_ghash.c:707
BLI_INLINE uint ghash_entryhash(const GHash *gh, const Entry *e)
Definition BLI_ghash.c:135
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.c:860
bool BLI_ghash_ensure_p(GHash *gh, void *key, void ***r_val)
Definition BLI_ghash.c:752
static void ghash_free_cb(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.c:612
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp)
Definition BLI_ghash.c:1034
void BLI_ghashIterator_init(GHashIterator *ghi, GHash *gh)
Definition BLI_ghash.c:895
GSet * BLI_gset_copy(const GSet *gs, GHashKeyCopyFP keycopyfp)
Definition BLI_ghash.c:949
static GHash * ghash_copy(const GHash *gh, GHashKeyCopyFP keycopyfp, GHashValCopyFP valcopyfp)
Definition BLI_ghash.c:636
void * BLI_ghash_lookup_default(const GHash *gh, const void *key, void *val_default)
Definition BLI_ghash.c:738
bool BLI_gset_add(GSet *gs, void *key)
Definition BLI_ghash.c:966
void * BLI_ghash_replace_key(GHash *gh, void *key)
Definition BLI_ghash.c:718
bool BLI_gset_pop(GSet *gs, GSetIterState *state, void **r_key)
Definition BLI_ghash.c:1009
GHash * BLI_ghash_new_ex(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info, const uint nentries_reserve)
Definition BLI_ghash.c:678
bool BLI_gset_remove(GSet *gs, const void *key, GSetKeyFreeFP keyfreefp)
Definition BLI_ghash.c:999
static void ghash_buckets_expand(GHash *gh, const uint nentries, const bool user_defined)
Definition BLI_ghash.c:249
struct GSet GSet
Definition BLI_ghash.h:341
GHashHashFP GSetHashFP
Definition BLI_ghash.h:343
bool(* GHashCmpFP)(const void *a, const void *b)
Definition BLI_ghash.h:37
void *(* GHashValCopyFP)(const void *val)
Definition BLI_ghash.h:41
void *(* GHashKeyCopyFP)(const void *key)
Definition BLI_ghash.h:40
GHashKeyFreeFP GSetKeyFreeFP
Definition BLI_ghash.h:345
unsigned int(* GHashHashFP)(const void *key)
Definition BLI_ghash.h:35
void(* GHashKeyFreeFP)(void *key)
Definition BLI_ghash.h:38
void(* GHashValFreeFP)(void *val)
Definition BLI_ghash.h:39
GHashCmpFP GSetCmpFP
Definition BLI_ghash.h:344
@ GHASH_FLAG_ALLOW_DUPES
Definition BLI_ghash.h:56
@ GHASH_FLAG_ALLOW_SHRINK
Definition BLI_ghash.h:57
MINLINE int max_ii(int a, int b)
void * BLI_mempool_alloc(BLI_mempool *pool) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1)
void void BLI_mempool_clear_ex(BLI_mempool *pool, int elem_num_reserve) ATTR_NONNULL(1)
void BLI_mempool_free(BLI_mempool *pool, void *addr) ATTR_NONNULL(1
BLI_mempool * BLI_mempool_create(unsigned int esize, unsigned int elem_num, unsigned int pchunk, unsigned int flag) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL
int BLI_mempool_len(const BLI_mempool *pool) ATTR_NONNULL(1)
@ BLI_MEMPOOL_NOP
Definition BLI_mempool.h:86
void BLI_mempool_destroy(BLI_mempool *pool) ATTR_NONNULL(1)
unsigned int uint
#define ARRAY_SIZE(arr)
#define MAX2(a, b)
#define UNLIKELY(x)
#define LIKELY(x)
typedef double(DMatrix)[4][4]
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
static T sum(const btAlignedObjectArray< T > &items)
#define NULL
#define UINT_MAX
Definition hash_md5.cc:44
int count
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
static ulong state[N]
#define hash
Definition noise.c:154
unsigned __int64 uint64_t
Definition stdint.h:90
struct BMEdge * e
struct Entry * next
Definition BLI_ghash.c:65
void * key
Definition BLI_ghash.c:67
Entry e
Definition BLI_ghash.c:71
void * val
Definition BLI_ghash.c:73
GHash * gh
Definition BLI_ghash.h:46
struct Entry * curEntry
Definition BLI_ghash.h:47
unsigned int curBucket
Definition BLI_ghash.h:48
GHashHashFP hashfp
Definition BLI_ghash.c:81
uint size_min
Definition BLI_ghash.c:89
uint limit_shrink
Definition BLI_ghash.c:87
uint flag
Definition BLI_ghash.c:95
uint limit_grow
Definition BLI_ghash.c:87
uint cursize
Definition BLI_ghash.c:89
BLI_mempool * entrypool
Definition BLI_ghash.c:85
uint nbuckets
Definition BLI_ghash.c:86
GHashCmpFP cmpfp
Definition BLI_ghash.c:82
uint nentries
Definition BLI_ghash.c:94
Entry ** buckets
Definition BLI_ghash.c:84
uint8_t flag
Definition wm_window.cc:138