X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=glib%2Fghash.c;h=b42dd1423223e46ca51149995e19ed8a4f211d42;hb=ea4f9ce8a060d53cbc299e4c384089f6cc926caa;hp=5cc52f1ea30bd2305c7427ecc0cb56a49c914dab;hpb=e1b41dcb9118b6e182119cb85fd05b45f07c059c;p=platform%2Fupstream%2Fglib.git diff --git a/glib/ghash.c b/glib/ghash.c index 5cc52f1..b42dd14 100644 --- a/glib/ghash.c +++ b/glib/ghash.c @@ -12,9 +12,7 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * License along with this library; if not, see . */ /* @@ -34,16 +32,18 @@ #include "ghash.h" +#include "glib-private.h" #include "gstrfuncs.h" #include "gatomic.h" #include "gtestutils.h" +#include "gslice.h" /** * SECTION:hash_tables * @title: Hash Tables * @short_description: associations between keys and values so that - * given a key the value can be found quickly + * given a key the value can be found quickly * * A #GHashTable provides associations between keys and values which is * optimized so that given a key, the associated value can be found @@ -81,113 +81,100 @@ * * To destroy a #GHashTable use g_hash_table_destroy(). * - * - * Using a GHashTable as a set - * - * A common use-case for hash tables is to store information about - * a set of keys, without associating any particular value with each + * A common use-case for hash tables is to store information about a + * set of keys, without associating any particular value with each * key. GHashTable optimizes one way of doing so: If you store only * key-value pairs where key == value, then GHashTable does not * allocate memory to store the values, which can be a considerable - * space saving, if your set is large. - * - * - * GHashTable * - * set_new (GHashFunc hash_func, - * GEqualFunc equal_func, - * GDestroyNotify destroy) - * { - * return g_hash_table_new_full (hash_func, equal_func, destroy, NULL); - * } - * - * void - * set_insert (GHashTable *set, - * gpointer element) - * { - * g_hash_table_insert (set, element, element); - * } - * - * gboolean - * set_contains (GHashTable *set, - * gpointer element) - * { - * return g_hash_table_lookup_extended (set, element, NULL, NULL); - * } - * - * gboolean - * set_remove (GHashTable *set, - * gpointer element) - * { - * return g_hash_table_remove (set, element); - * } - * - * + * space saving, if your set is large. The functions + * g_hash_table_add() and g_hash_table_contains() are designed to be + * used when using #GHashTable this way. */ /** * GHashTable: * * The #GHashTable struct is an opaque data structure to represent a - * Hash Table. It should only be - * accessed via the following functions. - **/ + * [Hash Table][glib-Hash-Tables]. It should only be accessed via the + * following functions. + */ /** * GHashFunc: - * @key: a key. - * @Returns: the hash value corresponding to the key. + * @key: a key * * Specifies the type of the hash function which is passed to * g_hash_table_new() when a #GHashTable is created. * * The function is passed a key and should return a #guint hash value. * The functions g_direct_hash(), g_int_hash() and g_str_hash() provide - * hash functions which can be used when the key is a #gpointer, #gint, + * hash functions which can be used when the key is a #gpointer, #gint*, * and #gchar* respectively. * - * The hash values should be evenly - * distributed over a fairly large range? The modulus is taken with the - * hash table size (a prime number) to find the 'bucket' to place each - * key into. The function should also be very fast, since it is called - * for each key lookup. - **/ + * g_direct_hash() is also the appropriate hash function for keys + * of the form `GINT_TO_POINTER (n)` (or similar macros). + * + * A good hash functions should produce + * hash values that are evenly distributed over a fairly large range. + * The modulus is taken with the hash table size (a prime number) to + * find the 'bucket' to place each key into. The function should also + * be very fast, since it is called for each key lookup. + * + * Note that the hash functions provided by GLib have these qualities, + * but are not particularly robust against manufactured keys that + * cause hash collisions. Therefore, you should consider choosing + * a more secure hash function when using a GHashTable with keys + * that originate in untrusted data (such as HTTP requests). + * Using g_str_hash() in that situation might make your application + * vulerable to + * [Algorithmic Complexity Attacks](https://lwn.net/Articles/474912/). + * + * The key to choosing a good hash is unpredictability. Even + * cryptographic hashes are very easy to find collisions for when the + * remainder is taken modulo a somewhat predictable prime number. There + * must be an element of randomness that an attacker is unable to guess. + * + * Returns: the hash value corresponding to the key + */ /** * GHFunc: - * @key: a key. - * @value: the value corresponding to the key. - * @user_data: user data passed to g_hash_table_foreach(). + * @key: a key + * @value: the value corresponding to the key + * @user_data: user data passed to g_hash_table_foreach() * * Specifies the type of the function passed to g_hash_table_foreach(). * It is called with each key/value pair, together with the @user_data * parameter which is passed to g_hash_table_foreach(). - **/ + */ /** * GHRFunc: - * @key: a key. - * @value: the value associated with the key. - * @user_data: user data passed to g_hash_table_remove(). - * @Returns: %TRUE if the key/value pair should be removed from the - * #GHashTable. + * @key: a key + * @value: the value associated with the key + * @user_data: user data passed to g_hash_table_remove() * * Specifies the type of the function passed to * g_hash_table_foreach_remove(). It is called with each key/value * pair, together with the @user_data parameter passed to * g_hash_table_foreach_remove(). It should return %TRUE if the * key/value pair should be removed from the #GHashTable. - **/ + * + * Returns: %TRUE if the key/value pair should be removed from the + * #GHashTable + */ /** * GEqualFunc: - * @a: a value. - * @b: a value to compare with. - * @Returns: %TRUE if @a = @b; %FALSE otherwise. + * @a: a value + * @b: a value to compare with * * Specifies the type of a function used to test two values for * equality. The function should return %TRUE if both values are equal * and %FALSE otherwise. - **/ + * + * Returns: %TRUE if @a = @b; %FALSE otherwise + */ /** * GHashTableIter: @@ -196,7 +183,23 @@ * to iterate over the elements of a #GHashTable. GHashTableIter * structures are typically allocated on the stack and then initialized * with g_hash_table_iter_init(). - **/ + */ + +/** + * g_hash_table_freeze: + * @hash_table: a #GHashTable + * + * This function is deprecated and will be removed in the next major + * release of GLib. It does nothing. + */ + +/** + * g_hash_table_thaw: + * @hash_table: a #GHashTable + * + * This function is deprecated and will be removed in the next major + * release of GLib. It does nothing. + */ #define HASH_TABLE_MIN_SHIFT 3 /* 1 << 3 == 8 buckets */ @@ -243,10 +246,14 @@ typedef struct int version; } RealIter; +G_STATIC_ASSERT (sizeof (GHashTableIter) == sizeof (RealIter)); +G_STATIC_ASSERT (_g_alignof (GHashTableIter) >= _g_alignof (RealIter)); + /* Each table size has an associated prime modulo (the first prime * lower than the table size) used to find the initial bucket. Probing * then works modulo 2^n. The prime modulo is necessary to get a - * good distribution with poor hash functions. */ + * good distribution with poor hash functions. + */ static const gint prime_mod [] = { 1, /* For 1 << 0 */ @@ -328,7 +335,6 @@ g_hash_table_set_shift_from_size (GHashTable *hash_table, gint size) * @hash_table: our #GHashTable * @key: the key to lookup against * @hash_return: key hash return location - * Return value: index of the described node * * Performs a lookup in the hash table, preserving extra information * usually needed for insertion. @@ -344,6 +350,8 @@ g_hash_table_set_shift_from_size (GHashTable *hash_table, gint size) * The computed hash value is returned in the variable pointed to * by @hash_return. This is to save insertions from having to compute * the hash record again for the new record. + * + * Returns: index of the described node */ static inline guint g_hash_table_lookup_node (GHashTable *hash_table, @@ -357,6 +365,13 @@ g_hash_table_lookup_node (GHashTable *hash_table, gboolean have_tombstone = FALSE; guint step = 0; + /* If this happens, then the application is probably doing too much work + * from a destroy notifier. The alternative would be to crash any second + * (as keys, etc. will be NULL). + * Applications need to either use g_hash_table_destroy, or ensure the hash + * table is empty prior to removing the last reference using g_hash_table_unref(). */ + g_assert (hash_table->ref_count > 0); + hash_value = hash_table->hash_func (key); if (G_UNLIKELY (!HASH_IS_REAL (hash_value))) hash_value = 2; @@ -418,7 +433,7 @@ g_hash_table_lookup_node (GHashTable *hash_table, */ static void g_hash_table_remove_node (GHashTable *hash_table, - int i, + gint i, gboolean notify) { gpointer key; @@ -457,11 +472,20 @@ g_hash_table_remove_node (GHashTable *hash_table, */ static void g_hash_table_remove_all_nodes (GHashTable *hash_table, - gboolean notify) + gboolean notify, + gboolean destruction) { int i; gpointer key; gpointer value; + gint old_size; + gpointer *old_keys; + gpointer *old_values; + guint *old_hashes; + + /* If the hash table is already empty, there is nothing to be done. */ + if (hash_table->nnodes == 0) + return; hash_table->nnodes = 0; hash_table->noccupied = 0; @@ -470,23 +494,52 @@ g_hash_table_remove_all_nodes (GHashTable *hash_table, (hash_table->key_destroy_func == NULL && hash_table->value_destroy_func == NULL)) { - memset (hash_table->hashes, 0, hash_table->size * sizeof (guint)); - memset (hash_table->keys, 0, hash_table->size * sizeof (gpointer)); - memset (hash_table->values, 0, hash_table->size * sizeof (gpointer)); + if (!destruction) + { + memset (hash_table->hashes, 0, hash_table->size * sizeof (guint)); + memset (hash_table->keys, 0, hash_table->size * sizeof (gpointer)); + memset (hash_table->values, 0, hash_table->size * sizeof (gpointer)); + } return; } - for (i = 0; i < hash_table->size; i++) + /* Keep the old storage space around to iterate over it. */ + old_size = hash_table->size; + old_keys = hash_table->keys; + old_values = hash_table->values; + old_hashes = hash_table->hashes; + + /* Now create a new storage space; If the table is destroyed we can use the + * shortcut of not creating a new storage. This saves the allocation at the + * cost of not allowing any recursive access. + * However, the application doesn't own any reference anymore, so access + * is not allowed. If accesses are done, then either an assert or crash + * *will* happen. */ + g_hash_table_set_shift (hash_table, HASH_TABLE_MIN_SHIFT); + if (!destruction) { - if (HASH_IS_REAL (hash_table->hashes[i])) + hash_table->keys = g_new0 (gpointer, hash_table->size); + hash_table->values = hash_table->keys; + hash_table->hashes = g_new0 (guint, hash_table->size); + } + else + { + hash_table->keys = NULL; + hash_table->values = NULL; + hash_table->hashes = NULL; + } + + for (i = 0; i < old_size; i++) + { + if (HASH_IS_REAL (old_hashes[i])) { - key = hash_table->keys[i]; - value = hash_table->values[i]; + key = old_keys[i]; + value = old_values[i]; - hash_table->hashes[i] = UNUSED_HASH_VALUE; - hash_table->keys[i] = NULL; - hash_table->values[i] = NULL; + old_hashes[i] = UNUSED_HASH_VALUE; + old_keys[i] = NULL; + old_values[i] = NULL; if (hash_table->key_destroy_func != NULL) hash_table->key_destroy_func (key); @@ -494,11 +547,14 @@ g_hash_table_remove_all_nodes (GHashTable *hash_table, if (hash_table->value_destroy_func != NULL) hash_table->value_destroy_func (value); } - else if (HASH_IS_TOMBSTONE (hash_table->hashes[i])) - { - hash_table->hashes[i] = UNUSED_HASH_VALUE; - } } + + /* Destroy old storage space. */ + if (old_keys != old_values) + g_free (old_values); + + g_free (old_keys); + g_free (old_hashes); } /* @@ -506,9 +562,9 @@ g_hash_table_remove_all_nodes (GHashTable *hash_table, * @hash_table: our #GHashTable * * Resizes the hash table to the optimal size based on the number of - * nodes currently held. If you call this function then a resize will - * occur, even if one does not need to occur. Use - * g_hash_table_maybe_resize() instead. + * nodes currently held. If you call this function then a resize will + * occur, even if one does not need to occur. + * Use g_hash_table_maybe_resize() instead. * * This function may "resize" the hash table to its current size, with * the side effect of cleaning up tombstones and otherwise optimizing @@ -591,26 +647,29 @@ g_hash_table_maybe_resize (GHashTable *hash_table) /** * g_hash_table_new: - * @hash_func: a function to create a hash value from a key. - * Hash values are used to determine where keys are stored within the - * #GHashTable data structure. The g_direct_hash(), g_int_hash(), - * g_int64_hash(), g_double_hash() and g_str_hash() functions are provided - * for some common types of keys. - * If hash_func is %NULL, g_direct_hash() is used. - * @key_equal_func: a function to check two keys for equality. This is - * used when looking up keys in the #GHashTable. The g_direct_equal(), - * g_int_equal(), g_int64_equal(), g_double_equal() and g_str_equal() - * functions are provided for the most common types of keys. - * If @key_equal_func is %NULL, keys are compared directly in a similar - * fashion to g_direct_equal(), but without the overhead of a function call. + * @hash_func: a function to create a hash value from a key + * @key_equal_func: a function to check two keys for equality * * Creates a new #GHashTable with a reference count of 1. * - * Return value: a new #GHashTable. - **/ -GHashTable* -g_hash_table_new (GHashFunc hash_func, - GEqualFunc key_equal_func) + * Hash values returned by @hash_func are used to determine where keys + * are stored within the #GHashTable data structure. The g_direct_hash(), + * g_int_hash(), g_int64_hash(), g_double_hash() and g_str_hash() + * functions are provided for some common types of keys. + * If @hash_func is %NULL, g_direct_hash() is used. + * + * @key_equal_func is used when looking up keys in the #GHashTable. + * The g_direct_equal(), g_int_equal(), g_int64_equal(), g_double_equal() + * and g_str_equal() functions are provided for the most common types + * of keys. If @key_equal_func is %NULL, keys are compared directly in + * a similar fashion to g_direct_equal(), but without the overhead of + * a function call. + * + * Returns: a new #GHashTable + */ +GHashTable * +g_hash_table_new (GHashFunc hash_func, + GEqualFunc key_equal_func) { return g_hash_table_new_full (hash_func, key_equal_func, NULL, NULL); } @@ -618,26 +677,34 @@ g_hash_table_new (GHashFunc hash_func, /** * g_hash_table_new_full: - * @hash_func: a function to create a hash value from a key. - * @key_equal_func: a function to check two keys for equality. - * @key_destroy_func: a function to free the memory allocated for the key - * used when removing the entry from the #GHashTable or %NULL if you - * don't want to supply such a function. - * @value_destroy_func: a function to free the memory allocated for the - * value used when removing the entry from the #GHashTable or %NULL if - * you don't want to supply such a function. - * - * Creates a new #GHashTable like g_hash_table_new() with a reference count - * of 1 and allows to specify functions to free the memory allocated for the - * key and value that get called when removing the entry from the #GHashTable. - * - * Return value: a new #GHashTable. - **/ -GHashTable* -g_hash_table_new_full (GHashFunc hash_func, - GEqualFunc key_equal_func, - GDestroyNotify key_destroy_func, - GDestroyNotify value_destroy_func) + * @hash_func: a function to create a hash value from a key + * @key_equal_func: a function to check two keys for equality + * @key_destroy_func: (allow-none): a function to free the memory allocated for the key + * used when removing the entry from the #GHashTable, or %NULL + * if you don't want to supply such a function. + * @value_destroy_func: (allow-none): a function to free the memory allocated for the + * value used when removing the entry from the #GHashTable, or %NULL + * if you don't want to supply such a function. + * + * Creates a new #GHashTable like g_hash_table_new() with a reference + * count of 1 and allows to specify functions to free the memory + * allocated for the key and value that get called when removing the + * entry from the #GHashTable. + * + * Since version 2.42 it is permissible for destroy notify functions to + * recursively remove further items from the hash table. This is only + * permissible if the application still holds a reference to the hash table. + * This means that you may need to ensure that the hash table is empty by + * calling g_hash_table_remove_all before releasing the last reference using + * g_hash_table_unref(). + * + * Returns: a new #GHashTable + */ +GHashTable * +g_hash_table_new_full (GHashFunc hash_func, + GEqualFunc key_equal_func, + GDestroyNotify key_destroy_func, + GDestroyNotify value_destroy_func) { GHashTable *hash_table; @@ -662,25 +729,25 @@ g_hash_table_new_full (GHashFunc hash_func, /** * g_hash_table_iter_init: - * @iter: an uninitialized #GHashTableIter. - * @hash_table: a #GHashTable. + * @iter: an uninitialized #GHashTableIter + * @hash_table: a #GHashTable * * Initializes a key/value pair iterator and associates it with * @hash_table. Modifying the hash table after calling this function * invalidates the returned iterator. - * |[ + * |[ * GHashTableIter iter; * gpointer key, value; * * g_hash_table_iter_init (&iter, hash_table); - * while (g_hash_table_iter_next (&iter, &key, &value)) + * while (g_hash_table_iter_next (&iter, &key, &value)) * { - * /* do something with key and value */ + * // do something with key and value * } * ]| * * Since: 2.16 - **/ + */ void g_hash_table_iter_init (GHashTableIter *iter, GHashTable *hash_table) @@ -699,18 +766,18 @@ g_hash_table_iter_init (GHashTableIter *iter, /** * g_hash_table_iter_next: - * @iter: an initialized #GHashTableIter. - * @key: a location to store the key, or %NULL. - * @value: a location to store the value, or %NULL. + * @iter: an initialized #GHashTableIter + * @key: (allow-none): a location to store the key, or %NULL + * @value: (allow-none): a location to store the value, or %NULL * * Advances @iter and retrieves the key and/or value that are now * pointed to as a result of this advancement. If %FALSE is returned, * @key and @value are not set, and the iterator becomes invalid. * - * Return value: %FALSE if the end of the #GHashTable has been reached. + * Returns: %FALSE if the end of the #GHashTable has been reached. * * Since: 2.16 - **/ + */ gboolean g_hash_table_iter_next (GHashTableIter *iter, gpointer *key, @@ -749,14 +816,14 @@ g_hash_table_iter_next (GHashTableIter *iter, /** * g_hash_table_iter_get_hash_table: - * @iter: an initialized #GHashTableIter. + * @iter: an initialized #GHashTableIter * * Returns the #GHashTable associated with @iter. * - * Return value: the #GHashTable associated with @iter. + * Returns: the #GHashTable associated with @iter. * * Since: 2.16 - **/ + */ GHashTable * g_hash_table_iter_get_hash_table (GHashTableIter *iter) { @@ -785,20 +852,29 @@ iter_remove_or_steal (RealIter *ri, gboolean notify) /** * g_hash_table_iter_remove: - * @iter: an initialized #GHashTableIter. + * @iter: an initialized #GHashTableIter * * Removes the key/value pair currently pointed to by the iterator * from its associated #GHashTable. Can only be called after - * g_hash_table_iter_next() returned %TRUE, and cannot be called more - * than once for the same key/value pair. + * g_hash_table_iter_next() returned %TRUE, and cannot be called + * more than once for the same key/value pair. * - * If the #GHashTable was created using g_hash_table_new_full(), the - * key and value are freed using the supplied destroy functions, otherwise - * you have to make sure that any dynamically allocated values are freed - * yourself. + * If the #GHashTable was created using g_hash_table_new_full(), + * the key and value are freed using the supplied destroy functions, + * otherwise you have to make sure that any dynamically allocated + * values are freed yourself. + * + * It is safe to continue iterating the #GHashTable afterward: + * |[ + * while (g_hash_table_iter_next (&iter, &key, &value)) + * { + * if (condition) + * g_hash_table_iter_remove (&iter); + * } + * ]| * * Since: 2.16 - **/ + */ void g_hash_table_iter_remove (GHashTableIter *iter) { @@ -810,42 +886,89 @@ g_hash_table_iter_remove (GHashTableIter *iter) * @hash_table: our #GHashTable * @node_index: pointer to node to insert/replace * @key_hash: key hash - * @key: key to replace with + * @key: (allow-none): key to replace with, or %NULL * @value: value to replace with + * @keep_new_key: whether to replace the key in the node with @key + * @reusing_key: whether @key was taken out of the existing node * * Inserts a value at @node_index in the hash table and updates it. + * + * If @key has been taken out of the existing node (ie it is not + * passed in via a g_hash_table_insert/replace) call, then @reusing_key + * should be %TRUE. + * + * Returns: %TRUE if the key did not exist yet */ -static void +static gboolean g_hash_table_insert_node (GHashTable *hash_table, guint node_index, guint key_hash, - gpointer key, - gpointer value, - gboolean keep_new_key) + gpointer new_key, + gpointer new_value, + gboolean keep_new_key, + gboolean reusing_key) { + gboolean already_exists; guint old_hash; - gpointer old_key; - gpointer old_value; - - if (G_UNLIKELY (hash_table->keys == hash_table->values && key != value)) - hash_table->values = g_memdup (hash_table->keys, sizeof (gpointer) * hash_table->size); + gpointer key_to_free = NULL; + gpointer value_to_free = NULL; old_hash = hash_table->hashes[node_index]; - old_key = hash_table->keys[node_index]; - old_value = hash_table->values[node_index]; - - if (HASH_IS_REAL (old_hash)) + already_exists = HASH_IS_REAL (old_hash); + + /* Proceed in three steps. First, deal with the key because it is the + * most complicated. Then consider if we need to split the table in + * two (because writing the value will result in the set invariant + * becoming broken). Then deal with the value. + * + * There are three cases for the key: + * + * - entry already exists in table, reusing key: + * free the just-passed-in new_key and use the existing value + * + * - entry already exists in table, not reusing key: + * free the entry in the table, use the new key + * + * - entry not already in table: + * use the new key, free nothing + * + * We update the hash at the same time... + */ + if (already_exists) { + /* Note: we must record the old value before writing the new key + * because we might change the value in the event that the two + * arrays are shared. + */ + value_to_free = hash_table->values[node_index]; + if (keep_new_key) - hash_table->keys[node_index] = key; - hash_table->values[node_index] = value; + { + key_to_free = hash_table->keys[node_index]; + hash_table->keys[node_index] = new_key; + } + else + key_to_free = new_key; } else { - hash_table->keys[node_index] = key; - hash_table->values[node_index] = value; hash_table->hashes[node_index] = key_hash; + hash_table->keys[node_index] = new_key; + } + + /* Step two: check if the value that we are about to write to the + * table is the same as the key in the same position. If it's not, + * split the table. + */ + if (G_UNLIKELY (hash_table->keys == hash_table->values && hash_table->keys[node_index] != new_value)) + hash_table->values = g_memdup (hash_table->keys, sizeof (gpointer) * hash_table->size); + + /* Step 3: Actually do the write */ + hash_table->values[node_index] = new_value; + /* Now, the bookkeeping... */ + if (!already_exists) + { hash_table->nnodes++; if (HASH_IS_UNUSED (old_hash)) @@ -860,29 +983,31 @@ g_hash_table_insert_node (GHashTable *hash_table, #endif } - if (HASH_IS_REAL (old_hash)) + if (already_exists) { - if (hash_table->key_destroy_func) - hash_table->key_destroy_func (keep_new_key ? old_key : key); + if (hash_table->key_destroy_func && !reusing_key) + (* hash_table->key_destroy_func) (key_to_free); if (hash_table->value_destroy_func) - hash_table->value_destroy_func (old_value); + (* hash_table->value_destroy_func) (value_to_free); } + + return !already_exists; } /** * g_hash_table_iter_replace: - * @iter: an initialized #GHashTableIter. + * @iter: an initialized #GHashTableIter * @value: the value to replace with * * Replaces the value currently pointed to by the iterator * from its associated #GHashTable. Can only be called after * g_hash_table_iter_next() returned %TRUE. * - * If you supplied a @value_destroy_func when creating the #GHashTable, - * the old value is freed using that function. + * If you supplied a @value_destroy_func when creating the + * #GHashTable, the old value is freed using that function. * - * Since: 2.29.9 - **/ + * Since: 2.30 + */ void g_hash_table_iter_replace (GHashTableIter *iter, gpointer value) @@ -903,7 +1028,7 @@ g_hash_table_iter_replace (GHashTableIter *iter, node_hash = ri->hash_table->hashes[ri->position]; key = ri->hash_table->keys[ri->position]; - g_hash_table_insert_node (ri->hash_table, ri->position, node_hash, key, value, TRUE); + g_hash_table_insert_node (ri->hash_table, ri->position, node_hash, key, value, TRUE, TRUE); #ifndef G_DISABLE_ASSERT ri->version++; @@ -913,16 +1038,16 @@ g_hash_table_iter_replace (GHashTableIter *iter, /** * g_hash_table_iter_steal: - * @iter: an initialized #GHashTableIter. + * @iter: an initialized #GHashTableIter * - * Removes the key/value pair currently pointed to by the iterator - * from its associated #GHashTable, without calling the key and value - * destroy functions. Can only be called after - * g_hash_table_iter_next() returned %TRUE, and cannot be called more - * than once for the same key/value pair. + * Removes the key/value pair currently pointed to by the + * iterator from its associated #GHashTable, without calling + * the key and value destroy functions. Can only be called + * after g_hash_table_iter_next() returned %TRUE, and cannot + * be called more than once for the same key/value pair. * * Since: 2.16 - **/ + */ void g_hash_table_iter_steal (GHashTableIter *iter) { @@ -932,16 +1057,16 @@ g_hash_table_iter_steal (GHashTableIter *iter) /** * g_hash_table_ref: - * @hash_table: a valid #GHashTable. + * @hash_table: a valid #GHashTable * * Atomically increments the reference count of @hash_table by one. * This function is MT-safe and may be called from any thread. * - * Return value: the passed in #GHashTable. + * Returns: the passed in #GHashTable * * Since: 2.10 - **/ -GHashTable* + */ +GHashTable * g_hash_table_ref (GHashTable *hash_table) { g_return_val_if_fail (hash_table != NULL, NULL); @@ -953,7 +1078,7 @@ g_hash_table_ref (GHashTable *hash_table) /** * g_hash_table_unref: - * @hash_table: a valid #GHashTable. + * @hash_table: a valid #GHashTable * * Atomically decrements the reference count of @hash_table by one. * If the reference count drops to 0, all keys and values will be @@ -961,7 +1086,7 @@ g_hash_table_ref (GHashTable *hash_table) * This function is MT-safe and may be called from any thread. * * Since: 2.10 - **/ + */ void g_hash_table_unref (GHashTable *hash_table) { @@ -969,7 +1094,7 @@ g_hash_table_unref (GHashTable *hash_table) if (g_atomic_int_dec_and_test (&hash_table->ref_count)) { - g_hash_table_remove_all_nodes (hash_table, TRUE); + g_hash_table_remove_all_nodes (hash_table, TRUE, TRUE); if (hash_table->keys != hash_table->values) g_free (hash_table->values); g_free (hash_table->keys); @@ -980,7 +1105,7 @@ g_hash_table_unref (GHashTable *hash_table) /** * g_hash_table_destroy: - * @hash_table: a #GHashTable. + * @hash_table: a #GHashTable * * Destroys all keys and values in the #GHashTable and decrements its * reference count by 1. If keys and/or values are dynamically allocated, @@ -988,7 +1113,7 @@ g_hash_table_unref (GHashTable *hash_table) * notifiers using g_hash_table_new_full(). In the latter case the destroy * functions you supplied will be called on all keys and values during the * destruction phase. - **/ + */ void g_hash_table_destroy (GHashTable *hash_table) { @@ -1000,19 +1125,19 @@ g_hash_table_destroy (GHashTable *hash_table) /** * g_hash_table_lookup: - * @hash_table: a #GHashTable. - * @key: the key to look up. + * @hash_table: a #GHashTable + * @key: the key to look up * * Looks up a key in a #GHashTable. Note that this function cannot * distinguish between a key that is not present and one which is present * and has the value %NULL. If you need this distinction, use * g_hash_table_lookup_extended(). * - * Return value: the associated value, or %NULL if the key is not found. - **/ + * Returns: (allow-none): the associated value, or %NULL if the key is not found + */ gpointer -g_hash_table_lookup (GHashTable *hash_table, - gconstpointer key) +g_hash_table_lookup (GHashTable *hash_table, + gconstpointer key) { guint node_index; guint node_hash; @@ -1030,8 +1155,8 @@ g_hash_table_lookup (GHashTable *hash_table, * g_hash_table_lookup_extended: * @hash_table: a #GHashTable * @lookup_key: the key to look up - * @orig_key: return location for the original key, or %NULL - * @value: return location for the value associated with the key, or %NULL + * @orig_key: (allow-none): return location for the original key, or %NULL + * @value: (allow-none): return location for the value associated with the key, or %NULL * * Looks up a key in the #GHashTable, returning the original key and the * associated value and a #gboolean which is %TRUE if the key was found. This @@ -1042,8 +1167,8 @@ g_hash_table_lookup (GHashTable *hash_table, * whether the %NULL key exists, provided the hash and equal functions * of @hash_table are %NULL-safe. * - * Return value: %TRUE if the key was found in the #GHashTable. - **/ + * Returns: %TRUE if the key was found in the #GHashTable + */ gboolean g_hash_table_lookup_extended (GHashTable *hash_table, gconstpointer lookup_key, @@ -1081,11 +1206,13 @@ g_hash_table_lookup_extended (GHashTable *hash_table, * Implements the common logic for the g_hash_table_insert() and * g_hash_table_replace() functions. * - * Do a lookup of @key. If it is found, replace it with the new - * @value (and perhaps the new @key). If it is not found, create a - * new node. + * Do a lookup of @key. If it is found, replace it with the new + * @value (and perhaps the new @key). If it is not found, create + * a new node. + * + * Returns: %TRUE if the key did not exist yet */ -static void +static gboolean g_hash_table_insert_internal (GHashTable *hash_table, gpointer key, gpointer value, @@ -1094,54 +1221,107 @@ g_hash_table_insert_internal (GHashTable *hash_table, guint key_hash; guint node_index; - g_return_if_fail (hash_table != NULL); + g_return_val_if_fail (hash_table != NULL, FALSE); node_index = g_hash_table_lookup_node (hash_table, key, &key_hash); - g_hash_table_insert_node (hash_table, node_index, key_hash, key, value, keep_new_key); + return g_hash_table_insert_node (hash_table, node_index, key_hash, key, value, keep_new_key, FALSE); } /** * g_hash_table_insert: - * @hash_table: a #GHashTable. - * @key: a key to insert. - * @value: the value to associate with the key. + * @hash_table: a #GHashTable + * @key: a key to insert + * @value: the value to associate with the key * * Inserts a new key and value into a #GHashTable. * - * If the key already exists in the #GHashTable its current value is replaced - * with the new value. If you supplied a @value_destroy_func when creating the - * #GHashTable, the old value is freed using that function. If you supplied - * a @key_destroy_func when creating the #GHashTable, the passed key is freed - * using that function. - **/ -void + * If the key already exists in the #GHashTable its current + * value is replaced with the new value. If you supplied a + * @value_destroy_func when creating the #GHashTable, the old + * value is freed using that function. If you supplied a + * @key_destroy_func when creating the #GHashTable, the passed + * key is freed using that function. + * + * Returns: %TRUE if the key did not exist yet + */ +gboolean g_hash_table_insert (GHashTable *hash_table, gpointer key, gpointer value) { - g_hash_table_insert_internal (hash_table, key, value, FALSE); + return g_hash_table_insert_internal (hash_table, key, value, FALSE); } /** * g_hash_table_replace: - * @hash_table: a #GHashTable. - * @key: a key to insert. - * @value: the value to associate with the key. + * @hash_table: a #GHashTable + * @key: a key to insert + * @value: the value to associate with the key * * Inserts a new key and value into a #GHashTable similar to - * g_hash_table_insert(). The difference is that if the key already exists - * in the #GHashTable, it gets replaced by the new key. If you supplied a - * @value_destroy_func when creating the #GHashTable, the old value is freed - * using that function. If you supplied a @key_destroy_func when creating the + * g_hash_table_insert(). The difference is that if the key + * already exists in the #GHashTable, it gets replaced by the + * new key. If you supplied a @value_destroy_func when creating + * the #GHashTable, the old value is freed using that function. + * If you supplied a @key_destroy_func when creating the * #GHashTable, the old key is freed using that function. - **/ -void + * + * Returns: %TRUE of the key did not exist yet + */ +gboolean g_hash_table_replace (GHashTable *hash_table, gpointer key, gpointer value) { - g_hash_table_insert_internal (hash_table, key, value, TRUE); + return g_hash_table_insert_internal (hash_table, key, value, TRUE); +} + +/** + * g_hash_table_add: + * @hash_table: a #GHashTable + * @key: a key to insert + * + * This is a convenience function for using a #GHashTable as a set. It + * is equivalent to calling g_hash_table_replace() with @key as both the + * key and the value. + * + * When a hash table only ever contains keys that have themselves as the + * corresponding value it is able to be stored more efficiently. See + * the discussion in the section description. + * + * Returns: %TRUE if the key did not exist yet + * + * Since: 2.32 + */ +gboolean +g_hash_table_add (GHashTable *hash_table, + gpointer key) +{ + return g_hash_table_insert_internal (hash_table, key, key, TRUE); +} + +/** + * g_hash_table_contains: + * @hash_table: a #GHashTable + * @key: a key to check + * + * Checks if @key is in @hash_table. + * + * Since: 2.32 + **/ +gboolean +g_hash_table_contains (GHashTable *hash_table, + gconstpointer key) +{ + guint node_index; + guint node_hash; + + g_return_val_if_fail (hash_table != NULL, FALSE); + + node_index = g_hash_table_lookup_node (hash_table, key, &node_hash); + + return HASH_IS_REAL (hash_table->hashes[node_index]); } /* @@ -1149,7 +1329,7 @@ g_hash_table_replace (GHashTable *hash_table, * @hash_table: our #GHashTable * @key: the key to remove * @notify: %TRUE if the destroy notify handlers are to be called - * Return value: %TRUE if a node was found and removed, else %FALSE + * Returns: %TRUE if a node was found and removed, else %FALSE * * Implements the common logic for the g_hash_table_remove() and * g_hash_table_steal() functions. @@ -1184,8 +1364,8 @@ g_hash_table_remove_internal (GHashTable *hash_table, /** * g_hash_table_remove: - * @hash_table: a #GHashTable. - * @key: the key to remove. + * @hash_table: a #GHashTable + * @key: the key to remove * * Removes a key and its associated value from a #GHashTable. * @@ -1194,8 +1374,8 @@ g_hash_table_remove_internal (GHashTable *hash_table, * you have to make sure that any dynamically allocated values are freed * yourself. * - * Return value: %TRUE if the key was found and removed from the #GHashTable. - **/ + * Returns: %TRUE if the key was found and removed from the #GHashTable + */ gboolean g_hash_table_remove (GHashTable *hash_table, gconstpointer key) @@ -1205,14 +1385,14 @@ g_hash_table_remove (GHashTable *hash_table, /** * g_hash_table_steal: - * @hash_table: a #GHashTable. - * @key: the key to remove. + * @hash_table: a #GHashTable + * @key: the key to remove * * Removes a key and its associated value from a #GHashTable without * calling the key and value destroy functions. * - * Return value: %TRUE if the key was found and removed from the #GHashTable. - **/ + * Returns: %TRUE if the key was found and removed from the #GHashTable + */ gboolean g_hash_table_steal (GHashTable *hash_table, gconstpointer key) @@ -1226,13 +1406,13 @@ g_hash_table_steal (GHashTable *hash_table, * * Removes all keys and their associated values from a #GHashTable. * - * If the #GHashTable was created using g_hash_table_new_full(), the keys - * and values are freed using the supplied destroy functions, otherwise you - * have to make sure that any dynamically allocated values are freed - * yourself. + * If the #GHashTable was created using g_hash_table_new_full(), + * the keys and values are freed using the supplied destroy functions, + * otherwise you have to make sure that any dynamically allocated + * values are freed yourself. * * Since: 2.12 - **/ + */ void g_hash_table_remove_all (GHashTable *hash_table) { @@ -1243,19 +1423,19 @@ g_hash_table_remove_all (GHashTable *hash_table) hash_table->version++; #endif - g_hash_table_remove_all_nodes (hash_table, TRUE); + g_hash_table_remove_all_nodes (hash_table, TRUE, FALSE); g_hash_table_maybe_resize (hash_table); } /** * g_hash_table_steal_all: - * @hash_table: a #GHashTable. + * @hash_table: a #GHashTable * * Removes all keys and their associated values from a #GHashTable * without calling the key and value destroy functions. * * Since: 2.12 - **/ + */ void g_hash_table_steal_all (GHashTable *hash_table) { @@ -1266,22 +1446,22 @@ g_hash_table_steal_all (GHashTable *hash_table) hash_table->version++; #endif - g_hash_table_remove_all_nodes (hash_table, FALSE); + g_hash_table_remove_all_nodes (hash_table, FALSE, FALSE); g_hash_table_maybe_resize (hash_table); } /* * g_hash_table_foreach_remove_or_steal: - * @hash_table: our #GHashTable + * @hash_table: a #GHashTable * @func: the user's callback function * @user_data: data for @func * @notify: %TRUE if the destroy notify handlers are to be called * - * Implements the common logic for g_hash_table_foreach_remove() and - * g_hash_table_foreach_steal(). + * Implements the common logic for g_hash_table_foreach_remove() + * and g_hash_table_foreach_steal(). * * Iterates over every node in the table, calling @func with the key - * and value of the node (and @user_data). If @func returns %TRUE the + * and value of the node (and @user_data). If @func returns %TRUE the * node is removed from the table. * * If @notify is true then the destroy notify handlers will be called @@ -1329,21 +1509,21 @@ g_hash_table_foreach_remove_or_steal (GHashTable *hash_table, /** * g_hash_table_foreach_remove: - * @hash_table: a #GHashTable. - * @func: the function to call for each key/value pair. - * @user_data: user data to pass to the function. + * @hash_table: a #GHashTable + * @func: the function to call for each key/value pair + * @user_data: user data to pass to the function * - * Calls the given function for each key/value pair in the #GHashTable. - * If the function returns %TRUE, then the key/value pair is removed from the - * #GHashTable. If you supplied key or value destroy functions when creating - * the #GHashTable, they are used to free the memory allocated for the removed - * keys and values. + * Calls the given function for each key/value pair in the + * #GHashTable. If the function returns %TRUE, then the key/value + * pair is removed from the #GHashTable. If you supplied key or + * value destroy functions when creating the #GHashTable, they are + * used to free the memory allocated for the removed keys and values. * - * See #GHashTableIter for an alternative way to loop over the + * See #GHashTableIter for an alternative way to loop over the * key/value pairs in the hash table. * - * Return value: the number of key/value pairs removed. - **/ + * Returns: the number of key/value pairs removed + */ guint g_hash_table_foreach_remove (GHashTable *hash_table, GHRFunc func, @@ -1357,19 +1537,20 @@ g_hash_table_foreach_remove (GHashTable *hash_table, /** * g_hash_table_foreach_steal: - * @hash_table: a #GHashTable. - * @func: the function to call for each key/value pair. - * @user_data: user data to pass to the function. + * @hash_table: a #GHashTable + * @func: the function to call for each key/value pair + * @user_data: user data to pass to the function * - * Calls the given function for each key/value pair in the #GHashTable. - * If the function returns %TRUE, then the key/value pair is removed from the - * #GHashTable, but no key or value destroy functions are called. + * Calls the given function for each key/value pair in the + * #GHashTable. If the function returns %TRUE, then the key/value + * pair is removed from the #GHashTable, but no key or value + * destroy functions are called. * * See #GHashTableIter for an alternative way to loop over the * key/value pairs in the hash table. * - * Return value: the number of key/value pairs removed. - **/ + * Returns: the number of key/value pairs removed. + */ guint g_hash_table_foreach_steal (GHashTable *hash_table, GHRFunc func, @@ -1383,9 +1564,9 @@ g_hash_table_foreach_steal (GHashTable *hash_table, /** * g_hash_table_foreach: - * @hash_table: a #GHashTable. - * @func: the function to call for each key/value pair. - * @user_data: user data to pass to the function. + * @hash_table: a #GHashTable + * @func: the function to call for each key/value pair + * @user_data: user data to pass to the function * * Calls the given function for each of the key/value pairs in the * #GHashTable. The function is passed the key and value of each @@ -1396,7 +1577,7 @@ g_hash_table_foreach_steal (GHashTable *hash_table, * * See g_hash_table_find() for performance caveats for linear * order searches in contrast to g_hash_table_lookup(). - **/ + */ void g_hash_table_foreach (GHashTable *hash_table, GHFunc func, @@ -1404,12 +1585,16 @@ g_hash_table_foreach (GHashTable *hash_table, { gint i; #ifndef G_DISABLE_ASSERT - gint version = hash_table->version; + gint version; #endif g_return_if_fail (hash_table != NULL); g_return_if_fail (func != NULL); +#ifndef G_DISABLE_ASSERT + version = hash_table->version; +#endif + for (i = 0; i < hash_table->size; i++) { guint node_hash = hash_table->hashes[i]; @@ -1427,30 +1612,30 @@ g_hash_table_foreach (GHashTable *hash_table, /** * g_hash_table_find: - * @hash_table: a #GHashTable. - * @predicate: function to test the key/value pairs for a certain property. - * @user_data: user data to pass to the function. - * - * Calls the given function for key/value pairs in the #GHashTable until - * @predicate returns %TRUE. The function is passed the key and value of - * each pair, and the given @user_data parameter. The hash table may not - * be modified while iterating over it (you can't add/remove items). - * - * Note, that hash tables are really only optimized for forward lookups, - * i.e. g_hash_table_lookup(). - * So code that frequently issues g_hash_table_find() or - * g_hash_table_foreach() (e.g. in the order of once per every entry in a - * hash table) should probably be reworked to use additional or different - * data structures for reverse lookups (keep in mind that an O(n) find/foreach - * operation issued for all n values in a hash table ends up needing O(n*n) - * operations). - * - * Return value: The value of the first key/value pair is returned, + * @hash_table: a #GHashTable + * @predicate: function to test the key/value pairs for a certain property + * @user_data: user data to pass to the function + * + * Calls the given function for key/value pairs in the #GHashTable + * until @predicate returns %TRUE. The function is passed the key + * and value of each pair, and the given @user_data parameter. The + * hash table may not be modified while iterating over it (you can't + * add/remove items). + * + * Note, that hash tables are really only optimized for forward + * lookups, i.e. g_hash_table_lookup(). So code that frequently issues + * g_hash_table_find() or g_hash_table_foreach() (e.g. in the order of + * once per every entry in a hash table) should probably be reworked + * to use additional or different data structures for reverse lookups + * (keep in mind that an O(n) find/foreach operation issued for all n + * values in a hash table ends up needing O(n*n) operations). + * + * Returns: (allow-none): The value of the first key/value pair is returned, * for which @predicate evaluates to %TRUE. If no pair with the * requested property is found, %NULL is returned. * * Since: 2.4 - **/ + */ gpointer g_hash_table_find (GHashTable *hash_table, GHRFunc predicate, @@ -1458,13 +1643,17 @@ g_hash_table_find (GHashTable *hash_table, { gint i; #ifndef G_DISABLE_ASSERT - gint version = hash_table->version; + gint version; #endif gboolean match; g_return_val_if_fail (hash_table != NULL, NULL); g_return_val_if_fail (predicate != NULL, NULL); +#ifndef G_DISABLE_ASSERT + version = hash_table->version; +#endif + match = FALSE; for (i = 0; i < hash_table->size; i++) @@ -1489,12 +1678,12 @@ g_hash_table_find (GHashTable *hash_table, /** * g_hash_table_size: - * @hash_table: a #GHashTable. + * @hash_table: a #GHashTable * * Returns the number of elements contained in the #GHashTable. * - * Return value: the number of key/value pairs in the #GHashTable. - **/ + * Returns: the number of key/value pairs in the #GHashTable. + */ guint g_hash_table_size (GHashTable *hash_table) { @@ -1508,12 +1697,12 @@ g_hash_table_size (GHashTable *hash_table) * @hash_table: a #GHashTable * * Retrieves every key inside @hash_table. The returned data is valid - * until @hash_table is modified. + * until changes to the hash release those keys. * - * Return value: a #GList containing all the keys inside the hash - * table. The content of the list is owned by the hash table and - * should not be modified or freed. Use g_list_free() when done - * using the list. + * Returns: a #GList containing all the keys inside the hash + * table. The content of the list is owned by the hash table and + * should not be modified or freed. Use g_list_free() when done + * using the list. * * Since: 2.14 */ @@ -1536,16 +1725,62 @@ g_hash_table_get_keys (GHashTable *hash_table) } /** + * g_hash_table_get_keys_as_array: + * @hash_table: a #GHashTable + * @length: (out): the length of the returned array + * + * Retrieves every key inside @hash_table, as an array. + * + * The returned array is %NULL-terminated but may contain %NULL as a + * key. Use @length to determine the true length if it's possible that + * %NULL was used as the value for a key. + * + * Note: in the common case of a string-keyed #GHashTable, the return + * value of this function can be conveniently cast to (gchar **). + * + * You should always free the return result with g_free(). In the + * above-mentioned case of a string-keyed hash table, it may be + * appropriate to use g_strfreev() if you call g_hash_table_steal_all() + * first to transfer ownership of the keys. + * + * Returns: (array length=length) (transfer container): a + * %NULL-terminated array containing each key from the table. + * + * Since: 2.40 + **/ +gpointer * +g_hash_table_get_keys_as_array (GHashTable *hash_table, + guint *length) +{ + gpointer *result; + guint i, j = 0; + + result = g_new (gpointer, hash_table->nnodes + 1); + for (i = 0; i < hash_table->size; i++) + { + if (HASH_IS_REAL (hash_table->hashes[i])) + result[j++] = hash_table->keys[i]; + } + g_assert_cmpint (j, ==, hash_table->nnodes); + result[j] = NULL; + + if (length) + *length = j; + + return result; +} + +/** * g_hash_table_get_values: * @hash_table: a #GHashTable * - * Retrieves every value inside @hash_table. The returned data is - * valid until @hash_table is modified. + * Retrieves every value inside @hash_table. The returned data + * is valid until @hash_table is modified. * - * Return value: a #GList containing all the values inside the hash - * table. The content of the list is owned by the hash table and - * should not be modified or freed. Use g_list_free() when done - * using the list. + * Returns: a #GList containing all the values inside the hash + * table. The content of the list is owned by the hash table and + * should not be modified or freed. Use g_list_free() when done + * using the list. * * Since: 2.14 */ @@ -1566,3 +1801,230 @@ g_hash_table_get_values (GHashTable *hash_table) return retval; } + +/* Hash functions. + */ + +/** + * g_str_equal: + * @v1: a key + * @v2: a key to compare with @v1 + * + * Compares two strings for byte-by-byte equality and returns %TRUE + * if they are equal. It can be passed to g_hash_table_new() as the + * @key_equal_func parameter, when using non-%NULL strings as keys in a + * #GHashTable. + * + * Note that this function is primarily meant as a hash table comparison + * function. For a general-purpose, %NULL-safe string comparison function, + * see g_strcmp0(). + * + * Returns: %TRUE if the two keys match + */ +gboolean +g_str_equal (gconstpointer v1, + gconstpointer v2) +{ + const gchar *string1 = v1; + const gchar *string2 = v2; + + return strcmp (string1, string2) == 0; +} + +/** + * g_str_hash: + * @v: a string key + * + * Converts a string to a hash value. + * + * 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. + * + * It can be passed to g_hash_table_new() as the @hash_func parameter, + * when using non-%NULL strings as keys in a #GHashTable. + * + * Returns: a hash value corresponding to the key + */ +guint +g_str_hash (gconstpointer v) +{ + const signed char *p; + guint32 h = 5381; + + for (p = v; *p != '\0'; p++) + h = (h << 5) + h + *p; + + return h; +} + +/** + * g_direct_hash: + * @v: (allow-none): a #gpointer key + * + * Converts a gpointer to a hash value. + * It can be passed to g_hash_table_new() as the @hash_func parameter, + * when using opaque pointers compared by pointer value as keys in a + * #GHashTable. + * + * This hash function is also appropriate for keys that are integers + * stored in pointers, such as `GINT_TO_POINTER (n)`. + * + * Returns: a hash value corresponding to the key. + */ +guint +g_direct_hash (gconstpointer v) +{ + return GPOINTER_TO_UINT (v); +} + +/** + * g_direct_equal: + * @v1: (allow-none): a key + * @v2: (allow-none): a key to compare with @v1 + * + * Compares two #gpointer arguments and returns %TRUE if they are equal. + * It can be passed to g_hash_table_new() as the @key_equal_func + * parameter, when using opaque pointers compared by pointer value as + * keys in a #GHashTable. + * + * This equality function is also appropriate for keys that are integers + * stored in pointers, such as `GINT_TO_POINTER (n)`. + * + * Returns: %TRUE if the two keys match. + */ +gboolean +g_direct_equal (gconstpointer v1, + gconstpointer v2) +{ + return v1 == v2; +} + +/** + * g_int_equal: + * @v1: a pointer to a #gint key + * @v2: a pointer to a #gint key to compare with @v1 + * + * Compares the two #gint values being pointed to and returns + * %TRUE if they are equal. + * It can be passed to g_hash_table_new() as the @key_equal_func + * parameter, when using non-%NULL pointers to integers as keys in a + * #GHashTable. + * + * Note that this function acts on pointers to #gint, not on #gint + * directly: if your hash table's keys are of the form + * `GINT_TO_POINTER (n)`, use g_direct_equal() instead. + * + * Returns: %TRUE if the two keys match. + */ +gboolean +g_int_equal (gconstpointer v1, + gconstpointer v2) +{ + return *((const gint*) v1) == *((const gint*) v2); +} + +/** + * g_int_hash: + * @v: a pointer to a #gint key + * + * Converts a pointer to a #gint to a hash value. + * It can be passed to g_hash_table_new() as the @hash_func parameter, + * when using non-%NULL pointers to integer values as keys in a #GHashTable. + * + * Note that this function acts on pointers to #gint, not on #gint + * directly: if your hash table's keys are of the form + * `GINT_TO_POINTER (n)`, use g_direct_hash() instead. + * + * Returns: a hash value corresponding to the key. + */ +guint +g_int_hash (gconstpointer v) +{ + return *(const gint*) v; +} + +/** + * g_int64_equal: + * @v1: a pointer to a #gint64 key + * @v2: a pointer to a #gint64 key to compare with @v1 + * + * Compares the two #gint64 values being pointed to and returns + * %TRUE if they are equal. + * It can be passed to g_hash_table_new() as the @key_equal_func + * parameter, when using non-%NULL pointers to 64-bit integers as keys in a + * #GHashTable. + * + * Returns: %TRUE if the two keys match. + * + * Since: 2.22 + */ +gboolean +g_int64_equal (gconstpointer v1, + gconstpointer v2) +{ + return *((const gint64*) v1) == *((const gint64*) v2); +} + +/** + * g_int64_hash: + * @v: a pointer to a #gint64 key + * + * Converts a pointer to a #gint64 to a hash value. + * + * It can be passed to g_hash_table_new() as the @hash_func parameter, + * when using non-%NULL pointers to 64-bit integer values as keys in a + * #GHashTable. + * + * Returns: a hash value corresponding to the key. + * + * Since: 2.22 + */ +guint +g_int64_hash (gconstpointer v) +{ + return (guint) *(const gint64*) v; +} + +/** + * g_double_equal: + * @v1: a pointer to a #gdouble key + * @v2: a pointer to a #gdouble key to compare with @v1 + * + * Compares the two #gdouble values being pointed to and returns + * %TRUE if they are equal. + * It can be passed to g_hash_table_new() as the @key_equal_func + * parameter, when using non-%NULL pointers to doubles as keys in a + * #GHashTable. + * + * Returns: %TRUE if the two keys match. + * + * Since: 2.22 + */ +gboolean +g_double_equal (gconstpointer v1, + gconstpointer v2) +{ + return *((const gdouble*) v1) == *((const gdouble*) v2); +} + +/** + * g_double_hash: + * @v: a pointer to a #gdouble key + * + * Converts a pointer to a #gdouble to a hash value. + * It can be passed to g_hash_table_new() as the @hash_func parameter, + * It can be passed to g_hash_table_new() as the @hash_func parameter, + * when using non-%NULL pointers to doubles as keys in a #GHashTable. + * + * Returns: a hash value corresponding to the key. + * + * Since: 2.22 + */ +guint +g_double_hash (gconstpointer v) +{ + return (guint) *(const gdouble*) v; +}