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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
|
use hash::fnv;
use htab;
use strings;
export type Value = (
i8 | i16 | i32 | i64 | f32 | f64
| []i8 | []i32 | []i64 | str
| []Value | Object);
export type Object = struct {
table: htab::table,
};
type Entry = (str, Value);
fn eq_fn(ctx: *opaque, key: *opaque) bool =
*(ctx: *str) == *(key: *str);
fn _get(object: *Object, hash: u64, key: str) nullable *Entry =
htab::get(&object.table, hash, &eq_fn, &key, size(Entry)):
nullable *Entry;
export fn newobject(cap: size) Object =
Object { table = htab::new(cap, size(Entry)) };
export fn count(object: *Object) size =
return htab::count(&object.table);
export fn get(object: *Object, key: str) nullable *Value = {
const hash = fnv::string64(key);
match (_get(object, hash, key)) {
case let entry: *Entry =>
return &entry.1;
case null =>
return null;
};
};
export fn set(object: *Object, key: str, value: Value) void = {
const hash = fnv::string64(key);
match (_get(object, hash, key)) {
case let entry: *Entry =>
finish(entry.1);
entry.1 = value;
case null =>
const entry = htab::add(&object.table, hash, size(Entry)):
*Entry;
*entry = (strings::dup(key), value);
};
};
export fn del(object: *Object, key: str) (Value | void) = {
const hash = fnv::string64(key);
match (_get(object, hash, key)) {
case let entry: *Entry =>
free(entry.0);
const value = entry.1;
htab::del(&object.table, entry, size(Entry));
return value;
case null => void;
};
};
export fn _clear(object: *Object) void = {
let it = htab::iter(&object.table);
for (true) match (htab::next(&it, size(Entry)): nullable *Entry) {
case let entry: *Entry =>
free(entry.0);
finish(entry.1);
case null => break;
};
};
export fn clear(object: *Object) void = {
_clear(object);
htab::clear(&object.table, size(Entry));
};
export type Iterator = struct {
iter: htab::iterator,
};
export fn iter(object: *Object) Iterator =
Iterator { iter = htab::iter(&object.table) };
export fn next(it: *Iterator) ((str, *Value) | void) = {
match (htab::next(&it.iter, size(Entry)): nullable *Entry) {
case let entry: *Entry =>
return (entry.0, &entry.1);
case null => void;
};
};
export fn dup(value: *Value) Value = {
match (*value) {
case let array: []i8 =>
return alloc(array...);
case let array: []i32 =>
return alloc(array...);
case let array: []i64 =>
return alloc(array...);
case let string: str =>
return strings::dup(string);
case let list: []Value =>
let list_ = alloc([]: [0]Value, len(list));
for (let i = 0z; i < len(list); i += 1) {
append(list_, dup(&list[i]));
};
return list_;
case let object: Object =>
let object_ = newobject(count(&object));
let it = iter(&object);
for (true) match (next(&it)) {
case let entry: (str, *Value) =>
set(&object_, entry.0, dup(entry.1));
case void => break;
};
return object_;
};
};
export fn finish(value: Value) void = {
match (value) {
case (i8 | i16 | i32 | i64 | f32 | f64) => void;
case let array: []i8 =>
free(array);
case let array: []i32 =>
free(array);
case let array: []i64 =>
free(array);
case let string: str =>
free(string);
case let list: []Value =>
for (let i = 0z; i < len(list); i += 1) {
finish(list[i]);
};
free(list);
case let object: Object =>
_clear(&object);
};
};
|