From 400d055f3cd2eecd2cc4b91a40eac4146ec61932 Mon Sep 17 00:00:00 2001 From: Andrea Canciani Date: Mon, 1 Aug 2011 19:01:16 +0200 Subject: [PATCH] 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. --- src/cairo-hash.c | 31 ++++++++++++++++++++++++++++--- src/cairo-scaled-font-subsets.c | 11 +---------- src/cairo-scaled-font.c | 14 +------------- src/cairo-xcb-connection.c | 11 ++--------- src/cairo-xcb-screen.c | 6 ------ 5 files changed, 32 insertions(+), 41 deletions(-) diff --git a/src/cairo-hash.c b/src/cairo-hash.c index 7cab89d90..98f48a8d2 100644 --- a/src/cairo-hash.c +++ b/src/cairo-hash.c @@ -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; diff --git a/src/cairo-scaled-font-subsets.c b/src/cairo-scaled-font-subsets.c index d3d9d65a0..0e9880a00 100644 --- a/src/cairo-scaled-font-subsets.c +++ b/src/cairo-scaled-font-subsets.c @@ -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); diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c index 6dc8ed39d..cb59bce67 100644 --- a/src/cairo-scaled-font.c +++ b/src/cairo-scaled-font.c @@ -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); diff --git a/src/cairo-xcb-connection.c b/src/cairo-xcb-connection.c index 3cba883c2..b25264848 100644 --- a/src/cairo-xcb-connection.c +++ b/src/cairo-xcb-connection.c @@ -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); diff --git a/src/cairo-xcb-screen.c b/src/cairo-xcb-screen.c index 7b5493f19..18e75a5cc 100644 --- a/src/cairo-xcb-screen.c +++ b/src/cairo-xcb-screen.c @@ -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); }