2019-09-17 19:28:31 +00:00
|
|
|
use std::collections::BTreeMap;
|
2019-10-20 21:24:44 +00:00
|
|
|
use std::collections::btree_map::{Iter, Keys, Entry};
|
2019-09-17 19:28:31 +00:00
|
|
|
use std::iter::{FromIterator, IntoIterator};
|
2018-12-09 13:28:01 +00:00
|
|
|
|
|
|
|
type Count = i32;
|
|
|
|
|
|
|
|
pub enum Net {
|
|
|
|
PresentToAbsent,
|
|
|
|
AbsentToAbsent,
|
|
|
|
AbsentToPresent,
|
|
|
|
PresentToPresent,
|
|
|
|
}
|
|
|
|
|
2019-10-20 21:24:44 +00:00
|
|
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
2018-12-09 13:28:01 +00:00
|
|
|
// Allows negative counts - a "delta"
|
2019-10-20 13:02:51 +00:00
|
|
|
pub struct BTreeBag<V: std::cmp::Ord> {
|
2019-09-17 19:28:31 +00:00
|
|
|
counts: BTreeMap<V, Count>,
|
2018-12-09 13:28:01 +00:00
|
|
|
}
|
|
|
|
|
2019-10-20 13:02:51 +00:00
|
|
|
impl<V: std::cmp::Ord> std::default::Default for BTreeBag<V> {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self::new()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<V: std::cmp::Ord> BTreeBag<V> {
|
2019-09-17 19:28:31 +00:00
|
|
|
pub fn new() -> BTreeBag<V> {
|
|
|
|
BTreeBag { counts: BTreeMap::new() }
|
2018-12-09 13:28:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn change(&mut self, key: V, delta: Count) -> Net { self._change(key, delta, false) }
|
|
|
|
pub fn change_clamped(&mut self, key: V, delta: Count) -> Net { self._change(key, delta, true) }
|
|
|
|
|
|
|
|
pub fn _change(&mut self, key: V, delta: Count, clamp: bool) -> Net {
|
|
|
|
let old_count = self[&key];
|
|
|
|
let mut new_count = old_count + delta;
|
|
|
|
if clamp { new_count = new_count.max(0) }
|
|
|
|
if new_count == 0 {
|
|
|
|
self.counts.remove(&key);
|
|
|
|
if old_count == 0 { Net::AbsentToAbsent } else { Net::PresentToAbsent }
|
|
|
|
} else {
|
|
|
|
self.counts.insert(key, new_count);
|
|
|
|
if old_count == 0 { Net::AbsentToPresent } else { Net::PresentToPresent }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn clear(&mut self) {
|
|
|
|
self.counts.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn contains_key(&self, key: &V) -> bool {
|
|
|
|
self.counts.contains_key(key)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn is_empty(&self) -> bool {
|
|
|
|
self.counts.is_empty()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn len(&self) -> usize {
|
|
|
|
self.counts.len()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn keys(&self) -> Keys<V, Count> {
|
|
|
|
self.counts.keys()
|
|
|
|
}
|
2019-10-20 21:24:44 +00:00
|
|
|
|
|
|
|
pub fn entry(&mut self, key: V) -> Entry<V, Count> {
|
|
|
|
self.counts.entry(key)
|
|
|
|
}
|
2019-09-17 19:28:31 +00:00
|
|
|
}
|
2018-12-09 13:28:01 +00:00
|
|
|
|
2019-10-20 13:02:51 +00:00
|
|
|
impl<'a, V: std::cmp::Ord> IntoIterator for &'a BTreeBag<V> {
|
2019-09-17 19:28:31 +00:00
|
|
|
type Item = (&'a V, &'a Count);
|
|
|
|
type IntoIter = Iter<'a, V, Count>;
|
|
|
|
|
|
|
|
fn into_iter(self) -> Self::IntoIter {
|
2018-12-09 13:28:01 +00:00
|
|
|
self.counts.iter()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-20 13:02:51 +00:00
|
|
|
impl<V: std::cmp::Ord> FromIterator<V> for BTreeBag<V> {
|
2019-09-17 19:28:31 +00:00
|
|
|
fn from_iter<I: IntoIterator<Item=V>>(iter: I) -> Self {
|
|
|
|
let mut bag = Self::new();
|
|
|
|
for k in iter {
|
|
|
|
bag.change(k, 1);
|
2018-12-09 13:28:01 +00:00
|
|
|
}
|
2019-09-17 19:28:31 +00:00
|
|
|
bag
|
2018-12-09 13:28:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-20 13:02:51 +00:00
|
|
|
impl<V: std::cmp::Ord> std::ops::Index<&V> for BTreeBag<V> {
|
2018-12-09 13:28:01 +00:00
|
|
|
type Output = Count;
|
|
|
|
fn index(&self, i: &V) -> &Count {
|
|
|
|
self.counts.get(i).unwrap_or(&0)
|
|
|
|
}
|
|
|
|
}
|