Skip to content

Commit

Permalink
add value versions of binary searches
Browse files Browse the repository at this point in the history
  • Loading branch information
ngtkana committed Nov 12, 2024
1 parent cb985c7 commit 57adb45
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 16 deletions.
67 changes: 55 additions & 12 deletions libs/riff/src/binary_search.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use std::cmp::Ordering::Less;
/// `{lower,upper}_bound`, etc
pub trait BinarySearch<T> {
fn partition_point<F: FnMut(&T) -> bool>(&self, pred: F) -> usize;
fn partition_point_value<F: FnMut(&T) -> bool>(&self, pred: F) -> Option<&T>;
fn lower_bound_by<F: FnMut(&T) -> Ordering>(&self, mut f: F) -> usize {
self.partition_point(|x| f(x) < Equal)
}
Expand All @@ -30,31 +31,73 @@ pub trait BinarySearch<T> {
{
self.upper_bound_by(|p| p.cmp(x))
}
fn lower_bound_value_by<F: FnMut(&T) -> Ordering>(&self, mut f: F) -> Option<&T> {
self.partition_point_value(|x| f(x) < Equal)
}
fn upper_bound_value_by<F: FnMut(&T) -> Ordering>(&self, mut f: F) -> Option<&T> {
self.partition_point_value(|x| f(x) <= Equal)
}
fn lower_bound_value_by_key<B: Ord, F: FnMut(&T) -> B>(&self, b: &B, mut f: F) -> Option<&T> {
self.lower_bound_value_by(|x| f(x).cmp(b))
}
fn upper_bound_value_by_key<B: Ord, F: FnMut(&T) -> B>(&self, b: &B, mut f: F) -> Option<&T> {
self.upper_bound_value_by(|x| f(x).cmp(b))
}
fn lower_bound_value(&self, x: &T) -> Option<&T>
where
T: Ord,
{
self.lower_bound_value_by(|p| p.cmp(x))
}
fn upper_bound_value(&self, x: &T) -> Option<&T>
where
T: Ord,
{
self.upper_bound_value_by(|p| p.cmp(x))
}
}

impl<T> BinarySearch<T> for [T] {
fn partition_point<F: FnMut(&T) -> bool>(&self, mut pred: F) -> usize {
self.binary_search_by(|x| if pred(x) { Less } else { Greater })
.unwrap_err()
}

fn partition_point_value<F: FnMut(&T) -> bool>(&self, pred: F) -> Option<&T> {
self.get(self.partition_point(pred))
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_vec_binary_search() {
let vec = vec![10, 12];
assert_eq!(vec.lower_bound(&9), 0);
assert_eq!(vec.lower_bound(&10), 0);
assert_eq!(vec.lower_bound(&11), 1);
assert_eq!(vec.lower_bound(&12), 1);
assert_eq!(vec.lower_bound(&13), 2);
assert_eq!(vec.upper_bound(&9), 0);
assert_eq!(vec.upper_bound(&10), 1);
assert_eq!(vec.upper_bound(&11), 1);
assert_eq!(vec.upper_bound(&12), 2);
assert_eq!(vec.upper_bound(&13), 2);
fn test_array_binary_search() {
let array = [10, 12];

assert_eq!(array.lower_bound(&9), 0);
assert_eq!(array.lower_bound(&10), 0);
assert_eq!(array.lower_bound(&11), 1);
assert_eq!(array.lower_bound(&12), 1);
assert_eq!(array.lower_bound(&13), 2);

assert_eq!(array.upper_bound(&9), 0);
assert_eq!(array.upper_bound(&10), 1);
assert_eq!(array.upper_bound(&11), 1);
assert_eq!(array.upper_bound(&12), 2);
assert_eq!(array.upper_bound(&13), 2);

assert_eq!(array.lower_bound_value(&9), Some(&10));
assert_eq!(array.lower_bound_value(&10), Some(&10));
assert_eq!(array.lower_bound_value(&11), Some(&12));
assert_eq!(array.lower_bound_value(&12), Some(&12));
assert_eq!(array.lower_bound_value(&13), None);

assert_eq!(array.upper_bound_value(&9), Some(&10));
assert_eq!(array.upper_bound_value(&10), Some(&12));
assert_eq!(array.upper_bound_value(&11), Some(&12));
assert_eq!(array.upper_bound_value(&12), None);
assert_eq!(array.upper_bound_value(&13), None);
}
}
12 changes: 8 additions & 4 deletions libs/riff/src/bitmask_iterators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ use super::numeric_traits::Unsigned;
///
/// Basic usage:
/// ```
/// use bitutils::combinations;
/// use riff::bitmask_combinations;
///
/// assert_eq!(combinations::<u32>(3, 2).collect::<Vec<_>>(), vec![3, 5, 6]);
/// assert_eq!(bitmask_combinations::<u32>(3, 2).collect::<Vec<_>>(), vec![
/// 3, 5, 6
/// ]);
/// ```
pub fn bitmask_combinations<T: Unsigned>(n: u32, k: u32) -> BitmaskCombinations<T> {
assert!(k < T::bit_length() && k < T::bit_length());
Expand Down Expand Up @@ -48,9 +50,11 @@ impl<T: Unsigned> Iterator for BitmaskCombinations<T> {
///
/// Basic usage:
/// ```
/// use bitutils::subsets;
/// use riff::bitmask_subsets;
///
/// assert_eq!(subsets(10u32).collect::<Vec<_>>(), vec![0, 2, 8, 10]);
/// assert_eq!(bitmask_subsets(10u32).collect::<Vec<_>>(), vec![
/// 0, 2, 8, 10
/// ]);
/// ```
pub fn bitmask_subsets<T: Unsigned>(bs: T) -> BitmaskSubsets<T> {
BitmaskSubsets {
Expand Down

0 comments on commit 57adb45

Please sign in to comment.