Browse Source

Add linear_search_reverse and linear_search_reverse_proc

Nia 11 months ago
parent
commit
3337d6b264
2 changed files with 104 additions and 0 deletions
  1. 69 0
      core/slice/slice.odin
  2. 35 0
      tests/core/slice/test_core_slice.odin

+ 69 - 0
core/slice/slice.odin

@@ -96,6 +96,14 @@ contains :: proc(array: $T/[]$E, value: E) -> bool where intrinsics.type_is_comp
 	return found
 	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)
 @(require_results)
 linear_search :: proc(array: $A/[]$T, key: T) -> (index: int, found: bool)
 linear_search :: proc(array: $A/[]$T, key: T) -> (index: int, found: bool)
 	where intrinsics.type_is_comparable(T) #no_bounds_check {
 	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
 	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)
 @(require_results)
 linear_search_proc :: proc(array: $A/[]$T, f: proc(T) -> bool) -> (index: int, found: bool) #no_bounds_check {
 linear_search_proc :: proc(array: $A/[]$T, f: proc(T) -> bool) -> (index: int, found: bool) #no_bounds_check {
 	for x, i in array {
 	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
 	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.
 	Binary search searches the given slice for the given element.
 	If the slice is not sorted, the returned index is unspecified and meaningless.
 	If the slice is not sorted, the returned index is unspecified and meaningless.

+ 35 - 0
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[:]),
 	testing.expectf(t, slice.equal(c[:], d[:]),
 		"Expected two separate empty slices of two dynamic arrays to be equal")
 		"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)
+}