1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
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(®.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));
};
|