hare

The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

commit e6cab9bc88bdc902fc43a3526bd8bc8d2e39e442
parent f65b9680cd17e14119bf7cb7d2e11c694a6bfb69
Author: Sebastian <sebastian@sebsite.pw>
Date:   Sat,  2 Apr 2022 00:05:25 -0400

sort: add bisect functions

Signed-off-by: Sebastian <sebastian@sebsite.pw>

Diffstat:
Mscripts/gen-stdlib | 1+
Msort/+test.ha | 34++++++++++++++++++++++++++++++++++
Asort/bisect.ha | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mstdlib.mk | 2++
4 files changed, 102 insertions(+), 0 deletions(-)

diff --git a/scripts/gen-stdlib b/scripts/gen-stdlib @@ -1066,6 +1066,7 @@ slices() { gensrcs_sort() { gen_srcs sort \ + bisect.ha \ search.ha \ sort.ha \ types.ha \ diff --git a/sort/+test.ha b/sort/+test.ha @@ -2,6 +2,40 @@ // (c) 2021 Drew DeVault <sir@cmpwn.com> // (c) 2021 Eyal Sawady <ecs@d2evs.net> +@test fn lbisect() void = { + const nums = [1, 3, 4, 4, 5, 7, 9, 11, 11, 11]; + for (let i = 0z; i < len(nums); i += 1) { + if (i != 0 && nums[i - 1] == nums[i]) continue; + const key = nums[i]; + assert(lbisect(nums, size(int), &key, &icmp) == i); + }; + const n = 0; + assert(lbisect(nums, size(int), &n, &icmp) == 0); + const n = 6; + assert(lbisect(nums, size(int), &n, &icmp) == 5); + const n = 8; + assert(lbisect(nums, size(int), &n, &icmp) == 6); + const n = 12; + assert(lbisect(nums, size(int), &n, &icmp) == len(nums)); +}; + +@test fn rbisect() void = { + const nums = [1, 3, 4, 4, 5, 7, 9, 11, 11, 11]; + for (let i = 0z; i < len(nums); i += 1) { + if (i != len(nums) - 1 && nums[i + 1] == nums[i]) continue; + const key = nums[i]; + assert(rbisect(nums, size(int), &key, &icmp) == i + 1); + }; + const n = 0; + assert(rbisect(nums, size(int), &n, &icmp) == 0); + const n = 6; + assert(rbisect(nums, size(int), &n, &icmp) == 5); + const n = 8; + assert(rbisect(nums, size(int), &n, &icmp) == 6); + const n = 12; + assert(rbisect(nums, size(int), &n, &icmp) == len(nums)); +}; + @test fn search() void = { const nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; for (let i = 0z; i < len(nums); i += 1) { diff --git a/sort/bisect.ha b/sort/bisect.ha @@ -0,0 +1,65 @@ +// License: MPL-2.0 +// (c) 2022 Sebastian <sebastian@sebsite.pw> + +// Determines the index that 'elem' should be inserted into sorted slice 'in'. +// If 'elem' already appears in the slice, inserting to the returned index will +// insert immediately before the first occurance. +export fn lbisect( + in: []const void, + sz: size, + elem: const *void, + cmp: *cmpfunc, +) size = { + let min = 0z, max = len(in); + const in = in: *[*]u8; + for (min < max) { + let i = (max - min) / 2 + min; + const r = cmp(elem, &in[i * sz]); + if (r < 0) { + max = i; + } else if (r > 0) { + min = i + 1; + } else { + if (i == 0) return 0; + for (i > 0; i -= 1) { + if (cmp(elem, &in[(i - 1) * sz]) != 0) { + break; + }; + }; + return i; + }; + }; + return max; +}; + +// Determines the index that 'elem' should be inserted into sorted slice 'in'. +// If 'elem' already appears in the slice, inserting to the returned index will +// insert immediately after the last occurance. +export fn rbisect( + in: []const void, + sz: size, + elem: const *void, + cmp: *cmpfunc, +) size = { + const nmemb = len(in); + let min = 0z, max = nmemb; + const in = in: *[*]u8; + for (min < max) { + let i = (max - min) / 2 + min; + const r = cmp(elem, &in[i * sz]); + if (r < 0) { + max = i; + } else if (r > 0) { + min = i + 1; + } else { + i += 1; + for (i < nmemb; i += 1) { + if (cmp(elem, &in[i * sz]) != 0) { + break; + }; + }; + return i; + }; + }; + return max; +}; diff --git a/stdlib.mk b/stdlib.mk @@ -1636,6 +1636,7 @@ $(HARECACHE)/slices/slices-any.ssa: $(stdlib_slices_any_srcs) $(stdlib_rt) $(std # sort (+any) stdlib_sort_any_srcs= \ + $(STDLIB)/sort/bisect.ha \ $(STDLIB)/sort/search.ha \ $(STDLIB)/sort/sort.ha \ $(STDLIB)/sort/types.ha @@ -3557,6 +3558,7 @@ $(TESTCACHE)/slices/slices-any.ssa: $(testlib_slices_any_srcs) $(testlib_rt) $(t # sort (+any) testlib_sort_any_srcs= \ + $(STDLIB)/sort/bisect.ha \ $(STDLIB)/sort/search.ha \ $(STDLIB)/sort/sort.ha \ $(STDLIB)/sort/types.ha \