1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
|
/*
* Part of Very Secure FTPd
* Licence: GPL v2
* Author: Chris Evans
* hash.c
*
* Routines to handle simple hash table lookups and modifications.
*/
#include "hash.h"
#include "sysutil.h"
#include "utility.h"
struct hash_node
{
void* p_key;
void* p_value;
struct hash_node* p_prev;
struct hash_node* p_next;
};
struct hash
{
unsigned int buckets;
unsigned int key_size;
unsigned int value_size;
hashfunc_t hash_func;
struct hash_node** p_nodes;
};
/* Internal functions */
struct hash_node** hash_get_bucket(struct hash* p_hash, void* p_key);
struct hash_node* hash_get_node_by_key(struct hash* p_hash, void* p_key);
struct hash*
hash_alloc(unsigned int buckets, unsigned int key_size,
unsigned int value_size, hashfunc_t hash_func)
{
unsigned int size;
struct hash* p_hash = vsf_sysutil_malloc(sizeof(*p_hash));
p_hash->buckets = buckets;
p_hash->key_size = key_size;
p_hash->value_size = value_size;
p_hash->hash_func = hash_func;
size = sizeof(struct hash_node*) * buckets;
p_hash->p_nodes = vsf_sysutil_malloc(size);
vsf_sysutil_memclr(p_hash->p_nodes, size);
return p_hash;
}
void*
hash_lookup_entry(struct hash* p_hash, void* p_key)
{
struct hash_node* p_node = hash_get_node_by_key(p_hash, p_key);
if (!p_node)
{
return p_node;
}
return p_node->p_value;
}
void
hash_add_entry(struct hash* p_hash, void* p_key, void* p_value)
{
struct hash_node** p_bucket;
struct hash_node* p_new_node;
if (hash_lookup_entry(p_hash, p_key))
{
bug("duplicate hash key");
}
p_bucket = hash_get_bucket(p_hash, p_key);
p_new_node = vsf_sysutil_malloc(sizeof(*p_new_node));
p_new_node->p_prev = 0;
p_new_node->p_next = 0;
p_new_node->p_key = vsf_sysutil_malloc(p_hash->key_size);
vsf_sysutil_memcpy(p_new_node->p_key, p_key, p_hash->key_size);
p_new_node->p_value = vsf_sysutil_malloc(p_hash->value_size);
vsf_sysutil_memcpy(p_new_node->p_value, p_value, p_hash->value_size);
if (!*p_bucket)
{
*p_bucket = p_new_node;
}
else
{
p_new_node->p_next = *p_bucket;
(*p_bucket)->p_prev = p_new_node;
*p_bucket = p_new_node;
}
}
void
hash_free_entry(struct hash* p_hash, void* p_key)
{
struct hash_node* p_node = hash_get_node_by_key(p_hash, p_key);
if (!p_node)
{
bug("hash node not found");
}
vsf_sysutil_free(p_node->p_key);
vsf_sysutil_free(p_node->p_value);
if (p_node->p_prev)
{
p_node->p_prev->p_next = p_node->p_next;
}
else
{
struct hash_node** p_bucket = hash_get_bucket(p_hash, p_key);
*p_bucket = p_node->p_next;
}
if (p_node->p_next)
{
p_node->p_next->p_prev = p_node->p_prev;
}
vsf_sysutil_free(p_node);
}
struct hash_node**
hash_get_bucket(struct hash* p_hash, void* p_key)
{
unsigned int bucket = (*p_hash->hash_func)(p_hash->buckets, p_key);
if (bucket >= p_hash->buckets)
{
bug("bad bucket lookup");
}
return &(p_hash->p_nodes[bucket]);
}
struct hash_node*
hash_get_node_by_key(struct hash* p_hash, void* p_key)
{
struct hash_node** p_bucket = hash_get_bucket(p_hash, p_key);
struct hash_node* p_node = *p_bucket;
if (!p_node)
{
return p_node;
}
while (p_node != 0 &&
vsf_sysutil_memcmp(p_key, p_node->p_key, p_hash->key_size) != 0)
{
p_node = p_node->p_next;
}
return p_node;
}
|