#define HASH_IS_TOOMBSTONE(h_) ((h_) == 1)
#define HASH_IS_REAL(h_) ((h_) >= 2)
-typedef struct _GHashNode GHashNode;
-
-struct _GHashNode
-{
- gpointer key;
- gpointer value;
-
- /* If key_hash == 0, node is not in use
- * If key_hash == 1, node is a tombstone
- * If key_hash >= 2, node contains data */
- guint key_hash;
-};
-
struct _GHashTable
{
gint size;
guint mask;
gint nnodes;
gint noccupied; /* nnodes + tombstones */
- GHashNode *nodes;
+
+ gpointer *keys;
+ guint *hashes;
+ gpointer *values;
+
GHashFunc hash_func;
GEqualFunc key_equal_func;
volatile gint ref_count;
* @hash_table: our #GHashTable
* @key: the key to lookup against (may be %NULL)
* @hash_return: optional key hash return location
- * Return value: index of the described #GHashNode
+ * Return value: index of the described node
*
* Performs a lookup in the hash table.
*
g_hash_table_lookup_node (GHashTable *hash_table,
gconstpointer key)
{
- GHashNode *node;
guint node_index;
guint hash_value;
guint step = 0;
hash_value = 2;
node_index = hash_value % hash_table->mod;
- node = &hash_table->nodes [node_index];
- while (!HASH_IS_UNUSED (node->key_hash))
+ while (!HASH_IS_UNUSED (hash_table->hashes[node_index]))
{
/* We first check if our full hash values
* are equal so we can avoid calling the full-blown
* key equality function in most cases.
*/
- if (node->key_hash == hash_value)
+ if (hash_table->hashes[node_index] == hash_value)
{
+ gpointer node_key = hash_table->keys[node_index];
+
if (hash_table->key_equal_func)
{
- if (hash_table->key_equal_func (node->key, key))
+ if (hash_table->key_equal_func (node_key, key))
break;
}
- else if (node->key == key)
+ else if (node_key == key)
{
break;
}
step++;
node_index += step;
node_index &= hash_table->mask;
- node = &hash_table->nodes [node_index];
}
return node_index;
* @hash_table: our #GHashTable
* @key: the key to lookup against
* @hash_return: key hash return location
- * Return value: index of the described #GHashNode
+ * Return value: index of the described node
*
* Performs a lookup in the hash table, preserving extra information
* usually needed for insertion.
gconstpointer key,
guint *hash_return)
{
- GHashNode *node;
guint node_index;
guint hash_value;
guint first_tombstone;
*hash_return = hash_value;
node_index = hash_value % hash_table->mod;
- node = &hash_table->nodes [node_index];
- while (!HASH_IS_UNUSED (node->key_hash))
+ while (!HASH_IS_UNUSED (hash_table->hashes[node_index]))
{
+ guint node_hash = hash_table->hashes[node_index];
+
/* We first check if our full hash values
* are equal so we can avoid calling the full-blown
* key equality function in most cases.
*/
- if (node->key_hash == hash_value)
+ if (node_hash == hash_value)
{
+ gpointer node_key = hash_table->keys[node_index];
+
if (hash_table->key_equal_func)
{
- if (hash_table->key_equal_func (node->key, key))
+ if (hash_table->key_equal_func (node_key, key))
return node_index;
}
- else if (node->key == key)
+ else if (node_key == key)
{
return node_index;
}
}
- else if (HASH_IS_TOOMBSTONE (node->key_hash) && !have_tombstone)
+ else if (HASH_IS_TOOMBSTONE (node_hash) && !have_tombstone)
{
first_tombstone = node_index;
have_tombstone = TRUE;
step++;
node_index += step;
node_index &= hash_table->mask;
- node = &hash_table->nodes [node_index];
}
if (have_tombstone)
*/
static void
g_hash_table_remove_node (GHashTable *hash_table,
- GHashNode *node,
+ int i,
gboolean notify)
{
if (notify && hash_table->key_destroy_func)
- hash_table->key_destroy_func (node->key);
+ hash_table->key_destroy_func (hash_table->keys[i]);
if (notify && hash_table->value_destroy_func)
- hash_table->value_destroy_func (node->value);
+ hash_table->value_destroy_func (hash_table->values[i]);
/* Erect tombstone */
- node->key_hash = 1;
+ hash_table->hashes[i] = 1;
/* Be GC friendly */
- node->key = NULL;
- node->value = NULL;
+ hash_table->keys[i] = NULL;
+ hash_table->values[i] = NULL;
hash_table->nnodes--;
}
{
for (i = 0; i < hash_table->size; i++)
{
- GHashNode *node = &hash_table->nodes [i];
-
- if (HASH_IS_REAL (node->key_hash))
+ if (HASH_IS_REAL (hash_table->hashes[i]))
{
if (hash_table->key_destroy_func != NULL)
- hash_table->key_destroy_func (node->key);
+ hash_table->key_destroy_func (hash_table->keys[i]);
if (hash_table->value_destroy_func != NULL)
- hash_table->value_destroy_func (node->value);
+ hash_table->value_destroy_func (hash_table->values[i]);
}
}
}
/* We need to set node->key_hash = 0 for all nodes - might as well be GC
* friendly and clear everything
*/
- memset (hash_table->nodes, 0, hash_table->size * sizeof (GHashNode));
+ 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));
hash_table->nnodes = 0;
hash_table->noccupied = 0;
static void
g_hash_table_resize (GHashTable *hash_table)
{
- GHashNode *new_nodes;
+ gpointer *new_keys;
+ gpointer *new_values;
+ guint *new_hashes;
gint old_size;
gint i;
old_size = hash_table->size;
g_hash_table_set_shift_from_size (hash_table, hash_table->nnodes * 2);
- new_nodes = g_new0 (GHashNode, hash_table->size);
+ new_keys = g_new0 (gpointer, hash_table->size);
+ new_values = g_new0 (gpointer, hash_table->size);
+ new_hashes = g_new0 (guint, hash_table->size);
for (i = 0; i < old_size; i++)
{
- GHashNode *node = &hash_table->nodes [i];
- GHashNode *new_node;
+ guint node_hash = hash_table->hashes[i];
guint hash_val;
guint step = 0;
- if (!HASH_IS_REAL (node->key_hash))
+ if (!HASH_IS_REAL (node_hash))
continue;
- hash_val = node->key_hash % hash_table->mod;
- new_node = &new_nodes [hash_val];
+ hash_val = node_hash % hash_table->mod;
- while (!HASH_IS_UNUSED (new_node->key_hash))
+ while (!HASH_IS_UNUSED (new_hashes[hash_val]))
{
step++;
hash_val += step;
hash_val &= hash_table->mask;
- new_node = &new_nodes [hash_val];
}
- *new_node = *node;
+ new_hashes[hash_val] = hash_table->hashes[i];
+ new_keys[hash_val] = hash_table->keys[i];
+ new_values[hash_val] = hash_table->values[i];
}
- g_free (hash_table->nodes);
- hash_table->nodes = new_nodes;
+ g_free (hash_table->keys);
+ g_free (hash_table->values);
+ g_free (hash_table->hashes);
+
+ hash_table->keys = new_keys;
+ hash_table->values = new_values;
+ hash_table->hashes = new_hashes;
+
hash_table->noccupied = hash_table->nnodes;
}
#endif
hash_table->key_destroy_func = key_destroy_func;
hash_table->value_destroy_func = value_destroy_func;
- hash_table->nodes = g_new0 (GHashNode, hash_table->size);
+ hash_table->keys = g_new0 (gpointer, hash_table->size);
+ hash_table->values = g_new0 (gpointer, hash_table->size);
+ hash_table->hashes = g_new0 (guint, hash_table->size);
return hash_table;
}
gpointer *value)
{
RealIter *ri = (RealIter *) iter;
- GHashNode *node;
gint position;
g_return_val_if_fail (iter != NULL, FALSE);
ri->position = position;
return FALSE;
}
-
- node = &ri->hash_table->nodes [position];
}
- while (!HASH_IS_REAL (node->key_hash));
+ while (!HASH_IS_REAL (ri->hash_table->hashes[position]));
if (key != NULL)
- *key = node->key;
+ *key = ri->hash_table->keys[position];
if (value != NULL)
- *value = node->value;
+ *value = ri->hash_table->values[position];
ri->position = position;
return TRUE;
g_return_if_fail (ri->position >= 0);
g_return_if_fail (ri->position < ri->hash_table->size);
- g_hash_table_remove_node (ri->hash_table, &ri->hash_table->nodes [ri->position], notify);
+ g_hash_table_remove_node (ri->hash_table, ri->position, notify);
#ifndef G_DISABLE_ASSERT
ri->version++;
if (g_atomic_int_exchange_and_add (&hash_table->ref_count, -1) - 1 == 0)
{
g_hash_table_remove_all_nodes (hash_table, TRUE);
- g_free (hash_table->nodes);
+ g_free (hash_table->keys);
+ g_free (hash_table->values);
+ g_free (hash_table->hashes);
g_slice_free (GHashTable, hash_table);
}
}
g_hash_table_lookup (GHashTable *hash_table,
gconstpointer key)
{
- GHashNode *node;
guint node_index;
g_return_val_if_fail (hash_table != NULL, NULL);
node_index = g_hash_table_lookup_node (hash_table, key);
- node = &hash_table->nodes [node_index];
- return HASH_IS_REAL (node->key_hash) ? node->value : NULL;
+ return HASH_IS_REAL (hash_table->hashes[node_index])
+ ? hash_table->values[node_index]
+ : NULL;
}
/**
gpointer *orig_key,
gpointer *value)
{
- GHashNode *node;
guint node_index;
g_return_val_if_fail (hash_table != NULL, FALSE);
node_index = g_hash_table_lookup_node (hash_table, lookup_key);
- node = &hash_table->nodes [node_index];
- if (!HASH_IS_REAL (node->key_hash))
+ if (!HASH_IS_REAL (hash_table->hashes[node_index]))
return FALSE;
if (orig_key)
- *orig_key = node->key;
+ *orig_key = hash_table->keys[node_index];
if (value)
- *value = node->value;
+ *value = hash_table->values[node_index];
return TRUE;
}
gpointer value,
gboolean keep_new_key)
{
- GHashNode *node;
guint node_index;
guint key_hash;
guint old_hash;
g_return_if_fail (hash_table->ref_count > 0);
node_index = g_hash_table_lookup_node_for_insertion (hash_table, key, &key_hash);
- node = &hash_table->nodes [node_index];
- old_hash = node->key_hash;
+ old_hash = hash_table->hashes[node_index];
if (HASH_IS_REAL (old_hash))
{
if (keep_new_key)
{
if (hash_table->key_destroy_func)
- hash_table->key_destroy_func (node->key);
- node->key = key;
+ hash_table->key_destroy_func (hash_table->keys[node_index]);
+ hash_table->keys[node_index] = key;
}
else
{
}
if (hash_table->value_destroy_func)
- hash_table->value_destroy_func (node->value);
+ hash_table->value_destroy_func (hash_table->values[node_index]);
- node->value = value;
+ hash_table->values[node_index] = value;
}
else
{
- node->key = key;
- node->value = value;
- node->key_hash = key_hash;
+ hash_table->keys[node_index] = key;
+ hash_table->values[node_index] = value;
+ hash_table->hashes[node_index] = key_hash;
hash_table->nnodes++;
gconstpointer key,
gboolean notify)
{
- GHashNode *node;
guint node_index;
g_return_val_if_fail (hash_table != NULL, FALSE);
node_index = g_hash_table_lookup_node (hash_table, key);
- node = &hash_table->nodes [node_index];
- if (!HASH_IS_REAL (node->key_hash))
+ if (!HASH_IS_REAL (hash_table->hashes[node_index]))
return FALSE;
- g_hash_table_remove_node (hash_table, node, notify);
+ g_hash_table_remove_node (hash_table, node_index, notify);
g_hash_table_maybe_resize (hash_table);
#ifndef G_DISABLE_ASSERT
for (i = 0; i < hash_table->size; i++)
{
- GHashNode *node = &hash_table->nodes [i];
+ guint node_hash = hash_table->hashes[i];
+ gpointer node_key = hash_table->keys[i];
+ gpointer node_value = hash_table->values[i];
- if (HASH_IS_REAL (node->key_hash) &&
- (* func) (node->key, node->value, user_data))
+ if (HASH_IS_REAL (node_hash) &&
+ (* func) (node_key, node_value, user_data))
{
- g_hash_table_remove_node (hash_table, node, notify);
+ g_hash_table_remove_node (hash_table, i, notify);
deleted++;
}
}
for (i = 0; i < hash_table->size; i++)
{
- GHashNode *node = &hash_table->nodes [i];
+ guint node_hash = hash_table->hashes[i];
+ gpointer node_key = hash_table->keys[i];
+ gpointer node_value = hash_table->values[i];
- if (HASH_IS_REAL (node->key_hash))
- (* func) (node->key, node->value, user_data);
+ if (HASH_IS_REAL (node_hash))
+ (* func) (node_key, node_value, user_data);
}
}
for (i = 0; i < hash_table->size; i++)
{
- GHashNode *node = &hash_table->nodes [i];
+ guint node_hash = hash_table->hashes[i];
+ gpointer node_key = hash_table->keys[i];
+ gpointer node_value = hash_table->values[i];
- if (HASH_IS_REAL (node->key_hash) &&
- predicate (node->key, node->value, user_data))
- return node->value;
+ if (HASH_IS_REAL (node_hash) &&
+ predicate (node_key, node_value, user_data))
+ return node_value;
}
return NULL;
retval = NULL;
for (i = 0; i < hash_table->size; i++)
{
- GHashNode *node = &hash_table->nodes [i];
-
- if (HASH_IS_REAL (node->key_hash))
- retval = g_list_prepend (retval, node->key);
+ if (HASH_IS_REAL (hash_table->hashes[i]))
+ retval = g_list_prepend (retval, hash_table->keys[i]);
}
return retval;
retval = NULL;
for (i = 0; i < hash_table->size; i++)
{
- GHashNode *node = &hash_table->nodes [i];
-
- if (HASH_IS_REAL (node->key_hash))
- retval = g_list_prepend (retval, node->value);
+ if (HASH_IS_REAL (hash_table->hashes[i]))
+ retval = g_list_prepend (retval, hash_table->values[i]);
}
return retval;