From b683e779ef83b88f6ffc503a1d1a4f3ec25a5cfa Mon Sep 17 00:00:00 2001 From: "Luke T. Shumaker" Date: Fri, 4 Oct 2024 16:43:55 -0600 Subject: wip srv --- lib9p/map.h | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 lib9p/map.h (limited to 'lib9p/map.h') 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 + * 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 -- cgit v1.2.3-2-g168b