2016-06-21 00:32:53 +00:00
|
|
|
|
|
|
|
#include "compat.h"
|
|
|
|
#include "hash.h"
|
|
|
|
#include "baselayer.h"
|
|
|
|
|
|
|
|
void hash_init(hashtable_t *t)
|
|
|
|
{
|
|
|
|
hash_free(t);
|
2019-12-07 23:50:20 +00:00
|
|
|
t->items = (hashitem_t **) Xaligned_calloc(16, t->size, sizeof(hashitem_t));
|
2016-06-21 00:32:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void hash_loop(hashtable_t *t, void(*func)(const char *, intptr_t))
|
|
|
|
{
|
2019-12-07 23:50:20 +00:00
|
|
|
if (t->items == nullptr)
|
2016-06-21 00:32:53 +00:00
|
|
|
return;
|
|
|
|
|
2019-12-07 23:50:20 +00:00
|
|
|
for (native_t i=0; i < t->size; i++)
|
|
|
|
for (auto item = t->items[i]; item != nullptr; item = item->next)
|
2016-06-21 00:32:53 +00:00
|
|
|
func(item->string, item->key);
|
|
|
|
}
|
|
|
|
|
|
|
|
void hash_free(hashtable_t *t)
|
|
|
|
{
|
2019-12-07 23:50:20 +00:00
|
|
|
if (t->items == nullptr)
|
2016-06-21 00:32:53 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
int remaining = t->size - 1;
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
2019-12-07 23:50:20 +00:00
|
|
|
auto cur = t->items[remaining];
|
2016-06-21 00:32:53 +00:00
|
|
|
|
|
|
|
while (cur)
|
|
|
|
{
|
2019-12-07 23:50:20 +00:00
|
|
|
auto tmp = cur;
|
2016-06-21 00:32:53 +00:00
|
|
|
cur = cur->next;
|
|
|
|
|
2019-06-25 11:29:08 +00:00
|
|
|
Xfree(tmp->string);
|
2019-12-07 23:50:20 +00:00
|
|
|
Xaligned_free(tmp);
|
2016-06-21 00:32:53 +00:00
|
|
|
}
|
|
|
|
} while (--remaining >= 0);
|
|
|
|
|
2019-12-07 23:50:20 +00:00
|
|
|
ALIGNED_FREE_AND_NULL(t->items);
|
2016-06-21 00:32:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void hash_add(hashtable_t *t, const char *s, intptr_t key, int32_t replace)
|
|
|
|
{
|
|
|
|
#ifdef DEBUGGINGAIDS
|
2019-12-07 23:50:20 +00:00
|
|
|
Bassert(t->items != nullptr);
|
2016-06-21 00:32:53 +00:00
|
|
|
#endif
|
2019-12-07 23:50:20 +00:00
|
|
|
uint32_t const code = hash_getcode(s) % t->size;
|
|
|
|
auto cur = t->items[code];
|
2016-06-21 00:32:53 +00:00
|
|
|
|
|
|
|
if (!cur)
|
|
|
|
{
|
2019-12-07 23:50:20 +00:00
|
|
|
cur = (hashitem_t *) Xaligned_alloc(16, sizeof(hashitem_t));
|
2016-06-21 00:32:53 +00:00
|
|
|
cur->string = Xstrdup(s);
|
2019-12-07 23:50:20 +00:00
|
|
|
cur->key = key;
|
|
|
|
cur->next = nullptr;
|
|
|
|
|
2016-06-21 00:32:53 +00:00
|
|
|
t->items[code] = cur;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-12-07 23:50:20 +00:00
|
|
|
hashitem_t *prev = nullptr;
|
2016-06-21 00:32:53 +00:00
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
if (Bstrcmp(s, cur->string) == 0)
|
|
|
|
{
|
|
|
|
if (replace) cur->key = key;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
prev = cur;
|
|
|
|
} while ((cur = cur->next));
|
|
|
|
|
2019-12-07 23:50:20 +00:00
|
|
|
cur = (hashitem_t *) Xaligned_alloc(16, sizeof(hashitem_t));
|
2016-06-21 00:32:53 +00:00
|
|
|
cur->string = Xstrdup(s);
|
2019-12-07 23:50:20 +00:00
|
|
|
cur->key = key;
|
|
|
|
cur->next = nullptr;
|
|
|
|
|
2016-06-21 00:32:53 +00:00
|
|
|
prev->next = cur;
|
|
|
|
}
|
|
|
|
|
|
|
|
// delete at most once
|
|
|
|
void hash_delete(hashtable_t *t, const char *s)
|
|
|
|
{
|
|
|
|
#ifdef DEBUGGINGAIDS
|
2019-12-07 23:50:20 +00:00
|
|
|
Bassert(t->items != nullptr);
|
2016-06-21 00:32:53 +00:00
|
|
|
#endif
|
2019-12-07 23:50:20 +00:00
|
|
|
uint32_t const code = hash_getcode(s) % t->size;
|
|
|
|
auto cur = t->items[code];
|
2016-06-21 00:32:53 +00:00
|
|
|
|
|
|
|
if (!cur)
|
|
|
|
return;
|
|
|
|
|
2019-12-07 23:50:20 +00:00
|
|
|
hashitem_t *prev = nullptr;
|
2016-06-21 00:32:53 +00:00
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
if (Bstrcmp(s, cur->string) == 0)
|
|
|
|
{
|
2019-06-25 11:29:08 +00:00
|
|
|
Xfree(cur->string);
|
2016-06-21 00:32:53 +00:00
|
|
|
|
|
|
|
if (!prev)
|
|
|
|
t->items[code] = cur->next;
|
|
|
|
else
|
|
|
|
prev->next = cur->next;
|
|
|
|
|
2019-12-07 23:50:20 +00:00
|
|
|
Xaligned_free(cur);
|
2016-06-21 00:32:53 +00:00
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
prev = cur;
|
|
|
|
} while ((cur = cur->next));
|
|
|
|
}
|
|
|
|
|
|
|
|
intptr_t hash_find(const hashtable_t * const t, char const * const s)
|
|
|
|
{
|
|
|
|
#ifdef DEBUGGINGAIDS
|
2019-12-07 23:50:20 +00:00
|
|
|
Bassert(t->items != nullptr);
|
2016-06-21 00:32:53 +00:00
|
|
|
#endif
|
2019-12-07 23:50:20 +00:00
|
|
|
auto cur = t->items[hash_getcode(s) % t->size];
|
2016-06-21 00:32:53 +00:00
|
|
|
|
|
|
|
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
|
2019-12-07 23:50:20 +00:00
|
|
|
Bassert(t->items != nullptr);
|
2016-06-21 00:32:53 +00:00
|
|
|
#endif
|
2019-12-07 23:50:20 +00:00
|
|
|
auto cur = t->items[hash_getcode(s) % t->size];
|
2016-06-21 00:32:53 +00:00
|
|
|
|
|
|
|
if (!cur)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
do
|
|
|
|
if (Bstrcasecmp(s, cur->string) == 0)
|
|
|
|
return cur->key;
|
|
|
|
while ((cur = cur->next));
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-12-07 23:50:20 +00:00
|
|
|
void inthash_free(inthashtable_t *t) { ALIGNED_FREE_AND_NULL(t->items); }
|
|
|
|
|
2016-06-21 00:32:53 +00:00
|
|
|
void inthash_init(inthashtable_t *t)
|
|
|
|
{
|
|
|
|
inthash_free(t);
|
2019-12-07 23:50:20 +00:00
|
|
|
t->items = (inthashitem_t *) Xaligned_calloc(16, t->count, sizeof(inthashitem_t));
|
2016-06-21 00:32:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void inthash_loop(inthashtable_t const *t, void(*func)(intptr_t, intptr_t))
|
|
|
|
{
|
2019-12-07 23:50:20 +00:00
|
|
|
if (t->items == nullptr)
|
2016-06-21 00:32:53 +00:00
|
|
|
return;
|
|
|
|
|
2019-12-07 23:50:20 +00:00
|
|
|
for (auto *item = t->items, *const items_end = t->items + t->count; item < items_end; ++item)
|
2016-06-21 00:32:53 +00:00
|
|
|
func(item->key, item->value);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void inthash_add(inthashtable_t *t, intptr_t key, intptr_t value, int32_t replace)
|
|
|
|
{
|
|
|
|
#ifdef DEBUGGINGAIDS
|
2019-12-07 23:50:20 +00:00
|
|
|
Bassert(t->items != nullptr);
|
2016-06-21 00:32:53 +00:00
|
|
|
#endif
|
2019-12-07 23:50:20 +00:00
|
|
|
auto seeker = t->items + inthash_getcode(key) % t->count;
|
2016-06-21 00:32:53 +00:00
|
|
|
|
2019-12-07 23:50:20 +00:00
|
|
|
if (seeker->collision == nullptr)
|
2016-06-21 00:32:53 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-07 23:50:20 +00:00
|
|
|
auto tail = seeker;
|
2016-06-21 00:32:53 +00:00
|
|
|
|
|
|
|
do
|
|
|
|
tail = t->items + (tail - t->items + 1) % t->count;
|
2019-12-07 23:50:20 +00:00
|
|
|
while (tail->collision != nullptr && tail != seeker);
|
2016-06-21 00:32:53 +00:00
|
|
|
|
|
|
|
if (EDUKE32_PREDICT_FALSE(tail == seeker))
|
2019-12-08 07:51:54 +00:00
|
|
|
I_Error("inthash_add(): table full!\n");
|
2016-06-21 00:32:53 +00:00
|
|
|
|
|
|
|
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
|
2019-12-07 23:50:20 +00:00
|
|
|
Bassert(t->items != nullptr);
|
2016-06-21 00:32:53 +00:00
|
|
|
#endif
|
2019-12-07 23:50:20 +00:00
|
|
|
auto seeker = t->items + inthash_getcode(key) % t->count;
|
2016-06-21 00:32:53 +00:00
|
|
|
|
2019-12-07 23:50:20 +00:00
|
|
|
if (seeker->collision == nullptr || seeker->key == key)
|
2016-06-21 00:32:53 +00:00
|
|
|
{
|
2019-12-07 23:50:20 +00:00
|
|
|
seeker->collision = nullptr;
|
2016-06-21 00:32:53 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (seeker != seeker->collision)
|
|
|
|
{
|
2019-12-07 23:50:20 +00:00
|
|
|
auto prev = seeker;
|
2016-06-21 00:32:53 +00:00
|
|
|
seeker = seeker->collision;
|
|
|
|
|
|
|
|
if (seeker->key == key)
|
|
|
|
{
|
|
|
|
prev->collision = seeker == seeker->collision ? prev : seeker->collision;
|
2019-12-07 23:50:20 +00:00
|
|
|
seeker->collision = nullptr;
|
2016-06-21 00:32:53 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
intptr_t inthash_find(inthashtable_t const *t, intptr_t key)
|
|
|
|
{
|
|
|
|
#ifdef DEBUGGINGAIDS
|
2019-12-07 23:50:20 +00:00
|
|
|
Bassert(t->items != nullptr);
|
2016-06-21 00:32:53 +00:00
|
|
|
#endif
|
2019-12-07 23:50:20 +00:00
|
|
|
auto seeker = t->items + inthash_getcode(key) % t->count;
|
2016-06-21 00:32:53 +00:00
|
|
|
|
2019-12-07 23:50:20 +00:00
|
|
|
if (seeker->collision == nullptr)
|
2016-06-21 00:32:53 +00:00
|
|
|
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;
|
|
|
|
}
|