From 8bc1e7c4f7236952d640ccf45e019dbcf875b502 Mon Sep 17 00:00:00 2001 From: Brendan Hansen Date: Mon, 6 Jun 2022 00:02:01 -0500 Subject: [PATCH] cleaned up array core library; added documentation --- core/builtin.onyx | 18 +++++++ core/container/array.onyx | 93 +++++++++++++++++--------------- core/runtime/info/proc_tags.onyx | 2 +- 3 files changed, 68 insertions(+), 45 deletions(-) diff --git a/core/builtin.onyx b/core/builtin.onyx index 3146e1fd..e90b3166 100644 --- a/core/builtin.onyx +++ b/core/builtin.onyx @@ -181,6 +181,24 @@ make :: #match { }, } +// +// This is a rather unique way of using the type matching system +// to select an overload. What is desired here is that when you say: +// +// make(Foo) +// +// You match the overload for make that is designed for making a Foo. +// However, you cannot use the type matching system to match by value. +// In order to get around this, `make` will pass a null pointer to this +// match procedure, that is casted to be a *pointer* to the desired type. +// Therefore, if you want to add your own make overload, you have to add +// a match to `__make_overload` that takes a *pointer* to the desired +// type as the first argument, and then an allocator as the second. +// Optionally, you can take a parameter between them that is an integer, +// useful when constructing things like arrays. +// +// See core/container/array.onyx for an example. +// __make_overload :: #match { // // This is the fallback option for make. It simply allocates a zero-intialized diff --git a/core/container/array.onyx b/core/container/array.onyx index 7a5bc4fc..c22d7566 100644 --- a/core/container/array.onyx +++ b/core/container/array.onyx @@ -188,6 +188,7 @@ filter :: macro (arr: ^[..] $T, body: Code) { while i := 0; i < arr.count - move { defer i += 1; + it := arr[i]; if !(#unquote body) do move += 1; if move != 0 do arr.data[i] = arr.data[i + move]; } @@ -195,12 +196,14 @@ filter :: macro (arr: ^[..] $T, body: Code) { arr.count -= move; } -fold_idx_elem :: (arr: [] $T, cmp: (T, T) -> bool) -> (i32, T) { +#local fold_idx_elem :: (arr: [] $T, $cmp: Code) -> (i32, T) { idx := 0; elem := arr[0]; for i: 1 .. arr.count { - if cmp(arr[i], elem) { + A := ^arr[i]; + B := ^elem; + if #unquote cmp { idx = i; elem = arr[i]; } @@ -209,19 +212,12 @@ fold_idx_elem :: (arr: [] $T, cmp: (T, T) -> bool) -> (i32, T) { return idx, elem; } -#local cmp_greater :: (x, y) => x > y; -#local cmp_less :: (x, y) => x < y; - -greatest :: #match { - (arr: [..] $T) -> (i32, T) { return fold_idx_elem(arr, cmp_greater); }, - (arr: [] $T) -> (i32, T) { return fold_idx_elem(arr, cmp_greater); }, - (arr: [$N] $T) -> (i32, T) { return fold_idx_elem(.{ cast(^T) arr, N }, cmp_greater); }, +greatest :: macro (arr: [] $T) -> (i32, T) { + return fold_idx_elem(arr, #(*A > *B)); } -least :: #match { - (arr: [..] $T) -> (i32, T) { return fold_idx_elem(arr, cmp_less); }, - (arr: [] $T) -> (i32, T) { return fold_idx_elem(arr, cmp_less); }, - (arr: [$N] $T) -> (i32, T) { return fold_idx_elem(.{ cast(^T) arr, N }, cmp_less); }, +least :: macro (arr: [] $T) -> (i32, T) { + return fold_idx_elem(arr, #(*A < *B)); } @@ -449,19 +445,30 @@ map :: #match { macro (arr: [] $T, data: $R, f: (T, R) -> T) do for ^it: arr do *it = f(*it, data);, } -every :: (arr: [] $T, predicate: (T) -> bool) -> bool { - val := true; - for ^it: arr do val = val && predicate(*it); - return val; +every :: #match {} +#match every macro (arr: [] $T, predicate: (T) -> bool) -> bool { + every :: every + return every(arr, #(predicate(it))); } -some :: (arr: [] $T, predicate: (T) -> bool) -> bool { - val := false; - for ^it: arr { - val = val || predicate(*it); - if val do break; +#match every macro (arr: [] $T, predicate_body: Code) -> bool { + for arr { + if !(#unquote predicate_body) do return false; } - return val; + return true; +} + +some :: #match {} +#match some macro (arr: [] $T, predicate: (T) -> bool) -> bool { + some :: some + return every(arr, #(predicate(it))); +} + +#match some macro (arr: [] $T, predicate_body: Code) -> bool { + for arr { + if #unquote predicate_body do return false; + } + return true; } fill :: (arr: [] $T, value: T) { @@ -503,35 +510,33 @@ find_ptr :: (arr: [] $T, value: T) -> ^T { return null; } -first :: (arr: [] $T, predicate: (T) -> bool) -> ^T { - for ^it: arr { - if predicate(*it) do return it; - } - - return null; +first :: #match {} +#match first macro (arr: [] $T, predicate: (T) -> bool) -> ^T { + first :: first + return first(arr, #(predicate(it))); } -first_where :: macro (arr: [] $T, cond: Code) -> ^T { +#match first macro (arr: [] $T, predicate_body: Code) -> ^T { // This is to preserve the semantics that "it" is // not a pointer (same as contains) - for^ it_: arr { - it := *it_; - if #unquote cond do return it_; + for ^it_ptr: arr { + it := *it_ptr; + if #unquote predicate_body do return it_ptr; } return null; } -count_where :: #match { - (arr: [] $T, predicate: (T) -> bool) -> u32 { - count: u32 = 0; - for ^it: arr do if predicate(*it) do count += 1; - return count; - }, +count_where :: #match {} +#match count_where macro (arr: [] $T, predicate: (T) -> bool) -> u32 { + count_where :: count_where + return count_where(arr, #(predicate(it))); +} - (arr: [] $T, predicate: (^T) -> bool) -> u32 { - count: u32 = 0; - for ^it: arr do if predicate(it) do count += 1; - return count; - }, +#match count_where macro (arr: [] $T, predicate_body: Code) -> u32 { + count: u32 = 0; + for arr { + if #unquote predicate_body do count += 1; + } + return count; } diff --git a/core/runtime/info/proc_tags.onyx b/core/runtime/info/proc_tags.onyx index b1107255..9f8826bf 100644 --- a/core/runtime/info/proc_tags.onyx +++ b/core/runtime/info/proc_tags.onyx @@ -32,7 +32,7 @@ get_procedures_with_tag :: ($tag_type: type_expr) -> [] GPWT_Result(tag_type) { results := make([..] GPWT_Result(tag_type)); for proc: tagged_procedures { - if tag := array.first_where(proc.tags, #(it.type == tag_type)); tag != null { + if tag := array.first(proc.tags, #(it.type == tag_type)); tag != null { array.push(^results, .{ func = proc.func, type = proc.type, -- 2.25.1