#[derive(Debug)]
pub struct PartialSumMap<K, V> {
keys: Vec<K>,
values: Vec<V>,
size: K,
}
impl<K: Clone + Ord + num_traits::Unsigned + num_traits::CheckedAdd, V> PartialSumMap<K, V> {
pub fn new() -> Self {
Self { keys: vec![], values: vec![], size: K::zero() }
}
pub fn push(&mut self, count: K, value: V) -> Result<(), Error> {
if count != K::zero() {
self.size = self.size.checked_add(&count).ok_or(Error::Overflow)?;
self.keys.push(self.size.clone() - K::one());
self.values.push(value);
}
Ok(())
}
pub fn max_index(&self) -> Option<K> {
self.keys.last().cloned()
}
pub fn size(&self) -> &K {
&self.size
}
pub fn find(&self, index: K) -> Option<&V> {
match self.keys.binary_search(&index) {
Ok(i) | Err(i) => self.values.get(i),
}
}
}
#[derive(Debug, PartialEq, Eq)]
pub enum Error {
Overflow,
}
impl std::error::Error for Error {}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
Self::Overflow => "partial sum overflow",
})
}
}
#[cfg(test)]
mod tests {
use super::{Error, PartialSumMap};
#[test]
fn empty_partial_map() {
let map = PartialSumMap::<u32, u32>::new();
assert_eq!(None, map.find(0));
assert_eq!(0, *map.size());
}
#[test]
fn basic_function() {
let mut map = PartialSumMap::<u32, u32>::new();
assert_eq!(None, map.max_index());
assert_eq!(0, *map.size());
for i in 0..10 {
map.push(1, i).unwrap();
assert_eq!(Some(i), map.max_index());
assert_eq!(i + 1, *map.size());
}
for i in 0..10 {
assert_eq!(Some(&i), map.find(i));
}
assert_eq!(None, map.find(10));
assert_eq!(None, map.find(0xFFFF_FFFF));
}
#[test]
fn zero_count() {
let mut map = PartialSumMap::<u32, u32>::new();
assert_eq!(Ok(()), map.push(0, 0));
assert_eq!(None, map.max_index());
assert_eq!(0, *map.size());
assert_eq!(Ok(()), map.push(10, 42));
assert_eq!(Some(9), map.max_index());
assert_eq!(10, *map.size());
assert_eq!(Ok(()), map.push(0, 43));
assert_eq!(Some(9), map.max_index());
assert_eq!(10, *map.size());
}
#[test]
fn close_to_limit() {
let mut map = PartialSumMap::<u32, u32>::new();
assert_eq!(Ok(()), map.push(0xFFFF_FFFE, 42)); assert_eq!(Some(&42), map.find(0xFFFF_FFFD));
assert_eq!(None, map.find(0xFFFF_FFFE));
assert_eq!(Err(Error::Overflow), map.push(100, 93)); assert_eq!(Some(&42), map.find(0xFFFF_FFFD));
assert_eq!(None, map.find(0xFFFF_FFFE));
assert_eq!(Ok(()), map.push(1, 322)); assert_eq!(Some(&42), map.find(0xFFFF_FFFD));
assert_eq!(Some(&322), map.find(0xFFFF_FFFE));
assert_eq!(None, map.find(0xFFFF_FFFF));
assert_eq!(Err(Error::Overflow), map.push(1, 1234)); assert_eq!(Some(&42), map.find(0xFFFF_FFFD));
assert_eq!(Some(&322), map.find(0xFFFF_FFFE));
assert_eq!(None, map.find(0xFFFF_FFFF));
}
}