Skip to content

Commit

Permalink
Merge pull request #38 from orxfun/binary_search_by-is-implemented
Browse files Browse the repository at this point in the history
`binary_search_by` is implemented
  • Loading branch information
orxfun authored May 12, 2024
2 parents 76c35ef + 528a460 commit c814235
Show file tree
Hide file tree
Showing 5 changed files with 149 additions and 3 deletions.
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "orx-split-vec"
version = "2.11.0"
version = "2.12.0"
edition = "2021"
authors = ["orxfun <[email protected]>"]
description = "An efficient constant access time vector with dynamic capacity and pinned elements."
Expand All @@ -10,7 +10,7 @@ keywords = ["vec", "array", "split", "fragments", "pinned"]
categories = ["data-structures", "rust-patterns"]

[dependencies]
orx-pinned-vec = "2.9"
orx-pinned-vec = "2.10"

[[bench]]
name = "serial_access"
Expand Down
137 changes: 137 additions & 0 deletions src/algorithms/binary_search.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
use crate::Fragment;
use std::cmp::Ordering;

pub fn binary_search_by<T, F>(fragments: &[Fragment<T>], mut compare: F) -> Result<usize, usize>
where
F: FnMut(&T) -> Ordering,
{
let mut f = 0;
let mut fragment_begin_idx = 0;

while let Some(fragment) = fragments.get(f) {
let result = fragment.binary_search_by(&mut compare);

match result {
Ok(idx_in_fragment) => {
let idx = fragment_begin_idx + idx_in_fragment;
return Ok(idx);
}
Err(idx_in_fragment) => match idx_in_fragment {
x if x == fragment.len() => {}
_ => {
let idx = fragment_begin_idx + idx_in_fragment;
return Err(idx);
}
},
}

fragment_begin_idx += fragment.len();
f += 1;
}

Err(fragment_begin_idx)
}

#[cfg(test)]
mod tests {
use super::*;
use crate::{test_all_growth_types, Growth, SplitVec};
use orx_pinned_vec::PinnedVec;

fn get_compare(value: usize) -> impl FnMut(&usize) -> Ordering {
move |x: &usize| x.cmp(&value)
}

#[test]
fn bin_search_empty() {
let cmp = get_compare(42);

let fragments = vec![];
let result = binary_search_by(&fragments, cmp);
assert_eq!(result, Err(0));
}

#[test]
fn bin_search_empty_first_fragment() {
let cmp = get_compare(42);

let fragments = vec![vec![].into()];
let result = binary_search_by(&fragments, cmp);
assert_eq!(result, Err(0));
}

#[test]
fn bin_search_empty_second_fragment() {
let fragments = vec![vec![1, 4, 5].into(), vec![].into()];

let result = binary_search_by(&fragments, get_compare(0));
assert_eq!(result, Err(0));

let result = binary_search_by(&fragments, get_compare(2));
assert_eq!(result, Err(1));

let result = binary_search_by(&fragments, get_compare(42));
assert_eq!(result, Err(3));

let result = binary_search_by(&fragments, get_compare(1));
assert_eq!(result, Ok(0));

let result = binary_search_by(&fragments, get_compare(4));
assert_eq!(result, Ok(1));

let result = binary_search_by(&fragments, get_compare(5));
assert_eq!(result, Ok(2));
}

#[test]
fn bin_search_three_fragments() {
let fragments = vec![vec![1, 4, 5].into(), vec![7].into(), vec![9, 10].into()];

let search = |x| binary_search_by(&fragments, get_compare(x));

assert_eq!(search(0), Err(0));
assert_eq!(search(1), Ok(0));
assert_eq!(search(2), Err(1));
assert_eq!(search(3), Err(1));
assert_eq!(search(4), Ok(1));
assert_eq!(search(5), Ok(2));
assert_eq!(search(6), Err(3));
assert_eq!(search(7), Ok(3));
assert_eq!(search(8), Err(4));
assert_eq!(search(9), Ok(4));
assert_eq!(search(10), Ok(5));
assert_eq!(search(11), Err(6));
}

#[test]
fn bin_search_randomized() {
use rand::prelude::*;
use rand_chacha::ChaCha8Rng;

fn test<G: Growth>(mut vec: SplitVec<usize, G>) {
let mut rng = ChaCha8Rng::seed_from_u64(8654);
let mut ref_vec = vec![];
let mut idx = 0;
while ref_vec.len() < 1033 {
if rng.gen::<f32>() < 0.85 {
ref_vec.push(idx);
vec.push(idx);
}
idx += 1;
}

for i in 0..(idx + 10) {
assert_eq!(
vec.binary_search_by(|x| x.cmp(&i)),
ref_vec.binary_search_by(|x| x.cmp(&i)),
);
assert_eq!(vec.binary_search(&i), ref_vec.binary_search(&i));
assert_eq!(
vec.binary_search_by_key(&(2 * i), |x| 2 * x),
ref_vec.binary_search_by_key(&(2 * i), |x| 2 * x),
);
}
}
test_all_growth_types!(test);
}
}
1 change: 1 addition & 0 deletions src/algorithms/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod binary_search;
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@
clippy::todo
)]

mod algorithms;
mod common_traits;
mod fragment;
mod growth;
Expand Down
9 changes: 8 additions & 1 deletion src/pinned_vec.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::cmp::Ordering;

use crate::{Growth, SplitVec};
use crate::{algorithms, Growth, SplitVec};
use orx_pinned_vec::utils::slice;
use orx_pinned_vec::{CapacityState, PinnedVec, PinnedVecGrowthError};

Expand Down Expand Up @@ -572,6 +572,13 @@ where
}
}

fn binary_search_by<F>(&self, f: F) -> Result<usize, usize>
where
F: FnMut(&T) -> Ordering,
{
algorithms::binary_search::binary_search_by(&self.fragments, f)
}

fn try_grow(&mut self) -> Result<usize, PinnedVecGrowthError> {
if self.len() < self.capacity() {
Err(PinnedVecGrowthError::CanOnlyGrowWhenVecIsAtCapacity)
Expand Down

0 comments on commit c814235

Please sign in to comment.