diff --git a/crypto/lhash/lhash.c b/crypto/lhash/lhash.c index e4fc3fd7..98ee60a5 100644 --- a/crypto/lhash/lhash.c +++ b/crypto/lhash/lhash.c @@ -139,15 +139,17 @@ size_t lh_num_items(const _LHASH *lh) { return lh->num_items; } // not found, it returns a pointer that points to a NULL pointer. If |out_hash| // is not NULL, then it also puts the hash value of |data| in |*out_hash|. static LHASH_ITEM **get_next_ptr_and_hash(const _LHASH *lh, uint32_t *out_hash, - const void *data) { - const uint32_t hash = lh->hash(data); + const void *data, + lhash_hash_func_helper call_hash_func, + lhash_cmp_func_helper call_cmp_func) { + const uint32_t hash = call_hash_func(lh->hash, data); if (out_hash != NULL) { *out_hash = hash; } LHASH_ITEM **ret = &lh->buckets[hash % lh->num_buckets]; for (LHASH_ITEM *cur = *ret; cur != NULL; cur = *ret) { - if (lh->comp(cur->data, data) == 0) { + if (call_cmp_func(lh->comp, cur->data, data) == 0) { break; } ret = &cur->next; @@ -173,8 +175,11 @@ static LHASH_ITEM **get_next_ptr_by_key(const _LHASH *lh, const void *key, return ret; } -void *lh_retrieve(const _LHASH *lh, const void *data) { - LHASH_ITEM **next_ptr = get_next_ptr_and_hash(lh, NULL, data); +void *lh_retrieve(const _LHASH *lh, const void *data, + lhash_hash_func_helper call_hash_func, + lhash_cmp_func_helper call_cmp_func) { + LHASH_ITEM **next_ptr = + get_next_ptr_and_hash(lh, NULL, data, call_hash_func, call_cmp_func); return *next_ptr == NULL ? NULL : (*next_ptr)->data; } @@ -247,12 +252,15 @@ static void lh_maybe_resize(_LHASH *lh) { } } -int lh_insert(_LHASH *lh, void **old_data, void *data) { +int lh_insert(_LHASH *lh, void **old_data, void *data, + lhash_hash_func_helper call_hash_func, + lhash_cmp_func_helper call_cmp_func) { uint32_t hash; LHASH_ITEM **next_ptr, *item; *old_data = NULL; - next_ptr = get_next_ptr_and_hash(lh, &hash, data); + next_ptr = + get_next_ptr_and_hash(lh, &hash, data, call_hash_func, call_cmp_func); if (*next_ptr != NULL) { @@ -279,10 +287,13 @@ int lh_insert(_LHASH *lh, void **old_data, void *data) { return 1; } -void *lh_delete(_LHASH *lh, const void *data) { +void *lh_delete(_LHASH *lh, const void *data, + lhash_hash_func_helper call_hash_func, + lhash_cmp_func_helper call_cmp_func) { LHASH_ITEM **next_ptr, *item, *ret; - next_ptr = get_next_ptr_and_hash(lh, NULL, data); + next_ptr = + get_next_ptr_and_hash(lh, NULL, data, call_hash_func, call_cmp_func); if (*next_ptr == NULL) { // No such element. @@ -300,8 +311,7 @@ void *lh_delete(_LHASH *lh, const void *data) { return ret; } -static void lh_doall_internal(_LHASH *lh, void (*no_arg_func)(void *), - void (*arg_func)(void *, void *), void *arg) { +void lh_doall_arg(_LHASH *lh, void (*func)(void *, void *), void *arg) { if (lh == NULL) { return; } @@ -315,11 +325,7 @@ static void lh_doall_internal(_LHASH *lh, void (*no_arg_func)(void *), LHASH_ITEM *next; for (LHASH_ITEM *cur = lh->buckets[i]; cur != NULL; cur = next) { next = cur->next; - if (arg_func) { - arg_func(cur->data, arg); - } else { - no_arg_func(cur->data); - } + func(cur->data, arg); } } @@ -333,14 +339,6 @@ static void lh_doall_internal(_LHASH *lh, void (*no_arg_func)(void *), lh_maybe_resize(lh); } -void lh_doall(_LHASH *lh, void (*func)(void *)) { - lh_doall_internal(lh, func, NULL, NULL); -} - -void lh_doall_arg(_LHASH *lh, void (*func)(void *, void *), void *arg) { - lh_doall_internal(lh, NULL, func, arg); -} - uint32_t lh_strhash(const char *c) { if (c == NULL) { return 0; diff --git a/include/openssl/lhash.h b/include/openssl/lhash.h index 77ca493a..c82bb8e6 100644 --- a/include/openssl/lhash.h +++ b/include/openssl/lhash.h @@ -104,11 +104,22 @@ typedef struct lhash_item_st { // equal, to zero depending on whether |*a| is equal, or not equal to |*b|, // respectively. Note the difference between this and |stack_cmp_func| in that // this takes pointers to the objects directly. +// +// This function's actual type signature is int (*)(const T*, const T*). The +// low-level |lh_*| functions will be passed a type-specific wrapper to call it +// correctly. typedef int (*lhash_cmp_func)(const void *a, const void *b); +typedef int (*lhash_cmp_func_helper)(lhash_cmp_func func, const void *a, + const void *b); // lhash_hash_func is a function that maps an object to a uniformly distributed // uint32_t. +// +// This function's actual type signature is uint32_t (*)(const T*). The +// low-level |lh_*| functions will be passed a type-specific wrapper to call it +// correctly. typedef uint32_t (*lhash_hash_func)(const void *a); +typedef uint32_t (*lhash_hash_func_helper)(lhash_hash_func func, const void *a); typedef struct lhash_st _LHASH; @@ -124,7 +135,9 @@ OPENSSL_EXPORT size_t lh_num_items(const _LHASH *lh); // lh_retrieve finds an element equal to |data| in the hash table and returns // it. If no such element exists, it returns NULL. -OPENSSL_EXPORT void *lh_retrieve(const _LHASH *lh, const void *data); +OPENSSL_EXPORT void *lh_retrieve(const _LHASH *lh, const void *data, + lhash_hash_func_helper call_hash_func, + lhash_cmp_func_helper call_cmp_func); // lh_retrieve_key finds an element matching |key|, given the specified hash and // comparison function. This differs from |lh_retrieve| in that the key may be a @@ -140,15 +153,15 @@ OPENSSL_EXPORT void *lh_retrieve_key(const _LHASH *lh, const void *key, // will be set to that value and it will be replaced. Otherwise, or in the // event of an error, |*old_data| will be set to NULL. It returns one on // success or zero in the case of an allocation error. -OPENSSL_EXPORT int lh_insert(_LHASH *lh, void **old_data, void *data); +OPENSSL_EXPORT int lh_insert(_LHASH *lh, void **old_data, void *data, + lhash_hash_func_helper call_hash_func, + lhash_cmp_func_helper call_cmp_func); // lh_delete removes an element equal to |data| from the hash table and returns // it. If no such element is found, it returns NULL. -OPENSSL_EXPORT void *lh_delete(_LHASH *lh, const void *data); - -// lh_doall calls |func| on each element of the hash table. -// TODO(fork): rename this -OPENSSL_EXPORT void lh_doall(_LHASH *lh, void (*func)(void *)); +OPENSSL_EXPORT void *lh_delete(_LHASH *lh, const void *data, + lhash_hash_func_helper call_hash_func, + lhash_cmp_func_helper call_cmp_func); // lh_doall_arg calls |func| on each element of the hash table and also passes // |arg| as the second argument. @@ -166,6 +179,16 @@ OPENSSL_EXPORT uint32_t lh_strhash(const char *c); typedef int (*lhash_##type##_cmp_func)(const type *, const type *); \ typedef uint32_t (*lhash_##type##_hash_func)(const type *); \ \ + OPENSSL_INLINE int lh_##type##_call_cmp_func(lhash_cmp_func func, \ + const void *a, const void *b) { \ + return ((lhash_##type##_cmp_func)func)((const type *)a, (const type *)b); \ + } \ + \ + OPENSSL_INLINE uint32_t lh_##type##_call_hash_func(lhash_hash_func func, \ + const void *a) { \ + return ((lhash_##type##_hash_func)func)((const type *)a); \ + } \ + \ OPENSSL_INLINE LHASH_OF(type) * \ lh_##type##_new(lhash_##type##_hash_func hash, \ lhash_##type##_cmp_func comp) { \ @@ -183,38 +206,72 @@ OPENSSL_EXPORT uint32_t lh_strhash(const char *c); \ OPENSSL_INLINE type *lh_##type##_retrieve(const LHASH_OF(type) *lh, \ const type *data) { \ - return (type *)lh_retrieve((const _LHASH *)lh, data); \ + return (type *)lh_retrieve((const _LHASH *)lh, data, \ + lh_##type##_call_hash_func, \ + lh_##type##_call_cmp_func); \ + } \ + \ + typedef struct { \ + int (*cmp_key)(const void *key, const type *value); \ + const void *key; \ + } LHASH_CMP_KEY_##type; \ + \ + OPENSSL_INLINE int lh_##type##_call_cmp_key(const void *key, \ + const void *value) { \ + const LHASH_CMP_KEY_##type *cb = (const LHASH_CMP_KEY_##type *)key; \ + return cb->cmp_key(cb->key, (const type *)value); \ } \ \ OPENSSL_INLINE type *lh_##type##_retrieve_key( \ const LHASH_OF(type) *lh, const void *key, uint32_t key_hash, \ int (*cmp_key)(const void *key, const type *value)) { \ - return (type *)lh_retrieve_key( \ - (const _LHASH *)lh, key, key_hash, \ - (int (*)(const void *, const void *))cmp_key); \ + LHASH_CMP_KEY_##type cb = {cmp_key, key}; \ + return (type *)lh_retrieve_key((const _LHASH *)lh, &cb, key_hash, \ + lh_##type##_call_cmp_key); \ } \ \ OPENSSL_INLINE int lh_##type##_insert(LHASH_OF(type) *lh, type **old_data, \ type *data) { \ void *old_data_void = NULL; \ - int ret = lh_insert((_LHASH *)lh, &old_data_void, data); \ + int ret = \ + lh_insert((_LHASH *)lh, &old_data_void, data, \ + lh_##type##_call_hash_func, lh_##type##_call_cmp_func); \ *old_data = (type *)old_data_void; \ return ret; \ } \ \ OPENSSL_INLINE type *lh_##type##_delete(LHASH_OF(type) *lh, \ const type *data) { \ - return (type *)lh_delete((_LHASH *)lh, data); \ + return (type *)lh_delete((_LHASH *)lh, data, lh_##type##_call_hash_func, \ + lh_##type##_call_cmp_func); \ + } \ + \ + typedef struct { \ + void (*doall)(type *); \ + void (*doall_arg)(type *, void *); \ + void *arg; \ + } LHASH_DOALL_##type; \ + \ + OPENSSL_INLINE void lh_##type##_call_doall(void *value, void *arg) { \ + const LHASH_DOALL_##type *cb = (const LHASH_DOALL_##type *)arg; \ + cb->doall((type *)value); \ + } \ + \ + OPENSSL_INLINE void lh_##type##_call_doall_arg(void *value, void *arg) { \ + const LHASH_DOALL_##type *cb = (const LHASH_DOALL_##type *)arg; \ + cb->doall_arg((type *)value, cb->arg); \ } \ \ OPENSSL_INLINE void lh_##type##_doall(LHASH_OF(type) *lh, \ void (*func)(type *)) { \ - lh_doall((_LHASH *)lh, (void (*)(void *))func); \ + LHASH_DOALL_##type cb = {func, NULL, NULL}; \ + lh_doall_arg((_LHASH *)lh, lh_##type##_call_doall, &cb); \ } \ \ OPENSSL_INLINE void lh_##type##_doall_arg( \ LHASH_OF(type) *lh, void (*func)(type *, void *), void *arg) { \ - lh_doall_arg((_LHASH *)lh, (void (*)(void *, void *))func, arg); \ + LHASH_DOALL_##type cb = {NULL, func, arg}; \ + lh_doall_arg((_LHASH *)lh, lh_##type##_call_doall_arg, &cb); \ }