use std::mem::swap;
use num_traits::{PrimInt, Unsigned};
use super::Overlapper;
use gtars_core::models::Interval;
#[derive(Debug, Clone)]
pub struct AIList<I, T>
where
I: PrimInt + Unsigned + Send + Sync,
T: Eq + Clone + Send + Sync,
{
starts: Vec<I>,
ends: Vec<I>,
max_ends: Vec<I>,
header_list: Vec<usize>,
stored_intervals: Vec<Interval<I, T>>,
}
#[derive(Debug, Default)]
struct DecomposeResult<I, T>
where
I: PrimInt + Unsigned + Send + Sync,
T: Eq + Clone + Send + Sync,
{
starts: Vec<I>,
ends: Vec<I>,
max_ends: Vec<I>,
stored_intervals: Vec<Interval<I, T>>,
l2: Vec<Interval<I, T>>,
}
impl<I, T> DecomposeResult<I, T>
where
I: PrimInt + Unsigned + Send + Sync,
T: Eq + Clone + Send + Sync,
{
fn clear(&mut self) {
self.starts.clear();
self.ends.clear();
self.max_ends.clear();
self.stored_intervals.clear();
self.l2.clear();
}
fn with_capacity(cap: usize) -> Self {
Self {
starts: Vec::with_capacity(cap),
ends: Vec::with_capacity(cap),
max_ends: Vec::with_capacity(cap),
stored_intervals: Vec::with_capacity(cap),
l2: Vec::with_capacity(cap),
}
}
}
impl<I, T> Overlapper<I, T> for AIList<I, T>
where
I: PrimInt + Unsigned + Send + Sync,
T: Eq + Clone + Send + Sync,
{
fn build(intervals: Vec<Interval<I, T>>) -> Self
where
Self: Sized,
{
let mut intervals = intervals;
intervals.sort_by_key(|key| key.start);
let mut starts = Vec::with_capacity(intervals.len());
let mut ends = Vec::with_capacity(intervals.len());
let mut max_ends = Vec::with_capacity(intervals.len());
let mut stored_intervals = Vec::with_capacity(intervals.len());
let mut results = DecomposeResult::with_capacity(intervals.len());
let mut header_list = vec![0];
loop {
Self::decompose(&intervals, 10, &mut results);
starts.append(&mut results.starts);
ends.append(&mut results.ends);
max_ends.append(&mut results.max_ends);
stored_intervals.append(&mut results.stored_intervals);
swap(&mut intervals, &mut results.l2);
if intervals.is_empty() {
break;
} else {
header_list.push(starts.len());
}
}
AIList {
starts,
ends,
max_ends,
header_list,
stored_intervals,
}
}
fn find(&self, start: I, end: I) -> Vec<Interval<I, T>> {
let mut results_list = Vec::new();
for i in 0..(self.header_list.len() - 1) {
results_list.append(&mut Self::query_slice(
start,
end,
&self.starts[self.header_list[i]..self.header_list[i + 1]],
&self.ends[self.header_list[i]..self.header_list[i + 1]],
&self.max_ends[self.header_list[i]..self.header_list[i + 1]],
&self.stored_intervals[self.header_list[i]..self.header_list[i + 1]],
));
}
let i = self.header_list.len() - 1;
results_list.extend(Self::query_slice(
start,
end,
&self.starts[self.header_list[i]..],
&self.ends[self.header_list[i]..],
&self.max_ends[self.header_list[i]..],
&self.stored_intervals[self.header_list[i]..],
));
results_list
}
fn find_iter<'a>(
&'a self,
start: I,
stop: I,
) -> Box<dyn Iterator<Item = &'a Interval<I, T>> + 'a> {
Box::new(IterFind::new(self, start, stop))
}
fn iter(&self) -> Box<dyn Iterator<Item = &Interval<I, T>> + '_> {
Box::new(self.stored_intervals.iter())
}
}
impl<I, T> AIList<I, T>
where
I: PrimInt + Unsigned + Send + Sync,
T: Eq + Clone + Send + Sync,
{
fn decompose(
intervals: &[Interval<I, T>],
minimum_coverage_length: usize,
scratch: &mut DecomposeResult<I, T>,
) {
scratch.clear();
for (index, interval) in intervals.iter().enumerate() {
let mut count = 0;
for i in 1..(minimum_coverage_length * 2) {
match intervals.get(index + i) {
Some(interval2) => {
if interval.end > interval2.end {
count += 1;
}
}
None => break,
}
}
if count >= minimum_coverage_length {
scratch.l2.push(Interval {
start: interval.start,
end: interval.end,
val: interval.val.clone(),
});
} else {
scratch.starts.push(interval.start);
scratch.ends.push(interval.end);
scratch.stored_intervals.push(interval.clone());
}
}
let mut max: I = I::zero();
for end in scratch.ends.iter() {
max = if max > *end { max } else { *end };
scratch.max_ends.push(max);
}
}
fn query_slice(
start: I,
end: I,
starts: &[I],
ends: &[I],
max_ends: &[I],
stored_intervals: &[Interval<I, T>],
) -> Vec<Interval<I, T>> {
let mut results_list = Vec::new();
let mut i = starts.partition_point(|&x| x < end);
while i > 0 {
i -= 1;
if start >= ends[i] {
if start > max_ends[i] {
return results_list;
}
} else {
results_list.push(stored_intervals[i].clone())
}
}
results_list
}
pub fn len(&self) -> usize {
self.starts.len()
}
pub fn is_empty(&self) -> bool {
self.starts.is_empty()
}
}
#[derive(Debug)]
pub struct IterFind<'a, I, T>
where
T: Eq + Clone + Send + Sync + 'a,
I: PrimInt + Unsigned + Send + Sync,
{
inner: &'a AIList<I, T>,
header_list_idx: usize,
list_idx: Option<usize>,
start: I,
stop: I,
}
impl<'a, I, T> IterFind<'a, I, T>
where
I: PrimInt + Unsigned + Send + Sync + 'a,
T: Eq + Clone + Send + Sync,
{
fn new(ailist: &'a AIList<I, T>, start: I, stop: I) -> Self {
Self {
inner: ailist,
header_list_idx: 0,
list_idx: None,
start,
stop,
}
}
}
impl<'a, I, T> Iterator for IterFind<'a, I, T>
where
I: PrimInt + Unsigned + Send + Sync,
T: Eq + Clone + Send + Sync + 'a,
{
type Item = &'a Interval<I, T>;
fn next(&mut self) -> Option<Self::Item> {
while self.header_list_idx < self.inner.header_list.len() {
let range = if self.header_list_idx == self.inner.header_list.len() - 1 {
self.inner.header_list[self.header_list_idx]..self.inner.starts.len()
} else {
self.inner.header_list[self.header_list_idx]
..self.inner.header_list[self.header_list_idx + 1]
};
let starts = &self.inner.starts[range.clone()];
let ends = &self.inner.ends[range.clone()];
let max_ends = &self.inner.max_ends[range.clone()];
let stored_intervalss = &self.inner.stored_intervals[range.clone()];
let i = if let Some(list_idx) = self.list_idx.as_mut() {
list_idx
} else {
self.list_idx = Some(starts.partition_point(|&x| x < self.stop));
self.list_idx.as_mut().unwrap()
};
while *i > 0 {
*i -= 1;
if self.start >= ends[*i] {
if self.start > max_ends[*i] {
break;
}
} else {
return Some(&stored_intervalss[*i]);
}
}
self.list_idx = None;
self.header_list_idx += 1;
}
None
}
}
#[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 = AIList::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 = AIList::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 = AIList::build(intervals);
let results = ailist.find(13, 15);
assert_eq!(results.is_empty(), true);
}
#[rstest]
fn test_empty_ailist() {
let ailist: AIList<u32, &str> = AIList::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);
}
#[rstest]
fn test_find_iter_overlapping_intervals(intervals: Vec<Interval<u32, &'static str>>) {
let ailist = AIList::build(intervals);
let results: Vec<&Interval<u32, &str>> = ailist.find_iter(2, 4).collect();
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);
assert_eq!(results.len(), 2);
let results: Vec<&Interval<u32, &str>> = ailist.find_iter(9, 11).collect();
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);
assert_eq!(results.len(), 2);
}
#[rstest]
fn test_find_iter_no_overlap(intervals: Vec<Interval<u32, &'static str>>) {
let ailist = AIList::build(intervals);
let results: Vec<&Interval<u32, &str>> = ailist.find_iter(13, 15).collect();
assert_eq!(results.is_empty(), true);
let results: Vec<&Interval<u32, &str>> = ailist.find_iter(0, 1).collect();
assert_eq!(results.is_empty(), true);
}
#[rstest]
fn test_find_iter_empty_ailist() {
let ailist: AIList<u32, &str> = AIList::build(vec![]);
let results: Vec<&Interval<u32, &str>> = ailist.find_iter(1, 2).collect();
assert_eq!(results.is_empty(), true);
}
#[rstest]
fn test_find_iter_matches_find(intervals: Vec<Interval<u32, &'static str>>) {
let ailist = AIList::build(intervals);
let test_queries = vec![(2, 4), (5, 8), (9, 11), (0, 15), (7, 9)];
for (start, end) in test_queries {
let find_results = ailist.find(start, end);
let find_iter_results: Vec<&Interval<u32, &str>> =
ailist.find_iter(start, end).collect();
assert_eq!(
find_results.len(),
find_iter_results.len(),
"Mismatch in number of results for query ({}, {})",
start,
end
);
for interval in &find_results {
assert!(
find_iter_results.contains(&interval),
"Interval {interval:?} from find() not found in find_iter() results",
);
}
}
}
#[rstest]
fn test_find_iter_single_interval() {
let intervals = vec![Interval {
start: 5,
end: 10,
val: "single",
}];
let ailist = AIList::build(intervals);
let results: Vec<&Interval<u32, &str>> = ailist.find_iter(6, 8).collect();
assert_eq!(results.len(), 1);
assert_eq!(results[0].val, "single");
let results: Vec<&Interval<u32, &str>> = ailist.find_iter(11, 15).collect();
assert_eq!(results.is_empty(), true);
}
#[rstest]
fn test_find_iter_complex_interval() {
let iv = |start: usize, end: usize| -> Interval<usize, ()> {
Interval {
start,
end,
val: (),
}
};
let intervals = vec![
iv(0, 30), iv(0, 10),
iv(0, 10),
iv(5, 15),
iv(5, 15),
iv(10, 20),
iv(10, 20),
iv(15, 25),
iv(15, 25),
iv(21, 22),
iv(22, 23),
iv(20, 30),
iv(20, 30),
iv(25, 100), iv(26, 27),
iv(27, 28),
iv(29, 30),
iv(30, 31),
iv(32, 33),
iv(50, 51),
iv(51, 52),
iv(52, 53),
iv(53, 54),
iv(55, 56),
iv(60, 61),
iv(70, 71),
];
let ailist = AIList::build(intervals);
assert_eq!(ailist.header_list.len(), 2);
let results: Vec<&Interval<usize, ()>> = ailist.find_iter(6, 8).collect();
assert_eq!(results.len(), 5);
let results: Vec<&Interval<usize, ()>> = ailist.find_iter(30, 35).collect();
assert_eq!(results.len(), 3);
let results: Vec<&Interval<usize, ()>> = ailist.find_iter(101, 150).collect();
assert_eq!(results.is_empty(), true);
}
}