mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-01-31 13:10:34 +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:
parent
44ad372adb
commit
be9e6893e5
3 changed files with 58 additions and 18 deletions
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue