mirror of
https://github.com/ZDoom/raze-gles.git
synced 2024-12-25 03:00:46 +00:00
Move hash table stuff out of engine.c and into hash.c/h.
git-svn-id: https://svn.eduke32.com/eduke32@5788 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
parent
aca0807a81
commit
cdcc983a22
9 changed files with 444 additions and 415 deletions
|
@ -43,6 +43,7 @@ ENGINE_OBJS = \
|
||||||
crc32 \
|
crc32 \
|
||||||
defs \
|
defs \
|
||||||
engine \
|
engine \
|
||||||
|
hash \
|
||||||
polymost \
|
polymost \
|
||||||
texcache \
|
texcache \
|
||||||
dxtfilter \
|
dxtfilter \
|
||||||
|
|
|
@ -137,6 +137,7 @@ ENGINE_OBJS= \
|
||||||
$(ENGINE_OBJ)\defs.$o \
|
$(ENGINE_OBJ)\defs.$o \
|
||||||
$(ENGINE_OBJ)\colmatch.$o \
|
$(ENGINE_OBJ)\colmatch.$o \
|
||||||
$(ENGINE_OBJ)\engine.$o \
|
$(ENGINE_OBJ)\engine.$o \
|
||||||
|
$(ENGINE_OBJ)\hash.$o \
|
||||||
$(ENGINE_OBJ)\glbuild.$o \
|
$(ENGINE_OBJ)\glbuild.$o \
|
||||||
$(ENGINE_OBJ)\texcache.$o \
|
$(ENGINE_OBJ)\texcache.$o \
|
||||||
$(ENGINE_OBJ)\kplib.$o \
|
$(ENGINE_OBJ)\kplib.$o \
|
||||||
|
|
|
@ -10,6 +10,7 @@ $(ENGINE_OBJ)/config.$o: $(ENGINE_SRC)/config.c $(ENGINE_INC)/compat.h $(ENGINE_
|
||||||
$(ENGINE_OBJ)/crc32.$o: $(ENGINE_SRC)/crc32.c $(ENGINE_INC)/crc32.h
|
$(ENGINE_OBJ)/crc32.$o: $(ENGINE_SRC)/crc32.c $(ENGINE_INC)/crc32.h
|
||||||
$(ENGINE_OBJ)/defs.$o: $(ENGINE_SRC)/defs.c $(ENGINE_INC)/build.h $(ENGINE_INC)/buildtypes.h $(ENGINE_INC)/baselayer.h $(ENGINE_INC)/scriptfile.h $(ENGINE_INC)/compat.h
|
$(ENGINE_OBJ)/defs.$o: $(ENGINE_SRC)/defs.c $(ENGINE_INC)/build.h $(ENGINE_INC)/buildtypes.h $(ENGINE_INC)/baselayer.h $(ENGINE_INC)/scriptfile.h $(ENGINE_INC)/compat.h
|
||||||
$(ENGINE_OBJ)/engine.$o: $(ENGINE_SRC)/engine.c $(ENGINE_INC)/compat.h $(ENGINE_INC)/build.h $(ENGINE_INC)/buildtypes.h $(ENGINE_INC)/pragmas.h $(ENGINE_INC)/cache1d.h $(ENGINE_INC)/a.h $(ENGINE_INC)/osd.h $(ENGINE_INC)/baselayer.h $(ENGINE_SRC)/engine_priv.h $(ENGINE_SRC)/engine_oldmap.h $(ENGINE_INC)/polymost.h $(ENGINE_INC)/hightile.h $(ENGINE_INC)/mdsprite.h $(ENGINE_INC)/polymer.h
|
$(ENGINE_OBJ)/engine.$o: $(ENGINE_SRC)/engine.c $(ENGINE_INC)/compat.h $(ENGINE_INC)/build.h $(ENGINE_INC)/buildtypes.h $(ENGINE_INC)/pragmas.h $(ENGINE_INC)/cache1d.h $(ENGINE_INC)/a.h $(ENGINE_INC)/osd.h $(ENGINE_INC)/baselayer.h $(ENGINE_SRC)/engine_priv.h $(ENGINE_SRC)/engine_oldmap.h $(ENGINE_INC)/polymost.h $(ENGINE_INC)/hightile.h $(ENGINE_INC)/mdsprite.h $(ENGINE_INC)/polymer.h
|
||||||
|
$(ENGINE_OBJ)/hash.$o: $(ENGINE_SRC)/hash.c $(ENGINE_INC)/hash.h
|
||||||
$(ENGINE_OBJ)/polymost.$o: $(ENGINE_SRC)/polymost.c $(ENGINE_INC)/lz4.h $(ENGINE_INC)/compat.h $(ENGINE_INC)/build.h $(ENGINE_INC)/buildtypes.h $(ENGINE_SRC)/engine_priv.h $(ENGINE_INC)/polymost.h $(ENGINE_INC)/hightile.h $(ENGINE_INC)/mdsprite.h $(ENGINE_INC)/texcache.h
|
$(ENGINE_OBJ)/polymost.$o: $(ENGINE_SRC)/polymost.c $(ENGINE_INC)/lz4.h $(ENGINE_INC)/compat.h $(ENGINE_INC)/build.h $(ENGINE_INC)/buildtypes.h $(ENGINE_SRC)/engine_priv.h $(ENGINE_INC)/polymost.h $(ENGINE_INC)/hightile.h $(ENGINE_INC)/mdsprite.h $(ENGINE_INC)/texcache.h
|
||||||
$(ENGINE_OBJ)/texcache.$o: $(ENGINE_SRC)/texcache.c $(ENGINE_INC)/texcache.h $(ENGINE_INC)/polymost.h $(ENGINE_INC)/dxtfilter.h $(ENGINE_INC)/kplib.h
|
$(ENGINE_OBJ)/texcache.$o: $(ENGINE_SRC)/texcache.c $(ENGINE_INC)/texcache.h $(ENGINE_INC)/polymost.h $(ENGINE_INC)/dxtfilter.h $(ENGINE_INC)/kplib.h
|
||||||
$(ENGINE_OBJ)/dxtfilter.$o: $(ENGINE_SRC)/dxtfilter.c $(ENGINE_INC)/dxtfilter.h $(ENGINE_INC)/texcache.h
|
$(ENGINE_OBJ)/dxtfilter.$o: $(ENGINE_SRC)/dxtfilter.c $(ENGINE_INC)/dxtfilter.h $(ENGINE_INC)/texcache.h
|
||||||
|
|
|
@ -1405,56 +1405,7 @@ int32_t loaddefinitionsfile(const char *fn);
|
||||||
// -2, board is dodgy
|
// -2, board is dodgy
|
||||||
int32_t loadoldboard(const char *filename, char fromwhere, vec3_t *dapos, int16_t *daang, int16_t *dacursectnum);
|
int32_t loadoldboard(const char *filename, char fromwhere, vec3_t *dapos, int16_t *daang, int16_t *dacursectnum);
|
||||||
|
|
||||||
|
#include "hash.h"
|
||||||
// Hash functions
|
|
||||||
|
|
||||||
typedef struct hashitem_ // size is 12/24 bytes.
|
|
||||||
{
|
|
||||||
char *string;
|
|
||||||
intptr_t key;
|
|
||||||
struct hashitem_ *next;
|
|
||||||
} hashitem_t;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
int32_t size;
|
|
||||||
hashitem_t **items;
|
|
||||||
} hashtable_t;
|
|
||||||
|
|
||||||
void hash_init(hashtable_t *t);
|
|
||||||
void hash_loop(hashtable_t *t, void (*func)(const char *, intptr_t));
|
|
||||||
void hash_free(hashtable_t *t);
|
|
||||||
intptr_t hash_findcase(hashtable_t const * const t, char const * const s);
|
|
||||||
intptr_t hash_find(hashtable_t const * const t, char const * const s);
|
|
||||||
void hash_add(hashtable_t *t, const char *s, intptr_t key, int32_t replace);
|
|
||||||
void hash_delete(hashtable_t *t, const char *s);
|
|
||||||
|
|
||||||
|
|
||||||
// Hash functions
|
|
||||||
// modified for raw binary keys and one big allocation, and maximum find() performance
|
|
||||||
|
|
||||||
typedef struct inthashitem_
|
|
||||||
{
|
|
||||||
intptr_t key;
|
|
||||||
intptr_t value;
|
|
||||||
struct inthashitem_ *collision; // use NULL to signify empty and pointer identity to signify end of linked list
|
|
||||||
} inthashitem_t;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
inthashitem_t * items;
|
|
||||||
uint32_t count;
|
|
||||||
} inthashtable_t;
|
|
||||||
|
|
||||||
void inthash_init(inthashtable_t *t);
|
|
||||||
void inthash_loop(inthashtable_t const *t, void (*func)(intptr_t, intptr_t));
|
|
||||||
void inthash_free(inthashtable_t *t);
|
|
||||||
intptr_t inthash_find(inthashtable_t const *t, intptr_t key);
|
|
||||||
void inthash_add(inthashtable_t *t, intptr_t key, intptr_t value, int32_t replace);
|
|
||||||
void inthash_delete(inthashtable_t *t, intptr_t key);
|
|
||||||
// keep the load factor below 0.75 and make sure the size is odd
|
|
||||||
// ideally we would find the next largest prime number
|
|
||||||
#define INTHASH_SIZE(size) ((size * 4u / 3u) | 1u)
|
|
||||||
|
|
||||||
#ifdef POLYMER
|
#ifdef POLYMER
|
||||||
# include "polymer.h"
|
# include "polymer.h"
|
||||||
|
|
65
polymer/eduke32/build/include/hash.h
Normal file
65
polymer/eduke32/build/include/hash.h
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef hash_h_
|
||||||
|
#define hash_h_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Hash functions
|
||||||
|
|
||||||
|
typedef struct hashitem_ // size is 12/24 bytes.
|
||||||
|
{
|
||||||
|
char *string;
|
||||||
|
intptr_t key;
|
||||||
|
struct hashitem_ *next;
|
||||||
|
} hashitem_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int32_t size;
|
||||||
|
hashitem_t **items;
|
||||||
|
} hashtable_t;
|
||||||
|
|
||||||
|
void hash_init(hashtable_t *t);
|
||||||
|
void hash_loop(hashtable_t *t, void(*func)(const char *, intptr_t));
|
||||||
|
void hash_free(hashtable_t *t);
|
||||||
|
intptr_t hash_findcase(hashtable_t const * const t, char const * const s);
|
||||||
|
intptr_t hash_find(hashtable_t const * const t, char const * const s);
|
||||||
|
void hash_add(hashtable_t *t, const char *s, intptr_t key, int32_t replace);
|
||||||
|
void hash_delete(hashtable_t *t, const char *s);
|
||||||
|
|
||||||
|
|
||||||
|
// Hash functions
|
||||||
|
// modified for raw binary keys and one big allocation, and maximum find() performance
|
||||||
|
|
||||||
|
typedef struct inthashitem_
|
||||||
|
{
|
||||||
|
intptr_t key;
|
||||||
|
intptr_t value;
|
||||||
|
struct inthashitem_ *collision; // use NULL to signify empty and pointer identity to signify end of linked list
|
||||||
|
} inthashitem_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
inthashitem_t * items;
|
||||||
|
uint32_t count;
|
||||||
|
} inthashtable_t;
|
||||||
|
|
||||||
|
void inthash_init(inthashtable_t *t);
|
||||||
|
void inthash_loop(inthashtable_t const *t, void(*func)(intptr_t, intptr_t));
|
||||||
|
void inthash_free(inthashtable_t *t);
|
||||||
|
intptr_t inthash_find(inthashtable_t const *t, intptr_t key);
|
||||||
|
void inthash_add(inthashtable_t *t, intptr_t key, intptr_t value, int32_t replace);
|
||||||
|
void inthash_delete(inthashtable_t *t, intptr_t key);
|
||||||
|
// keep the load factor below 0.75 and make sure the size is odd
|
||||||
|
// ideally we would find the next largest prime number
|
||||||
|
#define INTHASH_SIZE(size) ((size * 4u / 3u) | 1u)
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -18373,371 +18373,6 @@ void setpolymost2dview(void)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void hash_init(hashtable_t *t)
|
|
||||||
{
|
|
||||||
hash_free(t);
|
|
||||||
t->items=(hashitem_t **)Xcalloc(1, t->size * sizeof(hashitem_t));
|
|
||||||
}
|
|
||||||
|
|
||||||
void hash_loop(hashtable_t *t, void (*func)(const char *, intptr_t))
|
|
||||||
{
|
|
||||||
if (t->items == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (int32_t i=0; i < t->size; i++)
|
|
||||||
for (hashitem_t *item=t->items[i]; item != NULL; item = item->next)
|
|
||||||
func(item->string, item->key);
|
|
||||||
}
|
|
||||||
|
|
||||||
void hash_free(hashtable_t *t)
|
|
||||||
{
|
|
||||||
if (t->items == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
int remaining = t->size - 1;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
hashitem_t *cur = t->items[remaining];
|
|
||||||
|
|
||||||
int num = 0;
|
|
||||||
|
|
||||||
while (cur)
|
|
||||||
{
|
|
||||||
hashitem_t * const tmp = cur;
|
|
||||||
cur = cur->next;
|
|
||||||
|
|
||||||
Bfree(tmp->string);
|
|
||||||
Bfree(tmp);
|
|
||||||
num++;
|
|
||||||
}
|
|
||||||
} while (--remaining >= 0);
|
|
||||||
|
|
||||||
DO_FREE_AND_NULL(t->items);
|
|
||||||
}
|
|
||||||
|
|
||||||
// djb3 algorithm
|
|
||||||
static inline uint32_t hash_getcode(const char *s)
|
|
||||||
{
|
|
||||||
uint32_t h = 5381;
|
|
||||||
int32_t ch;
|
|
||||||
|
|
||||||
while ((ch = *s++) != '\0')
|
|
||||||
h = ((h << 5) + h) ^ ch;
|
|
||||||
|
|
||||||
return h;
|
|
||||||
}
|
|
||||||
|
|
||||||
void hash_add(hashtable_t *t, const char *s, intptr_t key, int32_t replace)
|
|
||||||
{
|
|
||||||
#ifdef DEBUGGINGAIDS
|
|
||||||
Bassert(t->items != NULL);
|
|
||||||
#else
|
|
||||||
if (EDUKE32_PREDICT_FALSE(t->items == NULL))
|
|
||||||
{
|
|
||||||
initprintf("hash_add(): table not initialized!\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
uint32_t code = hash_getcode(s) % t->size;
|
|
||||||
hashitem_t *cur = t->items[code];
|
|
||||||
|
|
||||||
if (!cur)
|
|
||||||
{
|
|
||||||
cur = (hashitem_t *)Xcalloc(1,sizeof(hashitem_t));
|
|
||||||
cur->string = Xstrdup(s);
|
|
||||||
cur->key = key;
|
|
||||||
cur->next = NULL;
|
|
||||||
t->items[code] = cur;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
hashitem_t *prev = NULL;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
if (Bstrcmp(s,cur->string) == 0)
|
|
||||||
{
|
|
||||||
if (replace) cur->key = key;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
prev = cur;
|
|
||||||
}
|
|
||||||
while ((cur = cur->next));
|
|
||||||
|
|
||||||
cur = (hashitem_t *)Xcalloc(1,sizeof(hashitem_t));
|
|
||||||
cur->string = Xstrdup(s);
|
|
||||||
cur->key = key;
|
|
||||||
cur->next = NULL;
|
|
||||||
prev->next = cur;
|
|
||||||
}
|
|
||||||
|
|
||||||
// delete at most once
|
|
||||||
void hash_delete(hashtable_t *t, const char *s)
|
|
||||||
{
|
|
||||||
#ifdef DEBUGGINGAIDS
|
|
||||||
Bassert(t->items != NULL);
|
|
||||||
#else
|
|
||||||
if (t->items == NULL)
|
|
||||||
{
|
|
||||||
initprintf("hash_delete(): table not initialized!\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
uint32_t code = hash_getcode(s) % t->size;
|
|
||||||
hashitem_t *cur = t->items[code];
|
|
||||||
|
|
||||||
if (!cur)
|
|
||||||
return;
|
|
||||||
|
|
||||||
hashitem_t *prev = NULL;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
if (Bstrcmp(s, cur->string) == 0)
|
|
||||||
{
|
|
||||||
Bfree(cur->string);
|
|
||||||
|
|
||||||
if (!prev)
|
|
||||||
t->items[code] = cur->next;
|
|
||||||
else
|
|
||||||
prev->next = cur->next;
|
|
||||||
|
|
||||||
Bfree(cur);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
prev = cur;
|
|
||||||
}
|
|
||||||
while ((cur = cur->next));
|
|
||||||
}
|
|
||||||
|
|
||||||
intptr_t hash_find(const hashtable_t * const t, char const * const s)
|
|
||||||
{
|
|
||||||
#ifdef DEBUGGINGAIDS
|
|
||||||
Bassert(t->items != NULL);
|
|
||||||
#else
|
|
||||||
if (t->items == NULL)
|
|
||||||
{
|
|
||||||
initprintf("hash_find(): table not initialized!\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
hashitem_t *cur = t->items[hash_getcode(s) % t->size];
|
|
||||||
|
|
||||||
if (!cur)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
do
|
|
||||||
if (Bstrcmp(s, cur->string) == 0)
|
|
||||||
return cur->key;
|
|
||||||
while ((cur = cur->next));
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
intptr_t hash_findcase(const hashtable_t * const t, char const * const s)
|
|
||||||
{
|
|
||||||
#ifdef DEBUGGINGAIDS
|
|
||||||
Bassert(t->items != NULL);
|
|
||||||
#else
|
|
||||||
if (t->items == NULL)
|
|
||||||
{
|
|
||||||
initprintf("hash_findcase(): table not initialized!\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
hashitem_t *cur = t->items[hash_getcode(s) % t->size];
|
|
||||||
|
|
||||||
if (!cur)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
do
|
|
||||||
if (Bstrcasecmp(s, cur->string) == 0)
|
|
||||||
return cur->key;
|
|
||||||
while ((cur = cur->next));
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void inthash_init(inthashtable_t *t)
|
|
||||||
{
|
|
||||||
if (EDUKE32_PREDICT_FALSE(!t->count))
|
|
||||||
{
|
|
||||||
initputs("inthash_add(): count is zero!\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
inthash_free(t);
|
|
||||||
|
|
||||||
t->items = (inthashitem_t *)Xcalloc(t->count, sizeof(inthashitem_t));
|
|
||||||
}
|
|
||||||
|
|
||||||
void inthash_loop(inthashtable_t const *t, void (*func)(intptr_t, intptr_t))
|
|
||||||
{
|
|
||||||
#ifdef DEBUGGINGAIDS
|
|
||||||
Bassert(t->items != NULL);
|
|
||||||
#else
|
|
||||||
if (EDUKE32_PREDICT_FALSE(t->items == NULL))
|
|
||||||
{
|
|
||||||
initputs("inthash_loop(): table not initialized!\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for (inthashitem_t const * item = t->items, * const items_end = t->items + t->count; item < items_end; ++item)
|
|
||||||
func(item->key, item->value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void inthash_free(inthashtable_t *t)
|
|
||||||
{
|
|
||||||
DO_FREE_AND_NULL(t->items);
|
|
||||||
}
|
|
||||||
|
|
||||||
// djb3 algorithm
|
|
||||||
static inline uint32_t inthash_getcode(intptr_t key)
|
|
||||||
{
|
|
||||||
uint32_t h = 5381;
|
|
||||||
|
|
||||||
for (uint8_t const * keybuf = (uint8_t *)&key, * const keybuf_end = keybuf + sizeof(intptr_t); keybuf < keybuf_end; ++keybuf)
|
|
||||||
h = ((h << 5) + h) ^ (uint32_t)*keybuf;
|
|
||||||
|
|
||||||
return h;
|
|
||||||
}
|
|
||||||
|
|
||||||
void inthash_add(inthashtable_t *t, intptr_t key, intptr_t value, int32_t replace)
|
|
||||||
{
|
|
||||||
#ifdef DEBUGGINGAIDS
|
|
||||||
Bassert(t->items != NULL);
|
|
||||||
#else
|
|
||||||
if (EDUKE32_PREDICT_FALSE(t->items == NULL))
|
|
||||||
{
|
|
||||||
initputs("inthash_add(): table not initialized!\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
inthashitem_t * seeker = t->items + inthash_getcode(key) % t->count;
|
|
||||||
|
|
||||||
if (seeker->collision == NULL)
|
|
||||||
{
|
|
||||||
seeker->key = key;
|
|
||||||
seeker->value = value;
|
|
||||||
seeker->collision = seeker;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (seeker->key == key)
|
|
||||||
{
|
|
||||||
if (replace)
|
|
||||||
seeker->value = value;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (seeker != seeker->collision)
|
|
||||||
{
|
|
||||||
seeker = seeker->collision;
|
|
||||||
|
|
||||||
if (seeker->key == key)
|
|
||||||
{
|
|
||||||
if (replace)
|
|
||||||
seeker->value = value;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inthashitem_t *tail = seeker;
|
|
||||||
|
|
||||||
do
|
|
||||||
tail = t->items + (tail - t->items + 1) % t->count;
|
|
||||||
while (tail->collision != NULL && tail != seeker);
|
|
||||||
|
|
||||||
if (EDUKE32_PREDICT_FALSE(tail == seeker))
|
|
||||||
{
|
|
||||||
initputs("inthash_add(): table full!\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
tail->key = key;
|
|
||||||
tail->value = value;
|
|
||||||
tail->collision = seeker->collision = tail;
|
|
||||||
}
|
|
||||||
|
|
||||||
// delete at most once
|
|
||||||
void inthash_delete(inthashtable_t *t, intptr_t key)
|
|
||||||
{
|
|
||||||
#ifdef DEBUGGINGAIDS
|
|
||||||
Bassert(t->items != NULL);
|
|
||||||
#else
|
|
||||||
if (EDUKE32_PREDICT_FALSE(t->items == NULL))
|
|
||||||
{
|
|
||||||
initputs("inthash_delete(): table not initialized!\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
inthashitem_t * seeker = t->items + inthash_getcode(key) % t->count;
|
|
||||||
|
|
||||||
if (seeker->collision == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (seeker->key == key)
|
|
||||||
{
|
|
||||||
seeker->collision = NULL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (seeker != seeker->collision)
|
|
||||||
{
|
|
||||||
inthashitem_t * const prev = seeker;
|
|
||||||
seeker = seeker->collision;
|
|
||||||
|
|
||||||
if (seeker->key == key)
|
|
||||||
{
|
|
||||||
prev->collision = seeker == seeker->collision ? prev : seeker->collision;
|
|
||||||
seeker->collision = NULL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
intptr_t inthash_find(inthashtable_t const *t, intptr_t key)
|
|
||||||
{
|
|
||||||
#ifdef DEBUGGINGAIDS
|
|
||||||
Bassert(t->items != NULL);
|
|
||||||
#else
|
|
||||||
if (EDUKE32_PREDICT_FALSE(t->items == NULL))
|
|
||||||
{
|
|
||||||
initputs("inthash_find(): table not initialized!\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
inthashitem_t const * seeker = t->items + inthash_getcode(key) % t->count;
|
|
||||||
|
|
||||||
if (seeker->collision == NULL)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (seeker->key == key)
|
|
||||||
return seeker->value;
|
|
||||||
|
|
||||||
while (seeker != seeker->collision)
|
|
||||||
{
|
|
||||||
seeker = seeker->collision;
|
|
||||||
|
|
||||||
if (seeker->key == key)
|
|
||||||
return seeker->value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* vim:ts=8:
|
* vim:ts=8:
|
||||||
*/
|
*/
|
||||||
|
|
367
polymer/eduke32/build/src/hash.c
Normal file
367
polymer/eduke32/build/src/hash.c
Normal file
|
@ -0,0 +1,367 @@
|
||||||
|
|
||||||
|
#include "compat.h"
|
||||||
|
#include "hash.h"
|
||||||
|
#include "baselayer.h"
|
||||||
|
|
||||||
|
void hash_init(hashtable_t *t)
|
||||||
|
{
|
||||||
|
hash_free(t);
|
||||||
|
t->items=(hashitem_t **) Xcalloc(1, t->size * sizeof(hashitem_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
void hash_loop(hashtable_t *t, void(*func)(const char *, intptr_t))
|
||||||
|
{
|
||||||
|
if (t->items == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (int32_t i=0; i < t->size; i++)
|
||||||
|
for (hashitem_t *item=t->items[i]; item != NULL; item = item->next)
|
||||||
|
func(item->string, item->key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hash_free(hashtable_t *t)
|
||||||
|
{
|
||||||
|
if (t->items == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int remaining = t->size - 1;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
hashitem_t *cur = t->items[remaining];
|
||||||
|
|
||||||
|
int num = 0;
|
||||||
|
|
||||||
|
while (cur)
|
||||||
|
{
|
||||||
|
hashitem_t * const tmp = cur;
|
||||||
|
cur = cur->next;
|
||||||
|
|
||||||
|
Bfree(tmp->string);
|
||||||
|
Bfree(tmp);
|
||||||
|
num++;
|
||||||
|
}
|
||||||
|
} while (--remaining >= 0);
|
||||||
|
|
||||||
|
DO_FREE_AND_NULL(t->items);
|
||||||
|
}
|
||||||
|
|
||||||
|
// djb3 algorithm
|
||||||
|
static inline uint32_t hash_getcode(const char *s)
|
||||||
|
{
|
||||||
|
uint32_t h = 5381;
|
||||||
|
int32_t ch;
|
||||||
|
|
||||||
|
while ((ch = *s++) != '\0')
|
||||||
|
h = ((h << 5) + h) ^ ch;
|
||||||
|
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hash_add(hashtable_t *t, const char *s, intptr_t key, int32_t replace)
|
||||||
|
{
|
||||||
|
#ifdef DEBUGGINGAIDS
|
||||||
|
Bassert(t->items != NULL);
|
||||||
|
#else
|
||||||
|
if (EDUKE32_PREDICT_FALSE(t->items == NULL))
|
||||||
|
{
|
||||||
|
initprintf("hash_add(): table not initialized!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint32_t code = hash_getcode(s) % t->size;
|
||||||
|
hashitem_t *cur = t->items[code];
|
||||||
|
|
||||||
|
if (!cur)
|
||||||
|
{
|
||||||
|
cur = (hashitem_t *) Xcalloc(1, sizeof(hashitem_t));
|
||||||
|
cur->string = Xstrdup(s);
|
||||||
|
cur->key = key;
|
||||||
|
cur->next = NULL;
|
||||||
|
t->items[code] = cur;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
hashitem_t *prev = NULL;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (Bstrcmp(s, cur->string) == 0)
|
||||||
|
{
|
||||||
|
if (replace) cur->key = key;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
prev = cur;
|
||||||
|
} while ((cur = cur->next));
|
||||||
|
|
||||||
|
cur = (hashitem_t *) Xcalloc(1, sizeof(hashitem_t));
|
||||||
|
cur->string = Xstrdup(s);
|
||||||
|
cur->key = key;
|
||||||
|
cur->next = NULL;
|
||||||
|
prev->next = cur;
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete at most once
|
||||||
|
void hash_delete(hashtable_t *t, const char *s)
|
||||||
|
{
|
||||||
|
#ifdef DEBUGGINGAIDS
|
||||||
|
Bassert(t->items != NULL);
|
||||||
|
#else
|
||||||
|
if (t->items == NULL)
|
||||||
|
{
|
||||||
|
initprintf("hash_delete(): table not initialized!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint32_t code = hash_getcode(s) % t->size;
|
||||||
|
hashitem_t *cur = t->items[code];
|
||||||
|
|
||||||
|
if (!cur)
|
||||||
|
return;
|
||||||
|
|
||||||
|
hashitem_t *prev = NULL;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (Bstrcmp(s, cur->string) == 0)
|
||||||
|
{
|
||||||
|
Bfree(cur->string);
|
||||||
|
|
||||||
|
if (!prev)
|
||||||
|
t->items[code] = cur->next;
|
||||||
|
else
|
||||||
|
prev->next = cur->next;
|
||||||
|
|
||||||
|
Bfree(cur);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
prev = cur;
|
||||||
|
} while ((cur = cur->next));
|
||||||
|
}
|
||||||
|
|
||||||
|
intptr_t hash_find(const hashtable_t * const t, char const * const s)
|
||||||
|
{
|
||||||
|
#ifdef DEBUGGINGAIDS
|
||||||
|
Bassert(t->items != NULL);
|
||||||
|
#else
|
||||||
|
if (t->items == NULL)
|
||||||
|
{
|
||||||
|
initprintf("hash_find(): table not initialized!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
hashitem_t *cur = t->items[hash_getcode(s) % t->size];
|
||||||
|
|
||||||
|
if (!cur)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
do
|
||||||
|
if (Bstrcmp(s, cur->string) == 0)
|
||||||
|
return cur->key;
|
||||||
|
while ((cur = cur->next));
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
intptr_t hash_findcase(const hashtable_t * const t, char const * const s)
|
||||||
|
{
|
||||||
|
#ifdef DEBUGGINGAIDS
|
||||||
|
Bassert(t->items != NULL);
|
||||||
|
#else
|
||||||
|
if (t->items == NULL)
|
||||||
|
{
|
||||||
|
initprintf("hash_findcase(): table not initialized!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
hashitem_t *cur = t->items[hash_getcode(s) % t->size];
|
||||||
|
|
||||||
|
if (!cur)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
do
|
||||||
|
if (Bstrcasecmp(s, cur->string) == 0)
|
||||||
|
return cur->key;
|
||||||
|
while ((cur = cur->next));
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void inthash_init(inthashtable_t *t)
|
||||||
|
{
|
||||||
|
if (EDUKE32_PREDICT_FALSE(!t->count))
|
||||||
|
{
|
||||||
|
initputs("inthash_add(): count is zero!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
inthash_free(t);
|
||||||
|
|
||||||
|
t->items = (inthashitem_t *) Xcalloc(t->count, sizeof(inthashitem_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
void inthash_loop(inthashtable_t const *t, void(*func)(intptr_t, intptr_t))
|
||||||
|
{
|
||||||
|
#ifdef DEBUGGINGAIDS
|
||||||
|
Bassert(t->items != NULL);
|
||||||
|
#else
|
||||||
|
if (EDUKE32_PREDICT_FALSE(t->items == NULL))
|
||||||
|
{
|
||||||
|
initputs("inthash_loop(): table not initialized!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (inthashitem_t const * item = t->items, *const items_end = t->items + t->count; item < items_end; ++item)
|
||||||
|
func(item->key, item->value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void inthash_free(inthashtable_t *t)
|
||||||
|
{
|
||||||
|
DO_FREE_AND_NULL(t->items);
|
||||||
|
}
|
||||||
|
|
||||||
|
// djb3 algorithm
|
||||||
|
static inline uint32_t inthash_getcode(intptr_t key)
|
||||||
|
{
|
||||||
|
uint32_t h = 5381;
|
||||||
|
|
||||||
|
for (uint8_t const * keybuf = (uint8_t *) &key, *const keybuf_end = keybuf + sizeof(intptr_t); keybuf < keybuf_end; ++keybuf)
|
||||||
|
h = ((h << 5) + h) ^ (uint32_t) *keybuf;
|
||||||
|
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
void inthash_add(inthashtable_t *t, intptr_t key, intptr_t value, int32_t replace)
|
||||||
|
{
|
||||||
|
#ifdef DEBUGGINGAIDS
|
||||||
|
Bassert(t->items != NULL);
|
||||||
|
#else
|
||||||
|
if (EDUKE32_PREDICT_FALSE(t->items == NULL))
|
||||||
|
{
|
||||||
|
initputs("inthash_add(): table not initialized!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
inthashitem_t * seeker = t->items + inthash_getcode(key) % t->count;
|
||||||
|
|
||||||
|
if (seeker->collision == NULL)
|
||||||
|
{
|
||||||
|
seeker->key = key;
|
||||||
|
seeker->value = value;
|
||||||
|
seeker->collision = seeker;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (seeker->key == key)
|
||||||
|
{
|
||||||
|
if (replace)
|
||||||
|
seeker->value = value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (seeker != seeker->collision)
|
||||||
|
{
|
||||||
|
seeker = seeker->collision;
|
||||||
|
|
||||||
|
if (seeker->key == key)
|
||||||
|
{
|
||||||
|
if (replace)
|
||||||
|
seeker->value = value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inthashitem_t *tail = seeker;
|
||||||
|
|
||||||
|
do
|
||||||
|
tail = t->items + (tail - t->items + 1) % t->count;
|
||||||
|
while (tail->collision != NULL && tail != seeker);
|
||||||
|
|
||||||
|
if (EDUKE32_PREDICT_FALSE(tail == seeker))
|
||||||
|
{
|
||||||
|
initputs("inthash_add(): table full!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tail->key = key;
|
||||||
|
tail->value = value;
|
||||||
|
tail->collision = seeker->collision = tail;
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete at most once
|
||||||
|
void inthash_delete(inthashtable_t *t, intptr_t key)
|
||||||
|
{
|
||||||
|
#ifdef DEBUGGINGAIDS
|
||||||
|
Bassert(t->items != NULL);
|
||||||
|
#else
|
||||||
|
if (EDUKE32_PREDICT_FALSE(t->items == NULL))
|
||||||
|
{
|
||||||
|
initputs("inthash_delete(): table not initialized!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
inthashitem_t * seeker = t->items + inthash_getcode(key) % t->count;
|
||||||
|
|
||||||
|
if (seeker->collision == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (seeker->key == key)
|
||||||
|
{
|
||||||
|
seeker->collision = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (seeker != seeker->collision)
|
||||||
|
{
|
||||||
|
inthashitem_t * const prev = seeker;
|
||||||
|
seeker = seeker->collision;
|
||||||
|
|
||||||
|
if (seeker->key == key)
|
||||||
|
{
|
||||||
|
prev->collision = seeker == seeker->collision ? prev : seeker->collision;
|
||||||
|
seeker->collision = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
intptr_t inthash_find(inthashtable_t const *t, intptr_t key)
|
||||||
|
{
|
||||||
|
#ifdef DEBUGGINGAIDS
|
||||||
|
Bassert(t->items != NULL);
|
||||||
|
#else
|
||||||
|
if (EDUKE32_PREDICT_FALSE(t->items == NULL))
|
||||||
|
{
|
||||||
|
initputs("inthash_find(): table not initialized!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
inthashitem_t const * seeker = t->items + inthash_getcode(key) % t->count;
|
||||||
|
|
||||||
|
if (seeker->collision == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (seeker->key == key)
|
||||||
|
return seeker->value;
|
||||||
|
|
||||||
|
while (seeker != seeker->collision)
|
||||||
|
{
|
||||||
|
seeker = seeker->collision;
|
||||||
|
|
||||||
|
if (seeker->key == key)
|
||||||
|
return seeker->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
|
@ -115,6 +115,7 @@
|
||||||
<ClInclude Include="build\include\glbuild.h" />
|
<ClInclude Include="build\include\glbuild.h" />
|
||||||
<ClInclude Include="build\include\glext.h" />
|
<ClInclude Include="build\include\glext.h" />
|
||||||
<ClInclude Include="build\include\gtkbits.h" />
|
<ClInclude Include="build\include\gtkbits.h" />
|
||||||
|
<ClInclude Include="build\include\hash.h" />
|
||||||
<ClInclude Include="build\include\hightile.h" />
|
<ClInclude Include="build\include\hightile.h" />
|
||||||
<ClInclude Include="build\include\jwzgles.h" />
|
<ClInclude Include="build\include\jwzgles.h" />
|
||||||
<ClInclude Include="build\include\jwzglesI.h" />
|
<ClInclude Include="build\include\jwzglesI.h" />
|
||||||
|
@ -265,6 +266,7 @@
|
||||||
<ClCompile Include="build\src\engine.c" />
|
<ClCompile Include="build\src\engine.c" />
|
||||||
<ClCompile Include="build\src\glbuild.c" />
|
<ClCompile Include="build\src\glbuild.c" />
|
||||||
<ClCompile Include="build\src\gtkbits.c" />
|
<ClCompile Include="build\src\gtkbits.c" />
|
||||||
|
<ClCompile Include="build\src\hash.c" />
|
||||||
<ClCompile Include="build\src\hightile.c" />
|
<ClCompile Include="build\src\hightile.c" />
|
||||||
<ClCompile Include="build\src\jwzgles.c" />
|
<ClCompile Include="build\src\jwzgles.c" />
|
||||||
<ClCompile Include="build\src\kplib.c" />
|
<ClCompile Include="build\src\kplib.c" />
|
||||||
|
|
|
@ -528,6 +528,9 @@
|
||||||
<ClInclude Include="source\inv.h">
|
<ClInclude Include="source\inv.h">
|
||||||
<Filter>eduke32\headers</Filter>
|
<Filter>eduke32\headers</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="build\include\hash.h">
|
||||||
|
<Filter>build\headers</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="build\src\a-c.c">
|
<ClCompile Include="build\src\a-c.c">
|
||||||
|
@ -926,6 +929,9 @@
|
||||||
<ClCompile Include="source\cmdline.c">
|
<ClCompile Include="source\cmdline.c">
|
||||||
<Filter>eduke32\source</Filter>
|
<Filter>eduke32\source</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="build\src\hash.c">
|
||||||
|
<Filter>build\source</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="Makefile.msvc">
|
<None Include="Makefile.msvc">
|
||||||
|
|
Loading…
Reference in a new issue