Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenlib/BLI_ghash.h')
-rw-r--r--source/blender/blenlib/BLI_ghash.h243
1 files changed, 241 insertions, 2 deletions
diff --git a/source/blender/blenlib/BLI_ghash.h b/source/blender/blenlib/BLI_ghash.h
index a2c5c6349a5..0194f9aad40 100644
--- a/source/blender/blenlib/BLI_ghash.h
+++ b/source/blender/blenlib/BLI_ghash.h
@@ -43,6 +43,10 @@ extern "C" {
# endif
#endif
+/* -------------------------------------------------------------------- */
+/** \name GHash Types
+ * \{ */
+
typedef unsigned int (*GHashHashFP)(const void *key);
/** returns false when equal */
typedef bool (*GHashCmpFP)(const void *a, const void *b);
@@ -74,53 +78,191 @@ enum {
#endif
};
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name GHash API
*
* Defined in `BLI_ghash.c`
* \{ */
+/**
+ * Creates a new, empty GHash.
+ *
+ * \param hashfp: Hash callback.
+ * \param cmpfp: Comparison callback.
+ * \param info: Identifier string for the GHash.
+ * \param nentries_reserve: Optionally reserve the number of members that the hash will hold.
+ * Use this to avoid resizing buckets if the size is known or can be closely approximated.
+ * \return An empty GHash.
+ */
GHash *BLI_ghash_new_ex(GHashHashFP hashfp,
GHashCmpFP cmpfp,
const char *info,
const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+/**
+ * Wraps #BLI_ghash_new_ex with zero entries reserved.
+ */
GHash *BLI_ghash_new(GHashHashFP hashfp,
GHashCmpFP cmpfp,
const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+/**
+ * Copy given GHash. Keys and values are also copied if relevant callback is provided,
+ * else pointers remain the same.
+ */
GHash *BLI_ghash_copy(const GHash *gh,
GHashKeyCopyFP keycopyfp,
GHashValCopyFP valcopyfp) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+/**
+ * Frees the GHash and its members.
+ *
+ * \param gh: The GHash to free.
+ * \param keyfreefp: Optional callback to free the key.
+ * \param valfreefp: Optional callback to free the value.
+ */
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp);
+/**
+ * Reserve given amount of entries (resize \a gh accordingly if needed).
+ */
void BLI_ghash_reserve(GHash *gh, const unsigned int nentries_reserve);
+/**
+ * Insert a key/value pair into the \a gh.
+ *
+ * \note Duplicates are not checked,
+ * the caller is expected to ensure elements are unique unless
+ * GHASH_FLAG_ALLOW_DUPES flag is set.
+ */
void BLI_ghash_insert(GHash *gh, void *key, void *val);
+/**
+ * Inserts a new value to a key that may already be in ghash.
+ *
+ * Avoids #BLI_ghash_remove, #BLI_ghash_insert calls (double lookups)
+ *
+ * \returns true if a new key has been added.
+ */
bool BLI_ghash_reinsert(
GHash *gh, void *key, void *val, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp);
+/**
+ * Replaces the key of an item in the \a gh.
+ *
+ * Use when a key is re-allocated or its memory location is changed.
+ *
+ * \returns The previous key or NULL if not found, the caller may free if it's needed.
+ */
void *BLI_ghash_replace_key(GHash *gh, void *key);
+/**
+ * Lookup the value of \a key in \a gh.
+ *
+ * \param key: The key to lookup.
+ * \returns the value for \a key or NULL.
+ *
+ * \note When NULL is a valid value, use #BLI_ghash_lookup_p to differentiate a missing key
+ * from a key with a NULL value. (Avoids calling #BLI_ghash_haskey before #BLI_ghash_lookup)
+ */
void *BLI_ghash_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT;
+/**
+ * A version of #BLI_ghash_lookup which accepts a fallback argument.
+ */
void *BLI_ghash_lookup_default(const GHash *gh,
const void *key,
void *val_default) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Lookup a pointer to the value of \a key in \a gh.
+ *
+ * \param key: The key to lookup.
+ * \returns the pointer to value for \a key or NULL.
+ *
+ * \note This has 2 main benefits over #BLI_ghash_lookup.
+ * - A NULL return always means that \a key isn't in \a gh.
+ * - The value can be modified in-place without further function calls (faster).
+ */
void **BLI_ghash_lookup_p(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT;
+/**
+ * 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) ATTR_WARN_UNUSED_RESULT;
+/**
+ * A version of #BLI_ghash_ensure_p that allows caller to re-assign the key.
+ * Typically used when the key is to be duplicated.
+ *
+ * \warning Caller _must_ write to \a r_key when returning false.
+ */
bool BLI_ghash_ensure_p_ex(GHash *gh, const void *key, void ***r_key, void ***r_val)
ATTR_WARN_UNUSED_RESULT;
+/**
+ * Remove \a key from \a gh, or return false if the key wasn't found.
+ *
+ * \param key: The key to remove.
+ * \param keyfreefp: Optional callback to free the key.
+ * \param valfreefp: Optional callback to free the value.
+ * \return true if \a key was removed from \a gh.
+ */
bool BLI_ghash_remove(GHash *gh,
const void *key,
GHashKeyFreeFP keyfreefp,
GHashValFreeFP valfreefp);
+/**
+ * Wraps #BLI_ghash_clear_ex with zero entries reserved.
+ */
void BLI_ghash_clear(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp);
+/**
+ * Reset \a gh clearing all entries.
+ *
+ * \param keyfreefp: Optional callback to free the key.
+ * \param valfreefp: Optional callback to free the value.
+ * \param nentries_reserve: Optionally reserve the number of members that the hash will hold.
+ */
void BLI_ghash_clear_ex(GHash *gh,
GHashKeyFreeFP keyfreefp,
GHashValFreeFP valfreefp,
const unsigned int nentries_reserve);
+/**
+ * Remove \a key from \a gh, returning the value or NULL if the key wasn't found.
+ *
+ * \param key: The key to remove.
+ * \param keyfreefp: Optional callback to free the key.
+ * \return the value of \a key int \a gh or NULL.
+ */
void *BLI_ghash_popkey(GHash *gh,
const void *key,
GHashKeyFreeFP keyfreefp) ATTR_WARN_UNUSED_RESULT;
+/**
+ * \return true if the \a key is in \a gh.
+ */
bool BLI_ghash_haskey(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Remove a random entry from \a gh, returning true
+ * if a key/value pair could be removed, false otherwise.
+ *
+ * \param r_key: The removed key.
+ * \param r_val: The removed value.
+ * \param state: Used for efficient removal.
+ * \return true if there was something to pop, false if ghash was already empty.
+ */
bool BLI_ghash_pop(GHash *gh, GHashIterState *state, void **r_key, void **r_val)
ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+/**
+ * \return size of the GHash.
+ */
unsigned int BLI_ghash_len(const GHash *gh) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Sets a GHash flag.
+ */
void BLI_ghash_flag_set(GHash *gh, unsigned int flag);
+/**
+ * Clear a GHash flag.
+ */
void BLI_ghash_flag_clear(GHash *gh, unsigned int flag);
/** \} */
@@ -129,10 +271,36 @@ void BLI_ghash_flag_clear(GHash *gh, unsigned int flag);
/** \name GHash Iterator
* \{ */
+/**
+ * Create a new GHashIterator. The hash table must not be mutated
+ * while the iterator is in use, and the iterator will step exactly
+ * #BLI_ghash_len(gh) times before becoming done.
+ *
+ * \param gh: The GHash to iterate over.
+ * \return Pointer to a new iterator.
+ */
GHashIterator *BLI_ghashIterator_new(GHash *gh) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+/**
+ * Init an already allocated GHashIterator. The hash table must not
+ * be mutated while the iterator is in use, and the iterator will
+ * step exactly #BLI_ghash_len(gh) times before becoming done.
+ *
+ * \param ghi: The GHashIterator to initialize.
+ * \param gh: The GHash to iterate over.
+ */
void BLI_ghashIterator_init(GHashIterator *ghi, GHash *gh);
+/**
+ * Free a GHashIterator.
+ *
+ * \param ghi: The iterator to free.
+ */
void BLI_ghashIterator_free(GHashIterator *ghi);
+/**
+ * Steps the iterator to the next index.
+ *
+ * \param ghi: The iterator.
+ */
void BLI_ghashIterator_step(GHashIterator *ghi);
BLI_INLINE void *BLI_ghashIterator_getKey(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT;
@@ -178,12 +346,11 @@ BLI_INLINE bool BLI_ghashIterator_done(const GHashIterator *ghi)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name GSet API
+/** \name GSet Types
* A 'set' implementation (unordered collection of unique elements).
*
* Internally this is a 'GHash' without any keys,
* which is why this API's are in the same header & source file.
- *
* \{ */
typedef struct GSet GSet;
@@ -195,6 +362,13 @@ typedef GHashKeyCopyFP GSetKeyCopyFP;
typedef GHashIterState GSetIterState;
+/** \} */
+
+/** \name GSet Public API
+ *
+ * Use ghash API to give 'set' functionality
+ * \{ */
+
GSet *BLI_gset_new_ex(GSetHashFP hashfp,
GSetCmpFP cmpfp,
const char *info,
@@ -202,17 +376,55 @@ GSet *BLI_gset_new_ex(GSetHashFP hashfp,
GSet *BLI_gset_new(GSetHashFP hashfp,
GSetCmpFP cmpfp,
const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+/**
+ * Copy given GSet. Keys are also copied if callback is provided, else pointers remain the same.
+ */
GSet *BLI_gset_copy(const GSet *gs, GSetKeyCopyFP keycopyfp) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
unsigned int BLI_gset_len(const GSet *gs) ATTR_WARN_UNUSED_RESULT;
void BLI_gset_flag_set(GSet *gs, unsigned int flag);
void BLI_gset_flag_clear(GSet *gs, unsigned int flag);
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp);
+/**
+ * Adds the key to the set (no checks for unique keys!).
+ * Matching #BLI_ghash_insert
+ */
void BLI_gset_insert(GSet *gs, void *key);
+/**
+ * A version of BLI_gset_insert which checks first if the key is in the set.
+ * \returns true if a new key has been added.
+ *
+ * \note GHash has no equivalent to this because typically the value would be different.
+ */
bool BLI_gset_add(GSet *gs, void *key);
+/**
+ * Set counterpart to #BLI_ghash_ensure_p_ex.
+ * similar to BLI_gset_add, except it returns the key pointer.
+ *
+ * \warning Caller _must_ write to \a r_key when returning false.
+ */
bool BLI_gset_ensure_p_ex(GSet *gs, const void *key, void ***r_key);
+/**
+ * Adds the key to the set (duplicates are managed).
+ * Matching #BLI_ghash_reinsert
+ *
+ * \returns true if a new key has been added.
+ */
bool BLI_gset_reinsert(GSet *gh, void *key, GSetKeyFreeFP keyfreefp);
+/**
+ * Replaces the key to the set if it's found.
+ * Matching #BLI_ghash_replace_key
+ *
+ * \returns The old key or NULL if not found.
+ */
void *BLI_gset_replace_key(GSet *gs, void *key);
bool BLI_gset_haskey(const GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Remove a random entry from \a gs, returning true if a key could be removed, false otherwise.
+ *
+ * \param r_key: The removed key.
+ * \param state: Used for efficient removal.
+ * \return true if there was something to pop, false if gset was already empty.
+ */
bool BLI_gset_pop(GSet *gs, GSetIterState *state, void **r_key) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
bool BLI_gset_remove(GSet *gs, const void *key, GSetKeyFreeFP keyfreefp);
@@ -220,7 +432,14 @@ void BLI_gset_clear_ex(GSet *gs, GSetKeyFreeFP keyfreefp, const unsigned int nen
void BLI_gset_clear(GSet *gs, GSetKeyFreeFP keyfreefp);
/* When set's are used for key & value. */
+/**
+ * Returns the pointer to the key if it's found.
+ */
void *BLI_gset_lookup(const GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT;
+/**
+ * Returns the pointer to the key if it's found, removing it from the GSet.
+ * \note Caller must handle freeing.
+ */
void *BLI_gset_pop_key(GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT;
/** \} */
@@ -282,9 +501,19 @@ BLI_INLINE bool BLI_gsetIterator_done(const GSetIterator *gsi)
/* For testing, debugging only */
#ifdef GHASH_INTERNAL_API
+/**
+ * \return number of buckets in the GHash.
+ */
int BLI_ghash_buckets_len(const GHash *gh);
int BLI_gset_buckets_len(const GSet *gs);
+/**
+ * Measure how well the hash function performs (1.0 is approx as good as random distribution),
+ * and return a few other stats like load,
+ * variance of the distribution of the entries in the buckets, etc.
+ *
+ * Smaller is better!
+ */
double BLI_ghash_calc_quality_ex(GHash *gh,
double *r_load,
double *r_variance,
@@ -300,6 +529,7 @@ double BLI_gset_calc_quality_ex(GSet *gs,
double BLI_ghash_calc_quality(GHash *gh);
double BLI_gset_calc_quality(GSet *gs);
#endif /* GHASH_INTERNAL_API */
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -346,6 +576,15 @@ double BLI_gset_calc_quality(GSet *gs);
unsigned int BLI_ghashutil_ptrhash(const void *key);
bool BLI_ghashutil_ptrcmp(const void *a, const void *b);
+/**
+ * This function implements the widely used `djb` hash apparently posted
+ * by Daniel Bernstein to `comp.lang.c` some time ago. The 32 bit
+ * unsigned hash value starts at 5381 and for each byte 'c' in the
+ * string, is updated: `hash = hash * 33 + c`.
+ * This function uses the signed value of each byte.
+ *
+ * NOTE: this is the same hash method that glib 2.34.0 uses.
+ */
unsigned int BLI_ghashutil_strhash_n(const char *key, size_t n);
#define BLI_ghashutil_strhash(key) \
(CHECK_TYPE_ANY(key, char *, const char *, const char *const), BLI_ghashutil_strhash_p(key))