Skip to content

Commit

Permalink
Merge pull request #21 from clint-white/relax-trait-bounds
Browse files Browse the repository at this point in the history
Relax trait bounds
  • Loading branch information
coriolinus committed May 5, 2022
2 parents 02eff96 + 1d49f69 commit b253d08
Showing 1 changed file with 91 additions and 71 deletions.
162 changes: 91 additions & 71 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,17 @@ pub struct Counter<T: Hash + Eq, N = usize> {
impl<T, N> Counter<T, N>
where
T: Hash + Eq,
N: PartialOrd + AddAssign + SubAssign + Zero + One,
{
/// Consumes this counter and returns a HashMap mapping the items to the counts.
pub fn into_map(self) -> HashMap<T, N> {
self.map
}
}

impl<T, N> Counter<T, N>
where
T: Hash + Eq,
N: Zero,
{
/// Create a new, empty `Counter`
pub fn new() -> Counter<T, N> {
Expand All @@ -185,6 +195,34 @@ where
}
}

/// Returns the sum of the counts.
///
/// Use [`len`] to get the number of elements in the counter and use `total` to get the sum of
/// their counts.
///
/// [`len`]: struct.Counter.html#method.len
///
/// # Examples
///
/// ```
/// # use counter::Counter;
/// let counter = Counter::init("abracadabra".chars());
/// assert_eq!(counter.total::<usize>(), 11);
/// assert_eq!(counter.len(), 5);
/// ```
pub fn total<'a, S>(&'a self) -> S
where
S: iter::Sum<&'a N>,
{
self.map.values().sum()
}
}

impl<T, N> Counter<T, N>
where
T: Hash + Eq,
N: AddAssign + Zero + One,
{
/// Create a new `Counter` initialized with the given iterable
pub fn init<I>(iterable: I) -> Counter<T, N>
where
Expand All @@ -205,12 +243,13 @@ where
*entry += N::one();
}
}
}

/// Consumes this counter and returns a HashMap mapping the items to the counts.
pub fn into_map(self) -> HashMap<T, N> {
self.map
}

impl<T, N> Counter<T, N>
where
T: Hash + Eq,
N: PartialOrd + SubAssign + Zero + One,
{
/// Remove the counts of the elements from the given iterable to this counter
///
/// Non-positive counts are automatically removed
Expand Down Expand Up @@ -318,33 +357,6 @@ where
}
}

impl<T, N> Counter<T, N>
where
T: Hash + Eq,
{
/// Returns the sum of the counts.
///
/// Use [`len`] to get the number of elements in the counter and use `total` to get the sum of
/// their counts.
///
/// [`len`]: struct.Counter.html#method.len
///
/// # Examples
///
/// ```
/// # use counter::Counter;
/// let counter = Counter::init("abracadabra".chars());
/// assert_eq!(counter.total::<usize>(), 11);
/// assert_eq!(counter.len(), 5);
/// ```
pub fn total<'a, S>(&'a self) -> S
where
S: iter::Sum<&'a N>,
{
self.map.values().sum()
}
}

impl<T, N> Default for Counter<T, N>
where
T: Hash + Eq,
Expand All @@ -360,7 +372,7 @@ where

impl<T, N> AddAssign for Counter<T, N>
where
T: Clone + Hash + Eq,
T: Hash + Eq,
N: Zero + AddAssign,
{
/// Add another counter to this counter
Expand All @@ -380,7 +392,7 @@ where
/// ```
fn add_assign(&mut self, rhs: Self) {
for (key, value) in rhs.map.into_iter() {
let entry = self.map.entry(key.clone()).or_insert_with(N::zero);
let entry = self.map.entry(key).or_insert_with(N::zero);
*entry += value;
}
}
Expand Down Expand Up @@ -486,8 +498,8 @@ where

impl<T, N> BitAnd for Counter<T, N>
where
T: Clone + Hash + Eq,
N: Clone + Ord + AddAssign + SubAssign + Zero + One,
T: Hash + Eq,
N: Ord + Zero,
{
type Output = Counter<T, N>;

Expand All @@ -506,30 +518,24 @@ where
/// let expect = [('a', 1), ('b', 1)].iter().cloned().collect::<HashMap<_, _>>();
/// assert_eq!(e.into_map(), expect);
/// ```
fn bitand(self, rhs: Counter<T, N>) -> Self::Output {
fn bitand(self, mut rhs: Counter<T, N>) -> Self::Output {
use std::cmp::min;
use std::collections::HashSet;

let self_keys = self.map.keys().collect::<HashSet<_>>();
let other_keys = rhs.map.keys().collect::<HashSet<_>>();
let both_keys = self_keys.intersection(&other_keys);

let mut counter = Counter::new();
for key in both_keys {
counter.map.insert(
(*key).clone(),
min(self.map.get(*key).unwrap(), rhs.map.get(*key).unwrap()).clone(),
);
for (key, lhs_count) in self.map {
if let Some(rhs_count) = rhs.remove(&key) {
let count = min(lhs_count, rhs_count);
counter.map.insert(key, count);
}
}

counter
}
}

impl<T, N> BitOr for Counter<T, N>
where
T: Clone + Hash + Eq,
N: Clone + Ord + Zero,
T: Hash + Eq,
N: Ord + Zero,
{
type Output = Counter<T, N>;

Expand All @@ -549,11 +555,27 @@ where
/// assert_eq!(e.into_map(), expect);
/// ```
fn bitor(mut self, rhs: Counter<T, N>) -> Self::Output {
use std::cmp::max;

for (key, value) in rhs.map.iter() {
let entry = self.map.entry(key.clone()).or_insert_with(N::zero);
*entry = max(&*entry, value).clone();
for (key, rhs_value) in rhs.map {
let entry = self.map.entry(key).or_insert_with(N::zero);
// We want to update the value of the now occupied entry in `self` with the maximum of
// its current value and `rhs_value`. If that max is `rhs_value`, we can just update
// the value of the entry. If the max is the current value, we do nothing. Note that
// `Ord::max()` returns the second argument (here `rhs_value`) if its two arguments are
// equal, justifying the use of the weak inequality below instead of a strict
// inequality.
//
// Doing it this way with an inequality instead of actually using `std::cmp::max()`
// lets us avoid trying (and failing) to move the non-copy value out of the entry in
// order to pass it as an argument to `std::cmp::max()`, while still holding a mutable
// reference to the value slot in the entry.
//
// And while using the inequality seemingly only requires the bound `N: PartialOrd`, we
// nevertheless prefer to require `Ord` as though we were using `std::cmp::max()`
// because the semantics of `BitOr` for `Counter` really do not make sense if there are
// possibly non-comparable values of type `N`.
if rhs_value >= *entry {
*entry = rhs_value;
}
}
self
}
Expand All @@ -562,7 +584,6 @@ where
impl<T, N> Deref for Counter<T, N>
where
T: Hash + Eq,
N: Clone,
{
type Target = CounterMap<T, N>;
fn deref(&self) -> &CounterMap<T, N> {
Expand All @@ -573,7 +594,6 @@ where
impl<T, N> DerefMut for Counter<T, N>
where
T: Hash + Eq,
N: Clone,
{
fn deref_mut(&mut self) -> &mut CounterMap<T, N> {
&mut self.map
Expand Down Expand Up @@ -725,7 +745,7 @@ impl<I, T, N> AddAssign<I> for Counter<T, N>
where
I: IntoIterator<Item = T>,
T: Hash + Eq,
N: PartialOrd + AddAssign + SubAssign + Zero + One,
N: AddAssign + Zero + One,
{
/// Directly add the counts of the elements of `I` to `self`
///
Expand All @@ -748,7 +768,7 @@ impl<I, T, N> Add<I> for Counter<T, N>
where
I: IntoIterator<Item = T>,
T: Hash + Eq,
N: PartialOrd + AddAssign + SubAssign + Zero + One,
N: AddAssign + Zero + One,
{
type Output = Self;
/// Consume self producing a Counter like self updated with the counts of
Expand All @@ -774,7 +794,7 @@ impl<I, T, N> SubAssign<I> for Counter<T, N>
where
I: IntoIterator<Item = T>,
T: Hash + Eq,
N: PartialOrd + AddAssign + SubAssign + Zero + One,
N: PartialOrd + SubAssign + Zero + One,
{
/// Directly subtract the counts of the elements of `I` from `self`,
/// keeping only items with a value greater than N::zero().
Expand All @@ -796,8 +816,8 @@ where
impl<I, T, N> Sub<I> for Counter<T, N>
where
I: IntoIterator<Item = T>,
T: Clone + Hash + Eq,
N: Clone + PartialOrd + AddAssign + SubAssign + Zero + One,
T: Hash + Eq,
N: PartialOrd + SubAssign + Zero + One,
{
type Output = Self;
/// Consume self producing a Counter like self with the counts of the
Expand All @@ -821,7 +841,7 @@ where
impl<T, N> iter::FromIterator<T> for Counter<T, N>
where
T: Hash + Eq,
N: PartialOrd + AddAssign + SubAssign + Zero + One,
N: AddAssign + Zero + One,
{
/// Produce a Counter from an iterator of items. This is called automatically
/// by `iter.collect()`.
Expand All @@ -842,7 +862,7 @@ where
impl<T, N> iter::FromIterator<(T, N)> for Counter<T, N>
where
T: Hash + Eq,
N: PartialOrd + AddAssign + SubAssign + Zero + One,
N: AddAssign + Zero,
{
/// `from_iter` creates a counter from `(item, count)` tuples.
///
Expand All @@ -869,7 +889,7 @@ where
impl<T, N> Extend<T> for Counter<T, N>
where
T: Hash + Eq,
N: PartialOrd + AddAssign + SubAssign + Zero + One,
N: AddAssign + Zero + One,
{
/// Extend a Counter with an iterator of items.
///
Expand All @@ -889,7 +909,7 @@ where
impl<T, N> Extend<(T, N)> for Counter<T, N>
where
T: Hash + Eq,
N: PartialOrd + AddAssign + SubAssign + Zero + One,
N: AddAssign + Zero,
{
/// Extend a counter with `(item, count)` tuples.
///
Expand All @@ -913,8 +933,8 @@ where

impl<'a, T: 'a, N: 'a> Extend<(&'a T, &'a N)> for Counter<T, N>
where
T: Hash + Eq + Copy,
N: PartialOrd + AddAssign + SubAssign + Zero + One + Copy,
T: Hash + Eq + Clone,
N: AddAssign + Zero + Clone,
{
/// Extend a counter with `(item, count)` tuples.
///
Expand All @@ -931,8 +951,8 @@ where
/// ```
fn extend<I: IntoIterator<Item = (&'a T, &'a N)>>(&mut self, iter: I) {
for (item, item_count) in iter.into_iter() {
let entry = self.map.entry(*item).or_insert_with(N::zero);
*entry += *item_count;
let entry = self.map.entry(item.clone()).or_insert_with(N::zero);
*entry += item_count.clone();
}
}
}
Expand Down

0 comments on commit b253d08

Please sign in to comment.