refactor(map): avoid duplicated khash_t types for values

This reduces the total number of khash_t instantiations from 22 to 8.

Make the khash internal functions take the size of values as a runtime
parameter. This is abstracted with typesafe Map containers which
are still specialized for both key, value type.

Introduce `Set(key)` type for when there is no value.

Refactor shada.c to use Map/Set instead of khash directly.
This requires `map_ref` operation to be more flexible.
Return pointers to both key and value, plus an indicator for new_item.
As a bonus, `map_key` is now redundant.

Instead of Map(cstr_t, FileMarks), use a pointer map as the FileMarks struct is
humongous.

Make `event_strings` actually work like an intern pool instead of wtf it
was doing before.
This commit is contained in:
bfredl
2023-05-14 18:45:56 +02:00
parent 33687f5e87
commit e2fdd53d8c
32 changed files with 408 additions and 462 deletions

View File

@@ -16,7 +16,6 @@
#include "klib/khash.h"
#include "nvim/gettext.h"
#include "nvim/map.h"
#include "nvim/map_defs.h"
#include "nvim/memory.h"
#define cstr_t_hash kh_str_hash_func
@@ -29,8 +28,6 @@
#define int_eq kh_int_hash_equal
#define handle_T_hash kh_int_hash_func
#define handle_T_eq kh_int_hash_equal
#define KittyKey_hash kh_int_hash_func
#define KittyKey_eq kh_int_hash_equal
#if defined(ARCH_64)
# define ptr_t_hash(key) uint64_t_hash((uint64_t)(key))
@@ -45,74 +42,69 @@
#define DEFAULT_INITIALIZER { 0 }
#define SSIZE_INITIALIZER { -1 }
#define KEY_IMPL(T) \
__KHASH_IMPL(T, , T, T##_hash, T##_eq) \
#define MAP_IMPL(T, U, ...) \
INITIALIZER_DECLARE(T, U, __VA_ARGS__); \
__KHASH_IMPL(T##_##U##_map, , T, U, 1, T##_hash, T##_eq) \
void map_##T##_##U##_destroy(Map(T, U) *map) \
{ \
kh_dealloc(T##_##U##_map, &map->table); \
} \
U map_##T##_##U##_get(Map(T, U) *map, T key) \
{ \
khiter_t k; \
if ((k = kh_get(T##_##U##_map, &map->table, key)) == kh_end(&map->table)) { \
if ((k = kh_get(T, &map->table, key)) == kh_end(&map->table)) { \
return INITIALIZER(T, U); \
} \
return kh_val(&map->table, k); \
} \
bool map_##T##_##U##_has(Map(T, U) *map, T key) \
{ \
return kh_get(T##_##U##_map, &map->table, key) != kh_end(&map->table); \
} \
T map_##T##_##U##_key(Map(T, U) *map, T key) \
{ \
khiter_t k; \
if ((k = kh_get(T##_##U##_map, &map->table, key)) == kh_end(&map->table)) { \
abort(); /* Caller must check map_has(). */ \
} \
return kh_key(&map->table, k); \
return kh_val(U, &map->table, k); \
} \
U map_##T##_##U##_put(Map(T, U) *map, T key, U value) \
{ \
STATIC_ASSERT(sizeof(U) <= KHASH_MAX_VAL_SIZE, "increase KHASH_MAX_VAL_SIZE"); \
int ret; \
U rv = INITIALIZER(T, U); \
khiter_t k = kh_put(T##_##U##_map, &map->table, key, &ret); \
khiter_t k = kh_put(T, &map->table, key, &ret, sizeof(U)); \
if (!ret) { \
rv = kh_val(&map->table, k); \
rv = kh_val(U, &map->table, k); \
} \
kh_val(&map->table, k) = value; \
kh_val(U, &map->table, k) = value; \
return rv; \
} \
U *map_##T##_##U##_ref(Map(T, U) *map, T key, bool put) \
U *map_##T##_##U##_ref(Map(T, U) *map, T key, T **key_alloc) \
{ \
khiter_t k = kh_get(T, &map->table, key); \
if (k == kh_end(&map->table)) { \
return NULL; \
} \
if (key_alloc) { \
*key_alloc = &kh_key(&map->table, k); \
} \
return &kh_val(U, &map->table, k); \
} \
U *map_##T##_##U##_put_ref(Map(T, U) *map, T key, T **key_alloc, bool *new_item) \
{ \
int ret; \
khiter_t k; \
if (put) { \
k = kh_put(T##_##U##_map, &map->table, key, &ret); \
if (ret) { \
kh_val(&map->table, k) = INITIALIZER(T, U); \
} \
} else { \
k = kh_get(T##_##U##_map, &map->table, key); \
if (k == kh_end(&map->table)) { \
return NULL; \
} \
khiter_t k = kh_put(T, &map->table, key, &ret, sizeof(U)); \
if (ret) { \
kh_val(U, &map->table, k) = INITIALIZER(T, U); \
} \
return &kh_val(&map->table, k); \
if (new_item) { \
*new_item = (bool)ret; \
} \
if (key_alloc) { \
*key_alloc = &kh_key(&map->table, k); \
} \
return &kh_val(U, &map->table, k); \
} \
U map_##T##_##U##_del(Map(T, U) *map, T key) \
U map_##T##_##U##_del(Map(T, U) *map, T key, T *key_alloc) \
{ \
U rv = INITIALIZER(T, U); \
khiter_t k; \
if ((k = kh_get(T##_##U##_map, &map->table, key)) != kh_end(&map->table)) { \
rv = kh_val(&map->table, k); \
kh_del(T##_##U##_map, &map->table, k); \
if ((k = kh_get(T, &map->table, key)) != kh_end(&map->table)) { \
rv = kh_val(U, &map->table, k); \
if (key_alloc) { \
*key_alloc = kh_key(&map->table, k); \
} \
kh_del(T, &map->table, k); \
} \
return rv; \
} \
void map_##T##_##U##_clear(Map(T, U) *map) \
{ \
kh_clear(T##_##U##_map, &map->table); \
}
static inline khint_t String_hash(String s)
@@ -162,7 +154,17 @@ static inline bool ColorKey_eq(ColorKey ae1, ColorKey ae2)
return memcmp(&ae1, &ae2, sizeof(ae1)) == 0;
}
KEY_IMPL(int)
KEY_IMPL(cstr_t)
KEY_IMPL(ptr_t)
KEY_IMPL(uint64_t)
KEY_IMPL(uint32_t)
KEY_IMPL(String)
KEY_IMPL(HlEntry)
KEY_IMPL(ColorKey)
MAP_IMPL(int, int, DEFAULT_INITIALIZER)
MAP_IMPL(int, ptr_t, DEFAULT_INITIALIZER)
MAP_IMPL(int, cstr_t, DEFAULT_INITIALIZER)
MAP_IMPL(cstr_t, ptr_t, DEFAULT_INITIALIZER)
MAP_IMPL(cstr_t, int, DEFAULT_INITIALIZER)
@@ -172,26 +174,19 @@ MAP_IMPL(uint64_t, ptr_t, DEFAULT_INITIALIZER)
MAP_IMPL(uint64_t, ssize_t, SSIZE_INITIALIZER)
MAP_IMPL(uint64_t, uint64_t, DEFAULT_INITIALIZER)
MAP_IMPL(uint32_t, uint32_t, DEFAULT_INITIALIZER)
MAP_IMPL(handle_T, ptr_t, DEFAULT_INITIALIZER)
MAP_IMPL(HlEntry, int, DEFAULT_INITIALIZER)
MAP_IMPL(String, handle_T, 0)
MAP_IMPL(String, int, DEFAULT_INITIALIZER)
MAP_IMPL(int, String, DEFAULT_INITIALIZER)
MAP_IMPL(ColorKey, ColorItem, COLOR_ITEM_INITIALIZER)
MAP_IMPL(KittyKey, cstr_t, DEFAULT_INITIALIZER)
/// Deletes a key:value pair from a string:pointer map, and frees the
/// storage of both key and value.
///
void pmap_del2(PMap(cstr_t) *map, const char *key)
{
if (pmap_has(cstr_t)(map, key)) {
void *k = (void *)pmap_key(cstr_t)(map, key);
void *v = pmap_get(cstr_t)(map, key);
pmap_del(cstr_t)(map, key);
xfree(k);
xfree(v);
}
cstr_t key_alloc = NULL;
ptr_t val = pmap_del(cstr_t)(map, key, &key_alloc);
xfree((void *)key_alloc);
xfree(val);
}