summaryrefslogtreecommitdiff
path: root/lib/hash.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/hash.c')
-rw-r--r--lib/hash.c75
1 files changed, 44 insertions, 31 deletions
diff --git a/lib/hash.c b/lib/hash.c
index f04c46284..884890694 100644
--- a/lib/hash.c
+++ b/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);
DEBUGASSERT(h->slots);
- l = FETCH_LIST(h, key, key_len);
+ 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;
+ 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;