cache the value of the hash function in the GHashNode. this speeds up

2006-12-27  Ryan Lortie  <desrt@desrt.ca>

        * glib/ghash.c: cache the value of the hash function
        in the GHashNode.  this speeds up resizing the hash
        table and it also allows a slight optimisation on
        lookups.  (#388332)
This commit is contained in:
Ryan Lortie 2006-12-27 05:43:40 +00:00 committed by Ryan Lortie
parent d1be55cccb
commit e6b78c9af1
2 changed files with 41 additions and 17 deletions

View File

@ -1,3 +1,10 @@
2006-12-27 Ryan Lortie <desrt@desrt.ca>
* glib/ghash.c: cache the value of the hash function
in the GHashNode. this speeds up resizing the hash
table and it also allows a slight optimisation on
lookups. (#388332)
2006-12-27 Matthias Clasen <mclasen@redhat.com> 2006-12-27 Matthias Clasen <mclasen@redhat.com>
* glib/gunicollate.c (g_utf8_collate_key): Don't modify * glib/gunicollate.c (g_utf8_collate_key): Don't modify

View File

@ -44,6 +44,7 @@ struct _GHashNode
{ {
gpointer key; gpointer key;
gpointer value; gpointer value;
guint key_hash;
GHashNode *next; GHashNode *next;
}; };
@ -70,9 +71,11 @@ struct _GHashTable
static void g_hash_table_resize (GHashTable *hash_table); static void g_hash_table_resize (GHashTable *hash_table);
static GHashNode** g_hash_table_lookup_node (GHashTable *hash_table, static GHashNode** g_hash_table_lookup_node (GHashTable *hash_table,
gconstpointer key); gconstpointer key,
guint *hash_return);
static GHashNode* g_hash_node_new (gpointer key, static GHashNode* g_hash_node_new (gpointer key,
gpointer value); gpointer value,
guint key_hash);
static void g_hash_node_destroy (GHashNode *hash_node, static void g_hash_node_destroy (GHashNode *hash_node,
GDestroyNotify key_destroy_func, GDestroyNotify key_destroy_func,
GDestroyNotify value_destroy_func); GDestroyNotify value_destroy_func);
@ -224,25 +227,35 @@ g_hash_table_destroy (GHashTable *hash_table)
static inline GHashNode** static inline GHashNode**
g_hash_table_lookup_node (GHashTable *hash_table, g_hash_table_lookup_node (GHashTable *hash_table,
gconstpointer key) gconstpointer key,
guint *hash_return)
{ {
GHashNode **node; GHashNode **node;
guint hash_value;
hash_value = (* hash_table->hash_func) (key);
node = &hash_table->nodes[hash_value % hash_table->size];
node = &hash_table->nodes if (hash_return)
[(* hash_table->hash_func) (key) % hash_table->size]; *hash_return = hash_value;
/* Hash table lookup needs to be fast. /* Hash table lookup needs to be fast.
* We therefore remove the extra conditional of testing * We therefore remove the extra conditional of testing
* whether to call the key_equal_func or not from * whether to call the key_equal_func or not from
* the inner loop. * the inner loop.
*
* Additional optimisation: first check if our full hash
* values are equal so we can avoid calling the full-blown
* key equality function in most cases.
*/ */
if (hash_table->key_equal_func) if (hash_table->key_equal_func)
while (*node && !(*hash_table->key_equal_func) ((*node)->key, key)) while (*node && (((*node)->key_hash != hash_value) ||
!(*hash_table->key_equal_func) ((*node)->key, key)))
node = &(*node)->next; node = &(*node)->next;
else else
while (*node && (*node)->key != key) while (*node && (*node)->key != key)
node = &(*node)->next; node = &(*node)->next;
return node; return node;
} }
@ -266,7 +279,7 @@ g_hash_table_lookup (GHashTable *hash_table,
g_return_val_if_fail (hash_table != NULL, NULL); g_return_val_if_fail (hash_table != NULL, NULL);
node = *g_hash_table_lookup_node (hash_table, key); node = *g_hash_table_lookup_node (hash_table, key, NULL);
return node ? node->value : NULL; return node ? node->value : NULL;
} }
@ -295,7 +308,7 @@ g_hash_table_lookup_extended (GHashTable *hash_table,
g_return_val_if_fail (hash_table != NULL, FALSE); g_return_val_if_fail (hash_table != NULL, FALSE);
node = *g_hash_table_lookup_node (hash_table, lookup_key); node = *g_hash_table_lookup_node (hash_table, lookup_key, NULL);
if (node) if (node)
{ {
@ -329,11 +342,12 @@ g_hash_table_insert (GHashTable *hash_table,
gpointer value) gpointer value)
{ {
GHashNode **node; GHashNode **node;
guint key_hash;
g_return_if_fail (hash_table != NULL); g_return_if_fail (hash_table != NULL);
g_return_if_fail (hash_table->ref_count > 0); g_return_if_fail (hash_table->ref_count > 0);
node = g_hash_table_lookup_node (hash_table, key); node = g_hash_table_lookup_node (hash_table, key, &key_hash);
if (*node) if (*node)
{ {
@ -353,7 +367,7 @@ g_hash_table_insert (GHashTable *hash_table,
} }
else else
{ {
*node = g_hash_node_new (key, value); *node = g_hash_node_new (key, value, key_hash);
hash_table->nnodes++; hash_table->nnodes++;
G_HASH_TABLE_RESIZE (hash_table); G_HASH_TABLE_RESIZE (hash_table);
} }
@ -378,11 +392,12 @@ g_hash_table_replace (GHashTable *hash_table,
gpointer value) gpointer value)
{ {
GHashNode **node; GHashNode **node;
guint key_hash;
g_return_if_fail (hash_table != NULL); g_return_if_fail (hash_table != NULL);
g_return_if_fail (hash_table->ref_count > 0); g_return_if_fail (hash_table->ref_count > 0);
node = g_hash_table_lookup_node (hash_table, key); node = g_hash_table_lookup_node (hash_table, key, &key_hash);
if (*node) if (*node)
{ {
@ -397,7 +412,7 @@ g_hash_table_replace (GHashTable *hash_table,
} }
else else
{ {
*node = g_hash_node_new (key, value); *node = g_hash_node_new (key, value, key_hash);
hash_table->nnodes++; hash_table->nnodes++;
G_HASH_TABLE_RESIZE (hash_table); G_HASH_TABLE_RESIZE (hash_table);
} }
@ -425,7 +440,7 @@ g_hash_table_remove (GHashTable *hash_table,
g_return_val_if_fail (hash_table != NULL, FALSE); g_return_val_if_fail (hash_table != NULL, FALSE);
node = g_hash_table_lookup_node (hash_table, key); node = g_hash_table_lookup_node (hash_table, key, NULL);
if (*node) if (*node)
{ {
dest = *node; dest = *node;
@ -493,7 +508,7 @@ g_hash_table_steal (GHashTable *hash_table,
g_return_val_if_fail (hash_table != NULL, FALSE); g_return_val_if_fail (hash_table != NULL, FALSE);
node = g_hash_table_lookup_node (hash_table, key); node = g_hash_table_lookup_node (hash_table, key, NULL);
if (*node) if (*node)
{ {
dest = *node; dest = *node;
@ -733,7 +748,7 @@ g_hash_table_resize (GHashTable *hash_table)
{ {
next = node->next; next = node->next;
hash_val = (* hash_table->hash_func) (node->key) % new_size; hash_val = node->key_hash % new_size;
node->next = new_nodes[hash_val]; node->next = new_nodes[hash_val];
new_nodes[hash_val] = node; new_nodes[hash_val] = node;
@ -746,12 +761,14 @@ g_hash_table_resize (GHashTable *hash_table)
static GHashNode* static GHashNode*
g_hash_node_new (gpointer key, g_hash_node_new (gpointer key,
gpointer value) gpointer value,
guint key_hash)
{ {
GHashNode *hash_node = g_slice_new (GHashNode); GHashNode *hash_node = g_slice_new (GHashNode);
hash_node->key = key; hash_node->key = key;
hash_node->value = value; hash_node->value = value;
hash_node->key_hash = key_hash;
hash_node->next = NULL; hash_node->next = NULL;
return hash_node; return hash_node;