summaryrefslogtreecommitdiff
path: root/nbt/value.ha
diff options
context:
space:
mode:
authorLassi Pulkkinen <lassi@pulk.fi>2024-10-31 03:11:21 +0200
committerLassi Pulkkinen <lassi@pulk.fi>2024-10-31 03:51:35 +0200
commitae44478b30d890fe0fb04022f44d474dcdcc3f9d (patch)
tree5f462459ae4b47d22114eed717d1382d08cf4dfe /nbt/value.ha
Initial commit (import old repo)HEADmain
Diffstat (limited to 'nbt/value.ha')
-rw-r--r--nbt/value.ha141
1 files changed, 141 insertions, 0 deletions
diff --git a/nbt/value.ha b/nbt/value.ha
new file mode 100644
index 0000000..cf4aa17
--- /dev/null
+++ b/nbt/value.ha
@@ -0,0 +1,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);
+ };
+};