extend the hash api to more easily support general cases

This commit is contained in:
Bill Currie 2001-08-16 02:51:53 +00:00
parent c02f4ed59e
commit 9ee3450265
3 changed files with 155 additions and 42 deletions

View file

@ -53,6 +53,19 @@ typedef struct hashtab_s hashtab_t;
hashtab_t *Hash_NewTable (int tsize, const char *(*gk)(void*,void*),
void (*f)(void*,void*), void *ud);
/*
change the hash and compare functions used by the Has_*Element functions.
the default hash function just returns the address of the element, and the
default compare just compares the addresses. compare is to return 0 for not
equal and non-0 otherwise.
gh takes the same parameters as gk above
cmp is element 1, element 2, userdata
*/
void Hash_SetHashCompare (hashtab_t *tab, unsigned long (*gh)(void*,void*),
int (*cmp)(void*,void*,void*));
/*
delete a hash table:
tab: the table to be deleted
@ -72,6 +85,7 @@ void Hash_FlushTable (hashtab_t *tab);
returns 0 for success, -1 for error.
*/
int Hash_Add (hashtab_t *tab, void *ele);
int Hash_AddElement (hashtab_t *tab, void *ele);
/*
find an element within a hash table:
@ -80,6 +94,7 @@ int Hash_Add (hashtab_t *tab, void *ele);
returns a pointer to the element if found, otherwise 0.
*/
void *Hash_Find (hashtab_t *tab, const char *key);
void *Hash_FindElement (hashtab_t *tab, void *ele);
/*
delete an element from a hash table:
@ -91,5 +106,12 @@ void *Hash_Find (hashtab_t *tab, const char *key);
responsibility.
*/
void *Hash_Del (hashtab_t *tab, const char *key);
void *Hash_DelElement (hashtab_t *tab, void *ele);
/*
returh the hash value of a string. this is the same function as used
internally.
*/
unsigned long Hash_String (const char *str);
#endif // __hash_h

View file

@ -51,14 +51,16 @@ struct hashlink_s {
struct hashtab_s {
size_t tab_size;
void *user_data;
int (*compare)(void*,void*,void*);
unsigned long (*get_hash)(void*,void*);
const char *(*get_key)(void*,void*);
void (*free_ele)(void*,void*);
struct hashlink_s *tab[1]; // variable size
};
static unsigned long
hash (const char *str)
unsigned long
Hash_String (const char *str)
{
//FIXME not 64 bit clean
#if 0
@ -85,9 +87,21 @@ hash (const char *str)
#endif
}
static unsigned long
get_hash (void *ele, void *data)
{
return (unsigned long)ele;
}
static int
compare (void *a, void *b, void *data)
{
return a == b;
}
hashtab_t *
Hash_NewTable (int tsize, const char *(*gk)(void*,void*), void (*f)(void*,void*),
void *ud)
Hash_NewTable (int tsize, const char *(*gk)(void*,void*),
void (*f)(void*,void*), void *ud)
{
hashtab_t *tab = calloc (1, field_offset (hashtab_t, tab[tsize]));
if (!tab)
@ -96,9 +110,20 @@ Hash_NewTable (int tsize, const char *(*gk)(void*,void*), void (*f)(void*,void*)
tab->user_data = ud;
tab->get_key = gk;
tab->free_ele = f;
tab->get_hash = get_hash;
tab->compare = compare;
return tab;
}
void
Hash_SetHashCompare (hashtab_t *tab, unsigned long (*gh)(void*,void*),
int (*cmp)(void*,void*,void*))
{
tab->get_hash = gh;
tab->compare = cmp;
}
void
Hash_DelTable (hashtab_t *tab)
{
@ -127,7 +152,25 @@ Hash_FlushTable (hashtab_t *tab)
int
Hash_Add (hashtab_t *tab, void *ele)
{
unsigned long h = hash (tab->get_key(ele, tab->user_data));
unsigned long h = Hash_String (tab->get_key(ele, tab->user_data));
size_t ind = h % tab->tab_size;
struct hashlink_s *lnk = malloc (sizeof (struct hashlink_s));
if (!lnk)
return -1;
if (tab->tab[ind])
tab->tab[ind]->prev = &lnk->next;
lnk->next = tab->tab[ind];
lnk->prev = &tab->tab[ind];
lnk->data = ele;
tab->tab[ind] = lnk;
return 0;
}
int
Hash_AddElement (hashtab_t *tab, void *ele)
{
unsigned long h = tab->get_hash (ele, tab->user_data);
size_t ind = h % tab->tab_size;
struct hashlink_s *lnk = malloc (sizeof (struct hashlink_s));
@ -145,7 +188,7 @@ Hash_Add (hashtab_t *tab, void *ele)
void *
Hash_Find (hashtab_t *tab, const char *key)
{
unsigned long h = hash (key);
unsigned long h = Hash_String (key);
size_t ind = h % tab->tab_size;
struct hashlink_s *lnk = tab->tab[ind];
@ -157,10 +200,25 @@ Hash_Find (hashtab_t *tab, const char *key)
return 0;
}
void *
Hash_FindElement (hashtab_t *tab, void *ele)
{
unsigned long h = tab->get_hash (ele, tab->user_data);
size_t ind = h % tab->tab_size;
struct hashlink_s *lnk = tab->tab[ind];
while (lnk) {
if (tab->compare (lnk->data, ele, tab->user_data))
return lnk->data;
lnk = lnk->next;
}
return 0;
}
void *
Hash_Del (hashtab_t *tab, const char *key)
{
unsigned long h = hash (key);
unsigned long h = Hash_String (key);
size_t ind = h % tab->tab_size;
struct hashlink_s *lnk = tab->tab[ind];
void *data;
@ -178,3 +236,25 @@ Hash_Del (hashtab_t *tab, const char *key)
}
return 0;
}
void *
Hash_DelElement (hashtab_t *tab, void *ele)
{
unsigned long h = tab->get_hash (ele, tab->user_data);
size_t ind = h % tab->tab_size;
struct hashlink_s *lnk = tab->tab[ind];
void *data;
while (lnk) {
if (tab->compare (lnk->data, ele, tab->user_data)) {
data = lnk->data;
if (lnk->next)
lnk->next->prev = lnk->prev;
*lnk->prev = lnk->next;
free (lnk);
return data;
}
lnk = lnk->next;
}
return 0;
}

View file

@ -55,39 +55,51 @@ PR_AddStatementRef (def_t *def, dstatement_t *st, int field)
}
}
static const char *
get_key (void *_op, void *_tab)
#define ROTL(x,n) (((x)<<(n))|(x)>>(32-n))
static unsigned long
get_hash (void *_op, void *_tab)
{
opcode_t *op = (opcode_t *)_op;
hashtab_t **tab = (hashtab_t **)_tab;
static char rep[100];
char *r = rep;
const char *s = op->name;
unsigned long hash;
if (tab == &opcode_priority_table) {
while (*s)
*r++ = *s++;
*r++ = op->priority + 2;
*r = 0;
hash = op->priority;
} else if (tab == &opcode_priority_type_table_ab) {
while (*s)
*r++ = *s++;
*r++ = op->priority + 2;
*r++ = op->type_a + 2;
*r++ = op->type_b + 2;
*r = 0;
hash = ~op->priority + ROTL(~op->type_a, 8) + ROTL(~op->type_b, 16);
} else if (tab == &opcode_priority_type_table_abc) {
while (*s)
*r++ = *s++;
*r++ = op->priority + 2;
*r++ = op->type_a + 2;
*r++ = op->type_b + 2;
*r++ = op->type_c + 2;
*r = 0;
hash = ~op->priority + ROTL(~op->type_a, 8) + ROTL(~op->type_b, 16)
+ ROTL(~op->type_c, 24);
} else {
abort ();
}
return rep;
return hash + Hash_String (op->name);;
}
static int
compare (void *_opa, void *_opb, void *_tab)
{
opcode_t *opa = (opcode_t *)_opa;
opcode_t *opb = (opcode_t *)_opb;
hashtab_t **tab = (hashtab_t **)_tab;
int cmp;
if (tab == &opcode_priority_table) {
cmp = opa->priority == opb->priority;
} else if (tab == &opcode_priority_type_table_ab) {
cmp = (opa->priority == opb->priority)
&& (opa->type_a == opb->type_a)
&& (opa->type_b == opb->type_b);
} else if (tab == &opcode_priority_type_table_abc) {
cmp = (opa->priority == opb->priority)
&& (opa->type_a == opb->type_a)
&& (opa->type_b == opb->type_b)
&& (opa->type_c == opb->type_c);
} else {
abort ();
}
return cmp && !strcmp (opa->name, opb->name);
}
opcode_t *
@ -95,7 +107,6 @@ PR_Opcode_Find (const char *name, int priority, def_t *var_a, def_t *var_b, def_
{
opcode_t op;
hashtab_t **tab;
char rep[100];
op.name = name;
op.priority = priority;
@ -107,12 +118,9 @@ PR_Opcode_Find (const char *name, int priority, def_t *var_a, def_t *var_b, def_
tab = &opcode_priority_type_table_ab;
else
tab = &opcode_priority_type_table_abc;
strcpy (rep, get_key (&op, tab));
//printf ("%s\n", rep);
return Hash_Find (*tab, rep);
return Hash_FindElement (*tab, &op);
} else {
strcpy (rep, get_key (&op, &opcode_priority_table));
return Hash_Find (opcode_priority_table, rep);
return Hash_FindElement (opcode_priority_table, &op);
}
}
@ -122,21 +130,24 @@ PR_Opcode_Init_Tables (void)
opcode_t *op;
PR_Opcode_Init ();
opcode_priority_table = Hash_NewTable (1021, get_key, 0,
opcode_priority_table = Hash_NewTable (1021, 0, 0,
&opcode_priority_table);
opcode_priority_type_table_ab = Hash_NewTable (1021, get_key, 0,
opcode_priority_type_table_ab = Hash_NewTable (1021, 0, 0,
&opcode_priority_type_table_ab);
opcode_priority_type_table_abc = Hash_NewTable (1021, get_key, 0,
opcode_priority_type_table_abc = Hash_NewTable (1021, 0, 0,
&opcode_priority_type_table_abc);
Hash_SetHashCompare (opcode_priority_table, get_hash, compare);
Hash_SetHashCompare (opcode_priority_type_table_ab, get_hash, compare);
Hash_SetHashCompare (opcode_priority_type_table_abc, get_hash, compare);
for (op = pr_opcodes; op->name; op++) {
if (op->min_version > options.version)
continue;
if (options.version == PROG_ID_VERSION
&& op->type_c == ev_integer)
op->type_c = ev_float;
Hash_Add (opcode_priority_table, op);
Hash_Add (opcode_priority_type_table_ab, op);
Hash_Add (opcode_priority_type_table_abc, op);
Hash_AddElement (opcode_priority_table, op);
Hash_AddElement (opcode_priority_type_table_ab, op);
Hash_AddElement (opcode_priority_type_table_abc, op);
if (!strcmp (op->name, "<DONE>")) {
op_done = op;
} else if (!strcmp (op->name, "<RETURN>")) {