diff --git a/CMakeLists.txt b/CMakeLists.txt index 5a2e526e..07764eb5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -294,7 +294,6 @@ endforeach() set(LOVR_SRC src/core/fs.c - src/core/map.c src/core/zip.c src/api/api.c src/api/l_lovr.c diff --git a/Tupfile.lua b/Tupfile.lua index 0d65c97e..cbb17d93 100644 --- a/Tupfile.lua +++ b/Tupfile.lua @@ -351,7 +351,6 @@ src = { 'src/util.c', 'src/core/os_' .. target .. '.c', 'src/core/fs.c', - 'src/core/map.c', 'src/core/zip.c', 'src/api/api.c', 'src/api/l_lovr.c' diff --git a/src/api/l_data_modelData.c b/src/api/l_data_modelData.c index de888d55..fe52585b 100644 --- a/src/api/l_data_modelData.c +++ b/src/api/l_data_modelData.c @@ -1,7 +1,6 @@ #include "api.h" #include "data/modelData.h" #include "core/maf.h" -#include "core/map.h" #include "shaders.h" #include #include diff --git a/src/core/map.c b/src/core/map.c deleted file mode 100644 index 02a0e7ef..00000000 --- a/src/core/map.c +++ /dev/null @@ -1,100 +0,0 @@ -#include "map.h" -#include "util.h" -#include -#include - -static uint32_t prevpo2(uint32_t x) { - x |= x >> 1; - x |= x >> 2; - x |= x >> 4; - x |= x >> 8; - x |= x >> 16; - return x - (x >> 1); -} - -static void map_rehash(map_t* map) { - map_t old = *map; - map->size <<= 1; - map->hashes = malloc(2 * map->size * sizeof(uint64_t)); - map->values = map->hashes + map->size; - lovrAssert(map->size && map->hashes, "Out of memory"); - memset(map->hashes, 0xff, 2 * map->size * sizeof(uint64_t)); - - if (old.hashes) { - uint64_t mask = map->size - 1; - for (uint32_t i = 0; i < old.size; i++) { - if (old.hashes[i] != MAP_NIL) { - uint64_t index = old.hashes[i] & mask; - while (map->hashes[index] != MAP_NIL) { - index = (index + 1) & mask; - } - map->hashes[index] = old.hashes[i]; - map->values[index] = old.values[i]; - } - } - free(old.hashes); - } -} - -static inline uint64_t map_find(map_t* map, uint64_t hash) { - uint64_t mask = map->size - 1; - uint64_t h = hash & mask; - - while (map->hashes[h] != hash && map->hashes[h] != MAP_NIL) { - h = (h + 1) & mask; - } - - return h; -} - -void map_init(map_t* map, uint32_t n) { - map->size = prevpo2(n) + !n; - map->used = 0; - map->hashes = NULL; - map_rehash(map); -} - -void map_free(map_t* map) { - free(map->hashes); -} - -uint64_t map_get(map_t* map, uint64_t hash) { - return map->values[map_find(map, hash)]; -} - -void map_set(map_t* map, uint64_t hash, uint64_t value) { - if (map->used >= (map->size >> 1) + (map->size >> 2)) { - map_rehash(map); - } - - uint64_t h = map_find(map, hash); - map->used += map->hashes[h] == MAP_NIL; - map->hashes[h] = hash; - map->values[h] = value; -} - -void map_remove(map_t* map, uint64_t hash) { - uint64_t h = map_find(map, hash); - - if (map->hashes[h] == MAP_NIL) { - return; - } - - uint64_t mask = map->size - 1; - uint64_t i = h; - - do { - i = (i + 1) & mask; - uint64_t x = map->hashes[i] & mask; - // Removing a key from an open-addressed hash table is complicated - if ((i > h && (x <= h || x > i)) || (i < h && (x <= h && x > i))) { - map->hashes[h] = map->hashes[i]; - map->values[h] = map->values[i]; - h = i; - } - } while (map->hashes[i] != MAP_NIL); - - map->hashes[i] = MAP_NIL; - map->values[i] = MAP_NIL; - map->used--; -} diff --git a/src/core/map.h b/src/core/map.h deleted file mode 100644 index 3e604a93..00000000 --- a/src/core/map.h +++ /dev/null @@ -1,18 +0,0 @@ -#include - -#pragma once - -#define MAP_NIL UINT64_MAX - -typedef struct { - uint32_t size; - uint32_t used; - uint64_t* hashes; - uint64_t* values; -} map_t; - -void map_init(map_t* map, uint32_t n); -void map_free(map_t* map); -uint64_t map_get(map_t* map, uint64_t hash); -void map_set(map_t* map, uint64_t hash, uint64_t value); -void map_remove(map_t* map, uint64_t hash); diff --git a/src/modules/data/modelData.h b/src/modules/data/modelData.h index 71a3a7fb..7589b957 100644 --- a/src/modules/data/modelData.h +++ b/src/modules/data/modelData.h @@ -1,4 +1,3 @@ -#include "core/map.h" #include "util.h" #include #include diff --git a/src/modules/data/modelData_obj.c b/src/modules/data/modelData_obj.c index 75abd1a4..1a755716 100644 --- a/src/modules/data/modelData_obj.c +++ b/src/modules/data/modelData_obj.c @@ -2,7 +2,6 @@ #include "data/blob.h" #include "data/image.h" #include "core/maf.h" -#include "core/map.h" #include "util.h" #include #include diff --git a/src/modules/filesystem/filesystem.c b/src/modules/filesystem/filesystem.c index 7b95bb8a..37e874a9 100644 --- a/src/modules/filesystem/filesystem.c +++ b/src/modules/filesystem/filesystem.c @@ -1,6 +1,5 @@ #include "filesystem/filesystem.h" #include "core/fs.h" -#include "core/map.h" #include "core/os.h" #include "util.h" #include "core/zip.h" diff --git a/src/modules/graphics/font.c b/src/modules/graphics/font.c index 7cf7c873..af8a8387 100644 --- a/src/modules/graphics/font.c +++ b/src/modules/graphics/font.c @@ -3,7 +3,6 @@ #include "graphics/texture.h" #include "data/rasterizer.h" #include "data/image.h" -#include "core/map.h" #include #include diff --git a/src/modules/thread/thread.c b/src/modules/thread/thread.c index 1d2607cb..0a8f0c8f 100644 --- a/src/modules/thread/thread.c +++ b/src/modules/thread/thread.c @@ -1,6 +1,5 @@ #include "thread/thread.h" #include "thread/channel.h" -#include "core/map.h" #include "util.h" #include #include diff --git a/src/util.c b/src/util.c index 611de3fc..61a17e61 100644 --- a/src/util.c +++ b/src/util.c @@ -1,4 +1,5 @@ #include "util.h" +#include #include #include @@ -63,6 +64,103 @@ void* arr_alloc(void* data, size_t size) { } } +// Hashmap +static uint32_t prevpo2(uint32_t x) { + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + return x - (x >> 1); +} + +static void map_rehash(map_t* map) { + map_t old = *map; + map->size <<= 1; + map->hashes = malloc(2 * map->size * sizeof(uint64_t)); + map->values = map->hashes + map->size; + lovrAssert(map->size && map->hashes, "Out of memory"); + memset(map->hashes, 0xff, 2 * map->size * sizeof(uint64_t)); + + if (old.hashes) { + uint64_t mask = map->size - 1; + for (uint32_t i = 0; i < old.size; i++) { + if (old.hashes[i] != MAP_NIL) { + uint64_t index = old.hashes[i] & mask; + while (map->hashes[index] != MAP_NIL) { + index = (index + 1) & mask; + } + map->hashes[index] = old.hashes[i]; + map->values[index] = old.values[i]; + } + } + free(old.hashes); + } +} + +static inline uint64_t map_find(map_t* map, uint64_t hash) { + uint64_t mask = map->size - 1; + uint64_t h = hash & mask; + + while (map->hashes[h] != hash && map->hashes[h] != MAP_NIL) { + h = (h + 1) & mask; + } + + return h; +} + +void map_init(map_t* map, uint32_t n) { + map->size = prevpo2(n) + !n; + map->used = 0; + map->hashes = NULL; + map_rehash(map); +} + +void map_free(map_t* map) { + free(map->hashes); +} + +uint64_t map_get(map_t* map, uint64_t hash) { + return map->values[map_find(map, hash)]; +} + +void map_set(map_t* map, uint64_t hash, uint64_t value) { + if (map->used >= (map->size >> 1) + (map->size >> 2)) { + map_rehash(map); + } + + uint64_t h = map_find(map, hash); + map->used += map->hashes[h] == MAP_NIL; + map->hashes[h] = hash; + map->values[h] = value; +} + +void map_remove(map_t* map, uint64_t hash) { + uint64_t h = map_find(map, hash); + + if (map->hashes[h] == MAP_NIL) { + return; + } + + uint64_t mask = map->size - 1; + uint64_t i = h; + + do { + i = (i + 1) & mask; + uint64_t x = map->hashes[i] & mask; + // Removing a key from an open-addressed hash table is complicated + if ((i > h && (x <= h || x > i)) || (i < h && (x <= h && x > i))) { + map->hashes[h] = map->hashes[i]; + map->values[h] = map->values[i]; + h = i; + } + } while (map->hashes[i] != MAP_NIL); + + map->hashes[i] = MAP_NIL; + map->values[i] = MAP_NIL; + map->used--; +} + // UTF-8 // https://github.com/starwing/luautf8 size_t utf8_decode(const char *s, const char *e, unsigned *pch) { diff --git a/src/util.h b/src/util.h index aacc726a..3a6ce7c5 100644 --- a/src/util.h +++ b/src/util.h @@ -83,6 +83,22 @@ static inline void _arr_reserve(void** data, size_t n, size_t* capacity, size_t lovrAssert(*data, "Out of memory"); } +// Hashmap +typedef struct { + uint64_t* hashes; + uint64_t* values; + uint32_t size; + uint32_t used; +} map_t; + +#define MAP_NIL UINT64_MAX + +void map_init(map_t* map, uint32_t n); +void map_free(map_t* map); +uint64_t map_get(map_t* map, uint64_t hash); +void map_set(map_t* map, uint64_t hash, uint64_t value); +void map_remove(map_t* map, uint64_t hash); + // UTF-8 size_t utf8_decode(const char *s, const char *e, unsigned *pch); void utf8_encode(uint32_t codepoint, char str[4]);