use num_traits::{
PrimInt, Unsigned,
identities::{one, zero},
};
use super::Overlapper;
use gtars_core::models::Interval;
#[derive(Debug, Clone)]
pub struct Bits<I, T>
where
I: PrimInt + Unsigned + Send + Sync,
T: Eq + Clone + Send + Sync,
{
pub intervals: Vec<Interval<I, T>>,
starts: Vec<I>,
ends: Vec<I>,
max_len: I,
cov: Option<I>,
pub overlaps_merged: bool,
}
impl<I, T> Overlapper<I, T> for Bits<I, T>
where
I: PrimInt + Unsigned + Send + Sync,
T: Eq + Clone + Send + Sync,
{
fn build(mut intervals: Vec<Interval<I, T>>) -> Self
where
Self: Sized,
{
intervals.sort();
let (mut starts, mut ends): (Vec<_>, Vec<_>) =
intervals.iter().map(|x| (x.start, x.end)).unzip();
starts.sort();
ends.sort();
let mut max_len = zero::<I>();
for interval in intervals.iter() {
let i_len = interval
.end
.checked_sub(&interval.start)
.unwrap_or_else(zero::<I>);
if i_len > max_len {
max_len = i_len;
}
}
Bits {
intervals,
starts,
ends,
max_len,
cov: None,
overlaps_merged: false,
}
}
#[inline]
fn find(&self, start: I, stop: I) -> Vec<Interval<I, T>> {
let finder = IterFind {
inner: self,
off: Self::lower_bound(
start.checked_sub(&self.max_len).unwrap_or_else(zero::<I>),
&self.intervals,
),
start,
stop,
};
finder.into_iter().cloned().collect()
}
fn find_iter<'a>(
&'a self,
start: I,
stop: I,
) -> Box<dyn Iterator<Item = &'a Interval<I, T>> + 'a> {
let finder = IterFind {
inner: self,
off: Self::lower_bound(
start.checked_sub(&self.max_len).unwrap_or_else(zero::<I>),
&self.intervals,
),
start,
stop,
};
Box::new(finder)
}
fn iter(&self) -> Box<dyn Iterator<Item = &Interval<I, T>> + '_> {
Box::new(self.intervals.iter())
}
}
impl<I, T> Bits<I, T>
where
I: PrimInt + Unsigned + Send + Sync,
T: Eq + Clone + Send + Sync,
{
pub fn insert(&mut self, elem: Interval<I, T>) {
let starts_insert_index = Self::bsearch_seq(elem.start, &self.starts);
let stops_insert_index = Self::bsearch_seq(elem.end, &self.ends);
let intervals_insert_index = Self::bsearch_seq_ref(&elem, &self.intervals);
let i_len = elem.end.checked_sub(&elem.start).unwrap_or_else(zero::<I>);
if i_len > self.max_len {
self.max_len = i_len;
}
self.starts.insert(starts_insert_index, elem.start);
self.ends.insert(stops_insert_index, elem.end);
self.intervals.insert(intervals_insert_index, elem);
self.cov = None;
self.overlaps_merged = false;
}
#[inline]
pub fn len(&self) -> usize {
self.intervals.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.intervals.is_empty()
}
#[inline]
pub fn iter(&'_ self) -> IterBits<'_, I, T> {
IterBits {
inner: self,
pos: 0,
}
}
#[inline]
pub fn lower_bound(start: I, intervals: &[Interval<I, T>]) -> usize {
let mut size = intervals.len();
let mut low = 0;
while size > 0 {
let half = size / 2;
let other_half = size - half;
let probe = low + half;
let other_low = low + other_half;
let v = &intervals[probe];
size = half;
low = if v.start < start { other_low } else { low }
}
low
}
#[inline]
pub fn bsearch_seq<K>(key: K, elems: &[K]) -> usize
where
K: PartialEq + PartialOrd,
{
Self::bsearch_seq_ref(&key, elems)
}
#[inline]
pub fn bsearch_seq_ref<K>(key: &K, elems: &[K]) -> usize
where
K: PartialEq + PartialOrd,
{
if elems.is_empty() || elems[0] >= *key {
return 0;
} else if elems[elems.len() - 1] < *key {
return elems.len();
}
let mut cursor = 0;
let mut length = elems.len();
while length > 1 {
let half = length >> 1;
length -= half;
cursor += (usize::from(elems[cursor + half - 1] < *key)) * half;
}
cursor
}
#[inline]
pub fn count(&self, start: I, stop: I) -> usize {
let len = self.intervals.len();
let first = Self::bsearch_seq(start + one::<I>(), &self.ends);
let last = Self::bsearch_seq(stop, &self.starts);
let num_cant_after = len - last;
len - first - num_cant_after
}
#[inline]
pub fn seek<'a>(&'a self, start: I, stop: I, cursor: &mut usize) -> IterFind<'a, I, T> {
if *cursor == 0 || (*cursor < self.intervals.len() && self.intervals[*cursor].start > start)
{
*cursor = Self::lower_bound(
start.checked_sub(&self.max_len).unwrap_or_else(zero::<I>),
&self.intervals,
);
}
while *cursor + 1 < self.intervals.len()
&& self.intervals[*cursor + 1].start
< start.checked_sub(&self.max_len).unwrap_or_else(zero::<I>)
{
*cursor += 1;
}
IterFind {
inner: self,
off: *cursor,
start,
stop,
}
}
}
#[derive(Debug)]
pub struct IterFind<'a, I, T>
where
T: Eq + Clone + Send + Sync + 'a,
I: PrimInt + Unsigned + Send + Sync,
{
inner: &'a Bits<I, T>,
off: usize,
start: I,
stop: I,
}
impl<'a, I, T> Iterator for IterFind<'a, I, T>
where
T: Eq + Clone + Send + Sync + 'a,
I: PrimInt + Unsigned + Send + Sync,
{
type Item = &'a Interval<I, T>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
while self.off < self.inner.intervals.len() {
let interval = &self.inner.intervals[self.off];
self.off += 1;
if interval.overlap(self.start, self.stop) {
return Some(interval);
} else if interval.start >= self.stop {
break;
}
}
None
}
}
pub struct IterBits<'a, I, T>
where
T: Eq + Clone + Send + Sync + 'a,
I: PrimInt + Unsigned + Send + Sync,
{
inner: &'a Bits<I, T>,
pos: usize,
}
impl<'a, I, T> Iterator for IterBits<'a, I, T>
where
T: Eq + Clone + Send + Sync + 'a,
I: PrimInt + Unsigned + Send + Sync,
{
type Item = &'a Interval<I, T>;
fn next(&mut self) -> Option<Self::Item> {
if self.pos >= self.inner.intervals.len() {
None
} else {
self.pos += 1;
self.inner.intervals.get(self.pos - 1)
}
}
}
impl<I, T> IntoIterator for Bits<I, T>
where
T: Eq + Clone + Send + Sync,
I: PrimInt + Unsigned + Send + Sync,
{
type Item = Interval<I, T>;
type IntoIter = ::std::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.intervals.into_iter()
}
}
impl<'a, I, T> IntoIterator for &'a Bits<I, T>
where
T: Eq + Clone + Send + Sync + 'a,
I: PrimInt + Unsigned + Send + Sync,
{
type Item = &'a Interval<I, T>;
type IntoIter = std::slice::Iter<'a, Interval<I, T>>;
fn into_iter(self) -> std::slice::Iter<'a, Interval<I, T>> {
self.intervals.iter()
}
}
impl<'a, I, T> IntoIterator for &'a mut Bits<I, T>
where
T: Eq + Clone + Send + Sync + 'a,
I: PrimInt + Unsigned + Send + Sync,
{
type Item = &'a mut Interval<I, T>;
type IntoIter = std::slice::IterMut<'a, Interval<I, T>>;
fn into_iter(self) -> std::slice::IterMut<'a, Interval<I, T>> {
self.intervals.iter_mut()
}
}
#[cfg(test)]
mod tests {
use super::*;
use pretty_assertions::{assert_eq, assert_ne};
use rstest::{fixture, rstest};
#[fixture]
fn intervals() -> Vec<Interval<u32, &'static str>> {
vec![
Interval {
start: 1,
end: 5,
val: "a",
},
Interval {
start: 3,
end: 7,
val: "b",
},
Interval {
start: 6,
end: 10,
val: "c",
},
Interval {
start: 8,
end: 12,
val: "d",
},
]
}
#[rstest]
fn test_build_and_len(intervals: Vec<Interval<u32, &'static str>>) {
let ailist = Bits::build(intervals.clone());
assert_eq!(ailist.len(), intervals.len());
assert_ne!(ailist.is_empty(), true);
}
#[rstest]
fn test_find_overlapping_intervals(intervals: Vec<Interval<u32, &'static str>>) {
let ailist = Bits::build(intervals);
let results = ailist.find(2, 4);
let vals: Vec<&str> = results.iter().map(|i| i.val).collect();
assert_eq!(vals.contains(&"a"), true);
assert_eq!(vals.contains(&"b"), true);
assert_eq!(vals.contains(&"c"), false);
let results = ailist.find(9, 11);
let vals: Vec<&str> = results.iter().map(|i| i.val).collect();
assert_eq!(vals.contains(&"c"), true);
assert_eq!(vals.contains(&"d"), true);
assert_eq!(vals.contains(&"a"), false);
}
#[rstest]
fn test_find_no_overlap(intervals: Vec<Interval<u32, &'static str>>) {
let ailist = Bits::build(intervals);
let results = ailist.find(13, 15);
assert_eq!(results.is_empty(), true);
}
#[rstest]
fn test_empty_ailist() {
let ailist: Bits<u32, &str> = Bits::build(vec![]);
assert_eq!(ailist.len(), 0);
assert_eq!(ailist.is_empty(), true);
let results = ailist.find(1, 2);
assert_eq!(results.is_empty(), true);
}
}