69
typedef struct EdgeEntry EdgeEntry;
71
typedef struct EdgeEntry {
72
struct EdgeEntry *next;
72
73
unsigned int v0, v1;
77
78
EdgeEntry **buckets;
78
79
BLI_mempool *epool;
79
unsigned int nbuckets, nentries, cursize;
80
unsigned int nbuckets, nentries;
81
unsigned int cursize, flag;
84
EdgeHash *BLI_edgehash_new(void)
86
EdgeHash *eh = MEM_callocN(sizeof(*eh), "EdgeHash");
85
/* -------------------------------------------------------------------- */
88
/** \name Internal Utility API
92
* Get the hash for a key.
94
BLI_INLINE unsigned int edgehash_keyhash(EdgeHash *eh, unsigned int v0, unsigned int v1)
98
return ((v0 * 39) ^ (v1 * 31)) % eh->nbuckets;
102
* Check if the number of items in the GHash is large enough to require more buckets.
104
BLI_INLINE bool edgehash_test_expand_buckets(const unsigned int nentries, const unsigned int nbuckets)
106
return (nentries > nbuckets * 3);
110
* Expand buckets to the next size up.
112
BLI_INLINE void edgehash_resize_buckets(EdgeHash *eh, const unsigned int nbuckets)
114
EdgeEntry **buckets_old = eh->buckets;
115
EdgeEntry **buckets_new;
116
const unsigned int nbuckets_old = eh->nbuckets;
120
BLI_assert(eh->nbuckets != nbuckets);
122
eh->nbuckets = nbuckets;
123
buckets_new = MEM_callocN(eh->nbuckets * sizeof(*eh->buckets), "eh buckets");
125
for (i = 0; i < nbuckets_old; i++) {
127
for (e = buckets_old[i]; e; e = e_next) {
128
const unsigned hash = edgehash_keyhash(eh, e->v0, e->v1);
130
e->next = buckets_new[hash];
131
buckets_new[hash] = e;
135
eh->buckets = buckets_new;
136
MEM_freeN(buckets_old);
140
* Increase initial bucket size to match a reserved ammount.
142
BLI_INLINE void edgehash_buckets_reserve(EdgeHash *eh, const unsigned int nentries_reserve)
144
while (edgehash_test_expand_buckets(nentries_reserve, eh->nbuckets)) {
145
eh->nbuckets = _ehash_hashsizes[++eh->cursize];
150
* Internal lookup function.
151
* Takes a hash argument to avoid calling #ghash_keyhash multiple times.
153
BLI_INLINE EdgeEntry *edgehash_lookup_entry_ex(EdgeHash *eh, unsigned int v0, unsigned int v1,
154
const unsigned int hash)
158
for (e = eh->buckets[hash]; e; e = e->next) {
159
if (UNLIKELY(v0 == e->v0 && v1 == e->v1)) {
167
* Internal lookup function. Only wraps #edgehash_lookup_entry_ex
169
BLI_INLINE EdgeEntry *edgehash_lookup_entry(EdgeHash *eh, unsigned int v0, unsigned int v1)
172
EDGE_ORD(v0, v1); /* ensure v0 is smaller */
173
hash = edgehash_keyhash(eh, v0, v1);
174
return edgehash_lookup_entry_ex(eh, v0, v1, hash);
178
static EdgeHash *edgehash_new(const char *info,
179
const unsigned int nentries_reserve,
180
const unsigned int entry_size)
182
EdgeHash *eh = MEM_mallocN(sizeof(*eh), info);
184
eh->nbuckets = _ehash_hashsizes[0]; /* eh->cursize */
89
eh->nbuckets = _ehash_hashsizes[eh->cursize];
91
eh->buckets = MEM_callocN(eh->nbuckets * sizeof(*eh->buckets), "eh buckets 2");
92
eh->epool = BLI_mempool_create(sizeof(EdgeEntry), 512, 512, BLI_MEMPOOL_SYSMALLOC);
189
/* if we have reserved the number of elements that this hash will contain */
190
if (nentries_reserve) {
191
edgehash_buckets_reserve(eh, nentries_reserve);
194
eh->buckets = MEM_callocN(eh->nbuckets * sizeof(*eh->buckets), "eh buckets");
195
eh->epool = BLI_mempool_create(entry_size, 512, 512, BLI_MEMPOOL_SYSMALLOC);
201
* Internal insert function.
202
* Takes a hash argument to avoid calling #edgehash_keyhash multiple times.
204
BLI_INLINE void edgehash_insert_ex(EdgeHash *eh, unsigned int v0, unsigned int v1, void *val,
207
EdgeEntry *e = BLI_mempool_alloc(eh->epool);
209
BLI_assert((eh->flag & EDGEHASH_FLAG_ALLOW_DUPES) || (BLI_edgehash_haskey(eh, v0, v1) == 0));
210
IS_EDGEHASH_ASSERT(eh);
212
/* this helps to track down errors with bad edge data */
214
BLI_assert(v0 != v1);
216
e->next = eh->buckets[hash];
220
eh->buckets[hash] = e;
222
if (UNLIKELY(edgehash_test_expand_buckets(++eh->nentries, eh->nbuckets))) {
223
edgehash_resize_buckets(eh, _ehash_hashsizes[++eh->cursize]);
228
* Insert function that doesn't set the value (use for EdgeSet)
230
BLI_INLINE void edgehash_insert_ex_keyonly(EdgeHash *eh, unsigned int v0, unsigned int v1,
233
EdgeEntry *e = BLI_mempool_alloc(eh->epool);
235
BLI_assert((eh->flag & EDGEHASH_FLAG_ALLOW_DUPES) || (BLI_edgehash_haskey(eh, v0, v1) == 0));
237
/* this helps to track down errors with bad edge data */
239
BLI_assert(v0 != v1);
241
e->next = eh->buckets[hash];
244
/* intentionally leave value unset */
245
eh->buckets[hash] = e;
247
if (UNLIKELY(edgehash_test_expand_buckets(++eh->nentries, eh->nbuckets))) {
248
edgehash_resize_buckets(eh, _ehash_hashsizes[++eh->cursize]);
252
BLI_INLINE void edgehash_insert(EdgeHash *eh, unsigned int v0, unsigned int v1, void *val)
255
EDGE_ORD(v0, v1); /* ensure v0 is smaller */
256
hash = edgehash_keyhash(eh, v0, v1);
257
edgehash_insert_ex(eh, v0, v1, val, hash);
261
* Run free callbacks for freeing entries.
263
static void edgehash_free_cb(EdgeHash *eh, EdgeHashFreeFP valfreefp)
267
BLI_assert(valfreefp);
269
for (i = 0; i < eh->nbuckets; i++) {
272
for (e = eh->buckets[i]; e; ) {
273
EdgeEntry *e_next = e->next;
275
if (valfreefp) valfreefp(e->val);
290
EdgeHash *BLI_edgehash_new_ex(const char *info,
291
const unsigned int nentries_reserve)
293
return edgehash_new(info,
298
EdgeHash *BLI_edgehash_new(const char *info)
300
return BLI_edgehash_new_ex(info, 0);
304
* Insert edge (\a v0, \a v1) into hash with given value, does
305
* not check for duplicates.
98
307
void BLI_edgehash_insert(EdgeHash *eh, unsigned int v0, unsigned int v1, void *val)
309
edgehash_insert(eh, v0, v1, val);
313
* Assign a new value to a key that may already be in edgehash.
315
bool BLI_edgehash_reinsert(EdgeHash *eh, unsigned int v0, unsigned int v1, void *val)
100
317
unsigned int hash;
101
EdgeEntry *e = BLI_mempool_alloc(eh->epool);
103
/* this helps to track down errors with bad edge data */
104
BLI_assert(v0 != v1);
320
IS_EDGEHASH_ASSERT(eh);
106
322
EDGE_ORD(v0, v1); /* ensure v0 is smaller */
108
hash = EDGE_HASH(v0, v1) % eh->nbuckets;
110
e->next = eh->buckets[hash];
114
eh->buckets[hash] = e;
116
if (UNLIKELY(++eh->nentries > eh->nbuckets / 2)) {
117
EdgeEntry **old = eh->buckets;
118
const unsigned int nold = eh->nbuckets;
121
eh->nbuckets = _ehash_hashsizes[++eh->cursize];
122
eh->buckets = MEM_callocN(eh->nbuckets * sizeof(*eh->buckets), "eh buckets");
124
for (i = 0; i < nold; i++) {
126
for (e = old[i]; e; e = e_next) {
128
hash = EDGE_HASH(e->v0, e->v1) % eh->nbuckets;
129
e->next = eh->buckets[hash];
130
eh->buckets[hash] = e;
323
hash = edgehash_keyhash(eh, v0, v1);
325
e = edgehash_lookup_entry_ex(eh, v0, v1, hash);
331
edgehash_insert_ex(eh, v0, v1, val, hash);
337
* Return pointer to value for given edge (\a v0, \a v1),
338
* or NULL if key does not exist in hash.
138
340
void **BLI_edgehash_lookup_p(EdgeHash *eh, unsigned int v0, unsigned int v1)
143
EDGE_ORD(v0, v1); /* ensure v0 is smaller */
145
hash = EDGE_HASH(v0, v1) % eh->nbuckets;
146
for (e = eh->buckets[hash]; e; e = e->next)
147
if (v0 == e->v0 && v1 == e->v1)
342
EdgeEntry *e = edgehash_lookup_entry(eh, v0, v1);
343
IS_EDGEHASH_ASSERT(eh);
344
return e ? &e->val : NULL;
348
* Return value for given edge (\a v0, \a v1), or NULL if
349
* if key does not exist in hash. (If need exists
350
* to differentiate between key-value being NULL and
351
* lack of key then see BLI_edgehash_lookup_p().
153
353
void *BLI_edgehash_lookup(EdgeHash *eh, unsigned int v0, unsigned int v1)
155
void **value_p = BLI_edgehash_lookup_p(eh, v0, v1);
157
return value_p ? *value_p : NULL;
355
EdgeEntry *e = edgehash_lookup_entry(eh, v0, v1);
356
IS_EDGEHASH_ASSERT(eh);
357
return e ? e->val : NULL;
361
* Return boolean true/false if edge (v0,v1) in hash.
160
363
bool BLI_edgehash_haskey(EdgeHash *eh, unsigned int v0, unsigned int v1)
162
return BLI_edgehash_lookup_p(eh, v0, v1) != NULL;
365
return (edgehash_lookup_entry(eh, v0, v1) != NULL);
369
* Return number of keys in hash.
165
371
int BLI_edgehash_size(EdgeHash *eh)
167
373
return (int)eh->nentries;
170
void BLI_edgehash_clear(EdgeHash *eh, EdgeHashFreeFP valfreefp)
377
* Remove all edges from hash.
379
void BLI_edgehash_clear_ex(EdgeHash *eh, EdgeHashFreeFP valfreefp,
380
const unsigned int nentries_reserve)
174
for (i = 0; i < eh->nbuckets; i++) {
177
for (e = eh->buckets[i]; e; ) {
178
EdgeEntry *n = e->next;
180
if (valfreefp) valfreefp(e->val);
181
BLI_mempool_free(eh->epool, e);
185
eh->buckets[i] = NULL;
383
edgehash_free_cb(eh, valfreefp);
385
eh->nbuckets = _ehash_hashsizes[0]; /* eh->cursize */
389
if (nentries_reserve) {
390
edgehash_buckets_reserve(eh, nentries_reserve);
393
MEM_freeN(eh->buckets);
394
eh->buckets = MEM_callocN(eh->nbuckets * sizeof(*eh->buckets), "eh buckets");
396
BLI_mempool_clear_ex(eh->epool, nentries_reserve ? (int)nentries_reserve : -1);
191
399
void BLI_edgehash_free(EdgeHash *eh, EdgeHashFreeFP valfreefp)
193
BLI_edgehash_clear(eh, valfreefp);
401
BLI_assert((int)eh->nentries == BLI_mempool_count(eh->epool));
404
edgehash_free_cb(eh, valfreefp);
195
406
BLI_mempool_destroy(eh->epool);
523
* Determine if an iterator is done.
262
525
bool BLI_edgehashIterator_isDone(EdgeHashIterator *ehi)
264
527
return (ehi->curEntry == NULL);
532
/* -------------------------------------------------------------------- */
535
/* Use edgehash API to give 'set' functionality */
537
/** \name EdgeSet Functions
539
EdgeSet *BLI_edgeset_new_ex(const char *info,
540
const unsigned int nentries_reserve)
542
EdgeSet *es = (EdgeSet *)edgehash_new(info,
544
sizeof(EdgeEntry) - sizeof(void *));
546
((EdgeHash *)es)->flag |= EDGEHASH_FLAG_IS_SET;
551
EdgeSet *BLI_edgeset_new(const char *info)
553
return BLI_edgeset_new_ex(info, 0);
556
int BLI_edgeset_size(EdgeSet *es)
558
return (int)((EdgeHash *)es)->nentries;
562
* Adds the key to the set (no checks for unique keys!).
563
* Matching #BLI_edgehash_insert
565
void BLI_edgeset_insert(EdgeSet *es, unsigned int v0, unsigned int v1)
568
EDGE_ORD(v0, v1); /* ensure v0 is smaller */
569
hash = edgehash_keyhash((EdgeHash *)es, v0, v1);
570
edgehash_insert_ex_keyonly((EdgeHash *)es, v0, v1, hash);
574
* Assign a new value to a key that may already be in edgehash.
576
bool BLI_edgeset_reinsert(EdgeSet *es, unsigned int v0, unsigned int v1)
581
EDGE_ORD(v0, v1); /* ensure v0 is smaller */
582
hash = edgehash_keyhash((EdgeHash *)es, v0, v1);
584
e = edgehash_lookup_entry_ex((EdgeHash *)es, v0, v1, hash);
589
edgehash_insert_ex_keyonly((EdgeHash *)es, v0, v1, hash);
594
bool BLI_edgeset_haskey(EdgeSet *es, unsigned int v0, unsigned int v1)
596
return (edgehash_lookup_entry((EdgeHash *)es, v0, v1) != NULL);
600
void BLI_edgeset_free(EdgeSet *es)
602
BLI_edgehash_free((EdgeHash *)es, NULL);