[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

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_DelContext (hashctx_t *hashctx);
/** clean out all the entries from a hash table, starting over again.
\param tab the table to be cleared
*/

View file

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

View file

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