+++ /dev/null
-package core.array
-
-// [..] T == Array(T)
-// where
-// Array :: struct (T: type_expr) {
-// data : T;
-// count : u32;
-// capacity : u32;
-// allocator : Allocator;
-// }
-
-// ---------------------------------
-// Dynamic Arrays
-// ---------------------------------
-make :: ($T: type_expr, capacity := 4, allocator := context.allocator) -> [..] T {
- arr : [..] T;
- init(^arr, capacity, allocator);
- return arr;
-}
-
-init :: (arr: ^[..] $T, capacity := 4, allocator := context.allocator) {
- arr.count = 0;
- arr.capacity = capacity;
- arr.allocator = allocator;
- arr.data = raw_alloc(allocator, sizeof T * arr.capacity);
-}
-
-free :: (arr: ^[..] $T) {
- arr.count = 0;
- arr.capacity = 0;
-
- raw_free(arr.allocator, arr.data);
- arr.data = null;
-}
-
-copy :: (arr: ^[..] $T, allocator := context.allocator) -> [..] T {
- new_arr : [..] T;
- init(^new_arr, arr.count, allocator);
- new_arr.count = arr.count;
-
- for i: 0 .. arr.count do new_arr.data[i] = arr.data[i];
- return new_arr;
-}
-
-copy_range :: (arr: ^[..] $T, r: range, allocator := context.allocator) -> [..] T {
- new_arr : [..] T;
- init(^new_arr, r.high - r.low, allocator);
- new_arr.count = r.high - r.low;
-
- for i: r do new_arr.data[i] = arr.data[i];
- return new_arr;
-}
-
-clear :: (arr: ^[..] $T) {
- arr.count = 0;
-}
-
-ensure_capacity :: (arr: ^[..] $T, capacity: u32) -> bool {
- if arr.capacity >= capacity do return true;
-
- while capacity > arr.capacity do arr.capacity <<= 1;
- new_data := raw_resize(arr.allocator, arr.data, sizeof T * arr.capacity);
- if new_data == null do return false;
- arr.data = new_data;
- return true;
-}
-
-push :: (arr: ^[..] $T, x: T) -> bool {
- if !ensure_capacity(arr, arr.count + 1) do return false;
- arr.data[arr.count] = x;
- arr.count += 1;
- return true;
-}
-
-insert :: (arr: ^[..] $T, idx: u32, x: T) -> bool {
- if !ensure_capacity(arr, arr.count + 1) do return false;
-
- arr.count += 1;
- while i := arr.count; i > idx {
- arr.data[i] = arr.data[i - 1];
- i -= 1;
- }
-
- arr.data[idx] = x;
- return true;
-}
-
-insert_empty :: (arr: ^[..] $T, idx: u32) -> bool {
- if !ensure_capacity(arr, arr.count + 1) do return false;
-
- arr.count += 1;
- while i := arr.count; i > idx {
- arr.data[i] = arr.data[i - 1];
- i -= 1;
- }
-
- return true;
-}
-
-remove :: (arr: ^[..] $T, elem: T) {
- move := 0;
-
- while i := 0; i < arr.count - move {
- defer i += 1;
-
- if arr.data[i + move] == elem do move += 1;
- if move != 0 do arr.data[i] = arr.data[i + move];
- }
-
- arr.count -= move;
-}
-
-delete :: (arr: ^[..] $T, idx: u32) {
- if idx >= arr.count do return;
-
- for i: idx .. arr.count - 1 {
- arr.data[i] = arr.data[i + 1];
- }
-
- arr.count -= 1;
-}
-
-fast_delete :: (arr: ^[..] $T, idx: u32) {
- if idx >= arr.count do return;
-
- arr.data[idx] = arr.data[arr.count - 1];
- arr.count -= 1;
-}
-
-pop :: (arr: ^[..] $T) -> T {
- arr.count -= 1;
- return arr.data[arr.count];
-}
-
-// Uses '==' to compare for equality.
-contains :: proc {
- (arr: ^[..] $T, x: T) -> bool {
- for it: *arr do if it == x do return true;
- return false;
- },
-
- (arr: [] $T, x: T) -> bool {
- for it: arr do if it == x do return true;
- return false;
- }
-}
-
-// Uses '+' to sum.
-sum :: proc {
- (arr: ^[..] $T, start: T = 0) -> T {
- sum := start;
- for it: *arr do sum += it;
- return sum;
- },
-
- (arr: [] $T, start: T = 0) -> T {
- sum := start;
- for it: arr do sum += it;
- return sum;
- }
-}
-
-average :: (arr: ^[..] $T) -> T {
- sum := cast(T) 0;
- for it: *arr do sum += it;
-
- return sum / cast(T) arr.count;
-}
-
-to_slice :: (arr: ^[..] $T) -> [] T {
- return arr.data[0 .. arr.count];
-}
-
-/*
-** Simple insertion sort
-** cmp should return >0 if left > right
-*/
-sort :: (arr: ^[..] $T, cmp: (T, T) -> i32) {
- for i: 1 .. arr.count {
- x := arr.data[i];
- j := i - 1;
-
- while j >= 0 && cmp(arr.data[j], x) > 0 {
- arr.data[j + 1] = arr.data[j];
- j -= 1;
- }
-
- arr.data[j + 1] = x;
- }
-}
-
-fold :: proc {
- (arr: ^[..] $T, init: $R, f: (T, R) -> R) -> R {
- val := init;
- for it: *arr do val = f(it, val);
- return val;
- },
-
- (arr: [] $T, init: $R, f: (T, R) -> R) -> R {
- val := init;
- for it: arr do val = f(it, val);
- return val;
- }
-}
-
-map :: proc {
- (arr: ^[..] $T, f: (^T) -> void) do for ^it: *arr do f(it);,
- (arr: ^[..] $T, f: (T) -> T) do for ^it: *arr do *it = f(*it);,
- (arr: ^[..] $T, data: $R, f: (T, R) -> T) do for ^it: *arr do *it = f(*it, data);,
- (arr: [] $T, f: (^T) -> void) do for ^it: arr do f(it);,
- (arr: [] $T, f: (T) -> T) do for ^it: arr do *it = f(*it);,
- (arr: [] $T, data: $R, f: (T, R) -> T) do for ^it: arr do *it = f(*it, data);,
-}
-
-#private_file
-fold_idx_elem :: (arr: ^$T, count: i32, cmp: (T, T) -> bool) -> (i32, T) {
- idx := 0;
- elem := arr[0];
-
- for i: 1 .. count {
- if cmp(arr[i], elem) {
- idx = i;
- elem = arr[i];
- }
- }
-
- return idx, elem;
-}
-
-#private_file cmp_greater :: (x: $T, y: T) -> bool do return x > y;
-#private_file cmp_less :: (x: $T, y: T) -> bool do return x < y;
-
-greatest :: proc {
- (arr: [..] $T) -> (i32, T) { return fold_idx_elem(arr.data, arr.count, cmp_greater); },
- (arr: [] $T) -> (i32, T) { return fold_idx_elem(arr.data, arr.count, cmp_greater); },
- (arr: [$N] $T) -> (i32, T) { return fold_idx_elem(cast(^T) arr, N, cmp_greater); },
-}
-
-least :: proc {
- (arr: [..] $T) -> (i32, T) { return fold_idx_elem(arr.data, arr.count, cmp_less); },
- (arr: [] $T) -> (i32, T) { return fold_idx_elem(arr.data, arr.count, cmp_less); },
- (arr: [$N] $T) -> (i32, T) { return fold_idx_elem(cast(^T) arr, N, cmp_less); },
-}
--- /dev/null
+package core.array
+
+// [..] T == Array(T)
+// where
+// Array :: struct (T: type_expr) {
+// data : T;
+// count : u32;
+// capacity : u32;
+// allocator : Allocator;
+// }
+
+// ---------------------------------
+// Dynamic Arrays
+// ---------------------------------
+make :: ($T: type_expr, capacity := 4, allocator := context.allocator) -> [..] T {
+ arr : [..] T;
+ init(^arr, capacity, allocator);
+ return arr;
+}
+
+init :: (arr: ^[..] $T, capacity := 4, allocator := context.allocator) {
+ arr.count = 0;
+ arr.capacity = capacity;
+ arr.allocator = allocator;
+ arr.data = raw_alloc(allocator, sizeof T * arr.capacity);
+}
+
+free :: (arr: ^[..] $T) {
+ arr.count = 0;
+ arr.capacity = 0;
+
+ raw_free(arr.allocator, arr.data);
+ arr.data = null;
+}
+
+copy :: (arr: ^[..] $T, allocator := context.allocator) -> [..] T {
+ new_arr : [..] T;
+ init(^new_arr, arr.count, allocator);
+ new_arr.count = arr.count;
+
+ for i: 0 .. arr.count do new_arr.data[i] = arr.data[i];
+ return new_arr;
+}
+
+copy_range :: (arr: ^[..] $T, r: range, allocator := context.allocator) -> [..] T {
+ new_arr : [..] T;
+ init(^new_arr, r.high - r.low, allocator);
+ new_arr.count = r.high - r.low;
+
+ for i: r do new_arr.data[i] = arr.data[i];
+ return new_arr;
+}
+
+clear :: (arr: ^[..] $T) {
+ arr.count = 0;
+}
+
+ensure_capacity :: (arr: ^[..] $T, capacity: u32) -> bool {
+ if arr.capacity >= capacity do return true;
+
+ while capacity > arr.capacity do arr.capacity <<= 1;
+ new_data := raw_resize(arr.allocator, arr.data, sizeof T * arr.capacity);
+ if new_data == null do return false;
+ arr.data = new_data;
+ return true;
+}
+
+push :: (arr: ^[..] $T, x: T) -> bool {
+ if !ensure_capacity(arr, arr.count + 1) do return false;
+ arr.data[arr.count] = x;
+ arr.count += 1;
+ return true;
+}
+
+insert :: (arr: ^[..] $T, idx: u32, x: T) -> bool {
+ if !ensure_capacity(arr, arr.count + 1) do return false;
+
+ arr.count += 1;
+ while i := arr.count; i > idx {
+ arr.data[i] = arr.data[i - 1];
+ i -= 1;
+ }
+
+ arr.data[idx] = x;
+ return true;
+}
+
+insert_empty :: (arr: ^[..] $T, idx: u32) -> bool {
+ if !ensure_capacity(arr, arr.count + 1) do return false;
+
+ arr.count += 1;
+ while i := arr.count; i > idx {
+ arr.data[i] = arr.data[i - 1];
+ i -= 1;
+ }
+
+ return true;
+}
+
+remove :: (arr: ^[..] $T, elem: T) {
+ move := 0;
+
+ while i := 0; i < arr.count - move {
+ defer i += 1;
+
+ if arr.data[i + move] == elem do move += 1;
+ if move != 0 do arr.data[i] = arr.data[i + move];
+ }
+
+ arr.count -= move;
+}
+
+delete :: (arr: ^[..] $T, idx: u32) {
+ if idx >= arr.count do return;
+
+ for i: idx .. arr.count - 1 {
+ arr.data[i] = arr.data[i + 1];
+ }
+
+ arr.count -= 1;
+}
+
+fast_delete :: (arr: ^[..] $T, idx: u32) {
+ if idx >= arr.count do return;
+
+ arr.data[idx] = arr.data[arr.count - 1];
+ arr.count -= 1;
+}
+
+pop :: (arr: ^[..] $T) -> T {
+ arr.count -= 1;
+ return arr.data[arr.count];
+}
+
+// Uses '==' to compare for equality.
+contains :: proc {
+ (arr: ^[..] $T, x: T) -> bool {
+ for it: *arr do if it == x do return true;
+ return false;
+ },
+
+ (arr: [] $T, x: T) -> bool {
+ for it: arr do if it == x do return true;
+ return false;
+ }
+}
+
+// Uses '+' to sum.
+sum :: proc {
+ (arr: ^[..] $T, start: T = 0) -> T {
+ sum := start;
+ for it: *arr do sum += it;
+ return sum;
+ },
+
+ (arr: [] $T, start: T = 0) -> T {
+ sum := start;
+ for it: arr do sum += it;
+ return sum;
+ }
+}
+
+average :: (arr: ^[..] $T) -> T {
+ sum := cast(T) 0;
+ for it: *arr do sum += it;
+
+ return sum / cast(T) arr.count;
+}
+
+to_slice :: (arr: ^[..] $T) -> [] T {
+ return arr.data[0 .. arr.count];
+}
+
+/*
+** Simple insertion sort
+** cmp should return >0 if left > right
+*/
+sort :: (arr: ^[..] $T, cmp: (T, T) -> i32) {
+ for i: 1 .. arr.count {
+ x := arr.data[i];
+ j := i - 1;
+
+ while j >= 0 && cmp(arr.data[j], x) > 0 {
+ arr.data[j + 1] = arr.data[j];
+ j -= 1;
+ }
+
+ arr.data[j + 1] = x;
+ }
+}
+
+fold :: proc {
+ (arr: ^[..] $T, init: $R, f: (T, R) -> R) -> R {
+ val := init;
+ for it: *arr do val = f(it, val);
+ return val;
+ },
+
+ (arr: [] $T, init: $R, f: (T, R) -> R) -> R {
+ val := init;
+ for it: arr do val = f(it, val);
+ return val;
+ }
+}
+
+map :: proc {
+ (arr: ^[..] $T, f: (^T) -> void) do for ^it: *arr do f(it);,
+ (arr: ^[..] $T, f: (T) -> T) do for ^it: *arr do *it = f(*it);,
+ (arr: ^[..] $T, data: $R, f: (T, R) -> T) do for ^it: *arr do *it = f(*it, data);,
+ (arr: [] $T, f: (^T) -> void) do for ^it: arr do f(it);,
+ (arr: [] $T, f: (T) -> T) do for ^it: arr do *it = f(*it);,
+ (arr: [] $T, data: $R, f: (T, R) -> T) do for ^it: arr do *it = f(*it, data);,
+}
+
+#private_file
+fold_idx_elem :: (arr: ^$T, count: i32, cmp: (T, T) -> bool) -> (i32, T) {
+ idx := 0;
+ elem := arr[0];
+
+ for i: 1 .. count {
+ if cmp(arr[i], elem) {
+ idx = i;
+ elem = arr[i];
+ }
+ }
+
+ return idx, elem;
+}
+
+#private_file cmp_greater :: (x: $T, y: T) -> bool do return x > y;
+#private_file cmp_less :: (x: $T, y: T) -> bool do return x < y;
+
+greatest :: proc {
+ (arr: [..] $T) -> (i32, T) { return fold_idx_elem(arr.data, arr.count, cmp_greater); },
+ (arr: [] $T) -> (i32, T) { return fold_idx_elem(arr.data, arr.count, cmp_greater); },
+ (arr: [$N] $T) -> (i32, T) { return fold_idx_elem(cast(^T) arr, N, cmp_greater); },
+}
+
+least :: proc {
+ (arr: [..] $T) -> (i32, T) { return fold_idx_elem(arr.data, arr.count, cmp_less); },
+ (arr: [] $T) -> (i32, T) { return fold_idx_elem(arr.data, arr.count, cmp_less); },
+ (arr: [$N] $T) -> (i32, T) { return fold_idx_elem(cast(^T) arr, N, cmp_less); },
+}
--- /dev/null
+package core.iter
+
+use package core.intrinsics.onyx { __zero_value }
+
+filter :: (it: Iterator($T), predicate: (T) -> bool) -> Iterator(T) {
+ FilterIterator :: struct (T: type_expr) {
+ iterator: Iterator(T);
+ predicate: (T) -> bool;
+ }
+
+ filter_iterator := new(#type FilterIterator(T));
+ filter_iterator.iterator = it;
+ filter_iterator.predicate = predicate;
+
+ next :: ($T: type_expr, data: rawptr) -> (T, bool) {
+ fi := cast(^FilterIterator(T)) data;
+
+ value, cont := fi.iterator.next(fi.iterator.data);
+ if cont {
+ while !fi.predicate(value) {
+ value, cont = fi.iterator.next(fi.iterator.data);
+ if !cont do return value, false;
+ }
+
+ return value, true;
+ } else {
+ return value, false;
+ }
+ }
+
+ close :: ($T: type_expr, data: rawptr) {
+ fi := cast(^FilterIterator(T)) data;
+ fi.iterator.close(fi.iterator.data);
+ cfree(data);
+ }
+
+ return .{
+ data = filter_iterator,
+ next = #solidify next { T=T },
+ close = #solidify close { T=T },
+ };
+}
+
+map :: (it: Iterator($T), transform: (T) -> $R) -> Iterator(R) {
+ MapIterator :: struct (T: type_expr, R: type_expr) {
+ iterator: Iterator(T);
+ transform: (T) -> R;
+ }
+
+ map_iterator := new(#type MapIterator(T, R));
+ map_iterator.iterator = it;
+ map_iterator.transform = transform;
+
+ next :: ($T: type_expr, $R: type_expr, data: rawptr) -> (R, bool) {
+ mi := cast(^MapIterator(T, R)) data;
+
+ value, cont := mi.iterator.next(mi.iterator.data);
+ if !cont do return value, false;
+
+ return mi.transform(value), true;
+ }
+
+ close :: ($T: type_expr, $R: type_expr, data: rawptr) {
+ mi := cast(^MapIterator(T, R)) data;
+ mi.iterator.close(mi.iterator.data);
+ cfree(data);
+ }
+
+ return .{
+ data = map_iterator,
+ next = #solidify next { T=T, R=R },
+ close = #solidify close { T=T, R=R },
+ };
+}
+
+take :: (it: Iterator($T), count: u32) -> Iterator(T) {
+ TakeIterator :: struct (T: type_expr) {
+ iterator: Iterator(T);
+ remaining: u32;
+ }
+
+ take_iterator := new(#type TakeIterator(T));
+ take_iterator.iterator = it;
+ take_iterator.remaining = count;
+
+ next :: ($T: type_expr, data: rawptr) -> (T, bool) {
+ ti := cast(^TakeIterator(T)) data;
+ if ti.remaining == 0 do return __zero_value(T), false;
+
+ ti.remaining -= 1;
+ return ti.iterator.next(ti.iterator.data);
+ }
+
+ close :: ($T: type_expr, data: rawptr) {
+ ti := cast(^TakeIterator(T)) data;
+ ti.iterator.close(ti.iterator.data);
+ cfree(data);
+ }
+
+ return .{
+ data = take_iterator,
+ next = #solidify next { T=T },
+ close = #solidify close { T=T },
+ };
+}
+
+take_while :: (it: Iterator($T), predicate: (T) -> bool) -> Iterator(T) {
+ TakeIterator :: struct (T: type_expr) {
+ iterator: Iterator(T);
+ predicate: (T) -> bool;
+ }
+
+ take_iterator := new(#type TakeIterator(T));
+ take_iterator.iterator = it;
+ take_iterator.predicate = predicate;
+
+ next :: ($T: type_expr, data: rawptr) -> (T, bool) {
+ ti := cast(^TakeIterator(T)) data;
+
+ value, cont := ti.iterator.next(ti.iterator.data);
+ if !cont do return value, false;
+
+ return value, ti.predicate(value);
+ }
+
+ close :: ($T: type_expr, data: rawptr) {
+ ti := cast(^TakeIterator(T)) data;
+ ti.iterator.close(ti.iterator.data);
+ cfree(data);
+ }
+
+ return .{
+ data = take_iterator,
+ next = #solidify next { T=T },
+ close = #solidify close { T=T },
+ };
+}
+
+skip :: (it: Iterator($T), count: u32) -> Iterator(T) {
+ SkipIterator :: struct (T: type_expr) {
+ iterator: Iterator(T);
+ to_skip: i32;
+ skipped: bool = false;
+ }
+
+ skip_iterator := new(#type SkipIterator(T));
+ skip_iterator.iterator = it;
+ skip_iterator.to_skip = count;
+
+ next :: ($T: type_expr, data: rawptr) -> (T, bool) {
+ si := cast(^SkipIterator(T)) data;
+
+ while !si.skipped && si.to_skip > 0 {
+ si.to_skip -= 1;
+ value, cont := si.iterator.next(si.iterator.data);
+
+ if !cont {
+ si.skipped = true;
+ return value, false;
+ }
+ }
+
+ return si.iterator.next(si.iterator.data);
+ }
+
+ close :: ($T: type_expr, data: rawptr) {
+ si := cast(^SkipIterator(T)) data;
+ si.iterator.close(si.iterator.data);
+ cfree(data);
+ }
+
+ return .{
+ data = skip_iterator,
+ next = #solidify next { T=T },
+ close = #solidify close { T=T },
+ };
+}
+
+fold :: (it: Iterator($T), initial_value: R, combine: (T, $R) -> R) -> R {
+ for value: it {
+ initial_value = combine(value, initial_value);
+ }
+
+ return initial_value;
+}
+
+to_array :: (it: Iterator($T), allocator := context.allocator) -> [..] T {
+ array :: package core.array
+
+ arr := array.make(T, allocator=allocator);
+ for v: it do array.push(^arr, v);
+
+ return arr;
+}
--- /dev/null
+package core.list
+
+ListElem :: struct (T: type_expr) {
+ next: ^ListElem(T) = null;
+ prev: ^ListElem(T) = null;
+ data: T;
+}
+
+List :: struct (T: type_expr) {
+ allocator: Allocator;
+
+ first: ^ListElem(T) = null;
+ last: ^ListElem(T) = null;
+}
+
+make :: ($T: type_expr, allocator := context.allocator) -> List(T) {
+ return .{ allocator = allocator };
+}
+
+push_end :: (list: ^List($T), x: T) {
+ new_elem := allocate_elem(list);
+ new_elem.data = x;
+
+ new_elem.prev = list.last;
+ list.last.next = new_elem;
+ list.last = new_elem;
+
+ if list.first == null do list.first = new_elem;
+}
+
+push_begin :: (list: ^List($T), x: T) {
+ new_elem := allocate_elem(list);
+ new_elem.data = x;
+
+ new_elem.next = list.first;
+ list.first.prev = new_elem;
+ list.first = new_elem;
+
+ if list.last == null do list.last = new_elem;
+}
+
+pop_end :: (list: ^List($T), default: T = 0) -> T {
+ if list.last == null do return default;
+
+ end := list.last;
+ list.last = list.last.prev;
+ list.last.next = null;
+
+ defer raw_free(list.allocator, end);
+ return end.data;
+}
+
+pop_begin :: (list: ^List($T), default: T = 0) -> T {
+ if list.last == null do return default;
+
+ begin := list.first;
+ list.first = list.first.next;
+ list.first.prev = null;
+
+ defer raw_free(list.allocator, begin);
+ return begin.data;
+}
+
+contains :: (list: ^List($T), x: T) -> bool {
+ elem := list.first;
+ while elem != null {
+ if elem.data == x do return true;
+ elem = elem.next;
+ }
+
+ return false;
+}
+
+get_iterator :: (list: ^List($T)) -> Iterator(T) {
+ iterator_next :: ($T: type_expr, data: rawptr) -> (T, bool) {
+ list_iter := cast(^ListIterator(T)) data;
+
+ use package core.intrinsics.onyx { __zero_value }
+ if list_iter.current == null do return __zero_value(T), false;
+
+ defer list_iter.current = list_iter.current.next;
+ return list_iter.current.data, true;
+ }
+
+ iterator_close :: (data: rawptr) {
+ cfree(data);
+ }
+
+ ListIterator :: struct (T: type_expr) {
+ current: ^ListElem(T);
+ }
+
+ list_iterator := new(#type ListIterator(T));
+ list_iterator.current = list.first;
+
+ return .{
+ data = list_iterator,
+ next = #solidify iterator_next { T = T },
+ close = iterator_close,
+ };
+}
+
+#private_file
+allocate_elem :: (list: ^List($T)) -> ^ListElem(T) {
+ return new(#type ListElem(T), allocator=list.allocator);
+}
--- /dev/null
+package core.map
+
+#private_file array :: package core.array
+#private_file string :: package core.string
+
+Map :: struct (K: type_expr, V: type_expr) {
+ hashes : [..] i32;
+ entries : [..] Entry(K, V);
+
+ // The value provided by `map.get`, if nothing was found.
+ default_value : V;
+
+ Entry :: struct (K: type_expr, V: type_expr) {
+ next : i32;
+ key : K;
+ value : V;
+ }
+}
+
+make :: ($Key: type_expr, $Value: type_expr, default: Value = 0, hash_count: i32 = 16) -> Map(Key, Value) {
+ map : Map(Key, Value);
+ init(^map, default = default, hash_count = hash_count);
+ return map;
+}
+
+init :: (use map: ^Map($K, $V), default: V = ~~0, hash_count: i32 = 16) {
+ array.init(^hashes, hash_count);
+ array.init(^entries, 4);
+
+ default_value = default;
+
+ for i: 0 .. hash_count do array.push(^hashes, -1);
+}
+
+free :: (use map: ^Map($K, $V)) {
+ array.free(^hashes);
+ array.free(^entries);
+}
+
+put :: (use map: ^Map($K, $V), key: K, value: V) {
+ lr := lookup(map, key);
+
+ if lr.entry_index >= 0 {
+ entries[lr.entry_index].value = value;
+ return;
+ }
+
+ entry : Map.Entry(K, V);
+ entry.key = key;
+ entry.value = value;
+ entry.next = hashes[lr.hash_index];
+
+ array.push(^entries, entry);
+
+ hashes[lr.hash_index] = entries.count - 1;
+}
+
+has :: (use map: ^Map($K, $V), key: K) -> bool {
+ lr := lookup(map, key);
+ return lr.entry_index >= 0;
+}
+
+get :: (use map: ^Map($K, $V), key: K) -> V {
+ lr := lookup(map, key);
+ if lr.entry_index >= 0 do return entries[lr.entry_index].value;
+
+ return default_value;
+}
+
+get_ptr :: (use map: ^Map($K, $V), key: K) -> ^V {
+ lr := lookup(map, key);
+ if lr.entry_index >= 0 do return ^entries[lr.entry_index].value;
+
+ return null;
+}
+
+delete :: (use map: ^Map($K, $V), key: K) {
+ lr := lookup(map, key);
+ if lr.entry_index < 0 do return;
+
+ if lr.entry_prev < 0 do hashes[lr.hash_index] = entries[lr.entry_index].next;
+ else do entries[lr.entry_prev].next = entries[lr.entry_index].next;
+
+ if lr.entry_index == entries.count - 1 {
+ array.pop(^entries);
+ return;
+ }
+
+ array.fast_delete(^entries, lr.entry_index);
+ last := lookup(map, entries[lr.entry_index].key);
+ if last.entry_prev >= 0 do entries[last.entry_prev].next = lr.entry_index;
+ else do hashes[last.hash_index] = lr.entry_index;
+}
+
+update :: (use map: ^Map($K, $V), key: K, f: (^V) -> void) {
+ lr := lookup(map, key);
+ if lr.entry_index < 0 do return;
+
+ f(^entries[lr.entry_index].value);
+}
+
+clear :: (use map: ^Map($K, $V)) {
+ for i: 0 .. hashes.count do hashes.data[i] = -1;
+ entries.count = 0;
+}
+
+empty :: (use map: ^Map($K, $V)) -> bool {
+ return entries.count == 0;
+}
+
+hash_function :: proc {
+ (key: rawptr) -> u32 { return 0xcbf29ce7 ^ cast(u32) key; },
+ (key: i32) -> u32 { return 0xcbf29ce7 ^ cast(u32) key; },
+ (key: i64) -> u32 { return cast(u32) (cast(u64) 0xcbf29ce7 ^ cast(u64) key); },
+ (key: str) -> u32 {
+ hash: u32 = 5381;
+ for ch: key do hash += (hash << 5) + ~~ch;
+ return hash;
+ },
+}
+
+// CLEANUP: This could be replaced with operator overloading of '=='
+cmp_function :: proc {
+ (a: rawptr, b: rawptr) -> bool { return a == b; },
+ (a: i32, b: i32) -> bool { return a == b; },
+ (a: i64, b: i64) -> bool { return a == b; },
+
+ string.equal,
+}
+
+//
+// Private symbols
+//
+
+#private_file
+MapLookupResult :: struct {
+ hash_index : i32 = -1;
+ entry_index : i32 = -1;
+ entry_prev : i32 = -1;
+}
+
+#private_file
+lookup :: (use map: ^Map($K, $V), key: K) -> MapLookupResult {
+ lr := MapLookupResult.{};
+
+ hash: u32 = hash_function(key); // You cannot use this type for the key, unless you add an overload.
+
+ lr.hash_index = hash % hashes.count;
+ lr.entry_index = hashes[lr.hash_index];
+
+ while lr.entry_index >= 0 {
+ if cmp_function(entries[lr.entry_index].key, key) do return lr;
+
+ lr.entry_prev = lr.entry_index;
+ lr.entry_index = entries[lr.entry_index].next;
+ }
+
+ return lr;
+}
+++ /dev/null
-package core.iter
-
-use package core.intrinsics.onyx { __zero_value }
-
-filter :: (it: Iterator($T), predicate: (T) -> bool) -> Iterator(T) {
- FilterIterator :: struct (T: type_expr) {
- iterator: Iterator(T);
- predicate: (T) -> bool;
- }
-
- filter_iterator := new(#type FilterIterator(T));
- filter_iterator.iterator = it;
- filter_iterator.predicate = predicate;
-
- next :: ($T: type_expr, data: rawptr) -> (T, bool) {
- fi := cast(^FilterIterator(T)) data;
-
- value, cont := fi.iterator.next(fi.iterator.data);
- if cont {
- while !fi.predicate(value) {
- value, cont = fi.iterator.next(fi.iterator.data);
- if !cont do return value, false;
- }
-
- return value, true;
- } else {
- return value, false;
- }
- }
-
- close :: ($T: type_expr, data: rawptr) {
- fi := cast(^FilterIterator(T)) data;
- fi.iterator.close(fi.iterator.data);
- cfree(data);
- }
-
- return .{
- data = filter_iterator,
- next = #solidify next { T=T },
- close = #solidify close { T=T },
- };
-}
-
-map :: (it: Iterator($T), transform: (T) -> $R) -> Iterator(R) {
- MapIterator :: struct (T: type_expr, R: type_expr) {
- iterator: Iterator(T);
- transform: (T) -> R;
- }
-
- map_iterator := new(#type MapIterator(T, R));
- map_iterator.iterator = it;
- map_iterator.transform = transform;
-
- next :: ($T: type_expr, $R: type_expr, data: rawptr) -> (R, bool) {
- mi := cast(^MapIterator(T, R)) data;
-
- value, cont := mi.iterator.next(mi.iterator.data);
- if !cont do return value, false;
-
- return mi.transform(value), true;
- }
-
- close :: ($T: type_expr, $R: type_expr, data: rawptr) {
- mi := cast(^MapIterator(T, R)) data;
- mi.iterator.close(mi.iterator.data);
- cfree(data);
- }
-
- return .{
- data = map_iterator,
- next = #solidify next { T=T, R=R },
- close = #solidify close { T=T, R=R },
- };
-}
-
-take :: (it: Iterator($T), count: u32) -> Iterator(T) {
- TakeIterator :: struct (T: type_expr) {
- iterator: Iterator(T);
- remaining: u32;
- }
-
- take_iterator := new(#type TakeIterator(T));
- take_iterator.iterator = it;
- take_iterator.remaining = count;
-
- next :: ($T: type_expr, data: rawptr) -> (T, bool) {
- ti := cast(^TakeIterator(T)) data;
- if ti.remaining == 0 do return __zero_value(T), false;
-
- ti.remaining -= 1;
- return ti.iterator.next(ti.iterator.data);
- }
-
- close :: ($T: type_expr, data: rawptr) {
- ti := cast(^TakeIterator(T)) data;
- ti.iterator.close(ti.iterator.data);
- cfree(data);
- }
-
- return .{
- data = take_iterator,
- next = #solidify next { T=T },
- close = #solidify close { T=T },
- };
-}
-
-take_while :: (it: Iterator($T), predicate: (T) -> bool) -> Iterator(T) {
- TakeIterator :: struct (T: type_expr) {
- iterator: Iterator(T);
- predicate: (T) -> bool;
- }
-
- take_iterator := new(#type TakeIterator(T));
- take_iterator.iterator = it;
- take_iterator.predicate = predicate;
-
- next :: ($T: type_expr, data: rawptr) -> (T, bool) {
- ti := cast(^TakeIterator(T)) data;
-
- value, cont := ti.iterator.next(ti.iterator.data);
- if !cont do return value, false;
-
- return value, ti.predicate(value);
- }
-
- close :: ($T: type_expr, data: rawptr) {
- ti := cast(^TakeIterator(T)) data;
- ti.iterator.close(ti.iterator.data);
- cfree(data);
- }
-
- return .{
- data = take_iterator,
- next = #solidify next { T=T },
- close = #solidify close { T=T },
- };
-}
-
-skip :: (it: Iterator($T), count: u32) -> Iterator(T) {
- SkipIterator :: struct (T: type_expr) {
- iterator: Iterator(T);
- to_skip: i32;
- skipped: bool = false;
- }
-
- skip_iterator := new(#type SkipIterator(T));
- skip_iterator.iterator = it;
- skip_iterator.to_skip = count;
-
- next :: ($T: type_expr, data: rawptr) -> (T, bool) {
- si := cast(^SkipIterator(T)) data;
-
- while !si.skipped && si.to_skip > 0 {
- si.to_skip -= 1;
- value, cont := si.iterator.next(si.iterator.data);
-
- if !cont {
- si.skipped = true;
- return value, false;
- }
- }
-
- return si.iterator.next(si.iterator.data);
- }
-
- close :: ($T: type_expr, data: rawptr) {
- si := cast(^SkipIterator(T)) data;
- si.iterator.close(si.iterator.data);
- cfree(data);
- }
-
- return .{
- data = skip_iterator,
- next = #solidify next { T=T },
- close = #solidify close { T=T },
- };
-}
-
-fold :: (it: Iterator($T), initial_value: R, combine: (T, $R) -> R) -> R {
- for value: it {
- initial_value = combine(value, initial_value);
- }
-
- return initial_value;
-}
-
-to_array :: (it: Iterator($T), allocator := context.allocator) -> [..] T {
- array :: package core.array
-
- arr := array.make(T, allocator=allocator);
- for v: it do array.push(^arr, v);
-
- return arr;
-}
+++ /dev/null
-package core.list
-
-ListElem :: struct (T: type_expr) {
- next: ^ListElem(T) = null;
- prev: ^ListElem(T) = null;
- data: T;
-}
-
-List :: struct (T: type_expr) {
- allocator: Allocator;
-
- first: ^ListElem(T) = null;
- last: ^ListElem(T) = null;
-}
-
-make :: ($T: type_expr, allocator := context.allocator) -> List(T) {
- return .{ allocator = allocator };
-}
-
-push_end :: (list: ^List($T), x: T) {
- new_elem := allocate_elem(list);
- new_elem.data = x;
-
- new_elem.prev = list.last;
- list.last.next = new_elem;
- list.last = new_elem;
-
- if list.first == null do list.first = new_elem;
-}
-
-push_begin :: (list: ^List($T), x: T) {
- new_elem := allocate_elem(list);
- new_elem.data = x;
-
- new_elem.next = list.first;
- list.first.prev = new_elem;
- list.first = new_elem;
-
- if list.last == null do list.last = new_elem;
-}
-
-pop_end :: (list: ^List($T), default: T = 0) -> T {
- if list.last == null do return default;
-
- end := list.last;
- list.last = list.last.prev;
- list.last.next = null;
-
- defer raw_free(list.allocator, end);
- return end.data;
-}
-
-pop_begin :: (list: ^List($T), default: T = 0) -> T {
- if list.last == null do return default;
-
- begin := list.first;
- list.first = list.first.next;
- list.first.prev = null;
-
- defer raw_free(list.allocator, begin);
- return begin.data;
-}
-
-contains :: (list: ^List($T), x: T) -> bool {
- elem := list.first;
- while elem != null {
- if elem.data == x do return true;
- elem = elem.next;
- }
-
- return false;
-}
-
-get_iterator :: (list: ^List($T)) -> Iterator(T) {
- iterator_next :: ($T: type_expr, data: rawptr) -> (T, bool) {
- list_iter := cast(^ListIterator(T)) data;
-
- use package core.intrinsics.onyx { __zero_value }
- if list_iter.current == null do return __zero_value(T), false;
-
- defer list_iter.current = list_iter.current.next;
- return list_iter.current.data, true;
- }
-
- iterator_close :: (data: rawptr) {
- cfree(data);
- }
-
- ListIterator :: struct (T: type_expr) {
- current: ^ListElem(T);
- }
-
- list_iterator := new(#type ListIterator(T));
- list_iterator.current = list.first;
-
- return .{
- data = list_iterator,
- next = #solidify iterator_next { T = T },
- close = iterator_close,
- };
-}
-
-#private_file
-allocate_elem :: (list: ^List($T)) -> ^ListElem(T) {
- return new(#type ListElem(T), allocator=list.allocator);
-}
+++ /dev/null
-package core.map
-
-#private_file array :: package core.array
-#private_file string :: package core.string
-
-Map :: struct (K: type_expr, V: type_expr) {
- hashes : [..] i32;
- entries : [..] Entry(K, V);
-
- // The value provided by `map.get`, if nothing was found.
- default_value : V;
-
- Entry :: struct (K: type_expr, V: type_expr) {
- next : i32;
- key : K;
- value : V;
- }
-}
-
-make :: ($Key: type_expr, $Value: type_expr, default: Value = 0, hash_count: i32 = 16) -> Map(Key, Value) {
- map : Map(Key, Value);
- init(^map, default = default, hash_count = hash_count);
- return map;
-}
-
-init :: (use map: ^Map($K, $V), default: V = ~~0, hash_count: i32 = 16) {
- array.init(^hashes, hash_count);
- array.init(^entries, 4);
-
- default_value = default;
-
- for i: 0 .. hash_count do array.push(^hashes, -1);
-}
-
-free :: (use map: ^Map($K, $V)) {
- array.free(^hashes);
- array.free(^entries);
-}
-
-put :: (use map: ^Map($K, $V), key: K, value: V) {
- lr := lookup(map, key);
-
- if lr.entry_index >= 0 {
- entries[lr.entry_index].value = value;
- return;
- }
-
- entry : Map.Entry(K, V);
- entry.key = key;
- entry.value = value;
- entry.next = hashes[lr.hash_index];
-
- array.push(^entries, entry);
-
- hashes[lr.hash_index] = entries.count - 1;
-}
-
-has :: (use map: ^Map($K, $V), key: K) -> bool {
- lr := lookup(map, key);
- return lr.entry_index >= 0;
-}
-
-get :: (use map: ^Map($K, $V), key: K) -> V {
- lr := lookup(map, key);
- if lr.entry_index >= 0 do return entries[lr.entry_index].value;
-
- return default_value;
-}
-
-get_ptr :: (use map: ^Map($K, $V), key: K) -> ^V {
- lr := lookup(map, key);
- if lr.entry_index >= 0 do return ^entries[lr.entry_index].value;
-
- return null;
-}
-
-delete :: (use map: ^Map($K, $V), key: K) {
- lr := lookup(map, key);
- if lr.entry_index < 0 do return;
-
- if lr.entry_prev < 0 do hashes[lr.hash_index] = entries[lr.entry_index].next;
- else do entries[lr.entry_prev].next = entries[lr.entry_index].next;
-
- if lr.entry_index == entries.count - 1 {
- array.pop(^entries);
- return;
- }
-
- array.fast_delete(^entries, lr.entry_index);
- last := lookup(map, entries[lr.entry_index].key);
- if last.entry_prev >= 0 do entries[last.entry_prev].next = lr.entry_index;
- else do hashes[last.hash_index] = lr.entry_index;
-}
-
-update :: (use map: ^Map($K, $V), key: K, f: (^V) -> void) {
- lr := lookup(map, key);
- if lr.entry_index < 0 do return;
-
- f(^entries[lr.entry_index].value);
-}
-
-clear :: (use map: ^Map($K, $V)) {
- for i: 0 .. hashes.count do hashes.data[i] = -1;
- entries.count = 0;
-}
-
-empty :: (use map: ^Map($K, $V)) -> bool {
- return entries.count == 0;
-}
-
-hash_function :: proc {
- (key: rawptr) -> u32 { return 0xcbf29ce7 ^ cast(u32) key; },
- (key: i32) -> u32 { return 0xcbf29ce7 ^ cast(u32) key; },
- (key: i64) -> u32 { return cast(u32) (cast(u64) 0xcbf29ce7 ^ cast(u64) key); },
- (key: str) -> u32 {
- hash: u32 = 5381;
- for ch: key do hash += (hash << 5) + ~~ch;
- return hash;
- },
-}
-
-// CLEANUP: This could be replaced with operator overloading of '=='
-cmp_function :: proc {
- (a: rawptr, b: rawptr) -> bool { return a == b; },
- (a: i32, b: i32) -> bool { return a == b; },
- (a: i64, b: i64) -> bool { return a == b; },
-
- string.equal,
-}
-
-//
-// Private symbols
-//
-
-#private_file
-MapLookupResult :: struct {
- hash_index : i32 = -1;
- entry_index : i32 = -1;
- entry_prev : i32 = -1;
-}
-
-#private_file
-lookup :: (use map: ^Map($K, $V), key: K) -> MapLookupResult {
- lr := MapLookupResult.{};
-
- hash: u32 = hash_function(key); // You cannot use this type for the key, unless you add an overload.
-
- lr.hash_index = hash % hashes.count;
- lr.entry_index = hashes[lr.hash_index];
-
- while lr.entry_index >= 0 {
- if cmp_function(entries[lr.entry_index].key, key) do return lr;
-
- lr.entry_prev = lr.entry_index;
- lr.entry_index = entries[lr.entry_index].next;
- }
-
- return lr;
-}
#load "core/alloc"
#load "core/memory"
-#load "core/array"
-#load "core/map"
-#load "core/list"
-#load "core/iter"
+#load "core/container/array"
+#load "core/container/map"
+#load "core/container/list"
+#load "core/container/iter"
#load "core/conv"
#load "core/math"