use std::cmp;
use crate::actions::{ConstructionActions, Trailed, TrailingActions};
#[derive(Clone, Debug)]
pub(crate) struct TrailedPartition {
elems: Vec<usize>,
positions: Vec<usize>,
layout: Vec<Trailed<i64>>,
}
impl TrailedPartition {
pub(crate) fn block_end(&self, root: usize, ctx: &impl TrailingActions) -> usize {
debug_assert_eq!(
self.block_root(self.elems[root], ctx),
root,
"block_end called with a non-root position"
);
ctx.trailed::<i64>(self.layout[root]) as usize
}
pub(crate) fn block_root(&self, elem: usize, ctx: &impl TrailingActions) -> usize {
let pos = self.positions[elem];
let info = ctx.trailed::<i64>(self.layout[pos]) as usize;
cmp::min(info, pos)
}
pub(crate) fn elements(&self) -> &[usize] {
&self.elems
}
pub(crate) fn new<C: ConstructionActions + ?Sized>(ctx: &mut C, n: usize) -> Self {
let layout: Vec<Trailed<i64>> = (0..n)
.map(|i| ctx.new_trailed::<i64>(if i == 0 { n as i64 } else { 0 }))
.collect();
Self {
elems: (0..n).collect(),
positions: (0..n).collect(),
layout,
}
}
pub(crate) fn split_off(
&mut self,
elems: &[usize],
ctx: &mut impl TrailingActions,
) -> (usize, Option<usize>) {
let orig_root = self.block_root(elems[0], ctx);
let orig_end = self.block_end(orig_root, ctx);
debug_assert!(elems.iter().all(|&i| self.block_root(i, ctx) == orig_root));
if elems.len() == (orig_end - orig_root) {
return (orig_root, None);
}
let mut new_end = orig_end;
for &elem in elems {
let pos = self.positions[elem];
let swap_pos = new_end - 1;
let swap_ele = self.elems[swap_pos];
self.elems[pos] = swap_ele;
self.elems[swap_pos] = elem;
self.positions[elem] = swap_pos;
self.positions[swap_ele] = pos;
new_end -= 1;
debug_assert!(new_end >= orig_root);
}
let new_root = new_end;
for &elem in elems {
let pos = self.positions[elem];
let _ = ctx.set_trailed::<i64>(
self.layout[pos],
if pos == new_root {
(new_root + elems.len()) as i64
} else {
new_root as i64
},
);
}
let _ = ctx.set_trailed::<i64>(self.layout[orig_root], new_end as i64);
(orig_root, Some(new_root))
}
}