diff options
Diffstat (limited to 'lib9p/map.h')
-rw-r--r-- | lib9p/map.h | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/lib9p/map.h b/lib9p/map.h new file mode 100644 index 0000000..a8d26b5 --- /dev/null +++ b/lib9p/map.h @@ -0,0 +1,102 @@ +/* lib9p/map.h - A really dumb map/dict data structur + * + * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-Licence-Identifier: AGPL-3.0-or-later + */ + +#include "internal.h" + +/** + * `#define` `NAME`, `KEY_T`, `VAL_T`, and `CAP`; then `#include + * "map.h". + */ + +#ifndef NAME +# error NAME must be defined +#endif +#ifndef KEY_T +# error KEY_T must be defined +#endif +#ifndef VAL_T +# error VAL_T must be defined +#endif +#ifndef CAP +# error CAP must be defined +#endif + +#ifndef MAP_KEY +#define MAP_KV(TNAME) CAT3(_,TNAME,_kv) +#define MAP_METHOD(TNAME, MNAME) CAT3(TNAME,_,MNAME) +#endif + +/* This implementation is just an array that we brute-force search + * over for a slot. I don't want to use the heap, which means + * statically-sized maps, and I'm probably going to choose a low + * static size, so this is fine. */ + +struct MAP_KV(NAME) { + bool set; + KEY_T key; + VAL_T val; +}; + +struct NAME { + size_t len; + struct MAP_KV(NAME) items[CAP]; +}; + +/** + * Load an item from the map; return a pointer to the in-map value, or + * NULL if the item is not in the map. + */ +static VAL_T *MAP_METHOD(NAME,load)(struct NAME *m, KEY_T k) { + if (!m->len) + return NULL; + for (size_t i = 0; i < ARRAY_LEN(m->items); i++) + if (m->items[i].set && m->items[i].key == k) + return &(m->items[i].val); + return NULL; +} + +/** + * Store an item into the map, perhaps replacing an existing value. + * Return a pointer to the in-map value, or NULL if the map is full. + */ +static VAL_T *MAP_METHOD(NAME,store)(struct NAME *m, KEY_T k, VAL_T v) { + VAL_T *old = MAP_METHOD(NAME,load)(m, k); + if (old) { + *old = v; + return old; + } + if (m->len == ARRAY_LEN(m->items)) + return NULL; + for (size_t i = 0; i < ARRAY_LEN(m->items); i++) + if (!m->items[i].set) { + m->items[i].set = true; + m->items[i].key = k; + m->items[i].val = v; + return &(m->items[i].val); + } + assert(false); +} + +/** + * Delete an item from the map. Returns true if an item was deleted, + * false if no such item was in the map. + */ +static bool MAP_METHOD(NAME,del)(struct NAME *m, KEY_T k) { + if (!m->len) + return NULL; + for (size_t i = 0; i < ARRAY_LEN(m->items); i++) + if (m->items[i].set && m->items[i].key == k) { + m->items[i].set = false; + m->len--; + return true; + } + return false; +} + +#undef NAME +#undef KEY_T +#undef VAL_T +#undef CAP |