use std::{cmp::Ordering, mem, ptr};
use index_list::IndexList;
pub use index_list::Index;
pub struct CutoffList<T> {
cutoff_positions: Vec<usize>,
following_ind: Vec<Index>,
list: IndexList<Entry<T>>,
}
struct Entry<T> {
value: T,
preceding_cutoffs: usize,
}
impl<T> CutoffList<T> {
pub fn new(cutoff_positions: Vec<usize>) -> Self {
assert!(
cutoff_positions.is_sorted(),
"{:?} is not sorted",
cutoff_positions
);
Self {
following_ind: vec![Index::new(); cutoff_positions.len()],
cutoff_positions,
list: IndexList::new(),
}
}
#[inline]
pub fn is_empty(&self) -> bool {
self.list.is_empty()
}
#[inline]
pub fn len(&self) -> usize {
self.list.len()
}
pub fn insert_first(&mut self, value: T) -> Index {
let new_last_pos = self.list.len();
let preceding_cutoffs = self.count_leading_zeros();
let new_index = self.list.insert_first(Entry {
value,
preceding_cutoffs,
});
let mut iter = self
.cutoff_positions
.iter()
.zip(self.following_ind.iter_mut());
for _ in 0..preceding_cutoffs {
let (_, ind) = iter.next().unwrap();
*ind = new_index;
}
for (p, ind) in iter {
if ind.is_some() {
assert!(*p < new_last_pos);
*ind = self.list.prev_index(*ind);
} else if *p == new_last_pos {
*ind = self.list.last_index();
} else {
assert!(*p > new_last_pos);
break;
}
let preceding_cutoffs = &mut self.list.get_mut(*ind).unwrap().preceding_cutoffs;
assert!(ptr::eq(p, &self.cutoff_positions[*preceding_cutoffs]));
*preceding_cutoffs += 1;
}
new_index
}
pub fn insert_last(&mut self, value: T) -> Index {
let mut preceding_cutoffs = 0;
let mut at_q = None;
let new_pos = self.list.len();
for (q, &cutoff) in self.cutoff_positions.iter().enumerate() {
match cutoff.cmp(&new_pos) {
Ordering::Less => {}
Ordering::Equal => {
at_q.get_or_insert(q);
}
Ordering::Greater => break,
}
preceding_cutoffs += 1;
}
let new_index = self.list.insert_last(Entry {
value,
preceding_cutoffs,
});
if let Some(q) = at_q {
for (&cutoff, ind) in self.cutoff_positions[q..]
.iter()
.zip(self.following_ind[q..].iter_mut())
{
assert!(ind.is_none());
if cutoff == new_pos {
*ind = new_index;
} else {
assert!(cutoff > new_pos);
break;
}
}
}
new_index
}
pub fn shift_to_front(&mut self, ind: Index) {
let prev_ind = self.list.prev_index(ind);
if prev_ind.is_none() {
return;
}
let leading_zeros = self.count_leading_zeros();
let preceding_cutoffs = mem::replace(
&mut self.list.get_mut(ind).unwrap().preceding_cutoffs,
leading_zeros,
);
let shifted = self.list.shift_index_to_front(ind);
assert!(shifted);
let mut iter = self.following_ind.iter_mut();
for _ in 0..leading_zeros {
*iter.next().unwrap() = ind;
}
for _ in leading_zeros..preceding_cutoffs {
let cutoff_ind = iter.next().unwrap();
if *cutoff_ind == ind {
*cutoff_ind = prev_ind;
} else {
assert!(cutoff_ind.is_some());
*cutoff_ind = self.list.prev_index(*cutoff_ind);
}
let preceding_cutoffs = &mut self.list.get_mut(*cutoff_ind).unwrap().preceding_cutoffs;
*preceding_cutoffs += 1;
}
}
pub fn remove(&mut self, index: Index) -> Option<T> {
let next_index = self.list.next_index(index);
let removed = self.list.remove(index)?;
let preceding_cutoffs = removed.preceding_cutoffs;
let (before, after) = self.following_ind.split_at_mut(preceding_cutoffs);
for ind in before.iter_mut().rev() {
if *ind == index {
*ind = next_index;
} else {
break;
}
}
for ind in after.iter_mut() {
if ind.is_none() {
break;
}
self.list.get_mut(*ind).unwrap().preceding_cutoffs -= 1;
*ind = self.list.next_index(*ind);
}
Some(removed.value)
}
#[inline]
fn count_leading_zeros(&mut self) -> usize {
self.cutoff_positions
.iter()
.take_while(|&&cutoff| cutoff == 0)
.count()
}
#[inline]
pub fn preceding_cutoffs(&self, ind: Index) -> Option<usize> {
self.list.get(ind).map(|entry| entry.preceding_cutoffs)
}
#[inline]
pub fn following_ind(&self, q: usize) -> Index {
self.following_ind.get(q).copied().unwrap_or_default()
}
#[inline]
pub fn get(&self, ind: Index) -> Option<&T> {
self.list.get(ind).map(|entry| &entry.value)
}
#[inline]
pub fn first_index(&self) -> Index {
self.list.first_index()
}
#[inline]
pub fn next_index(&self, ind: Index) -> Index {
self.list.next_index(ind)
}
#[cfg(test)]
fn validate(&self) {
assert_eq!(self.following_ind.len(), self.cutoff_positions.len());
assert!(self.cutoff_positions.is_sorted());
let mut idx = self.list.first_index();
let mut pos_pass1 = 0; let mut calculated_list_len = 0;
while idx.is_some() {
let entry = self.list.get(idx).unwrap();
let expected_prec_cutoffs = self.cutoff_positions.partition_point(|&c| c <= pos_pass1);
assert_eq!(entry.preceding_cutoffs, expected_prec_cutoffs);
idx = self.list.next_index(idx);
pos_pass1 += 1;
calculated_list_len = pos_pass1;
}
assert_eq!(calculated_list_len, self.list.len());
let mut list_node_idx = self.list.first_index();
let mut list_node_pos = 0;
for q in 0..self.cutoff_positions.len() {
let cutoff_pos = self.cutoff_positions[q];
let stored_following_idx = self.following_ind[q];
while list_node_idx.is_some() && list_node_pos < cutoff_pos {
list_node_idx = self.list.next_index(list_node_idx);
list_node_pos += 1;
}
let actual_following_idx = list_node_idx;
assert_eq!(stored_following_idx, actual_following_idx);
}
}
}
#[cfg(test)]
mod tests;