summaryrefslogtreecommitdiff
path: root/common/hash.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/hash.c')
-rw-r--r--common/hash.c130
1 files changed, 102 insertions, 28 deletions
diff --git a/common/hash.c b/common/hash.c
index 7d67e53..6471803 100644
--- a/common/hash.c
+++ b/common/hash.c
@@ -88,10 +88,14 @@ struct hash_t
#ifdef HASH_COPYKEYS
unsigned int klen;
#endif
+#ifdef HASH_CALLBACKS
+ hash_free_val_t f_free;
+ void* arg;
+#endif
};
-#define INITIAL_MAX 15 /* tunable == 2^n - 1 */
+#define INITIAL_MAX 15 /* tunable == 2^n - 1 */
/*
* Hash creation functions.
@@ -102,10 +106,18 @@ static hash_entry_t** alloc_array(hash_t* ht, unsigned int max)
return malloc(sizeof(*(ht->array)) * (max + 1));
}
-#ifdef HASH_COPYKEYS
-hash_t* hash_create(size_t klen)
+#ifdef HASH_CALLBACKS
+ #ifdef HASH_COPYKEYS
+hash_t* hash_create(size_t klen, hash_free_val_t f_free, void* arg)
+ #else
+hash_t* hash_create(hash_free_val_t f_free, void* arg)
+ #endif
#else
+ #ifdef HASH_COPYKEYS
+hash_t* hash_create(size_t klen)
+ #else
hash_t* hash_create()
+ #endif
#endif
{
hash_t* ht = malloc(sizeof(hash_t));
@@ -117,7 +129,10 @@ hash_t* hash_create()
#ifdef HASH_COPYKEYS
ht->klen = klen;
#endif
-
+#ifdef HASH_CALLBACKS
+ ht->f_free = f_free;
+ ht->arg = arg;
+#endif
if(!ht->array)
{
free(ht);
@@ -132,7 +147,13 @@ void hash_free(hash_t* ht)
hash_index_t* hi;
for(hi = hash_first(ht); hi; hi = hash_next(hi))
+ {
+#ifdef HASH_CALLBACKS
+ if(hi->ths->val && ht->f_free)
+ ht->f_free(ht->arg, (void*)hi->ths->val);
+#endif
free(hi->ths);
+ }
if(ht->array)
free(ht->array);
@@ -362,58 +383,64 @@ void* hash_get(hash_t* ht, const void *key, size_t klen)
}
#ifdef HASH_COPYKEYS
-int hash_set(hash_t* ht, const void* key, const void* val)
+int hash_set(hash_t* ht, const void* key, void* val)
{
hash_entry_t** hep = find_entry(ht, key, val);
#else
-int hash_set(hash_t* ht, const void* key, size_t klen, const void* val)
+int hash_set(hash_t* ht, const void* key, size_t klen, void* val)
{
hash_entry_t** hep = find_entry(ht, key, klen, val);
#endif
if(hep && *hep)
{
- if(val)
- {
- /* replace entry */
- (*hep)->val = val;
+#ifdef HASH_CALLBACKS
+ if((*hep)->val && (*hep)->val != val && ht->f_free)
+ ht->f_free(ht->arg, (void*)((*hep)->val));
+#endif
+
+ /* replace entry */
+ (*hep)->val = val;
#ifdef HASH_TIMESTAMP
- /* Update or set the timestamp */
- (*hep)->stamp = time(NULL);
+ /* Update or set the timestamp */
+ (*hep)->stamp = time(NULL);
#endif
- /* check that the collision rate isn't too high */
- if(ht->count > ht->max)
- {
- if(!expand_array(ht))
- return 0;
- }
-
- return 1;
+ /* check that the collision rate isn't too high */
+ if(ht->count > ht->max)
+ {
+ if(!expand_array(ht))
+ return 0;
}
+
+ return 1;
}
return 0;
}
#ifdef HASH_COPYKEYS
-void hash_rem(hash_t* ht, const void* key)
+void* hash_rem(hash_t* ht, const void* key)
{
hash_entry_t** hep = find_entry(ht, key, NULL);
#else
-void hash_rem(hash_t* ht, const void* key, size_t klen)
+void* hash_rem(hash_t* ht, const void* key, size_t klen)
{
hash_entry_t** hep = find_entry(ht, key, klen, NULL);
#endif
+ void* val = NULL;
if(hep && *hep)
{
hash_entry_t* old = *hep;
*hep = (*hep)->next;
--ht->count;
+ val = (void*)old->val;
free(old);
}
+
+ return val;
}
unsigned int hash_count(hash_t* ht)
@@ -426,6 +453,7 @@ int hash_purge(hash_t* ht, time_t stamp)
{
hash_index_t* hi;
int r = 0;
+ void* val;
for(hi = hash_first(ht); hi; hi = hash_next(hi))
{
@@ -433,9 +461,14 @@ int hash_purge(hash_t* ht, time_t stamp)
{
/* No need to check for errors as we're deleting */
#ifdef HASH_COPYKEYS
- hash_rem(ht, KEY_DATA(hi->ths));
+ val = hash_rem(ht, KEY_DATA(hi->ths));
#else
- hash_rem(ht, hi->ths->key, hi->ths->klen);
+ val = hash_rem(ht, hi->ths->key, hi->ths->klen);
+#endif
+
+#ifdef HASH_CALLBACKS
+ if(val && ht->f_free)
+ (ht->f_free)(ht->arg, val);
#endif
r++;
@@ -446,17 +479,58 @@ int hash_purge(hash_t* ht, time_t stamp)
}
#ifdef HASH_COPYKEYS
-void* hash_touch(hash_index_t* hi, const void** key);
+void hash_touch(hash_t* ht, const void* key)
{
hash_entry_t** hep = find_entry(ht, key, NULL);
#else
-void* hash_touch(hash_index_t* hi, const void** key, size_t* klen);
+void hash_touch(hash_t* ht, const void* key, size_t* klen)
{
hash_entry_t** hep = find_entry(ht, key, klen, NULL);
#endif
- if(he && *he)
- ((*he)->stamp) = time(NULL);
+ if(hep && *hep)
+ ((*hep)->stamp) = time(NULL);
+}
+
+int hash_bump(hash_t* ht)
+{
+ hash_index_t* hi;
+ void* key = NULL;
+ void* val = NULL;
+ time_t least = 0;
+#ifndef HASH_COPYKEYS
+ size_t klen = 0;
+#endif
+
+ for(hi = hash_first(ht); hi; hi = hash_next(hi))
+ {
+ if(least == 0 || hi->ths->stamp < least)
+ {
+ least = hi->ths->stamp;
+ key = KEY_DATA(hi->ths);
+#ifndef HASH_COPYKEYS
+ klen = hi->this->klen;
+#endif
+ }
+ }
+
+ if(key)
+ {
+#ifdef HASH_COPYKEYS
+ val = hash_rem(ht, key);
+#else
+ val = hash_rem(ht, key, klen);
+#endif
+
+#ifdef HASH_CALLBACKS
+ if(val && ht->f_free)
+ (ht->f_free)(ht->arg, (void*)val);
+#endif
+
+ return 1;
+ }
+
+ return 0;
}
#endif /* HASH_TIMESTAMP */