Completely removed the buggy, inflexible, and incomplete new_hash_table
implementation. Some cleanups of the other code. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@2112 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
8f6008b482
commit
d92e4b19e4
|
@ -4,23 +4,32 @@
|
||||||
** Distributed under the terms of the NewOS License.
|
** Distributed under the terms of the NewOS License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <KernelExport.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
#include <Errors.h>
|
#include <Errors.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <khash.h>
|
#include <khash.h>
|
||||||
|
|
||||||
// ToDo: this file apparently contains two different hash implementations
|
#define TRACE_HASH 0
|
||||||
// get rid of one of them, and update the external code.
|
#if TRACE_HASH
|
||||||
|
# define TRACE(x) dprintf x
|
||||||
|
#else
|
||||||
|
# define TRACE(x) ;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ToDo: the hashtable is not expanded when necessary (no load factor, no nothing)
|
||||||
|
// Could try to use pools instead of malloc() for the elements - might be
|
||||||
|
// faster than the current approach.
|
||||||
|
|
||||||
struct hash_table {
|
struct hash_table {
|
||||||
struct hash_elem **table;
|
struct hash_element **table;
|
||||||
int next_ptr_offset;
|
int next_ptr_offset;
|
||||||
unsigned int table_size;
|
uint32 table_size;
|
||||||
int num_elems;
|
int num_elements;
|
||||||
int flags;
|
int flags;
|
||||||
int (*compare_func)(void *e, const void *key);
|
int (*compare_func)(void *e, const void *key);
|
||||||
unsigned int (*hash_func)(void *e, const void *key, unsigned int range);
|
uint32 (*hash_func)(void *e, const void *key, uint32 range);
|
||||||
};
|
};
|
||||||
|
|
||||||
// XXX gross hack
|
// XXX gross hack
|
||||||
|
@ -29,91 +38,101 @@ struct hash_table {
|
||||||
#define PUT_IN_NEXT(t, e, val) (*(unsigned long *)NEXT_ADDR(t, e) = (long)(val))
|
#define PUT_IN_NEXT(t, e, val) (*(unsigned long *)NEXT_ADDR(t, e) = (long)(val))
|
||||||
|
|
||||||
|
|
||||||
void *
|
static inline void *
|
||||||
hash_init(unsigned int table_size, int next_ptr_offset,
|
next_element(hash_table *table, void *element)
|
||||||
|
{
|
||||||
|
// ToDo: should we use this instead of the NEXT() macro?
|
||||||
|
return (void *)(*(unsigned long *)NEXT_ADDR(table, element));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct hash_table *
|
||||||
|
hash_init(uint32 table_size, int next_ptr_offset,
|
||||||
int compare_func(void *e, const void *key),
|
int compare_func(void *e, const void *key),
|
||||||
unsigned int hash_func(void *e, const void *key, unsigned int range))
|
uint32 hash_func(void *e, const void *key, uint32 range))
|
||||||
{
|
{
|
||||||
struct hash_table *t;
|
struct hash_table *t;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
|
if (compare_func == NULL || hash_func == NULL) {
|
||||||
|
dprintf("hash_init() called with NULL function pointer\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
t = (struct hash_table *)malloc(sizeof(struct hash_table));
|
t = (struct hash_table *)malloc(sizeof(struct hash_table));
|
||||||
if (t == NULL)
|
if (t == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
t->table = (struct hash_elem **)malloc(sizeof(void *) * table_size);
|
t->table = (struct hash_element **)malloc(sizeof(void *) * table_size);
|
||||||
if (t->table == NULL) {
|
if (t->table == NULL) {
|
||||||
free(t);
|
free(t);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i<table_size; i++)
|
for (i = 0; i < table_size; i++)
|
||||||
t->table[i] = NULL;
|
t->table[i] = NULL;
|
||||||
|
|
||||||
t->table_size = table_size;
|
t->table_size = table_size;
|
||||||
t->next_ptr_offset = next_ptr_offset;
|
t->next_ptr_offset = next_ptr_offset;
|
||||||
t->flags = 0;
|
t->flags = 0;
|
||||||
t->num_elems = 0;
|
t->num_elements = 0;
|
||||||
t->compare_func = compare_func;
|
t->compare_func = compare_func;
|
||||||
t->hash_func = hash_func;
|
t->hash_func = hash_func;
|
||||||
|
|
||||||
// dprintf("hash_init: created table 0x%x, next_ptr_offset %d, compare_func 0x%x, hash_func 0x%x\n",
|
TRACE(("hash_init: created table %p, next_ptr_offset %d, compare_func %p, hash_func %p\n",
|
||||||
// t, next_ptr_offset, compare_func, hash_func);
|
t, next_ptr_offset, compare_func, hash_func));
|
||||||
|
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
hash_uninit(void *_hash_table)
|
hash_uninit(struct hash_table *table)
|
||||||
{
|
{
|
||||||
struct hash_table *t = (struct hash_table *)_hash_table;
|
ASSERT(table->num_elements == 0);
|
||||||
|
|
||||||
#if 0
|
free(table->table);
|
||||||
if(t->num_elems > 0) {
|
free(table);
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
free(t->table);
|
|
||||||
free(t);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
status_t
|
||||||
hash_insert(void *_hash_table, void *e)
|
hash_insert(struct hash_table *table, void *element)
|
||||||
{
|
{
|
||||||
struct hash_table *t = (struct hash_table *)_hash_table;
|
uint32 hash;
|
||||||
unsigned int hash;
|
|
||||||
|
|
||||||
// dprintf("hash_insert: table 0x%x, element 0x%x\n", t, e);
|
ASSERT(table != NULL && element != NULL);
|
||||||
|
TRACE(("hash_insert: table 0x%x, element 0x%x\n", table, element));
|
||||||
|
|
||||||
hash = t->hash_func(e, NULL, t->table_size);
|
hash = table->hash_func(element, NULL, table->table_size);
|
||||||
PUT_IN_NEXT(t, e, t->table[hash]);
|
PUT_IN_NEXT(table, element, table->table[hash]);
|
||||||
t->table[hash] = (struct hash_elem *)e;
|
table->table[hash] = (struct hash_element *)element;
|
||||||
t->num_elems++;
|
table->num_elements++;
|
||||||
|
|
||||||
|
// ToDo: resize hash table if it's grown too much!
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int hash_remove(void *_hash_table, void *e)
|
status_t
|
||||||
|
hash_remove(struct hash_table *table, void *_element)
|
||||||
{
|
{
|
||||||
struct hash_table *t = (struct hash_table *)_hash_table;
|
uint32 hash = table->hash_func(_element, NULL, table->table_size);
|
||||||
void *i, *last_i;
|
void *element, *lastElement = NULL;
|
||||||
unsigned int hash;
|
|
||||||
|
|
||||||
hash = t->hash_func(e, NULL, t->table_size);
|
for (element = table->table[hash]; element != NULL; lastElement = element, element = NEXT(table, element)) {
|
||||||
last_i = NULL;
|
if (element == _element) {
|
||||||
for (i = t->table[hash]; i != NULL; last_i = i, i = NEXT(t, i)) {
|
if (lastElement != NULL) {
|
||||||
if (i == e) {
|
// connect the previous entry with the next one
|
||||||
if (last_i != NULL)
|
PUT_IN_NEXT(table, lastElement, NEXT(table, element));
|
||||||
PUT_IN_NEXT(t, last_i, NEXT(t, i));
|
} else
|
||||||
else
|
table->table[hash] = (struct hash_element *)NEXT(table, element);
|
||||||
t->table[hash] = (struct hash_elem *)NEXT(t, i);
|
table->num_elements--;
|
||||||
t->num_elems--;
|
|
||||||
return B_NO_ERROR;
|
return B_OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,16 +141,14 @@ int hash_remove(void *_hash_table, void *e)
|
||||||
|
|
||||||
|
|
||||||
void *
|
void *
|
||||||
hash_find(void *_hash_table, void *e)
|
hash_find(struct hash_table *table, void *searchedElement)
|
||||||
{
|
{
|
||||||
struct hash_table *t = (struct hash_table *)_hash_table;
|
uint32 hash = table->hash_func(searchedElement, NULL, table->table_size);
|
||||||
void *i;
|
void *element;
|
||||||
unsigned int hash;
|
|
||||||
|
|
||||||
hash = t->hash_func(e, NULL, t->table_size);
|
for (element = table->table[hash]; element != NULL; element = NEXT(table, element)) {
|
||||||
for (i = t->table[hash]; i != NULL; i = NEXT(t, i)) {
|
if (element == searchedElement)
|
||||||
if (i == e)
|
return element;
|
||||||
return i;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -139,19 +156,14 @@ hash_find(void *_hash_table, void *e)
|
||||||
|
|
||||||
|
|
||||||
void *
|
void *
|
||||||
hash_lookup(void *_hash_table, const void *key)
|
hash_lookup(struct hash_table *table, const void *key)
|
||||||
{
|
{
|
||||||
struct hash_table *t = (struct hash_table *)_hash_table;
|
uint32 hash = table->hash_func(NULL, key, table->table_size);
|
||||||
void *i;
|
void *element;
|
||||||
unsigned int hash;
|
|
||||||
|
|
||||||
if (t->compare_func == NULL)
|
for (element = table->table[hash]; element != NULL; element = NEXT(table, element)) {
|
||||||
return NULL;
|
if (table->compare_func(element, key) == 0)
|
||||||
|
return element;
|
||||||
hash = t->hash_func(NULL, key, t->table_size);
|
|
||||||
for (i = t->table[hash]; i != NULL; i = NEXT(t, i)) {
|
|
||||||
if (t->compare_func(i, key) == 0)
|
|
||||||
return i;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -159,264 +171,74 @@ hash_lookup(void *_hash_table, const void *key)
|
||||||
|
|
||||||
|
|
||||||
struct hash_iterator *
|
struct hash_iterator *
|
||||||
hash_open(void *_hash_table, struct hash_iterator *i)
|
hash_open(struct hash_table *table, struct hash_iterator *iterator)
|
||||||
{
|
{
|
||||||
struct hash_table *t = (struct hash_table *)_hash_table;
|
if (iterator == NULL) {
|
||||||
|
iterator = (struct hash_iterator *)malloc(sizeof(struct hash_iterator));
|
||||||
if (i == NULL) {
|
if (iterator == NULL)
|
||||||
i = (struct hash_iterator *)malloc(sizeof(struct hash_iterator));
|
|
||||||
if (i == NULL)
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
hash_rewind(t, i);
|
hash_rewind(table, iterator);
|
||||||
|
|
||||||
return i;
|
return iterator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
hash_close(void *_hash_table, struct hash_iterator *i, bool freeIterator)
|
hash_close(struct hash_table *table, struct hash_iterator *iterator, bool freeIterator)
|
||||||
{
|
{
|
||||||
if (freeIterator)
|
if (freeIterator)
|
||||||
free(i);
|
free(iterator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
hash_rewind(void *_hash_table, struct hash_iterator *i)
|
hash_rewind(struct hash_table *table, struct hash_iterator *iterator)
|
||||||
{
|
{
|
||||||
i->ptr = NULL;
|
iterator->current = NULL;
|
||||||
i->bucket = -1;
|
iterator->bucket = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void *
|
void *
|
||||||
hash_next(void *_hash_table, struct hash_iterator *i)
|
hash_next(struct hash_table *table, struct hash_iterator *iterator)
|
||||||
{
|
{
|
||||||
struct hash_table *t = (struct hash_table *)_hash_table;
|
uint32 index;
|
||||||
unsigned int index;
|
|
||||||
|
|
||||||
restart:
|
restart:
|
||||||
if (!i->ptr) {
|
if (iterator->current == NULL) {
|
||||||
for (index = (unsigned int)(i->bucket + 1); index < t->table_size; index++) {
|
// get next bucket
|
||||||
if (t->table[index]) {
|
for (index = (uint32)(iterator->bucket + 1); index < table->table_size; index++) {
|
||||||
i->bucket = index;
|
if (table->table[index]) {
|
||||||
i->ptr = t->table[index];
|
iterator->bucket = index;
|
||||||
|
iterator->current = table->table[index];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
i->ptr = NEXT(t, i->ptr);
|
iterator->current = NEXT(table, iterator->current);
|
||||||
if (!i->ptr)
|
if (!iterator->current)
|
||||||
goto restart;
|
goto restart;
|
||||||
}
|
}
|
||||||
|
|
||||||
return i->ptr;
|
return iterator->current;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
unsigned int
|
uint32
|
||||||
hash_hash_str( const char *str )
|
hash_hash_string(const char *string)
|
||||||
{
|
{
|
||||||
char ch;
|
uint32 hash = 0;
|
||||||
unsigned int hash = 0;
|
char c;
|
||||||
|
|
||||||
// we assume hash to be at least 32 bits
|
// we assume hash to be at least 32 bits
|
||||||
while ((ch = *str++) != 0) {
|
while ((c = *string++) != 0) {
|
||||||
hash ^= hash >> 28;
|
hash ^= hash >> 28;
|
||||||
hash <<= 4;
|
hash <<= 4;
|
||||||
hash ^= ch;
|
hash ^= c;
|
||||||
}
|
}
|
||||||
|
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define MAX_INITIAL 15;
|
|
||||||
|
|
||||||
/*
|
|
||||||
static void nhash_this(hash_table_index *hi, const void **key, ssize_t *klen,
|
|
||||||
void **val)
|
|
||||||
{
|
|
||||||
if (key) *key = hi->this->key;
|
|
||||||
if (klen) *klen = hi->this->klen;
|
|
||||||
if (val) *val = (void*)hi->this->val;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
new_hash_table *
|
|
||||||
hash_make(void)
|
|
||||||
{
|
|
||||||
status_t rv;
|
|
||||||
new_hash_table *nn;
|
|
||||||
|
|
||||||
nn = (new_hash_table *)malloc(sizeof(new_hash_table));
|
|
||||||
if (nn == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
nn->count = 0;
|
|
||||||
nn->max = MAX_INITIAL;
|
|
||||||
|
|
||||||
nn->array = (hash_entry **)malloc(sizeof(hash_entry) * (nn->max + 1));
|
|
||||||
if (nn == NULL) {
|
|
||||||
free(nn);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
memset(nn->array, 0, sizeof(hash_entry) * (nn->max +1));
|
|
||||||
rv = pool_init(&nn->pool, sizeof(hash_entry));
|
|
||||||
if (rv < B_OK || nn->pool == NULL) {
|
|
||||||
free(nn->array);
|
|
||||||
free(nn);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return nn;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static hash_index *
|
|
||||||
new_hash_next(hash_index *hi)
|
|
||||||
{
|
|
||||||
hi->this_idx = hi->next;
|
|
||||||
while (!hi->this_idx) {
|
|
||||||
if (hi->index > hi->nh->max)
|
|
||||||
return NULL;
|
|
||||||
hi->this_idx = hi->nh->array[hi->index++];
|
|
||||||
}
|
|
||||||
hi->next = hi->this_idx->next;
|
|
||||||
return hi;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static hash_index *
|
|
||||||
new_hash_first(new_hash_table *nh)
|
|
||||||
{
|
|
||||||
hash_index *hi = &nh->iterator;
|
|
||||||
hi->nh = nh;
|
|
||||||
hi->index = 0;
|
|
||||||
hi->this_idx = hi->next = NULL;
|
|
||||||
return new_hash_next(hi);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
expand_array(new_hash_table *nh)
|
|
||||||
{
|
|
||||||
hash_index *hi;
|
|
||||||
hash_entry **new_array;
|
|
||||||
int new_max = (nh->max + 1) * 2 - 1;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
new_array = (hash_entry **)malloc(sizeof(hash_entry) * new_max + 1);
|
|
||||||
if (new_array == NULL)
|
|
||||||
panic("khash, expand_array failed\n"); // XXX stupid, this function should return an error if it failes
|
|
||||||
memset(new_array, 0, sizeof(hash_entry) * new_max + 1);
|
|
||||||
for (hi = new_hash_first(nh); hi; hi = new_hash_next(hi)) {
|
|
||||||
i = hi->this_idx->hash & new_max;
|
|
||||||
hi->this_idx->next = new_array[i];
|
|
||||||
new_array[i] = hi->this_idx;
|
|
||||||
}
|
|
||||||
free(nh->array);
|
|
||||||
nh->array = new_array;
|
|
||||||
nh->max = new_max;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static hash_entry **
|
|
||||||
find_entry(new_hash_table *nh, const void *key, ssize_t klen, const void *val)
|
|
||||||
{
|
|
||||||
hash_entry **hep;
|
|
||||||
hash_entry *he;
|
|
||||||
const unsigned char *p;
|
|
||||||
int hash = 0;
|
|
||||||
ssize_t i;
|
|
||||||
|
|
||||||
ASSERT(nh != NULL);
|
|
||||||
|
|
||||||
for (p = key, i = klen; i; i--, p++)
|
|
||||||
hash = hash * 33 + *p;
|
|
||||||
|
|
||||||
for (hep = &nh->array[hash & nh->max], he = *hep; he; hep = &he->next, he = *hep) {
|
|
||||||
// dprintf("khash, find_entry looking at hep %p, he %p\n", hep, he);
|
|
||||||
if (he->hash == hash && he->klen == klen && memcmp(he->key, key, klen) == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (val == 0) /* val == 0 means we only lookup, and don't insert */
|
|
||||||
return he ? hep : NULL;
|
|
||||||
|
|
||||||
/* add a new linked-list entry */
|
|
||||||
he = (hash_entry *)pool_get(nh->pool);
|
|
||||||
if (he == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/* copy the key */
|
|
||||||
he->key = malloc(klen);
|
|
||||||
if (he->key == NULL) {
|
|
||||||
pool_put(nh->pool, he);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
memcpy(he->key, key, klen);
|
|
||||||
|
|
||||||
he->next = NULL;
|
|
||||||
he->hash = hash;
|
|
||||||
he->klen = klen;
|
|
||||||
he->val = val;
|
|
||||||
*hep = he;
|
|
||||||
nh->count++;
|
|
||||||
return hep;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void *
|
|
||||||
hash_get(new_hash_table *nh, const void *key, ssize_t klen)
|
|
||||||
{
|
|
||||||
hash_entry **hepp;
|
|
||||||
hash_entry *hep;
|
|
||||||
|
|
||||||
ASSERT(nh != NULL);
|
|
||||||
|
|
||||||
hepp = find_entry(nh, key, klen, NULL);
|
|
||||||
// dprintf("khash, find_entry returned %p\n", hepp);
|
|
||||||
if (hepp == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
hep = *hepp;
|
|
||||||
if (hep == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
return (void *) hep->val; /* XXX casting away the const */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
hash_set(new_hash_table *nh, const void *key, ssize_t klen, const void *val)
|
|
||||||
{
|
|
||||||
hash_entry **hep;
|
|
||||||
hash_entry *old;
|
|
||||||
|
|
||||||
ASSERT(nh != NULL);
|
|
||||||
|
|
||||||
hep = find_entry(nh, key, klen, val);
|
|
||||||
ASSERT(hep != NULL);
|
|
||||||
|
|
||||||
if (*hep) {
|
|
||||||
if (!val) {
|
|
||||||
/* delete it */
|
|
||||||
old = *hep;
|
|
||||||
*hep = (*hep)->next;
|
|
||||||
--nh->count;
|
|
||||||
pool_put(nh->pool, old);
|
|
||||||
} else {
|
|
||||||
/* replace it */
|
|
||||||
(*hep)->val = val;
|
|
||||||
if (nh->count > nh->max)
|
|
||||||
expand_array(nh);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else ASSERT(false);
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue