#![no_std]
use core::cmp::Ordering::{self, Less, Greater};
pub trait ExactSearch {
type Item;
fn exact_search(&self, x: &Self::Item) -> Result<usize, usize>
where
Self::Item: Ord;
fn exact_search_by<'a, F>(&'a self, f: F) -> Result<usize, usize>
where
F: FnMut(&'a Self::Item) -> Ordering;
fn exact_search_by_key<'a, K, F>(&'a self, key: &K, f: F) -> Result<usize, usize>
where
F: FnMut(&'a Self::Item) -> K,
K: Ord;
}
impl<T> ExactSearch for [T] {
type Item = T;
#[inline]
fn exact_search(&self, x: &Self::Item) -> Result<usize, usize>
where
Self::Item: Ord,
{
self.exact_search_by(|candidate| candidate.cmp(x))
}
#[inline]
fn exact_search_by<'a, F>(&'a self, mut f: F) -> Result<usize, usize>
where
F: FnMut(&'a Self::Item) -> Ordering,
{
let mut size = self.len();
if size == 0 {
return Err(0);
}
let mut base = 0;
while size > 1 {
let half = size / 2;
let mid = base + half;
let cmp = f(unsafe { self.get_unchecked(mid) });
if cmp == Ordering::Equal {
return Ok(mid);
}
base = core::hint::select_unpredictable(cmp == Greater, base, mid);
size -= half;
}
match f(unsafe { self.get_unchecked(base) }) {
Ordering::Less => Err(base + 1),
Ordering::Equal => Ok(base),
Ordering::Greater => Err(base),
}
}
#[inline]
fn exact_search_by_key<'a, K, F>(&'a self, key: &K, mut f: F) -> Result<usize, usize>
where
F: FnMut(&'a Self::Item) -> K,
K: Ord,
{
self.exact_search_by(|candidate| f(candidate).cmp(key))
}
}
pub trait Ext {
type Item;
fn lower_bound(&self, x: &Self::Item) -> usize
where
Self::Item: Ord;
fn lower_bound_by<'a, F>(&'a self, f: F) -> usize
where
F: FnMut(&'a Self::Item) -> Ordering;
fn lower_bound_by_key<'a, K, F>(&'a self, k: &K, f: F) -> usize
where
F: FnMut(&'a Self::Item) -> K,
K: Ord;
fn upper_bound(&self, x: &Self::Item) -> usize
where
Self::Item: Ord;
fn upper_bound_by<'a, F>(&'a self, f: F) -> usize
where
F: FnMut(&'a Self::Item) -> Ordering;
fn upper_bound_by_key<'a, K, F>(&'a self, k: &K, f: F) -> usize
where
F: FnMut(&'a Self::Item) -> K,
K: Ord;
fn equal_range(&self, x: &Self::Item) -> core::ops::Range<usize>
where
Self::Item: Ord;
fn equal_range_by<'a, F>(&'a self, f: F) -> core::ops::Range<usize>
where
F: FnMut(&'a Self::Item) -> Ordering;
fn equal_range_by_key<'a, K, F>(&'a self, k: &K, f: F) -> core::ops::Range<usize>
where
F: FnMut(&'a Self::Item) -> K,
K: Ord;
fn next_permutation(&mut self) -> bool
where
Self::Item: Ord;
fn prev_permutation(&mut self) -> bool
where
Self::Item: Ord;
fn apply_permutation(&mut self, permutation: &mut [isize]);
fn apply_inverse_permutation(&mut self, permutation: &mut [isize]);
}
impl<T> Ext for [T] {
type Item = T;
fn lower_bound(&self, x: &Self::Item) -> usize
where
T: Ord,
{
self.lower_bound_by(|y| y.cmp(x))
}
fn lower_bound_by<'a, F>(&'a self, mut f: F) -> usize
where
F: FnMut(&'a Self::Item) -> Ordering,
{
let s = self;
let mut size = s.len();
if size == 0 {
return 0;
}
let mut base = 0usize;
while size > 1 {
let half = size / 2;
let mid = base + half;
let cmp = f(unsafe { s.get_unchecked(mid) });
base = if cmp == Less { mid } else { base };
size -= half;
}
let cmp = f(unsafe { s.get_unchecked(base) });
base + (cmp == Less) as usize
}
fn lower_bound_by_key<'a, K, F>(&'a self, k: &K, mut f: F) -> usize
where
F: FnMut(&'a Self::Item) -> K,
K: Ord,
{
self.lower_bound_by(|e| f(e).cmp(k))
}
fn upper_bound(&self, x: &Self::Item) -> usize
where
T: Ord,
{
self.upper_bound_by(|y| y.cmp(x))
}
fn upper_bound_by<'a, F>(&'a self, mut f: F) -> usize
where
F: FnMut(&'a Self::Item) -> Ordering,
{
let s = self;
let mut size = s.len();
if size == 0 {
return 0;
}
let mut base = 0usize;
while size > 1 {
let half = size / 2;
let mid = base + half;
let cmp = f(unsafe { s.get_unchecked(mid) });
base = if cmp == Greater { base } else { mid };
size -= half;
}
let cmp = f(unsafe { s.get_unchecked(base) });
base + (cmp != Greater) as usize
}
fn upper_bound_by_key<'a, K, F>(&'a self, k: &K, mut f: F) -> usize
where
F: FnMut(&'a Self::Item) -> K,
K: Ord,
{
self.upper_bound_by(|e| f(e).cmp(k))
}
fn equal_range(&self, x: &Self::Item) -> core::ops::Range<usize>
where
T: Ord,
{
self.equal_range_by(|y| y.cmp(x))
}
fn equal_range_by<'a, F>(&'a self, mut f: F) -> core::ops::Range<usize>
where
F: FnMut(&'a Self::Item) -> Ordering,
{
let s = self;
let mut size = s.len();
if size == 0 {
return 0..0;
}
let mut base = (0usize, 0usize);
while size > 1 {
let half = size / 2;
let mid = (base.0 + half, base.1 + half);
let cmp = (
f(unsafe { s.get_unchecked(mid.0) }),
f(unsafe { s.get_unchecked(mid.1) }),
);
base = (
if cmp.0 == Less { mid.0 } else { base.0 },
if cmp.1 == Greater { base.1 } else { mid.1 },
);
size -= half;
}
let cmp = (
f(unsafe { s.get_unchecked(base.0) }),
f(unsafe { s.get_unchecked(base.1) }),
);
base.0 + (cmp.0 == Less) as usize..base.1 + (cmp.1 != Greater) as usize
}
fn equal_range_by_key<'a, K, F>(&'a self, k: &K, mut f: F) -> core::ops::Range<usize>
where
F: FnMut(&'a Self::Item) -> K,
K: Ord,
{
self.equal_range_by(|e| f(e).cmp(k))
}
fn next_permutation(&mut self) -> bool
where
Self::Item: Ord
{
if self.len() <= 1 { return false; }
let last = self.len() - 1;
let mut a = last;
loop {
let mut b = a;
a -= 1;
if self[a] < self[b] {
b = last;
while self[a] >= self[b] {
b -= 1;
}
self.swap(a, b);
self[a+1..].reverse();
return true;
}
if a == 0 {
self.reverse();
return false;
}
}
}
fn prev_permutation(&mut self) -> bool
where
Self::Item: Ord
{
if self.len() <= 1 { return false; }
let last = self.len() - 1;
let mut a = last;
loop {
let mut b = a;
a -= 1;
if self[b] < self[a] {
b = last;
while self[b] >= self[a] {
b -= 1;
}
self.swap(a, b);
self[a+1..].reverse();
return true;
}
if a == 0 {
self.reverse();
return false;
}
}
}
fn apply_permutation(&mut self, perm: &mut [isize]) {
assert_eq!(self.len(), perm.len());
assert!(self.len() < isize::MAX as usize);
for i in 0..self.len() as isize {
let mut c = perm[i as usize];
if c < 0 {
perm[i as usize] = !c;
} else if i != c {
loop {
let n = perm[c as usize];
self.swap(c as usize, n as usize);
perm[c as usize] = !n;
c = n;
if i == c { break; }
}
}
}
}
fn apply_inverse_permutation(&mut self, perm: &mut [isize]) {
assert_eq!(self.len(), perm.len());
assert!(self.len() < isize::MAX as usize);
for i in 0..self.len() as isize {
let mut c = perm[i as usize];
if c < 0 {
perm[i as usize] = !c;
} else if i != c {
loop {
self.swap(c as usize, i as usize);
let n = perm[c as usize];
perm[c as usize] = !n;
c = n;
if i == c { break; }
}
}
}
}
}
pub trait Ext2 {
fn invert_permutation(&mut self);
}
impl Ext2 for [isize] {
fn invert_permutation(&mut self) {
assert!(self.len() < isize::MAX as usize);
for i in 0..self.len() as isize {
let mut c = self[i as usize];
if c < 0 {
self[i as usize] = !c;
} else if i != c {
let mut n = i;
loop {
let t = self[c as usize];
self[c as usize] = !n;
n = c;
c = t;
if c == i {
self[i as usize] = n;
break;
}
}
}
}
}
}
#[cfg(test)]
mod tests {
extern crate std;
use super::{ExactSearch, Ext};
#[test]
fn exact_search_matches_insertion_semantics() {
for size in 0..=128 {
let values: std::vec::Vec<u32> = (0..size).map(|value| value * 2 + 2).collect();
for needle in 0..=(size * 2 + 4) {
let insertion = values.partition_point(|candidate| candidate < &needle);
let expected = match values.get(insertion) {
Some(candidate) if candidate == &needle => Ok(insertion),
_ => Err(insertion),
};
assert_eq!(values.exact_search(&needle), expected, "size={size}, needle={needle}");
assert_eq!(
values.exact_search_by(|candidate| candidate.cmp(&needle)),
expected,
"size={size}, needle={needle}",
);
assert_eq!(
values.exact_search_by_key(&needle, |candidate| *candidate),
expected,
"size={size}, needle={needle}",
);
}
}
}
#[test]
fn exact_search_accepts_any_equal_duplicate() {
let values = [1, 3, 3, 3, 5];
let found = values.exact_search(&3).unwrap();
assert_eq!(values[found], 3);
}
#[test]
fn lower_bound() {
let b: [u32; 0] = [];
assert_eq!(b.lower_bound(&0), 0);
let b = [1, 3, 3, 5];
assert_eq!(b.lower_bound(&0), 0);
assert_eq!(b.lower_bound(&1), 0);
assert_eq!(b.lower_bound(&2), 1);
assert_eq!(b.lower_bound(&3), 1);
assert_eq!(b.lower_bound(&4), 3);
assert_eq!(b.lower_bound(&5), 3);
assert_eq!(b.lower_bound(&6), 4);
}
#[test]
fn upper_bound() {
let b: [u32; 0] = [];
assert_eq!(b.upper_bound(&0), 0);
let b = [1, 3, 3, 5];
assert_eq!(b.upper_bound(&0), 0);
assert_eq!(b.upper_bound(&1), 1);
assert_eq!(b.upper_bound(&2), 1);
assert_eq!(b.upper_bound(&3), 3);
assert_eq!(b.upper_bound(&4), 3);
assert_eq!(b.upper_bound(&5), 4);
assert_eq!(b.upper_bound(&6), 4);
}
#[test]
fn equal_range() {
let b: [u32; 0] = [];
assert_eq!(b.equal_range(&0), 0..0);
let b = [1, 3, 3, 5];
assert_eq!(b.equal_range(&0), 0..0);
assert_eq!(b.equal_range(&1), 0..1);
assert_eq!(b.equal_range(&2), 1..1);
assert_eq!(b.equal_range(&3), 1..3);
assert_eq!(b.equal_range(&4), 3..3);
assert_eq!(b.equal_range(&5), 3..4);
assert_eq!(b.equal_range(&6), 4..4);
}
}