hash: Compare hash values before calling keys_equal

If the hash value is different, the keys cannot be equal. Testing this
beforehand can avoid a few function calls and shares this optimization
across all cairo-hash uses.
This commit is contained in:
Andrea Canciani 2011-08-01 19:01:16 +02:00
parent 02665975d3
commit 400d055f3c
5 changed files with 32 additions and 41 deletions

View file

@ -127,6 +127,25 @@ struct _cairo_hash_table {
unsigned long iterating; /* Iterating, no insert, no resize */
};
/**
* _cairo_hash_table_uid_keys_equal:
* @key_a: the first key to be compared
* @key_b: the second key to be compared
*
* Provides a cairo_hash_keys_equal_func_t which always returns
* %TRUE. This is useful to create hash tables using keys whose hash
* completely describes the key, because in this special case
* comparing the hashes is sufficient to guarantee that the keys are
* equal.
*
* Return value: %TRUE.
**/
static cairo_bool_t
_cairo_hash_table_uid_keys_equal (const void *key_a, const void *key_b)
{
return TRUE;
}
/**
* _cairo_hash_table_create:
* @keys_equal: a function to return %TRUE if two keys are equal
@ -139,6 +158,9 @@ struct _cairo_hash_table {
* _cairo_hash_table_remove), and other times both a key and a value
* will be necessary, (as in _cairo_hash_table_insert).
*
* If @keys_equal is %NULL, two keys will be considered equal if and
* only if their hashes are equal.
*
* See #cairo_hash_entry_t for more details.
*
* Return value: the new hash table or %NULL if out of memory.
@ -154,7 +176,10 @@ _cairo_hash_table_create (cairo_hash_keys_equal_func_t keys_equal)
return NULL;
}
hash_table->keys_equal = keys_equal;
if (keys_equal == NULL)
hash_table->keys_equal = _cairo_hash_table_uid_keys_equal;
else
hash_table->keys_equal = keys_equal;
hash_table->arrangement = &hash_table_arrangements[0];
@ -316,7 +341,7 @@ _cairo_hash_table_lookup (cairo_hash_table_t *hash_table,
entry = hash_table->entries[idx];
if (ENTRY_IS_LIVE (entry)) {
if (hash_table->keys_equal (key, entry))
if (entry->hash == key->hash && hash_table->keys_equal (key, entry))
return entry;
} else if (ENTRY_IS_FREE (entry))
return NULL;
@ -330,7 +355,7 @@ _cairo_hash_table_lookup (cairo_hash_table_t *hash_table,
entry = hash_table->entries[idx];
if (ENTRY_IS_LIVE (entry)) {
if (hash_table->keys_equal (key, entry))
if (entry->hash == key->hash && hash_table->keys_equal (key, entry))
return entry;
} else if (ENTRY_IS_FREE (entry))
return NULL;

View file

@ -152,15 +152,6 @@ _cairo_sub_font_glyph_init_key (cairo_sub_font_glyph_t *sub_font_glyph,
sub_font_glyph->base.hash = scaled_font_glyph_index;
}
static cairo_bool_t
_cairo_sub_font_glyphs_equal (const void *key_a, const void *key_b)
{
const cairo_sub_font_glyph_t *sub_font_glyph_a = key_a;
const cairo_sub_font_glyph_t *sub_font_glyph_b = key_b;
return sub_font_glyph_a->base.hash == sub_font_glyph_b->base.hash;
}
static cairo_sub_font_glyph_t *
_cairo_sub_font_glyph_create (unsigned long scaled_font_glyph_index,
unsigned int subset_id,
@ -314,7 +305,7 @@ _cairo_sub_font_create (cairo_scaled_font_subsets_t *parent,
sub_font->num_glyphs_in_latin_subset = 0;
sub_font->max_glyphs_per_subset = max_glyphs_per_subset;
sub_font->sub_font_glyphs = _cairo_hash_table_create (_cairo_sub_font_glyphs_equal);
sub_font->sub_font_glyphs = _cairo_hash_table_create (NULL);
if (unlikely (sub_font->sub_font_glyphs == NULL)) {
free (sub_font);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);

View file

@ -638,9 +638,6 @@ _cairo_scaled_font_keys_equal (const void *abstract_key_a,
const cairo_scaled_font_t *key_a = abstract_key_a;
const cairo_scaled_font_t *key_b = abstract_key_b;
if (key_a->hash_entry.hash != key_b->hash_entry.hash)
return FALSE;
return key_a->original_font_face == key_b->original_font_face &&
memcmp ((unsigned char *)(&key_a->font_matrix.xx),
(unsigned char *)(&key_b->font_matrix.xx),
@ -668,15 +665,6 @@ _cairo_scaled_font_matches (const cairo_scaled_font_t *scaled_font,
cairo_font_options_equal (&scaled_font->options, options);
}
static cairo_bool_t
_cairo_scaled_glyphs_equal (const void *abstract_a, const void *abstract_b)
{
const cairo_scaled_glyph_t *a = abstract_a;
const cairo_scaled_glyph_t *b = abstract_b;
return a->hash_entry.hash == b->hash_entry.hash;
}
/*
* Basic #cairo_scaled_font_t object management
*/
@ -725,7 +713,7 @@ _cairo_scaled_font_init (cairo_scaled_font_t *scaled_font,
return status;
}
scaled_font->glyphs = _cairo_hash_table_create (_cairo_scaled_glyphs_equal);
scaled_font->glyphs = _cairo_hash_table_create (NULL);
if (unlikely (scaled_font->glyphs == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);

View file

@ -500,13 +500,6 @@ _device_flush (void *device)
return CAIRO_STATUS_SUCCESS;
}
static cairo_bool_t
_xrender_formats_equal (const void *A, const void *B)
{
const cairo_xcb_xrender_format_t *a = A, *b = B;
return a->key.hash == b->key.hash;
}
static void
_pluck_xrender_format (void *entry,
void *closure)
@ -633,7 +626,7 @@ _cairo_xcb_connection_get (xcb_connection_t *xcb_connection)
cairo_list_init (&connection->fonts);
cairo_list_init (&connection->screens);
cairo_list_init (&connection->link);
connection->xrender_formats = _cairo_hash_table_create (_xrender_formats_equal);
connection->xrender_formats = _cairo_hash_table_create (NULL);
if (connection->xrender_formats == NULL) {
CAIRO_MUTEX_FINI (connection->device.mutex);
free (connection);
@ -641,7 +634,7 @@ _cairo_xcb_connection_get (xcb_connection_t *xcb_connection)
goto unlock;
}
connection->visual_to_xrender_format = _cairo_hash_table_create (_xrender_formats_equal);
connection->visual_to_xrender_format = _cairo_hash_table_create (NULL);
if (connection->visual_to_xrender_format == NULL) {
_cairo_hash_table_destroy (connection->xrender_formats);
CAIRO_MUTEX_FINI (connection->device.mutex);

View file

@ -97,9 +97,6 @@ _linear_pattern_cache_entry_equal (const void *A, const void *B)
{
const struct pattern_cache_entry *a = A, *b = B;
if (a->key.hash != b->key.hash)
return FALSE;
return _cairo_linear_pattern_equal (&a->pattern.gradient.linear,
&b->pattern.gradient.linear);
}
@ -109,9 +106,6 @@ _radial_pattern_cache_entry_equal (const void *A, const void *B)
{
const struct pattern_cache_entry *a = A, *b = B;
if (a->key.hash != b->key.hash)
return FALSE;
return _cairo_radial_pattern_equal (&a->pattern.gradient.radial,
&b->pattern.gradient.radial);
}