mirror of
https://github.com/curl/curl.git
synced 2026-08-26 08:53:32 +03:00
hash: lazy-alloc the table in Curl_hash_add()
This makes Curl_hash_init() infallible which saves error paths. Closes #8132
This commit is contained in:
parent
e43ad4b474
commit
254f7bd78a
10 changed files with 78 additions and 83 deletions
77
lib/hash.c
77
lib/hash.c
|
|
@ -53,32 +53,25 @@ hash_element_dtor(void *user, void *element)
|
|||
* @unittest: 1602
|
||||
* @unittest: 1603
|
||||
*/
|
||||
int
|
||||
void
|
||||
Curl_hash_init(struct Curl_hash *h,
|
||||
int slots,
|
||||
hash_function hfunc,
|
||||
comp_function comparator,
|
||||
Curl_hash_dtor dtor)
|
||||
{
|
||||
if(!slots || !hfunc || !comparator ||!dtor) {
|
||||
return 1; /* failure */
|
||||
}
|
||||
DEBUGASSERT(h);
|
||||
DEBUGASSERT(slots);
|
||||
DEBUGASSERT(hfunc);
|
||||
DEBUGASSERT(comparator);
|
||||
DEBUGASSERT(dtor);
|
||||
|
||||
h->table = NULL;
|
||||
h->hash_func = hfunc;
|
||||
h->comp_func = comparator;
|
||||
h->dtor = dtor;
|
||||
h->size = 0;
|
||||
h->slots = slots;
|
||||
|
||||
h->table = malloc(slots * sizeof(struct Curl_llist));
|
||||
if(h->table) {
|
||||
int i;
|
||||
for(i = 0; i < slots; ++i)
|
||||
Curl_llist_init(&h->table[i], (Curl_llist_dtor) hash_element_dtor);
|
||||
return 0; /* fine */
|
||||
}
|
||||
h->slots = 0;
|
||||
return 1; /* failure */
|
||||
}
|
||||
|
||||
static struct Curl_hash_element *
|
||||
|
|
@ -98,8 +91,9 @@ mk_hash_element(const void *key, size_t key_len, const void *p)
|
|||
|
||||
#define FETCH_LIST(x,y,z) &x->table[x->hash_func(y, z, x->slots)]
|
||||
|
||||
/* Insert the data in the hash. If there already was a match in the hash,
|
||||
* that data is replaced.
|
||||
/* Insert the data in the hash. If there already was a match in the hash, that
|
||||
* data is replaced. This function also "lazily" allocates the table if
|
||||
* needed, as it isn't done in the _init function (anymore).
|
||||
*
|
||||
* @unittest: 1305
|
||||
* @unittest: 1602
|
||||
|
|
@ -111,7 +105,18 @@ Curl_hash_add(struct Curl_hash *h, void *key, size_t key_len, void *p)
|
|||
struct Curl_hash_element *he;
|
||||
struct Curl_llist_element *le;
|
||||
struct Curl_llist *l;
|
||||
|
||||
DEBUGASSERT(h);
|
||||
DEBUGASSERT(h->slots);
|
||||
if(!h->table) {
|
||||
int i;
|
||||
h->table = malloc(h->slots * sizeof(struct Curl_llist));
|
||||
if(!h->table)
|
||||
return NULL; /* OOM */
|
||||
for(i = 0; i < h->slots; ++i)
|
||||
Curl_llist_init(&h->table[i], hash_element_dtor);
|
||||
}
|
||||
|
||||
l = FETCH_LIST(h, key, key_len);
|
||||
|
||||
for(le = l->head; le; le = le->next) {
|
||||
|
|
@ -142,15 +147,19 @@ int Curl_hash_delete(struct Curl_hash *h, void *key, size_t key_len)
|
|||
{
|
||||
struct Curl_llist_element *le;
|
||||
struct Curl_llist *l;
|
||||
DEBUGASSERT(h->slots);
|
||||
l = FETCH_LIST(h, key, key_len);
|
||||
|
||||
for(le = l->head; le; le = le->next) {
|
||||
struct Curl_hash_element *he = le->ptr;
|
||||
if(h->comp_func(he->key, he->key_len, key, key_len)) {
|
||||
Curl_llist_remove(l, le, (void *) h);
|
||||
--h->size;
|
||||
return 0;
|
||||
DEBUGASSERT(h);
|
||||
DEBUGASSERT(h->slots);
|
||||
if(h->table) {
|
||||
l = FETCH_LIST(h, key, key_len);
|
||||
|
||||
for(le = l->head; le; le = le->next) {
|
||||
struct Curl_hash_element *he = le->ptr;
|
||||
if(h->comp_func(he->key, he->key_len, key, key_len)) {
|
||||
Curl_llist_remove(l, le, (void *) h);
|
||||
--h->size;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
|
|
@ -166,7 +175,8 @@ Curl_hash_pick(struct Curl_hash *h, void *key, size_t key_len)
|
|||
struct Curl_llist_element *le;
|
||||
struct Curl_llist *l;
|
||||
|
||||
if(h) {
|
||||
DEBUGASSERT(h);
|
||||
if(h->table) {
|
||||
DEBUGASSERT(h->slots);
|
||||
l = FETCH_LIST(h, key, key_len);
|
||||
for(le = l->head; le; le = le->next) {
|
||||
|
|
@ -209,13 +219,13 @@ Curl_hash_apply(Curl_hash *h, void *user,
|
|||
void
|
||||
Curl_hash_destroy(struct Curl_hash *h)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < h->slots; ++i) {
|
||||
Curl_llist_destroy(&h->table[i], (void *) h);
|
||||
if(h->table) {
|
||||
int i;
|
||||
for(i = 0; i < h->slots; ++i) {
|
||||
Curl_llist_destroy(&h->table[i], (void *) h);
|
||||
}
|
||||
Curl_safefree(h->table);
|
||||
}
|
||||
|
||||
Curl_safefree(h->table);
|
||||
h->size = 0;
|
||||
h->slots = 0;
|
||||
}
|
||||
|
|
@ -240,7 +250,7 @@ Curl_hash_clean_with_criterium(struct Curl_hash *h, void *user,
|
|||
struct Curl_llist *list;
|
||||
int i;
|
||||
|
||||
if(!h)
|
||||
if(!h || !h->table)
|
||||
return;
|
||||
|
||||
for(i = 0; i < h->slots; ++i) {
|
||||
|
|
@ -295,6 +305,9 @@ Curl_hash_next_element(struct Curl_hash_iterator *iter)
|
|||
{
|
||||
struct Curl_hash *h = iter->hash;
|
||||
|
||||
if(!h->table)
|
||||
return NULL; /* empty hash, nothing to return */
|
||||
|
||||
/* Get the next element in the current list, if any */
|
||||
if(iter->current_element)
|
||||
iter->current_element = iter->current_element->next;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue