use crate::error::{Error, Result};
use crate::identical::Identical;
use crate::rle::{Rle, RleRef};
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub enum Keep {
#[default]
First,
Last,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct MergePlan {
pub ends: Vec<i64>,
pub offsets: Vec<usize>,
}
impl MergePlan {
pub fn num_groups(&self) -> usize {
self.ends.len()
}
pub fn group_ids(&self) -> Vec<usize> {
let mut ids = Vec::with_capacity(self.offsets.last().copied().unwrap_or(0));
for (group, bounds) in self.offsets.windows(2).enumerate() {
ids.extend(std::iter::repeat_n(group, bounds[1] - bounds[0]));
}
ids
}
}
fn check_mask(num_runs: usize, mask: &[bool]) -> Result<()> {
let expected = num_runs.saturating_sub(1);
if mask.len() != expected {
return Err(Error::LengthMismatch {
what: "merge mask and neighbouring run pairs",
left: mask.len(),
right: expected,
});
}
Ok(())
}
pub fn merge_plan(ends: &[i64], mask: &[bool]) -> Result<MergePlan> {
check_mask(ends.len(), mask)?;
let mut out = MergePlan {
ends: Vec::new(),
offsets: vec![0],
};
for (r, &end) in ends.iter().enumerate() {
if mask.get(r).copied().unwrap_or(false) {
continue;
}
out.ends.push(end);
out.offsets.push(r + 1);
}
Ok(out)
}
pub(crate) fn is_merged<V: Identical>(values: &[V]) -> bool {
values.windows(2).all(|w| !w[0].identical(&w[1]))
}
pub(crate) fn merged<V: Clone + Identical>(rle: RleRef<'_, V>) -> Rle<V> {
let mut out = Rle::new();
for (&end, value) in rle.ends.iter().zip(rle.values) {
out.push_merged(end, value.clone());
}
out
}
impl<V> Rle<V> {
pub fn merge(self) -> Self
where
V: Identical,
{
self.merge_where(|values, w, r| values[w].identical(&values[r]), Keep::First)
}
pub fn merge_by<F: FnMut(&V, &V) -> bool>(self, mut pred: F) -> Self {
let mask: Vec<bool> = self.values.windows(2).map(|w| pred(&w[0], &w[1])).collect();
self.merge_mask(&mask, Keep::First)
.expect("the mask has one entry per neighbouring pair")
}
pub fn merge_mask(self, mask: &[bool], keep: Keep) -> Result<Self> {
check_mask(self.ends.len(), mask)?;
Ok(self.merge_where(|_, _, r| mask[r - 1], keep))
}
fn merge_where<F>(mut self, mut join: F, keep: Keep) -> Self
where
F: FnMut(&[V], usize, usize) -> bool,
{
if self.ends.is_empty() {
return self;
}
let mut w = 0;
for r in 1..self.ends.len() {
if join(&self.values, w, r) {
self.ends[w] = self.ends[r];
if keep == Keep::Last {
self.values.swap(w, r);
}
} else {
w += 1;
self.ends[w] = self.ends[r];
self.values.swap(w, r);
}
}
self.ends.truncate(w + 1);
self.values.truncate(w + 1);
self
}
}