summaryrefslogtreecommitdiff
path: root/hashtable.c
diff options
context:
space:
mode:
Diffstat (limited to 'hashtable.c')
-rw-r--r--hashtable.c42
1 files changed, 34 insertions, 8 deletions
diff --git a/hashtable.c b/hashtable.c
index 2d06a66e..17133dd2 100644
--- a/hashtable.c
+++ b/hashtable.c
@@ -1,7 +1,7 @@
/*
* Routines to provide a memory-efficient hashtable.
*
- * Copyright (C) 2007-2018 Wayne Davison
+ * Copyright (C) 2007-2020 Wayne Davison
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -66,9 +66,19 @@ void hashtable_destroy(struct hashtable *tbl)
free(tbl);
}
-/* This returns the node for the indicated key, either newly created or
- * already existing. Returns NULL if not allocating and not found. */
-void *hashtable_find(struct hashtable *tbl, int64 key, int allocate_if_missing)
+/* Returns the node that holds the indicated key if it exists. When it does not
+ * exist, it returns either NULL (when data_when_new is NULL), or it returns a
+ * new node with its node->data set to the indicated value.
+ *
+ * If your code doesn't know the data value for a new node in advance (usually
+ * because it doesn't know if a node is new or not) you should pass in a unique
+ * (non-0) value that you can use to check if the returned node is new. You can
+ * then overwrite the data with any value you want (even 0) since it only needs
+ * to be different than whatever data_when_new value you use later on.
+ *
+ * This return is a void* just because it might be pointing at a ht_int32_node
+ * or a ht_int64_node, and that makes the caller's assignment a little easier. */
+void *hashtable_find(struct hashtable *tbl, int64 key, void *data_when_new)
{
int key64 = tbl->key64;
struct ht_int32_node *node;
@@ -79,7 +89,7 @@ void *hashtable_find(struct hashtable *tbl, int64 key, int allocate_if_missing)
exit_cleanup(RERR_MESSAGEIO);
}
- if (allocate_if_missing && tbl->entries > HASH_LOAD_LIMIT(tbl->size)) {
+ if (data_when_new && tbl->entries > HASH_LOAD_LIMIT(tbl->size)) {
void *old_nodes = tbl->nodes;
int size = tbl->size * 2;
int i;
@@ -99,8 +109,12 @@ void *hashtable_find(struct hashtable *tbl, int64 key, int allocate_if_missing)
int64 move_key = HT_KEY(move_node, key64);
if (move_key == 0)
continue;
- node = hashtable_find(tbl, move_key, 1);
- node->data = move_node->data;
+ if (move_node->data)
+ hashtable_find(tbl, move_key, move_node->data);
+ else {
+ node = hashtable_find(tbl, move_key, "");
+ node->data = 0;
+ }
}
free(old_nodes);
@@ -155,7 +169,7 @@ void *hashtable_find(struct hashtable *tbl, int64 key, int allocate_if_missing)
if (nkey == key)
return node;
if (nkey == 0) {
- if (!allocate_if_missing)
+ if (!data_when_new)
return NULL;
break;
}
@@ -167,6 +181,7 @@ void *hashtable_find(struct hashtable *tbl, int64 key, int allocate_if_missing)
((struct ht_int64_node*)node)->key = key;
else
node->key = (int32)key;
+ node->data = data_when_new;
tbl->entries++;
return node;
}
@@ -453,16 +468,27 @@ uint32_t hashlittle(const void *key, size_t length)
switch(length) /* all the case statements fall through */
{
case 12: c+=((uint32_t)k[11])<<24;
+ /* FALLTHROUGH */
case 11: c+=((uint32_t)k[10])<<16;
+ /* FALLTHROUGH */
case 10: c+=((uint32_t)k[9])<<8;
+ /* FALLTHROUGH */
case 9 : c+=k[8];
+ /* FALLTHROUGH */
case 8 : b+=((uint32_t)k[7])<<24;
+ /* FALLTHROUGH */
case 7 : b+=((uint32_t)k[6])<<16;
+ /* FALLTHROUGH */
case 6 : b+=((uint32_t)k[5])<<8;
+ /* FALLTHROUGH */
case 5 : b+=k[4];
+ /* FALLTHROUGH */
case 4 : a+=((uint32_t)k[3])<<24;
+ /* FALLTHROUGH */
case 3 : a+=((uint32_t)k[2])<<16;
+ /* FALLTHROUGH */
case 2 : a+=((uint32_t)k[1])<<8;
+ /* FALLTHROUGH */
case 1 : a+=k[0];
break;
case 0 : return c;