#[cfg(test)]
mod membership_queries_tests;
#[cfg(test)]
mod statistics_tests;
use int_interval::U32CO;
#[derive(Clone, Debug, Default, PartialEq, Eq)]
#[repr(transparent)]
pub struct U32COBatchSet(Vec<U32CO>);
impl U32COBatchSet {
#[inline]
pub fn into_inner(self) -> Vec<U32CO> {
self.0
}
#[inline]
pub fn as_slice(&self) -> &[U32CO] {
&self.0
}
}
impl U32COBatchSet {
#[inline]
pub fn contains_interval(&self, iv: U32CO) -> bool {
let slice = self.as_slice();
let i = slice.partition_point(|seg| seg.start() <= iv.start());
i > 0 && slice[i - 1].contains_interval(iv)
}
#[inline]
pub fn contains_point(&self, x: u32) -> bool {
let slice = self.as_slice();
let i = slice.partition_point(|seg| seg.start() <= x);
i > 0 && slice[i - 1].contains(x)
}
#[inline]
pub fn interval_containing_point(&self, x: u32) -> Option<U32CO> {
let slice = self.as_slice();
let i = slice.partition_point(|seg| seg.start() <= x);
if i == 0 {
return None;
}
let iv = slice[i - 1];
iv.contains(x).then_some(iv)
}
#[inline]
pub fn intersects(&self, q: U32CO) -> bool {
let slice = self.as_slice();
let i = slice.partition_point(|seg| seg.start() < q.end_excl());
if i == 0 {
return false;
}
let mut j = i - 1;
while j < slice.len() {
let iv = slice[j];
if iv.start() >= q.end_excl() {
break;
}
if iv.intersects(q) {
return true;
}
j += 1;
}
false
}
}
impl U32COBatchSet {
#[inline]
pub fn iter_intervals(&self) -> impl Iterator<Item = U32CO> {
self.as_slice().iter().copied()
}
#[inline]
pub fn iter_points(&self) -> impl Iterator<Item = u32> {
self.iter_intervals().flat_map(U32CO::iter)
}
}
impl U32COBatchSet {
#[inline]
pub fn interval_count(&self) -> u32 {
self.0.len() as u32
}
#[inline]
pub fn point_count(&self) -> u32 {
self.0.iter().map(|iv| iv.len()).sum()
}
#[inline]
pub fn coverage_len_of(&self, q: U32CO) -> u32 {
let slice = self.as_slice();
let mut i = slice.partition_point(|seg| seg.start() < q.start());
i = i.saturating_sub(1);
let mut acc = 0u32;
while i < slice.len() {
let iv = slice[i];
if iv.start() >= q.end_excl() {
break;
}
if let Some(overlap) = iv.intersection(q) {
acc += overlap.len();
}
i += 1;
}
acc
}
#[inline]
pub fn coverage_ratio_of(&self, q: U32CO) -> f32 {
self.coverage_len_of(q) as f32 / q.len() as f32
}
}
mod construction {
use super::*;
#[inline]
fn normalize(mut xs: Vec<U32CO>) -> Vec<U32CO> {
if xs.len() <= 1 {
return xs;
}
xs.sort_unstable_by(|a, b| {
a.start()
.cmp(&b.start())
.then(a.end_excl().cmp(&b.end_excl()))
});
let mut out = Vec::with_capacity(xs.len());
for iv in xs {
match out.last_mut() {
None => out.push(iv),
Some(last) => {
if last.is_contiguous_with(iv) {
*last = last.convex_hull(iv);
} else {
out.push(iv);
}
}
}
}
out
}
impl From<Vec<U32CO>> for U32COBatchSet {
#[inline]
fn from(value: Vec<U32CO>) -> Self {
Self(normalize(value))
}
}
impl<const N: usize> From<[U32CO; N]> for U32COBatchSet {
#[inline]
fn from(value: [U32CO; N]) -> Self {
Self::from(Vec::from(value))
}
}
impl FromIterator<U32CO> for U32COBatchSet {
#[inline]
fn from_iter<T: IntoIterator<Item = U32CO>>(iter: T) -> Self {
Self::from(iter.into_iter().collect::<Vec<_>>())
}
}
}