1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
use crate::{InvalidOrderError, OrderResult};
use core::cmp::Ordering;
pub trait TryBinarySearch<T> {
#[inline]
fn try_binary_search(&self, x: &T) -> OrderResult<Result<usize, usize>>
where
T: PartialOrd<T>,
{
self.try_binary_search_by(|a| a.partial_cmp(x))
}
fn try_binary_search_by<F>(&self, compare: F) -> OrderResult<Result<usize, usize>>
where
F: FnMut(&T) -> Option<Ordering>;
#[inline]
fn try_binary_search_by_key<K, F>(&self, b: &K, f: F) -> OrderResult<Result<usize, usize>>
where
F: FnMut(&T) -> Option<K>,
K: PartialOrd<K>,
{
let mut fk = f;
self.try_binary_search_by(|a| fk(a)?.partial_cmp(b))
}
}
impl<T> TryBinarySearch<T> for [T] {
#[inline]
fn try_binary_search_by<F>(&self, compare: F) -> OrderResult<Result<usize, usize>>
where
F: FnMut(&T) -> Option<Ordering>,
{
try_binary_search_by_inner(self, compare).ok_or(InvalidOrderError)
}
}
fn try_binary_search_by_inner<T, F>(slice: &[T], compare: F) -> Option<Result<usize, usize>>
where
F: FnMut(&T) -> Option<Ordering>,
{
let s = slice;
let mut size = s.len();
if size == 0 {
return Some(Err(0));
}
let mut compare = compare;
let mut base = 0usize;
while size > 1 {
let half = size / 2;
let mid = base + half;
let cmp = compare(unsafe { s.get_unchecked(mid) });
if let Some(cmp_1) = cmp {
base = if cmp_1 == Ordering::Greater {
base
} else {
mid
};
size -= half;
} else {
return None;
}
}
if let Some(cmp) = compare(unsafe { s.get_unchecked(base) }) {
Some(if cmp == Ordering::Equal {
Ok(base)
} else {
Err(base + (cmp == Ordering::Less) as usize)
})
} else {
return None;
}
}
#[cfg(test)]
#[cfg(feature = "std")]
mod tests {
use crate::*;
use rand::distributions::Standard;
use rand::prelude::*;
use std::print;
use std::vec::Vec;
#[test]
fn try_binary_search_ok() {
let rng = thread_rng();
let mut v: Vec<f32> = Standard.sample_iter(rng).take(100).collect();
assert!(v.try_sort().is_ok());
let b = random();
print!("t {}", b);
let i = v.try_binary_search(&b);
assert!(i.is_ok());
let ik = match i.unwrap() {
Ok(o) => o,
Err(e) => e,
};
for sm in v[..ik].iter() {
assert!(sm < &b);
}
for sm in v[ik..].iter() {
assert!(sm >= &b);
}
}
}