diff options
author | Campbell Barton <ideasman42@gmail.com> | 2015-04-06 12:55:08 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2015-04-06 13:33:02 +0300 |
commit | dd129125b6f6c9fff5ef4423b221cf68fedbd188 (patch) | |
tree | d88d9cd1ffb7130b2950c8e3c675d55b8ded183c /source | |
parent | 3639a70eaec1d49e5634f2cd5f6d4ecb7d79ef14 (diff) |
GHash: ensure function, avoids multiple lookups
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/blenlib/BLI_ghash.h | 1 | ||||
-rw-r--r-- | source/blender/blenlib/intern/BLI_ghash.c | 46 |
2 files changed, 47 insertions, 0 deletions
diff --git a/source/blender/blenlib/BLI_ghash.h b/source/blender/blenlib/BLI_ghash.h index 16d18ef1315..a00ddeefb2b 100644 --- a/source/blender/blenlib/BLI_ghash.h +++ b/source/blender/blenlib/BLI_ghash.h @@ -79,6 +79,7 @@ bool BLI_ghash_reinsert(GHash *gh, void *key, void *val, GHashKeyFreeFP keyfre void *BLI_ghash_lookup(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT; void *BLI_ghash_lookup_default(GHash *gh, const void *key, void *val_default) ATTR_WARN_UNUSED_RESULT; void **BLI_ghash_lookup_p(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT; +bool BLI_ghash_ensure_p(GHash *gh, void *key, void ***r_val) ATTR_WARN_UNUSED_RESULT; bool BLI_ghash_remove(GHash *gh, void *key, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp); void BLI_ghash_clear(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp); void BLI_ghash_clear_ex(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp, diff --git a/source/blender/blenlib/intern/BLI_ghash.c b/source/blender/blenlib/intern/BLI_ghash.c index 11848804194..dae7af6a927 100644 --- a/source/blender/blenlib/intern/BLI_ghash.c +++ b/source/blender/blenlib/intern/BLI_ghash.c @@ -445,6 +445,22 @@ BLI_INLINE void ghash_insert_ex( } /** + * Insert function that takes a pre-allocated entry. + */ +BLI_INLINE void ghash_insert_ex_keyonly_entry( + GHash *gh, void *key, const unsigned int bucket_index, + Entry *e) +{ + BLI_assert((gh->flag & GHASH_FLAG_ALLOW_DUPES) || (BLI_ghash_haskey(gh, key) == 0)); + + e->next = gh->buckets[bucket_index]; + e->key = key; + gh->buckets[bucket_index] = e; + + ghash_buckets_expand(gh, ++gh->nentries, false); +} + +/** * Insert function that doesn't set the value (use for GSet) */ BLI_INLINE void ghash_insert_ex_keyonly( @@ -721,6 +737,36 @@ void **BLI_ghash_lookup_p(GHash *gh, const void *key) } /** + * Ensure \a key is exists in \a gh. + * + * This handles the common situation where the caller needs ensure a key is added to \a gh, + * constructing a new value in the case the key isn't found. + * Otherwise use the existing value. + * + * Such situations typically incur multiple lookups, however this function + * avoids them by ensuring the key is added, + * returning a pointer to the value so it can be used or initialized by the caller. + * + * \returns true when the value didn't need to be added. + * (when false, the caller _must_ initialize the value). + */ +bool BLI_ghash_ensure_p(GHash *gh, void *key, void ***r_val) +{ + const unsigned int hash = ghash_keyhash(gh, key); + const unsigned int bucket_index = ghash_bucket_index(gh, hash); + GHashEntry *e = (GHashEntry *)ghash_lookup_entry_ex(gh, key, bucket_index); + const bool haskey = (e != NULL); + + if (!haskey) { + e = BLI_mempool_alloc(gh->entrypool); + ghash_insert_ex_keyonly_entry(gh, key, bucket_index, (Entry *)e); + } + + *r_val = &e->val; + return haskey; +} + +/** * Remove \a key from \a gh, or return false if the key wasn't found. * * \param key The key to remove. |