mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-10 15:22:04 +00:00
extend the hash api to more easily support general cases
This commit is contained in:
parent
c02f4ed59e
commit
9ee3450265
3 changed files with 155 additions and 42 deletions
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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>")) {
|
||||
|
|
Loading…
Reference in a new issue