use std::collections::HashMap;
use std::ops::Range;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PhysicalSelection {
ranges: Vec<Range<u32>>,
}
impl PhysicalSelection {
#[allow(dead_code)] pub(crate) fn from_sorted_ranges(ranges: Vec<Range<u32>>) -> Self {
debug_assert!(
ranges.iter().all(|r| r.start < r.end),
"all ranges must be non-empty"
);
debug_assert!(
ranges.windows(2).all(|w| w[0].end <= w[1].start),
"ranges must be sorted and non-overlapping"
);
Self { ranges }
}
pub fn from_ids(ids: impl IntoIterator<Item = u32>) -> Self {
let mut sorted: Vec<u32> = ids.into_iter().collect();
sorted.sort_unstable();
sorted.dedup();
let mut ranges = Vec::new();
let mut iter = sorted.into_iter();
if let Some(first) = iter.next() {
let mut start = first;
let mut end = first + 1;
for id in iter {
if id == end {
end += 1;
} else {
ranges.push(start..end);
start = id;
end = id + 1;
}
}
ranges.push(start..end);
}
Self { ranges }
}
pub fn ranges(&self) -> &[Range<u32>] {
&self.ranges
}
pub fn row_count(&self) -> usize {
self.ranges.iter().map(|r| (r.end - r.start) as usize).sum()
}
pub fn is_empty(&self) -> bool {
self.ranges.is_empty()
}
pub fn iter_ids(&self) -> impl Iterator<Item = u32> + '_ {
self.ranges.iter().flat_map(Clone::clone)
}
pub fn virtual_order_map(&self, virtual_ids: &[u32]) -> Vec<usize> {
let phys_to_virtual: HashMap<u32, usize> = virtual_ids
.iter()
.enumerate()
.map(|(vi, &pi)| (pi, vi))
.collect();
self.iter_ids()
.map(|phys_id| phys_to_virtual[&phys_id])
.collect()
}
}