use std::ops::Range;
pub(super) struct Partition<K, V> {
keys: Vec<K>,
vals: Vec<V>,
}
impl<K, V> Default for Partition<K, V> {
fn default() -> Self {
Self {
keys: Vec::new(),
vals: Vec::new(),
}
}
}
impl<K: Ord + Copy, V> Partition<K, V> {
pub(super) const fn is_empty(&self) -> bool {
self.keys.is_empty()
}
pub(super) const fn len(&self) -> usize {
self.keys.len()
}
pub(super) fn drain_runs(&mut self) -> Vec<(K, Vec<V>)> {
let keys = std::mem::take(&mut self.keys);
let vals = std::mem::take(&mut self.vals);
let mut vals = vals.into_iter();
let mut runs = Vec::new();
let mut i = 0;
while i < keys.len() {
let key = keys[i];
let mut j = i + 1;
while j < keys.len() && keys[j] == key {
j += 1;
}
runs.push((key, vals.by_ref().take(j - i).collect()));
i = j;
}
runs
}
fn lower_bound(&self, key: &K) -> usize {
self.keys.partition_point(|k| k < key)
}
fn run_starting_at(&self, idx: usize) -> Range<usize> {
let key = self.keys[idx];
let mut end = idx + 1;
while end < self.keys.len() && self.keys[end] == key {
end += 1;
}
idx..end
}
fn run_ending_at(&self, idx: usize) -> Range<usize> {
let key = self.keys[idx];
let mut start = idx;
while start > 0 && self.keys[start - 1] == key {
start -= 1;
}
start..idx + 1
}
pub(super) fn run_range(&self, key: &K) -> Range<usize> {
let start = self.lower_bound(key);
if self.keys.get(start) != Some(key) {
return start..start;
}
let mut end = start + 1;
while end < self.keys.len() && self.keys[end] == *key {
end += 1;
}
start..end
}
pub(super) fn values(&self, key: &K) -> &[V] {
&self.vals[self.run_range(key)]
}
pub(super) fn value_at(&self, idx: usize) -> &V {
&self.vals[idx]
}
pub(super) fn insert_at(&mut self, idx: usize, key: K, value: V) {
self.keys.insert(idx, key);
self.vals.insert(idx, value);
}
pub(super) fn remove(&mut self, idx: usize) -> V {
self.keys.remove(idx);
self.vals.remove(idx)
}
pub(super) fn remove_run(&mut self, range: Range<usize>) {
self.keys.drain(range.clone());
self.vals.drain(range);
}
pub(super) fn set(&mut self, idx: usize, value: V) {
self.vals[idx] = value;
}
pub(super) fn first_values(&self) -> Option<&[V]> {
if self.keys.is_empty() {
return None;
}
Some(&self.vals[self.run_starting_at(0)])
}
pub(super) fn last_values(&self) -> Option<&[V]> {
let last = self.keys.len().checked_sub(1)?;
Some(&self.vals[self.run_ending_at(last)])
}
pub(super) fn next_values_after(&self, key: &K) -> Option<&[V]> {
let idx = self.keys.partition_point(|k| *k <= *key);
if idx >= self.keys.len() {
return None;
}
Some(&self.vals[self.run_starting_at(idx)])
}
pub(super) fn prev_values_before(&self, key: &K) -> Option<&[V]> {
let prev = self.lower_bound(key).checked_sub(1)?;
Some(&self.vals[self.run_ending_at(prev)])
}
}
#[cfg(test)]
mod tests {
use super::*;
fn insert<K: Ord + Copy, V>(p: &mut Partition<K, V>, key: K, value: V) {
let end = p.run_range(&key).end;
p.insert_at(end, key, value);
}
#[test]
fn test_partition_empty() {
let p = Partition::<u16, u64>::default();
assert_eq!(p.values(&5), &[] as &[u64]);
assert_eq!(p.run_range(&5), 0..0);
assert!(p.first_values().is_none());
assert!(p.last_values().is_none());
assert!(p.next_values_after(&5).is_none());
assert!(p.prev_values_before(&5).is_none());
}
#[test]
fn test_partition_sorted_insert() {
let mut p = Partition::<u16, u64>::default();
for (k, v) in [(30u16, 300u64), (10, 100), (20, 200)] {
insert(&mut p, k, v);
}
assert_eq!(p.keys, vec![10, 20, 30]);
assert_eq!(p.vals, vec![100, 200, 300]);
assert_eq!(p.first_values(), Some(&[100u64] as &[u64]));
assert_eq!(p.last_values(), Some(&[300u64] as &[u64]));
assert_eq!(p.values(&20), &[200]);
assert_eq!(p.values(&25), &[] as &[u64]);
}
#[test]
fn test_partition_navigation() {
let mut p = Partition::<u16, u64>::default();
for (k, v) in [(10u16, 100u64), (20, 200), (20, 222), (30, 300)] {
insert(&mut p, k, v);
}
assert_eq!(p.next_values_after(&5), Some(&[100u64] as &[u64]));
assert_eq!(p.next_values_after(&10), Some(&[200u64, 222] as &[u64]));
assert_eq!(p.next_values_after(&20), Some(&[300u64] as &[u64]));
assert!(p.next_values_after(&30).is_none());
assert!(p.prev_values_before(&10).is_none());
assert_eq!(p.prev_values_before(&20), Some(&[100u64] as &[u64]));
assert_eq!(p.prev_values_before(&25), Some(&[200u64, 222] as &[u64]));
assert_eq!(p.prev_values_before(&999), Some(&[300u64] as &[u64]));
}
#[test]
fn test_partition_collision_run_append_order() {
let mut p = Partition::<u16, u64>::default();
insert(&mut p, 10, 1);
insert(&mut p, 20, 2);
insert(&mut p, 10, 11);
insert(&mut p, 10, 111);
assert_eq!(p.values(&10), &[1, 11, 111]);
assert_eq!(p.values(&20), &[2]);
assert_eq!(p.keys, vec![10, 10, 10, 20]);
assert_eq!(p.run_range(&10), 0..3);
assert_eq!(p.run_range(&20), 3..4);
}
#[test]
fn test_partition_remove_keeps_alignment() {
let mut p = Partition::<u16, u64>::default();
for (k, v) in [(10u16, 1u64), (10, 11), (20, 2)] {
insert(&mut p, k, v);
}
let removed = p.remove(1);
assert_eq!(removed, 11);
assert_eq!(p.keys, vec![10, 20]);
assert_eq!(p.vals, vec![1, 2]);
assert_eq!(p.values(&10), &[1]);
}
#[test]
fn test_partition_set() {
let mut p = Partition::<u16, u64>::default();
insert(&mut p, 10, 1);
p.set(0, 99);
assert_eq!(p.values(&10), &[99]);
}
#[test]
fn test_partition_drain_runs() {
let mut p = Partition::<u16, u64>::default();
for (k, v) in [(10u16, 1u64), (20, 2), (10, 11), (10, 111)] {
insert(&mut p, k, v);
}
assert_eq!(p.len(), 4);
let runs = p.drain_runs();
assert_eq!(runs, vec![(10, vec![1, 11, 111]), (20, vec![2])]);
assert!(p.is_empty());
assert_eq!(p.len(), 0);
}
}