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(®.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(®.nametoid, hash, size(u32)); *(entry: *u32) = id; return id; }; fn idreg_clear(reg: *IdRegistry) void = { strings::freeall(reg.idtoname); htab::finish(®.nametoid); reg.idtoname = []; reg.nametoid = htab::new(0, size(u32)); };