52a3801208
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@10 a95241bf-73f2-0310-859d-f6bbb57e9c96
211 lines
4.3 KiB
C
211 lines
4.3 KiB
C
/* Generic hash table. No real clue where hash_elem is defined...*/
|
|
/*
|
|
** Copyright 2001, Travis Geiselbrecht. All rights reserved.
|
|
** Distributed under the terms of the NewOS License.
|
|
*/
|
|
|
|
#include <memheap.h>
|
|
#include <debug.h>
|
|
#include <Errors.h>
|
|
#include <string.h>
|
|
#include <khash.h>
|
|
|
|
#define malloc kmalloc
|
|
#define free kfree
|
|
|
|
struct hash_table {
|
|
struct hash_elem **table;
|
|
int next_ptr_offset;
|
|
unsigned int table_size;
|
|
int num_elems;
|
|
int flags;
|
|
int (*compare_func)(void *e, const void *key);
|
|
unsigned int (*hash_func)(void *e, const void *key, unsigned int range);
|
|
};
|
|
|
|
// XXX gross hack
|
|
#define NEXT_ADDR(t, e) ((void *)(((unsigned long)(e)) + (t)->next_ptr_offset))
|
|
#define NEXT(t, e) ((void *)(*(unsigned long *)NEXT_ADDR(t, e)))
|
|
#define PUT_IN_NEXT(t, e, val) (*(unsigned long *)NEXT_ADDR(t, e) = (long)(val))
|
|
|
|
void *hash_init(unsigned int table_size, int next_ptr_offset,
|
|
int compare_func(void *e, const void *key),
|
|
unsigned int hash_func(void *e, const void *key, unsigned int range))
|
|
{
|
|
struct hash_table *t;
|
|
unsigned int i;
|
|
|
|
t = (struct hash_table *)malloc(sizeof(struct hash_table));
|
|
if(t == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
t->table = (struct hash_elem **)malloc(sizeof(void *) * table_size);
|
|
for(i = 0; i<table_size; i++)
|
|
t->table[i] = NULL;
|
|
t->table_size = table_size;
|
|
t->next_ptr_offset = next_ptr_offset;
|
|
t->flags = 0;
|
|
t->num_elems = 0;
|
|
t->compare_func = compare_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",
|
|
// t, next_ptr_offset, compare_func, hash_func);
|
|
|
|
return t;
|
|
}
|
|
|
|
int hash_uninit(void *_hash_table)
|
|
{
|
|
struct hash_table *t = (struct hash_table *)_hash_table;
|
|
|
|
#if 0
|
|
if(t->num_elems > 0) {
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
free(t->table);
|
|
free(t);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int hash_insert(void *_hash_table, void *e)
|
|
{
|
|
struct hash_table *t = (struct hash_table *)_hash_table;
|
|
unsigned int hash;
|
|
|
|
// dprintf("hash_insert: table 0x%x, element 0x%x\n", t, e);
|
|
|
|
hash = t->hash_func(e, NULL, t->table_size);
|
|
PUT_IN_NEXT(t, e, t->table[hash]);
|
|
t->table[hash] = (struct hash_elem *)e;
|
|
t->num_elems++;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int hash_remove(void *_hash_table, void *e)
|
|
{
|
|
struct hash_table *t = (struct hash_table *)_hash_table;
|
|
void *i, *last_i;
|
|
unsigned int hash;
|
|
|
|
hash = t->hash_func(e, NULL, t->table_size);
|
|
last_i = NULL;
|
|
for(i = t->table[hash]; i != NULL; last_i = i, i = NEXT(t, i)) {
|
|
if(i == e) {
|
|
if(last_i != NULL)
|
|
PUT_IN_NEXT(t, last_i, NEXT(t, i));
|
|
else
|
|
t->table[hash] = (struct hash_elem *)NEXT(t, i);
|
|
t->num_elems--;
|
|
return B_NO_ERROR;
|
|
}
|
|
}
|
|
|
|
return ERR_GENERAL;
|
|
}
|
|
|
|
void *hash_find(void *_hash_table, void *e)
|
|
{
|
|
struct hash_table *t = (struct hash_table *)_hash_table;
|
|
void *i;
|
|
unsigned int hash;
|
|
|
|
hash = t->hash_func(e, NULL, t->table_size);
|
|
for(i = t->table[hash]; i != NULL; i = NEXT(t, i)) {
|
|
if(i == e) {
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void *hash_lookup(void *_hash_table, const void *key)
|
|
{
|
|
struct hash_table *t = (struct hash_table *)_hash_table;
|
|
void *i;
|
|
unsigned int hash;
|
|
|
|
if(t->compare_func == NULL)
|
|
return NULL;
|
|
|
|
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;
|
|
}
|
|
|
|
struct hash_iterator *hash_open(void *_hash_table, struct hash_iterator *i)
|
|
{
|
|
struct hash_table *t = (struct hash_table *)_hash_table;
|
|
|
|
if(i == NULL) {
|
|
i = (struct hash_iterator *)malloc(sizeof(struct hash_iterator));
|
|
if(i == NULL)
|
|
return NULL;
|
|
}
|
|
|
|
hash_rewind(t, i);
|
|
|
|
return i;
|
|
}
|
|
|
|
void hash_close(void *_hash_table, struct hash_iterator *i, bool free_iterator)
|
|
{
|
|
if(free_iterator)
|
|
free(i);
|
|
}
|
|
|
|
void hash_rewind(void *_hash_table, struct hash_iterator *i)
|
|
{
|
|
i->ptr = NULL;
|
|
i->bucket = -1;
|
|
}
|
|
|
|
void *hash_next(void *_hash_table, struct hash_iterator *i)
|
|
{
|
|
struct hash_table *t = (struct hash_table *)_hash_table;
|
|
unsigned int index;
|
|
|
|
restart:
|
|
if(!i->ptr) {
|
|
for(index = (unsigned int)(i->bucket + 1); index < t->table_size; index++) {
|
|
if(t->table[index]) {
|
|
i->bucket = index;
|
|
i->ptr = t->table[index];
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
i->ptr = NEXT(t, i->ptr);
|
|
if(!i->ptr)
|
|
goto restart;
|
|
}
|
|
|
|
return i->ptr;
|
|
}
|
|
|
|
unsigned int hash_hash_str( const char *str )
|
|
{
|
|
char ch;
|
|
unsigned int hash = 0;
|
|
|
|
// we assume hash to be at least 32 bits
|
|
while( (ch = *str++) != 0 ) {
|
|
hash ^= hash >> 28;
|
|
hash <<= 4;
|
|
hash ^= ch;
|
|
}
|
|
|
|
return hash;
|
|
}
|