#![doc = include_str!("../README.mkd")]
#[derive(Debug)]
pub struct PrefixSumVec<T, Idx = usize> {
indices: Vec<Idx>,
values: Vec<T>,
}
impl<T, Idx> PrefixSumVec<T, Idx> {
pub fn new() -> Self {
Self {
indices: vec![],
values: vec![],
}
}
pub fn clear(&mut self) {
self.indices.clear();
self.values.clear();
}
pub fn max_index(&self) -> Option<&Idx> {
self.indices.last()
}
fn grow_if_necessary(&mut self) -> Result<(), std::collections::TryReserveError> {
if self.values.len() == self.values.capacity() {
self.values.try_reserve(1)?;
}
if self.indices.len() == self.indices.capacity() {
self.values.try_reserve(1)?;
}
Ok(())
}
}
impl<T, Idx: Ord> PrefixSumVec<T, Idx> {
pub fn get(&self, index: &Idx) -> Option<&T> {
match self.indices.binary_search(index) {
Ok(i) | Err(i) => self.values.get(i),
}
}
}
impl<T, Idx: Index> PrefixSumVec<T, Idx> {
fn new_index(&self, additional_count: Idx) -> Result<Idx, TryPushError> {
match self.max_index() {
Some(current_max) => additional_count
.checked_add(current_max)
.ok_or(TryPushError::Overflow),
None => Ok(additional_count.decrement()),
}
}
pub fn try_push_many(&mut self, count: Idx, value: T) -> Result<(), TryPushError> {
if count.is_zero() {
return Ok(());
}
let new_index = self.new_index(count)?;
self.grow_if_necessary().map_err(TryPushError::Reserve)?;
self.indices.push(new_index);
self.values.push(value);
Ok(())
}
}
impl<T: PartialEq, Idx: Index> PrefixSumVec<T, Idx> {
pub fn try_push_more(&mut self, count: Idx, value: T) -> Result<(), TryPushError> {
if count.is_zero() {
return Ok(());
}
if let Some(lastval) = self.values.last_mut() {
if PartialEq::eq(&*lastval, &value) {
let new_index = self.new_index(count)?;
let old_index = self.indices.pop();
self.indices.push(new_index);
drop(old_index);
return Ok(());
}
}
self.try_push_many(count, value)
}
}
pub trait Index: Sized {
fn is_zero(&self) -> bool;
fn decrement(self) -> Self;
fn checked_add(self, other: &Self) -> Option<Self>;
}
macro_rules! impl_primitive_index {
($($ty: ty),*) => {
$(impl Index for $ty {
fn is_zero(&self) -> bool { *self == 0 }
fn decrement(self) -> Self { self - 1 }
fn checked_add(self, other: &Self) -> Option<Self> { self.checked_add(*other) }
})*
}
}
impl_primitive_index!(u8, u16, u32, u64, u128, usize);
impl_primitive_index!(i8, i16, i32, i64, i128, isize);
impl<K, Idx: Ord> std::ops::Index<Idx> for PrefixSumVec<K, Idx> {
type Output = K;
fn index(&self, index: Idx) -> &Self::Output {
self.get(&index).expect("index out of range")
}
}
impl<K, Idx: Ord> std::ops::Index<&Idx> for PrefixSumVec<K, Idx> {
type Output = K;
fn index(&self, index: &Idx) -> &Self::Output {
self.get(index).expect("index out of range")
}
}
#[non_exhaustive]
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum TryPushError {
Reserve(std::collections::TryReserveError),
Overflow,
}
impl std::error::Error for TryPushError {}
impl std::fmt::Display for TryPushError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
TryPushError::Reserve(_) => "could not reserve additional capacity",
TryPushError::Overflow => "the index type overflowed",
})
}
}
pub struct CompressedIter<'a, T, Idx> {
inner: std::iter::Zip<std::slice::Iter<'a, Idx>, std::slice::Iter<'a, T>>,
}
impl<'a, T, Idx> Iterator for CompressedIter<'a, T, Idx> {
type Item = (&'a Idx, &'a T);
fn next(&mut self) -> Option<Self::Item> {
self.inner.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
fn count(self) -> usize {
self.inner.count()
}
fn last(self) -> Option<Self::Item> {
self.inner.last()
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
self.inner.nth(n)
}
fn for_each<F: FnMut(Self::Item)>(self, f: F) {
self.inner.for_each(f)
}
fn collect<B: std::iter::FromIterator<Self::Item>>(self) -> B {
self.inner.collect()
}
fn partition<B, F>(self, f: F) -> (B, B)
where
B: Default + Extend<Self::Item>,
F: FnMut(&Self::Item) -> bool,
{
self.inner.partition(f)
}
fn fold<B, F>(self, init: B, f: F) -> B
where
F: FnMut(B, Self::Item) -> B,
{
self.inner.fold(init, f)
}
fn reduce<F>(self, f: F) -> Option<Self::Item>
where
F: FnMut(Self::Item, Self::Item) -> Self::Item,
{
self.inner.reduce(f)
}
fn all<F>(&mut self, f: F) -> bool
where
F: FnMut(Self::Item) -> bool,
{
self.inner.all(f)
}
fn any<F: FnMut(Self::Item) -> bool>(&mut self, f: F) -> bool {
self.inner.any(f)
}
fn find<P: FnMut(&Self::Item) -> bool>(&mut self, predicate: P) -> Option<Self::Item> {
self.inner.find(predicate)
}
fn find_map<B, F: FnMut(Self::Item) -> Option<B>>(&mut self, f: F) -> Option<B> {
self.inner.find_map(f)
}
fn position<P: FnMut(Self::Item) -> bool>(&mut self, predicate: P) -> Option<usize> {
self.inner.position(predicate)
}
fn rposition<P: FnMut(Self::Item) -> bool>(&mut self, predicate: P) -> Option<usize> {
self.inner.rposition(predicate)
}
fn max(self) -> Option<Self::Item>
where
Self::Item: Ord,
{
self.inner.max()
}
fn min(self) -> Option<Self::Item>
where
Self::Item: Ord,
{
self.inner.min()
}
fn max_by_key<B: Ord, F: FnMut(&Self::Item) -> B>(self, f: F) -> Option<Self::Item> {
self.inner.max_by_key(f)
}
fn max_by<F>(self, compare: F) -> Option<Self::Item>
where
F: FnMut(&Self::Item, &Self::Item) -> std::cmp::Ordering,
{
self.inner.max_by(compare)
}
fn min_by_key<B: Ord, F: FnMut(&Self::Item) -> B>(self, f: F) -> Option<Self::Item> {
self.inner.min_by_key(f)
}
fn min_by<F>(self, compare: F) -> Option<Self::Item>
where
F: FnMut(&Self::Item, &Self::Item) -> std::cmp::Ordering,
{
self.inner.min_by(compare)
}
fn sum<S: std::iter::Sum<Self::Item>>(self) -> S {
self.inner.sum()
}
fn product<P: std::iter::Product<Self::Item>>(self) -> P {
self.inner.product()
}
fn cmp<I>(self, other: I) -> std::cmp::Ordering
where
I: IntoIterator<Item = Self::Item>,
Self::Item: Ord,
{
self.inner.cmp(other)
}
fn partial_cmp<I>(self, other: I) -> Option<std::cmp::Ordering>
where
I: IntoIterator,
Self::Item: PartialOrd<I::Item>,
{
self.inner.partial_cmp(other)
}
fn eq<I>(self, other: I) -> bool
where
I: IntoIterator,
Self::Item: PartialEq<I::Item>,
{
self.inner.eq(other)
}
fn ne<I>(self, other: I) -> bool
where
I: IntoIterator,
Self::Item: PartialEq<I::Item>,
{
self.inner.ne(other)
}
fn lt<I>(self, other: I) -> bool
where
I: IntoIterator,
Self::Item: PartialOrd<I::Item>,
{
self.inner.lt(other)
}
fn le<I>(self, other: I) -> bool
where
I: IntoIterator,
Self::Item: PartialOrd<I::Item>,
Self: Sized,
{
self.inner.le(other)
}
fn gt<I>(self, other: I) -> bool
where
I: IntoIterator,
Self::Item: PartialOrd<I::Item>,
{
self.inner.gt(other)
}
fn ge<I>(self, other: I) -> bool
where
I: IntoIterator,
Self::Item: PartialOrd<I::Item>,
{
self.inner.ge(other)
}
}
impl<'a, T, Idx> DoubleEndedIterator for CompressedIter<'a, T, Idx> {
fn next_back(&mut self) -> Option<Self::Item> {
self.inner.next_back()
}
}
impl<'a, T, Idx> ExactSizeIterator for CompressedIter<'a, T, Idx> {
fn len(&self) -> usize {
self.inner.len()
}
}
impl<'a, T, Idx> std::iter::FusedIterator for CompressedIter<'a, T, Idx> {}
impl<'a, T, Idx> CompressedIter<'a, T, Idx> {
#[allow(dead_code)]
fn _assert_fused_iterator(mut self) {
fn is_fused<T: std::iter::FusedIterator>(_: T) {}
is_fused(&mut self.inner);
}
}
impl<'a, T, Idx> IntoIterator for &'a PrefixSumVec<T, Idx> {
type Item = (&'a Idx, &'a T);
type IntoIter = CompressedIter<'a, T, Idx>;
fn into_iter(self) -> Self::IntoIter {
CompressedIter {
inner: self.indices.iter().zip(self.values.iter()),
}
}
}
#[cfg(test)]
mod tests {
use super::{PrefixSumVec, TryPushError};
#[test]
fn empty_partial_map() {
let map = PrefixSumVec::<u32, u32>::new();
assert_eq!(None, map.get(&0));
assert_eq!(None, map.max_index());
}
#[test]
fn basic_function() {
let mut map = PrefixSumVec::<u32, u32>::new();
assert_eq!(None, map.max_index());
for i in 0..10 {
map.try_push_many(1, i).unwrap();
assert_eq!(Some(&i), map.max_index());
}
for i in 0..10 {
assert_eq!(Some(&i), map.get(&i));
}
assert_eq!(None, map.get(&10));
assert_eq!(None, map.get(&0xFFFF_FFFF));
}
#[test]
fn zero_count() {
let mut map = PrefixSumVec::<u32, u32>::new();
assert_eq!(Ok(()), map.try_push_many(0, 0));
assert_eq!(None, map.max_index());
assert_eq!(Ok(()), map.try_push_many(10, 42));
assert_eq!(Some(&9), map.max_index());
assert_eq!(Ok(()), map.try_push_many(0, 43));
assert_eq!(Some(&9), map.max_index());
}
#[test]
fn close_to_limit() {
let mut map = PrefixSumVec::<u32, u32>::new();
assert_eq!(Ok(()), map.try_push_many(0xFFFF_FFFE, 42));
assert_eq!(Some(&42), map.get(&0xFFFF_FFFD));
assert_eq!(None, map.get(&0xFFFF_FFFE));
assert_eq!(Err(TryPushError::Overflow), map.try_push_many(100, 93));
assert_eq!(Some(&42), map.get(&0xFFFF_FFFD));
assert_eq!(None, map.get(&0xFFFF_FFFE));
assert_eq!(Ok(()), map.try_push_many(1, 322));
assert_eq!(Some(&42), map.get(&0xFFFF_FFFD));
assert_eq!(Some(&322), map.get(&0xFFFF_FFFE));
assert_eq!(None, map.get(&0xFFFF_FFFF));
assert_eq!(Err(TryPushError::Overflow), map.try_push_many(2, 1234));
assert_eq!(Some(&42), map.get(&0xFFFF_FFFD));
assert_eq!(Some(&322), map.get(&0xFFFF_FFFE));
assert_eq!(Some(&0xFFFF_FFFE), map.max_index());
assert_eq!(None, map.get(&0xFFFF_FFFF));
assert_eq!(Ok(()), map.try_push_many(1, 1234));
assert_eq!(Some(&42), map.get(&0xFFFF_FFFD));
assert_eq!(Some(&322), map.get(&0xFFFF_FFFE));
assert_eq!(Some(&0xFFFF_FFFF), map.max_index());
assert_eq!(Some(&1234), map.get(&0xFFFF_FFFF));
assert_eq!(Ok(()), map.try_push_many(0, 12345));
assert_eq!(Err(TryPushError::Overflow), map.try_push_many(1, 12345));
}
#[test]
fn try_push_more() {
let mut map = PrefixSumVec::<u32, u32>::new();
assert_eq!(Ok(()), map.try_push_more(0, 0));
assert_eq!(None, map.max_index());
assert_eq!(Ok(()), map.try_push_more(10, 42));
assert_eq!(Some(&9), map.max_index());
assert_eq!(Ok(()), map.try_push_more(0, 43));
assert_eq!(Some(&9), map.max_index());
assert_eq!(Ok(()), map.try_push_more(10, 42));
assert_eq!(Some(&19), map.max_index());
assert_eq!(Ok(()), map.try_push_more(10, 44));
assert_eq!(Some(&29), map.max_index());
let representation = map.into_iter().map(|(&a, &b)| (a, b)).collect::<Vec<_>>();
assert_eq!(vec![(19, 42), (29, 44)], representation);
}
}