summaryrefslogtreecommitdiff
path: root/idreg.ha
diff options
context:
space:
mode:
Diffstat (limited to 'idreg.ha')
-rw-r--r--idreg.ha72
1 files changed, 72 insertions, 0 deletions
diff --git a/idreg.ha b/idreg.ha
new file mode 100644
index 0000000..1cdd74a
--- /dev/null
+++ b/idreg.ha
@@ -0,0 +1,72 @@
+use hash::fnv;
+use htab;
+use strings;
+use types;
+
+type IdRegistry = struct {
+ idtoname: []str,
+ nametoid: htab::table, // u32
+};
+
+def HTAB_EMPTY = htab::table {
+ // XXX: harec limitation...
+ table = &htab::empty,
+ nslots = 1,
+ ...
+};
+
+def IDREG_EMPTY = IdRegistry {
+ nametoid = HTAB_EMPTY,
+ ...
+};
+
+fn newidreg() IdRegistry =
+ IdRegistry {
+ idtoname = [],
+ nametoid = htab::new(0, size(u32)),
+ };
+
+fn idreg_count(reg: *IdRegistry) u32 =
+ len(reg.idtoname): u32;
+
+fn idreg_exists(reg: *IdRegistry, id: u32) bool =
+ id < len(reg.idtoname);
+
+fn idreg_getname(reg: *IdRegistry, id: u32) str =
+ reg.idtoname[id];
+
+fn idreg_eqfunc(ctx: *opaque, entry: *opaque) bool = {
+ const ctx = ctx: *(*IdRegistry, str);
+ return ctx.1 == ctx.0.idtoname[*(entry: *u32)];
+};
+
+fn idreg_lookup(reg: *IdRegistry, name: str) (u32 | void) = {
+ const hash = fnv::string64(name);
+ match (htab::get(&reg.nametoid, hash,
+ &idreg_eqfunc, &(reg, name), size(u32))) {
+ case let entry: *opaque =>
+ return *(entry: *u32);
+ case null => void;
+ };
+};
+
+fn idreg_register(reg: *IdRegistry, name: str) u32 = {
+ assert(idreg_lookup(reg, name) is void, "already registered");
+ assert(len(reg.idtoname) < types::U32_MAX, "registry full");
+
+ const id = len(reg.idtoname): u32;
+ append(reg.idtoname, strings::dup(name));
+
+ const hash = fnv::string64(name);
+ const entry = htab::add(&reg.nametoid, hash, size(u32));
+ *(entry: *u32) = id;
+
+ return id;
+};
+
+fn idreg_clear(reg: *IdRegistry) void = {
+ strings::freeall(reg.idtoname);
+ htab::finish(&reg.nametoid);
+ reg.idtoname = [];
+ reg.nametoid = htab::new(0, size(u32));
+};