diff --git a/polymer/eduke32/Makefile b/polymer/eduke32/Makefile
index d68ef1e95..3b43146b3 100644
--- a/polymer/eduke32/Makefile
+++ b/polymer/eduke32/Makefile
@@ -43,6 +43,7 @@ ENGINE_OBJS = \
crc32 \
defs \
engine \
+ hash \
polymost \
texcache \
dxtfilter \
diff --git a/polymer/eduke32/Makefile.msvc b/polymer/eduke32/Makefile.msvc
index db415d23c..bb22d869d 100644
--- a/polymer/eduke32/Makefile.msvc
+++ b/polymer/eduke32/Makefile.msvc
@@ -137,6 +137,7 @@ ENGINE_OBJS= \
$(ENGINE_OBJ)\defs.$o \
$(ENGINE_OBJ)\colmatch.$o \
$(ENGINE_OBJ)\engine.$o \
+ $(ENGINE_OBJ)\hash.$o \
$(ENGINE_OBJ)\glbuild.$o \
$(ENGINE_OBJ)\texcache.$o \
$(ENGINE_OBJ)\kplib.$o \
diff --git a/polymer/eduke32/build/Makefile.deps b/polymer/eduke32/build/Makefile.deps
index b415837ca..0122bcc00 100644
--- a/polymer/eduke32/build/Makefile.deps
+++ b/polymer/eduke32/build/Makefile.deps
@@ -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)/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)/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)/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
diff --git a/polymer/eduke32/build/include/build.h b/polymer/eduke32/build/include/build.h
index c3ca2edbd..0c144835d 100644
--- a/polymer/eduke32/build/include/build.h
+++ b/polymer/eduke32/build/include/build.h
@@ -1405,56 +1405,7 @@ int32_t loaddefinitionsfile(const char *fn);
// -2, board is dodgy
int32_t loadoldboard(const char *filename, char fromwhere, vec3_t *dapos, int16_t *daang, int16_t *dacursectnum);
-
-// 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)
+#include "hash.h"
#ifdef POLYMER
# include "polymer.h"
diff --git a/polymer/eduke32/build/include/hash.h b/polymer/eduke32/build/include/hash.h
new file mode 100644
index 000000000..9e37df63f
--- /dev/null
+++ b/polymer/eduke32/build/include/hash.h
@@ -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
\ No newline at end of file
diff --git a/polymer/eduke32/build/src/engine.c b/polymer/eduke32/build/src/engine.c
index 809555f78..0573bbf6c 100644
--- a/polymer/eduke32/build/src/engine.c
+++ b/polymer/eduke32/build/src/engine.c
@@ -18373,371 +18373,6 @@ void setpolymost2dview(void)
#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:
*/
diff --git a/polymer/eduke32/build/src/hash.c b/polymer/eduke32/build/src/hash.c
new file mode 100644
index 000000000..4ad39b588
--- /dev/null
+++ b/polymer/eduke32/build/src/hash.c
@@ -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;
+}
diff --git a/polymer/eduke32/eduke32.vcxproj b/polymer/eduke32/eduke32.vcxproj
index 7e7e1242c..ed867aac2 100644
--- a/polymer/eduke32/eduke32.vcxproj
+++ b/polymer/eduke32/eduke32.vcxproj
@@ -115,6 +115,7 @@
+
@@ -265,6 +266,7 @@
+
diff --git a/polymer/eduke32/eduke32.vcxproj.filters b/polymer/eduke32/eduke32.vcxproj.filters
index 61cd119a9..e60f51248 100644
--- a/polymer/eduke32/eduke32.vcxproj.filters
+++ b/polymer/eduke32/eduke32.vcxproj.filters
@@ -528,6 +528,9 @@
eduke32\headers
+
+ build\headers
+
@@ -926,6 +929,9 @@
eduke32\source
+
+ build\source
+