From 3337d6b264dd69f1ad0004d93d78259bb48088d0 Mon Sep 17 00:00:00 2001 From: Nia <108984073+kawaii-Code@users.noreply.github.com> Date: Wed, 25 Sep 2024 16:41:55 +0300 Subject: [PATCH] Add linear_search_reverse and linear_search_reverse_proc --- core/slice/slice.odin | 69 +++++++++++++++++++++++++++ tests/core/slice/test_core_slice.odin | 35 ++++++++++++++ 2 files changed, 104 insertions(+) diff --git a/core/slice/slice.odin b/core/slice/slice.odin index 99ad15547..5d0189b5d 100644 --- a/core/slice/slice.odin +++ b/core/slice/slice.odin @@ -96,6 +96,14 @@ contains :: proc(array: $T/[]$E, value: E) -> bool where intrinsics.type_is_comp return found } +/* + Searches the given element in the given slice in O(n) time. + + Returns the first index at which the given element can be found in the slice, + or -1 if it is not present. + + If you need a custom compare procedure, see `linear_search_proc` +*/ @(require_results) linear_search :: proc(array: $A/[]$T, key: T) -> (index: int, found: bool) where intrinsics.type_is_comparable(T) #no_bounds_check { @@ -107,6 +115,12 @@ linear_search :: proc(array: $A/[]$T, key: T) -> (index: int, found: bool) return -1, false } +/* + Searches the given element in the given slice in O(n) time, using the given predicate. + + Returns the first index at which the given element can be found in the slice, + or -1 if it is not present. +*/ @(require_results) linear_search_proc :: proc(array: $A/[]$T, f: proc(T) -> bool) -> (index: int, found: bool) #no_bounds_check { for x, i in array { @@ -117,6 +131,61 @@ linear_search_proc :: proc(array: $A/[]$T, f: proc(T) -> bool) -> (index: int, f return -1, false } +/* + Reverse linear search searches the given element in the given slice in O(n) time, + starting from the slice end. + + Returns the last index at which the given element can be found in the slice, + or -1 if it is not present + + # Examples + + ``` + index: int + found: bool + + a := []i32{1, 1, 1, 2} + + index, found = linear_search_reverse(a, 2) + assert(index == 3 && found == true) + + index, found = linear_search_reverse(a, 1) + assert(index == 2 && found == true) + + index, found = linear_search_reverse(a, 0) + assert(index == -1 && found == false) + ``` + + If you need a custom compare procedure, see `linear_search_reverse_proc` +*/ +@(require_results) +linear_search_reverse :: proc(array: $A/[]$T, key: T) -> (index: int, found: bool) + where intrinsics.type_is_comparable(T) #no_bounds_check { + #reverse for x, i in array { + if x == key { + return i, true + } + } + return -1, false +} + +/* + Searches the given element in the given slice in O(n) time, starting from the end of + the slice and using the given predicate. + + Returns the last index at which the given element can be found in the slice, + or -1 if it is not present +*/ +@(require_results) +linear_search_reverse_proc :: proc(array: $A/[]$T, f: proc(T) -> bool) -> (index: int, found: bool) #no_bounds_check { + #reverse for x, i in array { + if f(x) { + return i, true + } + } + return -1, false +} + /* Binary search searches the given slice for the given element. If the slice is not sorted, the returned index is unspecified and meaningless. diff --git a/tests/core/slice/test_core_slice.odin b/tests/core/slice/test_core_slice.odin index 16d5b23a4..9c77f872d 100644 --- a/tests/core/slice/test_core_slice.odin +++ b/tests/core/slice/test_core_slice.odin @@ -306,3 +306,38 @@ test_compare_empty :: proc(t: ^testing.T) { testing.expectf(t, slice.equal(c[:], d[:]), "Expected two separate empty slices of two dynamic arrays to be equal") } + +@test +test_linear_search_reverse :: proc(t: ^testing.T) { + index: int + found: bool + + s := []i32{0, 50, 50, 100} + + index, found = slice.linear_search_reverse(s, 100) + testing.expect(t, found) + testing.expect_value(t, index, len(s) - 1) + + index, found = slice.linear_search_reverse(s[len(s) - 1:], 100) + testing.expect(t, found) + testing.expect_value(t, index, 0) + + index, found = slice.linear_search_reverse(s, 50) + testing.expect(t, found) + testing.expect_value(t, index, 2) + + index, found = slice.linear_search_reverse(s, 0) + testing.expect(t, found) + testing.expect_value(t, index, 0) + + index, found = slice.linear_search_reverse(s, -1) + testing.expect(t, !found) + + less_than_80 :: proc(x: i32) -> bool { + return x < 80 + } + + index, found = slice.linear_search_reverse_proc(s, less_than_80) + testing.expect(t, found) + testing.expect_value(t, index, 2) +}