0
0
Fork 0
mirror of https://git.code.sf.net/p/quake/quakeforge synced 2025-03-01 15:01:00 +00:00

[util] Free up hash links

Finally, hash links can be freed when the hash context is no longer
relevant. The context is created automatically when needed, and the
owner can delete the context when its done with the relevant hash
tables.
This commit is contained in:
Bill Currie 2023-03-04 02:07:31 +09:00
parent 44ad372adb
commit be9e6893e5
3 changed files with 58 additions and 18 deletions
include/QF
libs/util
ruamoko/qwaq/builtins

View file

@ -93,6 +93,8 @@ void Hash_SetHashCompare (hashtab_t *tab, uintptr_t (*gh)(const void*,void*),
*/ */
void Hash_DelTable (hashtab_t *tab); void Hash_DelTable (hashtab_t *tab);
void Hash_DelContext (hashctx_t *hashctx);
/** clean out all the entries from a hash table, starting over again. /** clean out all the entries from a hash table, starting over again.
\param tab the table to be cleared \param tab the table to be cleared
*/ */

View file

@ -51,6 +51,15 @@ typedef struct hashlink_s {
void *data; void *data;
} hashlink_t; } hashlink_t;
typedef struct hlinkset_s {
struct hlinkset_s *next;
} hlinkset_t;
struct hashctx_s {
hlinkset_t *linksets;
hashlink_t *free_hashlinks;
};
struct hashtab_s { struct hashtab_s {
size_t tab_size; size_t tab_size;
unsigned int size_bits; unsigned int size_bits;
@ -60,38 +69,41 @@ struct hashtab_s {
uintptr_t (*get_hash)(const void*,void*); uintptr_t (*get_hash)(const void*,void*);
const char *(*get_key)(const void*,void*); const char *(*get_key)(const void*,void*);
void (*free_ele)(void*,void*); void (*free_ele)(void*,void*);
hashlink_t **hashlink_freelist; hashctx_t *hashctx;
hashlink_t *tab[1]; // variable size hashlink_t *tab[1]; // variable size
}; };
static hashlink_t * static hashlink_t *
new_hashlink (hashlink_t **free_hashlinks) new_hashlink (hashctx_t *hctx)
{ {
hashlink_t *link; hashlink_t *link;
if (!*free_hashlinks) { if (!hctx->free_hashlinks) {
int i; int i;
if (!(*free_hashlinks = calloc (1024, sizeof (hashlink_t)))) hlinkset_t *linkset = malloc (sizeof (hlinkset_t)
return 0; + 1024 * sizeof (hashlink_t));
for (i = 0, link = *free_hashlinks; i < 1023; i++, link++) linkset->next = hctx->linksets;
hctx->linksets = linkset;
hctx->free_hashlinks = (hashlink_t *) &linkset[1];
for (i = 0, link = hctx->free_hashlinks; i < 1023; i++, link++)
link->next = link + 1; link->next = link + 1;
link->next = 0; link->next = 0;
} }
link = *free_hashlinks; link = hctx->free_hashlinks;
*free_hashlinks = link->next; hctx->free_hashlinks = link->next;
link->next = 0; link->next = 0;
return link; return link;
} }
static void static void
free_hashlink (hashlink_t *link, hashlink_t **free_hashlinks) free_hashlink (hashlink_t *link, hashctx_t *hctx)
{ {
link->next = *free_hashlinks; link->next = hctx->free_hashlinks;
*free_hashlinks = link; hctx->free_hashlinks = link;
} }
static hashlink_t *default_hashlink_freelist; static hashctx_t *default_hashctx;
VISIBLE uintptr_t VISIBLE uintptr_t
Hash_String (const char *str) Hash_String (const char *str)
@ -208,6 +220,23 @@ get_index (uintptr_t hash, size_t size, size_t bits)
#endif #endif
} }
static void
hash_shutdown (void *data)
{
Hash_DelContext (default_hashctx);
}
VISIBLE void
Hash_DelContext (hashctx_t *hashctx)
{
while (hashctx->linksets) {
hlinkset_t *l = hashctx->linksets->next;
free (hashctx->linksets);
hashctx->linksets = l;
}
free (hashctx);
}
VISIBLE hashtab_t * VISIBLE hashtab_t *
Hash_NewTable (int tsize, const char *(*gk)(const void*,void*), Hash_NewTable (int tsize, const char *(*gk)(const void*,void*),
void (*f)(void*,void*), void *ud, hashctx_t **hctx) void (*f)(void*,void*), void *ud, hashctx_t **hctx)
@ -220,9 +249,15 @@ Hash_NewTable (int tsize, const char *(*gk)(const void*,void*),
tab->get_key = gk; tab->get_key = gk;
tab->free_ele = f; tab->free_ele = f;
if (!hctx) { if (!hctx) {
hctx = (hashctx_t **) &default_hashlink_freelist; hctx = &default_hashctx;
if (!default_hashctx) {
Sys_RegisterShutdown (hash_shutdown, 0);
}
} }
tab->hashlink_freelist = (hashlink_t **) hctx; if (!*hctx) {
*hctx = calloc (1, sizeof (hashctx_t));
}
tab->hashctx = *hctx;
while (tsize) { while (tsize) {
tab->size_bits++; tab->size_bits++;
@ -259,7 +294,7 @@ Hash_FlushTable (hashtab_t *tab)
hashlink_t *t = tab->tab[i]->next; hashlink_t *t = tab->tab[i]->next;
void *data = tab->tab[i]->data; void *data = tab->tab[i]->data;
free_hashlink (tab->tab[i], tab->hashlink_freelist); free_hashlink (tab->tab[i], tab->hashctx);
tab->tab[i] = t; tab->tab[i] = t;
if (tab->free_ele) if (tab->free_ele)
tab->free_ele (data, tab->user_data); tab->free_ele (data, tab->user_data);
@ -272,7 +307,7 @@ static int
hash_add_element (hashtab_t *tab, uintptr_t h, void *ele) hash_add_element (hashtab_t *tab, uintptr_t h, void *ele)
{ {
size_t ind = get_index (h, tab->tab_size, tab->size_bits); size_t ind = get_index (h, tab->tab_size, tab->size_bits);
hashlink_t *lnk = new_hashlink (tab->hashlink_freelist); hashlink_t *lnk = new_hashlink (tab->hashctx);
if (!lnk) if (!lnk)
return -1; return -1;
@ -415,7 +450,7 @@ Hash_Del (hashtab_t *tab, const char *key)
if (lnk->next) if (lnk->next)
lnk->next->prev = lnk->prev; lnk->next->prev = lnk->prev;
*lnk->prev = lnk->next; *lnk->prev = lnk->next;
free_hashlink (lnk, tab->hashlink_freelist); free_hashlink (lnk, tab->hashctx);
tab->num_ele--; tab->num_ele--;
return data; return data;
} }
@ -438,7 +473,7 @@ Hash_DelElement (hashtab_t *tab, void *ele)
if (lnk->next) if (lnk->next)
lnk->next->prev = lnk->prev; lnk->next->prev = lnk->prev;
*lnk->prev = lnk->next; *lnk->prev = lnk->next;
free_hashlink (lnk, tab->hashlink_freelist); free_hashlink (lnk, tab->hashctx);
tab->num_ele--; tab->num_ele--;
return data; return data;
} }

View file

@ -42,6 +42,7 @@
#include "QF/cmd.h" #include "QF/cmd.h"
#include "QF/cvar.h" #include "QF/cvar.h"
#include "QF/gib.h" #include "QF/gib.h"
#include "QF/hash.h"
#include "QF/idparse.h" #include "QF/idparse.h"
#include "QF/keys.h" #include "QF/keys.h"
#include "QF/progs.h" #include "QF/progs.h"
@ -320,6 +321,8 @@ run_progs (void *data)
PR_Shutdown (thread->pr); PR_Shutdown (thread->pr);
free (thread->pr); free (thread->pr);
thread->pr = 0; thread->pr = 0;
Hash_DelContext (thread->hashctx);
thread->hashctx = 0;
return thread; return thread;
} }