Document bag.rs
This commit is contained in:
parent
5e5ee0bbdd
commit
1154261062
53
src/bag.rs
53
src/bag.rs
|
@ -2,18 +2,36 @@ use std::collections::BTreeMap;
|
||||||
use std::collections::btree_map::{Iter, Keys, Entry};
|
use std::collections::btree_map::{Iter, Keys, Entry};
|
||||||
use std::iter::{FromIterator, IntoIterator};
|
use std::iter::{FromIterator, IntoIterator};
|
||||||
|
|
||||||
|
/// Element counts in [`BTreeBag`]s are 32-bit signed integers.
|
||||||
pub type Count = i32;
|
pub type Count = i32;
|
||||||
|
|
||||||
|
/// Represents the "net change" to the count of a given `key` after a
|
||||||
|
/// change-in-count has been applied via [`BTreeBag::change`] and
|
||||||
|
/// friends.
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub enum Net {
|
pub enum Net {
|
||||||
|
/// The key previously had non-zero count, now has zero count.
|
||||||
PresentToAbsent,
|
PresentToAbsent,
|
||||||
|
/// The key's count stayed the same, at zero.
|
||||||
AbsentToAbsent,
|
AbsentToAbsent,
|
||||||
|
/// The key previously had zero count, now has non-zero count.
|
||||||
AbsentToPresent,
|
AbsentToPresent,
|
||||||
|
/// The key's count was previously, and is now also, non-zero.
|
||||||
PresentToPresent,
|
PresentToPresent,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A bag datastructure (mapping from values `V` to [`Count`]s
|
||||||
|
/// internally).
|
||||||
|
///
|
||||||
|
/// A bag may have a *negative* count against a particular element.
|
||||||
|
/// Such a bag is called a "delta", and can be used to represent a
|
||||||
|
/// *change* against a bag containing only positive counts.
|
||||||
|
///
|
||||||
|
/// Every value of type `V` notionally has a zero count associated
|
||||||
|
/// with it at the start of the bag's lifetime; so a bag is a *total*
|
||||||
|
/// mapping from elements of `V` to counts.
|
||||||
|
///
|
||||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
// Allows negative counts - a "delta"
|
|
||||||
pub struct BTreeBag<V: std::cmp::Ord> {
|
pub struct BTreeBag<V: std::cmp::Ord> {
|
||||||
counts: BTreeMap<V, Count>,
|
counts: BTreeMap<V, Count>,
|
||||||
total: isize,
|
total: isize,
|
||||||
|
@ -26,13 +44,26 @@ impl<V: std::cmp::Ord> std::default::Default for BTreeBag<V> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V: std::cmp::Ord> BTreeBag<V> {
|
impl<V: std::cmp::Ord> BTreeBag<V> {
|
||||||
|
/// Construct a new, empty bag.
|
||||||
pub fn new() -> BTreeBag<V> {
|
pub fn new() -> BTreeBag<V> {
|
||||||
BTreeBag { counts: BTreeMap::new(), total: 0 }
|
BTreeBag { counts: BTreeMap::new(), total: 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn change(&mut self, key: V, delta: Count) -> Net { self._change(key, delta, false) }
|
/// Apply a change-in-count (`delta`) against `key`, allowing the
|
||||||
pub fn change_clamped(&mut self, key: V, delta: Count) -> Net { self._change(key, delta, true) }
|
/// resulting count to be negative if needed.
|
||||||
|
pub fn change(&mut self, key: V, delta: Count) -> Net {
|
||||||
|
self._change(key, delta, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Apply a change-in-count (`delta`) against `key`, preventing
|
||||||
|
/// the resulting count from dropping below zero (by clamping it
|
||||||
|
/// at zero in that case).
|
||||||
|
pub fn change_clamped(&mut self, key: V, delta: Count) -> Net {
|
||||||
|
self._change(key, delta, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Apply a change-in-count (`delta`) against `key`, clamping the
|
||||||
|
/// resulting count at zero iff `clamp` is `true`.
|
||||||
pub fn _change(&mut self, key: V, delta: Count, clamp: bool) -> Net {
|
pub fn _change(&mut self, key: V, delta: Count, clamp: bool) -> Net {
|
||||||
let old_count = self[&key];
|
let old_count = self[&key];
|
||||||
let mut new_count = old_count + delta;
|
let mut new_count = old_count + delta;
|
||||||
|
@ -47,31 +78,47 @@ impl<V: std::cmp::Ord> BTreeBag<V> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Removes all elements from the bag, leaving it empty with a zero total count.
|
||||||
pub fn clear(&mut self) {
|
pub fn clear(&mut self) {
|
||||||
self.counts.clear();
|
self.counts.clear();
|
||||||
self.total = 0;
|
self.total = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// `true` iff `key` has a non-zero count associated with it.
|
||||||
|
///
|
||||||
|
/// Note that `true` will be returned even when the count is *negative*.
|
||||||
|
///
|
||||||
pub fn contains_key(&self, key: &V) -> bool {
|
pub fn contains_key(&self, key: &V) -> bool {
|
||||||
self.counts.contains_key(key)
|
self.counts.contains_key(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// `true` iff no element of the bag has a non-zero count.
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.counts.is_empty()
|
self.counts.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Yields the number of elements having a non-zero count.
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
self.counts.len()
|
self.counts.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Answers the sum of all counts in the bag.
|
||||||
|
///
|
||||||
|
/// For bags with no negative counts, this is the same as the
|
||||||
|
/// number of "distinct copies" of elements in the bag.
|
||||||
pub fn total(&self) -> isize {
|
pub fn total(&self) -> isize {
|
||||||
self.total
|
self.total
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Iterates over elements in the bag with non-zero counts.
|
||||||
pub fn keys(&self) -> Keys<V, Count> {
|
pub fn keys(&self) -> Keys<V, Count> {
|
||||||
self.counts.keys()
|
self.counts.keys()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Retrieves an [`Entry`] for `key`.
|
||||||
|
///
|
||||||
|
/// Note that the `Entry` will be "absent" when `key` has a zero
|
||||||
|
/// associated count.
|
||||||
pub fn entry(&mut self, key: V) -> Entry<V, Count> {
|
pub fn entry(&mut self, key: V) -> Entry<V, Count> {
|
||||||
self.counts.entry(key)
|
self.counts.entry(key)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue