ferroui_base/utilities/
binary_search_extension.rs1use std::cmp::Ordering;
18
19pub struct BinarySearchExtension;
26
27impl BinarySearchExtension {
28 fn get_median(low: i32, hi: i32) -> i32 {
29 debug_assert!(low <= hi);
30 debug_assert!(hi - low >= 0, "Length overflow!");
31 low + ((hi - low) >> 1)
32 }
33
34 pub fn binary_search<T>(list: &[T], value: &T, comparer: impl Fn(&T, &T) -> Ordering) -> i32 {
39 Self::binary_search_range(list, 0, list.len() as i32, value, comparer)
40 }
41
42 pub fn binary_search_range<T>(
48 list: &[T],
49 index: i32,
50 length: i32,
51 value: &T,
52 comparer: impl Fn(&T, &T) -> Ordering,
53 ) -> i32 {
54 let mut lo = index;
56 let mut hi = index + length - 1;
57 while lo <= hi {
58 let i = Self::get_median(lo, hi);
59 match comparer(&list[i as usize], value) {
60 Ordering::Equal => return i,
61 Ordering::Less => lo = i + 1,
62 Ordering::Greater => hi = i - 1,
63 }
64 }
65 !lo
66 }
67}
68
69#[cfg(test)]
70mod tests {
71 use super::*;
73
74 fn compare(a: &i32, b: &i32) -> Ordering {
75 a.cmp(b)
76 }
77
78 #[test]
79 fn finds_an_item_or_the_complement_of_the_next_larger_one() {
80 let list = [1, 3, 5, 7];
81 let empty: [i32; 0] = [];
82
83 assert_eq!(0, BinarySearchExtension::binary_search(&list, &1, compare));
84 assert_eq!(3, BinarySearchExtension::binary_search(&list, &7, compare));
85 assert_eq!(!0, BinarySearchExtension::binary_search(&list, &0, compare));
86 assert_eq!(!2, BinarySearchExtension::binary_search(&list, &4, compare));
87 assert_eq!(!4, BinarySearchExtension::binary_search(&list, &8, compare));
88 assert_eq!(!0, BinarySearchExtension::binary_search(&empty, &8, compare));
89 }
90
91 #[test]
92 fn searches_a_range() {
93 let list = [9, 1, 3, 5, 0];
94
95 assert_eq!(2, BinarySearchExtension::binary_search_range(&list, 1, 3, &3, compare));
96 assert_eq!(!1, BinarySearchExtension::binary_search_range(&list, 1, 3, &0, compare));
97 assert_eq!(!4, BinarySearchExtension::binary_search_range(&list, 1, 3, &6, compare));
98 }
99
100 #[test]
101 fn the_first_item_visited_wins_among_equal_items() {
102 let list = [2, 2, 2, 2, 2];
103 assert_eq!(2, BinarySearchExtension::binary_search(&list, &2, compare));
104 }
105}