quakeforge/libs/ruamoko/rua_hash.c
Bill Currie a6b932025c [gamecode] Provide builtins with information about their parameters
This will make it possible for the engine to set up their parameter
pointers when running Ruamoko progs. At this stage, it doesn't matter
*too* much, except for varargs functions, because no builtin yet takes
anything larger than a float quaternion, but it will be critical when
double or long vec3 and vec4 values are passed.
2022-01-23 22:27:27 +09:00

393 lines
9.2 KiB
C

/*
bi_hash.c
QuakeC hash table api
Copyright (C) 2003 Bill Currie
Author: Bill Currie <bill@taniwha.org>
Date: 2003/4/7
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#ifdef HAVE_STRING_H
# include <string.h>
#endif
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#include <stdlib.h>
#include "QF/hash.h"
#include "QF/progs.h"
#include "rua_internal.h"
typedef struct bi_hashtab_s {
struct bi_hashtab_s *next;
struct bi_hashtab_s **prev;
progs_t *pr;
hashtab_t *tab;
pr_func_t gk;
pr_func_t gh;
pr_func_t cmp;
pr_func_t f;
pr_ptr_t ud;
} bi_hashtab_t;
typedef struct {
PR_RESMAP (bi_hashtab_t) table_map;
bi_hashtab_t *tabs;
} hash_resources_t;
static bi_hashtab_t *
table_new (hash_resources_t *res)
{
return PR_RESNEW (res->table_map);
}
static void
table_free (hash_resources_t *res, bi_hashtab_t *table)
{
PR_RESFREE (res->table_map, table);
}
static void
table_reset (hash_resources_t *res)
{
PR_RESRESET (res->table_map);
}
static inline bi_hashtab_t *
table_get (hash_resources_t *res, int index)
{
return PR_RESGET(res->table_map, index);
}
static inline int __attribute__((pure))
table_index (hash_resources_t *res, bi_hashtab_t *table)
{
return PR_RESINDEX(res->table_map, table);
}
static const char *
bi_get_key (const void *key, void *_ht)
{
bi_hashtab_t *ht = (bi_hashtab_t *)_ht;
PR_RESET_PARAMS (ht->pr);
P_INT (ht->pr, 0) = (intptr_t) (key);
P_INT (ht->pr, 1) = ht->ud;
ht->pr->pr_argc = 2;
PR_ExecuteProgram (ht->pr, ht->gk);
return PR_GetString (ht->pr, R_STRING (ht->pr));
}
static uintptr_t
bi_get_hash (const void *key, void *_ht)
{
bi_hashtab_t *ht = (bi_hashtab_t *)_ht;
PR_RESET_PARAMS (ht->pr);
P_INT (ht->pr, 0) = (intptr_t) (key);
P_INT (ht->pr, 1) = ht->ud;
ht->pr->pr_argc = 2;
PR_ExecuteProgram (ht->pr, ht->gh);
return R_INT (ht->pr);
}
static int
bi_compare (const void *key1, const void *key2, void *_ht)
{
bi_hashtab_t *ht = (bi_hashtab_t *)_ht;
PR_RESET_PARAMS (ht->pr);
P_INT (ht->pr, 0) = (intptr_t) (key1);
P_INT (ht->pr, 1) = (intptr_t) (key2);
P_INT (ht->pr, 2) = ht->ud;
ht->pr->pr_argc = 3;
PR_ExecuteProgram (ht->pr, ht->cmp);
return R_INT (ht->pr);
}
static void
bi_free (void *key, void *_ht)
{
bi_hashtab_t *ht = (bi_hashtab_t *)_ht;
PR_RESET_PARAMS (ht->pr);
P_INT (ht->pr, 0) = (intptr_t) (key);
P_INT (ht->pr, 1) = ht->ud;
ht->pr->pr_argc = 2;
PR_ExecuteProgram (ht->pr, ht->f);
}
static void
bi_Hash_NewTable (progs_t *pr)
{
hash_resources_t *res = PR_Resources_Find (pr, "Hash");
int tsize = P_INT (pr, 0);
const char *(*gk)(const void*,void*);
void (*f)(void*,void*);
bi_hashtab_t *ht;
ht = table_new (res);
ht->pr = pr;
ht->gk = P_FUNCTION (pr, 1);
ht->f = P_FUNCTION (pr, 2);
ht->ud = P_INT (pr, 3); // don't convert pointer for speed reasons
ht->next = res->tabs;
ht->prev = &res->tabs;
if (res->tabs)
res->tabs->prev = &ht->next;
res->tabs = ht;
gk = ht->gk ? bi_get_key : 0;
f = ht->f ? bi_free : 0;
ht->tab = Hash_NewTable (tsize, gk, f, ht, pr->hashlink_freelist);
R_INT (pr) = table_index (res, ht);
}
static bi_hashtab_t *
get_table (progs_t *pr, const char *name, int index)
{
hash_resources_t *res = PR_Resources_Find (pr, "Hash");
bi_hashtab_t *ht = table_get (res, index);
if (!ht)
PR_RunError (pr, "invalid hash table index passed to %s", name + 3);
return ht;
}
static void
bi_Hash_SetHashCompare (progs_t *pr)
{
bi_hashtab_t *ht = get_table (pr, __FUNCTION__, P_INT (pr, 0));
uintptr_t (*gh)(const void*,void*);
int (*cmp)(const void*,const void*,void*);
ht->gh = P_FUNCTION (pr, 1);
ht->cmp = P_FUNCTION (pr, 2);
gh = ht->gh ? bi_get_hash : 0;
cmp = ht->cmp ? bi_compare : 0;
Hash_SetHashCompare (ht->tab, gh, cmp);
}
static void
bi_Hash_DelTable (progs_t *pr)
{
hash_resources_t *res = PR_Resources_Find (pr, "Hash");
bi_hashtab_t *ht = get_table (pr, __FUNCTION__, P_INT (pr, 0));
Hash_DelTable (ht->tab);
*ht->prev = ht->next;
if (ht->next)
ht->next->prev = ht->prev;
table_free (res, ht);
}
static void
bi_Hash_FlushTable (progs_t *pr)
{
bi_hashtab_t *ht = get_table (pr, __FUNCTION__, P_INT (pr, 0));
Hash_FlushTable (ht->tab);
}
static void
bi_Hash_Add (progs_t *pr)
{
bi_hashtab_t *ht = get_table (pr, __FUNCTION__, P_INT (pr, 0));
R_INT (pr) = Hash_Add (ht->tab, (void *) (intptr_t) P_INT (pr, 1));
}
static void
bi_Hash_AddElement (progs_t *pr)
{
bi_hashtab_t *ht = get_table (pr, __FUNCTION__, P_INT (pr, 0));
R_INT (pr) = Hash_AddElement (ht->tab, (void *) (intptr_t) P_INT (pr, 1));
}
static void
bi_Hash_Find (progs_t *pr)
{
bi_hashtab_t *ht = get_table (pr, __FUNCTION__, P_INT (pr, 0));
R_INT (pr) = (intptr_t) Hash_Find (ht->tab, P_GSTRING (pr, 1));
}
static void
bi_Hash_FindElement (progs_t *pr)
{
bi_hashtab_t *ht = get_table (pr, __FUNCTION__, P_INT (pr, 0));
R_INT (pr) = (intptr_t) Hash_FindElement (ht->tab,
(void *) (intptr_t) P_INT (pr, 1));
}
static void
bi_Hash_FindList (progs_t *pr)
{
bi_hashtab_t *ht = get_table (pr, __FUNCTION__, P_INT (pr, 0));
void **list, **l;
pr_type_t *pr_list;
int count;
list = Hash_FindList (ht->tab, P_GSTRING (pr, 1));
for (count = 1, l = list; *l; l++)
count++;
pr_list = PR_Zone_Malloc (pr, count * sizeof (pr_type_t));
// the hash tables stores progs pointers...
for (count = 0, l = list; *l; l++)
pr_list[count++].int_var = (intptr_t) *l;
free (list);
RETURN_POINTER (pr, pr_list);
}
static void
bi_Hash_FindElementList (progs_t *pr)
{
bi_hashtab_t *ht = get_table (pr, __FUNCTION__, P_INT (pr, 0));
void **list, **l;
pr_type_t *pr_list;
int count;
list = Hash_FindElementList (ht->tab, (void *) (intptr_t) P_INT (pr, 1));
for (count = 1, l = list; *l; l++)
count++;
pr_list = PR_Zone_Malloc (pr, count * sizeof (pr_type_t));
// the hash tables stores progs pointers...
for (count = 0, l = list; *l; l++)
pr_list[count++].int_var = (intptr_t) *l;
free (list);
RETURN_POINTER (pr, pr_list);
}
static void
bi_Hash_Del (progs_t *pr)
{
bi_hashtab_t *ht = get_table (pr, __FUNCTION__, P_INT (pr, 0));
R_INT (pr) = (intptr_t) Hash_Del (ht->tab, P_GSTRING (pr, 1));
}
static void
bi_Hash_DelElement (progs_t *pr)
{
bi_hashtab_t *ht = get_table (pr, __FUNCTION__, P_INT (pr, 0));
R_INT (pr) = (intptr_t) Hash_DelElement (ht->tab,
(void *) (intptr_t) P_INT (pr, 1));
}
static void
bi_Hash_Free (progs_t *pr)
{
bi_hashtab_t *ht = get_table (pr, __FUNCTION__, P_INT (pr, 0));
Hash_Free (ht->tab, (void *) (intptr_t) P_INT (pr, 1));
}
static void
bi_Hash_String (progs_t *pr)
{
R_INT (pr) = Hash_String (P_GSTRING (pr, 0));
}
static void
bi_Hash_Buffer (progs_t *pr)
{
R_INT (pr) = Hash_Buffer (P_GPOINTER (pr, 0), P_INT (pr, 1));
}
static void
bi_Hash_GetList (progs_t *pr)
{
bi_hashtab_t *ht = get_table (pr, __FUNCTION__, P_INT (pr, 0));
void **list, **l;
pr_type_t *pr_list;
int count;
list = Hash_GetList (ht->tab);
for (count = 1, l = list; *l; l++)
count++;
pr_list = PR_Zone_Malloc (pr, count * sizeof (pr_type_t));
// the hash tables stores progs pointers...
for (count = 0, l = list; *l; l++)
pr_list[count++].int_var = (intptr_t) *l;
free (list);
RETURN_POINTER (pr, pr_list);
}
static void
bi_Hash_Stats (progs_t *pr)
{
bi_hashtab_t *ht = get_table (pr, __FUNCTION__, P_INT (pr, 0));
Hash_Stats (ht->tab);
}
static void
bi_hash_clear (progs_t *pr, void *data)
{
hash_resources_t *res = (hash_resources_t *) data;
bi_hashtab_t *ht;
for (ht = res->tabs; ht; ht = ht->next)
Hash_DelTable (ht->tab);
res->tabs = 0;
table_reset (res);
}
#define bi(x,np,params...) {#x, bi_##x, -1, np, {params}}
#define p(type) PR_PARAM(type)
static builtin_t builtins[] = {
bi(Hash_NewTable, 4, p(int), p(func), p(func), p(ptr)),
bi(Hash_SetHashCompare, 3, p(ptr), p(func), p(func)),
bi(Hash_DelTable, 1, p(ptr)),
bi(Hash_FlushTable, 1, p(ptr)),
bi(Hash_Add, 2, p(ptr), p(ptr)),
bi(Hash_AddElement, 2, p(ptr), p(ptr)),
bi(Hash_Find, 2, p(ptr), p(string)),
bi(Hash_FindElement, 2, p(ptr), p(ptr)),
bi(Hash_FindList, 2, p(ptr), p(string)),
bi(Hash_FindElementList, 2, p(ptr), p(ptr)),
bi(Hash_Del, 2, p(ptr), p(string)),
bi(Hash_DelElement, 2, p(ptr), p(ptr)),
bi(Hash_Free, 2, p(ptr), p(ptr)),
bi(Hash_String, 1, p(string)),
bi(Hash_Buffer, 2, p(ptr), p(int)),
bi(Hash_GetList, 1, p(ptr)),
bi(Hash_Stats, 1, p(ptr)),
{0}
};
void
RUA_Hash_Init (progs_t *pr, int secure)
{
hash_resources_t *res = calloc (1, sizeof (hash_resources_t));
res->tabs = 0;
PR_Resources_Register (pr, "Hash", res, bi_hash_clear);
PR_RegisterBuiltins (pr, builtins);
}