aboutsummaryrefslogtreecommitdiff
path: root/map
diff options
context:
space:
mode:
authorJulian Hurst <julian.hurst@digdash.com>2025-01-15 18:08:44 +0100
committerJulian Hurst <julian.hurst@digdash.com>2025-01-15 18:31:21 +0100
commit0490236116c4fcf80563251e4175dbcc78e05787 (patch)
tree4c702a8c0de8840984c3dd969da4827e3135476b /map
parent4129e3dba2cc3953af6b97fc1c99a1516b9214cd (diff)
downloadhatask-0490236116c4fcf80563251e4175dbcc78e05787.tar.gz
Add get command to get misc properties from tasks
Unknown entries in the task metadata are now added to a misc map and can be gotten via the get command.
Diffstat (limited to 'map')
-rw-r--r--map/map.ha117
1 files changed, 117 insertions, 0 deletions
diff --git a/map/map.ha b/map/map.ha
new file mode 100644
index 0000000..e266032
--- /dev/null
+++ b/map/map.ha
@@ -0,0 +1,117 @@
+use hash::fnv;
+use strings;
+
+def BUCKETSZ: size = 32z;
+
+export type map = struct {
+ buckets: [BUCKETSZ][]entry,
+};
+
+export type entry = struct {
+ hash: size,
+ key: str,
+ val: str,
+};
+
+export type iterator = struct {
+ i: size,
+ j: size,
+ m: map,
+};
+
+export fn newmap() map = {
+ return map {
+ ...
+ };
+};
+
+export fn newiterator(m: map) iterator = {
+ return iterator {
+ i = 0z,
+ j = 0z,
+ m = m,
+ };
+};
+
+export fn put(m: *map, k: str, v: str) void = {
+ const s = fnv::string(k);
+ const bucket = &m.buckets[s%len(m.buckets)];
+ for (let e &.. bucket) {
+ if (e.hash == s) {
+ e.val = v;
+ return;
+ };
+ };
+ append(bucket, entry {
+ hash = s,
+ key = strings::dup(k),
+ val = strings::dup(v),
+ })!;
+};
+
+export fn get(m: map, k: str) (str | void) = {
+ const s = fnv::string(k);
+ const bucket = m.buckets[s%len(m.buckets)];
+ for (let e .. bucket) {
+ if (e.hash == s) {
+ return e.val;
+ };
+ };
+ return;
+};
+
+export fn next(it: *iterator) (entry | done) = {
+ if (len(it.m.buckets) == 0 || len(it.m.buckets) <= it.i) {
+ return done;
+ };
+ for (true) {
+ if (len(it.m.buckets) <= it.i) {
+ return done;
+ };
+ const b = it.m.buckets[it.i];
+ if (len(b) == 0 || len(b) <= it.j) {
+ it.i += 1;
+ it.j = 0;
+ } else {
+ const e = b[it.j];
+ it.j += 1;
+ return e;
+ };
+ };
+};
+
+export fn finishmap(m: *map) void = {
+ for (let e &.. m.buckets) {
+ finishentries(e);
+ };
+};
+
+fn finishentries(e: *[]entry) void = {
+ for (let i = 0z; i < len(e); i += 1) {
+ free(e[i].key);
+ free(e[i].val);
+ };
+};
+
+@test fn testmap() void = {
+ const m = newmap();
+ defer finishmap(&m);
+ put(&m, "test", "value");
+ const v = get(m, "test");
+ assert(v is str);
+ assert(v as str == "value");
+};
+
+@test fn testit() void = {
+ const m = newmap();
+ defer finishmap(&m);
+ put(&m, "test", "value");
+ let it = newiterator(m);
+ let count = 0;
+ for (let e => next(&it)) {
+ count += 1;
+ assert(e.key == "test");
+ assert(e.val == "value");
+ };
+ assert(count == 1);
+};