From d8e44dc6855c5065050b1bcb26e2708a63934797 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 22 Sep 2015 19:07:30 +0200 Subject: [PATCH] reduce duplicate hash computation in json_object_object_add() This can be a very considerable performance saver. --- json_object.c | 6 ++++-- linkhash.c | 16 +++++++++++----- linkhash.h | 43 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 7 deletions(-) diff --git a/json_object.c b/json_object.c index 8ed0239..e06c7ac 100644 --- a/json_object.c +++ b/json_object.c @@ -403,10 +403,11 @@ void json_object_object_add(struct json_object* jso, const char *key, // and re-adding it, so the existing key remains valid. json_object *existing_value = NULL; struct lh_entry *existing_entry; - existing_entry = lh_table_lookup_entry(jso->o.c_object, (void*)key); + const unsigned long hash = lh_get_hash(jso->o.c_object, (void*)key); + existing_entry = lh_table_lookup_entry_w_hash(jso->o.c_object, (void*)key, hash); if (!existing_entry) { - lh_table_insert(jso->o.c_object, strdup(key), val); + lh_table_insert_w_hash(jso->o.c_object, strdup(key), val, hash); return; } existing_value = (void *)existing_entry->v; @@ -415,6 +416,7 @@ void json_object_object_add(struct json_object* jso, const char *key, existing_entry->v = val; } + int json_object_object_length(struct json_object *jso) { return lh_table_length(jso->o.c_object); diff --git a/linkhash.c b/linkhash.c index 712c387..b4763cf 100644 --- a/linkhash.c +++ b/linkhash.c @@ -490,14 +490,13 @@ void lh_table_free(struct lh_table *t) } -int lh_table_insert(struct lh_table *t, void *k, const void *v) +int lh_table_insert_w_hash(struct lh_table *t, void *k, const void *v, const unsigned long h) { - unsigned long h, n; + unsigned long n; t->inserts++; if(t->count >= t->size * LH_LOAD_FACTOR) lh_table_resize(t, t->size * 2); - h = t->hash_fn(k); n = h % t->size; while( 1 ) { @@ -522,11 +521,14 @@ int lh_table_insert(struct lh_table *t, void *k, const void *v) return 0; } +int lh_table_insert(struct lh_table *t, void *k, const void *v) +{ + return lh_table_insert_w_hash(t, k, v, lh_get_hash(t, k)); +} -struct lh_entry* lh_table_lookup_entry(struct lh_table *t, const void *k) +struct lh_entry* lh_table_lookup_entry_w_hash(struct lh_table *t, const void *k, const unsigned long h) { - unsigned long h = t->hash_fn(k); unsigned long n = h % t->size; int count = 0; @@ -541,6 +543,10 @@ struct lh_entry* lh_table_lookup_entry(struct lh_table *t, const void *k) return NULL; } +struct lh_entry* lh_table_lookup_entry(struct lh_table *t, const void *k) +{ + return lh_table_lookup_entry_w_hash(t, k, lh_get_hash(t, k)); +} const void* lh_table_lookup(struct lh_table *t, const void *k) { diff --git a/linkhash.h b/linkhash.h index 950d09f..66f2d97 100644 --- a/linkhash.h +++ b/linkhash.h @@ -231,6 +231,20 @@ extern void lh_table_free(struct lh_table *t); extern int lh_table_insert(struct lh_table *t, void *k, const void *v); +/** + * Insert a record into the table. This one accepts the key's hash in additon + * to the key. This is an exension to support functions that need to calculate + * the hash several times and allows them to do it just once and then pass + * in the hash to all utility functions. Depending on use case, this can be a + * very considerate performance improvement. + * @param t the table to insert into. + * @param k a pointer to the key to insert. + * @param v a pointer to the value to insert. + * @param h hash value of the key to insert + */ +extern int lh_table_insert_w_hash(struct lh_table *t, void *k, const void *v, const unsigned long h); + + /** * Lookup a record into the table. * @param t the table to lookup @@ -239,6 +253,19 @@ extern int lh_table_insert(struct lh_table *t, void *k, const void *v); */ extern struct lh_entry* lh_table_lookup_entry(struct lh_table *t, const void *k); +/** + * Lookup a record into the table. This one accepts the key's hash in additon + * to the key. This is an exension to support functions that need to calculate + * the hash several times and allows them to do it just once and then pass + * in the hash to all utility functions. Depending on use case, this can be a + * very considerate performance improvement. + * @param t the table to lookup + * @param k a pointer to the key to lookup + * @param h hash value of the key to lookup + * @return a pointer to the record structure of the value or NULL if it does not exist. + */ +extern struct lh_entry* lh_table_lookup_entry_w_hash(struct lh_table *t, const void *k, const unsigned long h); + /** * Lookup a record into the table * @param t the table to lookup @@ -285,6 +312,22 @@ extern int lh_table_length(struct lh_table *t); void lh_abort(const char *msg, ...); void lh_table_resize(struct lh_table *t, int new_size); + +/** + * Calculate the hash of a key for a given table. + * This is an exension to support functions that need to calculate + * the hash several times and allows them to do it just once and then pass + * in the hash to all utility functions. Depending on use case, this can be a + * very considerate performance improvement. + * @param t the table (used to obtain hash function) + * @param k a pointer to the key to lookup + * @return the key's hash + */ +static inline unsigned long lh_get_hash(const struct lh_table *t, const void *k) +{ + return t->hash_fn(k); +} + #ifdef __cplusplus } #endif