summaryrefslogtreecommitdiff
path: root/lib9p/map.h
diff options
context:
space:
mode:
Diffstat (limited to 'lib9p/map.h')
-rw-r--r--lib9p/map.h102
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