use serde::{Deserialize, Serialize};
use smallvec::SmallVec;
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct ChangeBatch<T, const X: usize = 2> {
updates: SmallVec<[(T, i64); X]>,
clean: usize,
}
impl<T, const X: usize> ChangeBatch<T, X> {
pub fn new() -> Self {
ChangeBatch {
updates: SmallVec::new(),
clean: 0,
}
}
pub fn with_capacity(capacity: usize) -> Self {
ChangeBatch {
updates: SmallVec::with_capacity(capacity),
clean: 0,
}
}
pub fn is_dirty(&self) -> bool {
self.updates.len() > self.clean
}
pub fn unstable_internal_updates(&self) -> &SmallVec<[(T, i64); X]> { &self.updates }
pub fn unstable_internal_clean(&self) -> usize { self.clean }
#[inline]
pub fn clear(&mut self) {
self.updates.clear();
self.clean = 0;
}
}
impl<T, const X: usize> ChangeBatch<T, X>
where
T: Ord,
{
pub fn new_from(key: T, val: i64) -> Self {
let mut result = ChangeBatch::new();
result.update(key, val);
result
}
#[inline]
pub fn update(&mut self, item: T, value: i64) {
self.updates.push((item, value));
self.maintain_bounds();
}
#[inline]
pub fn extend<I: Iterator<Item=(T, i64)>>(&mut self, iterator: I) {
self.updates.extend(iterator);
self.maintain_bounds();
}
pub fn into_inner(mut self) -> SmallVec<[(T, i64); X]> {
self.compact();
self.updates
}
#[inline]
pub fn iter(&mut self) -> std::slice::Iter<'_, (T, i64)> {
self.compact();
self.updates.iter()
}
#[inline]
pub fn drain(&mut self) -> smallvec::Drain<'_, [(T, i64); X]> {
self.compact();
self.clean = 0;
self.updates.drain(..)
}
#[inline]
pub fn is_empty(&mut self) -> bool {
if self.clean > self.updates.len() / 2 {
false
}
else {
self.compact();
self.updates.is_empty()
}
}
#[inline]
pub fn len(&mut self) -> usize {
self.compact();
self.updates.len()
}
#[inline]
pub fn drain_into(&mut self, other: &mut ChangeBatch<T, X>) where T: Clone {
if other.updates.is_empty() {
::std::mem::swap(self, other);
}
else {
other.extend(self.updates.drain(..));
self.clean = 0;
}
}
#[inline]
pub fn compact(&mut self) {
if self.clean < self.updates.len() && self.updates.len() > 1 {
self.updates.sort_unstable_by(|x,y| x.0.cmp(&y.0));
for i in 0 .. self.updates.len() - 1 {
if self.updates[i].0 == self.updates[i+1].0 {
self.updates[i+1].1 += self.updates[i].1;
self.updates[i].1 = 0;
}
}
self.updates.retain(|x| x.1 != 0);
}
self.clean = self.updates.len();
}
fn maintain_bounds(&mut self) {
if self.updates.len() > 32 && self.updates.len() >> 1 >= self.clean {
self.compact()
}
}
}
impl<T, const X: usize> Default for ChangeBatch<T, X> {
fn default() -> Self {
Self::new()
}
}