Skip to content

Commit bf114d3

Browse files
committed
Make HashBag::difference() iterate over (&'a T, usize)
1 parent e70be47 commit bf114d3

File tree

1 file changed

+24
-31
lines changed

1 file changed

+24
-31
lines changed

src/lib.rs

+24-31
Original file line numberDiff line numberDiff line change
@@ -710,18 +710,20 @@ where
710710
///
711711
/// ```
712712
/// use hashbag::HashBag;
713+
/// use std::collections::HashSet;
714+
/// use std::iter::FromIterator;
713715
///
714716
/// let a: HashBag<_> = [1, 2, 3, 3].iter().cloned().collect();
715717
/// let b: HashBag<_> = [2, 3].iter().cloned().collect();
716-
/// let expected: HashBag<_> = [1, 3].iter().cloned().collect();
717-
/// let actual: HashBag<_> = a.difference(&b).cloned().collect();
718+
/// let expected: HashSet<_> = HashSet::from_iter([(&1, 1), (&3, 1)]);
719+
/// let actual: HashSet<_> = a.difference(&b).collect();
718720
/// assert_eq!(expected, actual);
719721
/// ```
720722
pub fn difference<'a>(&'a self, other: &'a HashBag<T, S>) -> Difference<'a, T, S> {
721723
Difference {
722-
base_iter: self.iter(),
724+
items: self.items.iter(),
723725
other,
724-
removed_from_other: HashMap::new(),
726+
upper_bound: self.count,
725727
}
726728
}
727729

@@ -1136,21 +1138,20 @@ impl<'a, T> Iterator for Drain<'a, T> {
11361138
/// This `struct` is created by [`HashBag::difference`].
11371139
/// See its documentation for more.
11381140
pub struct Difference<'a, T, S = RandomState> {
1139-
/// An iterator over "self"
1140-
base_iter: Iter<'a, T>,
1141+
/// An iterator over `self` items
1142+
items: std::collections::hash_map::Iter<'a, T, usize>,
11411143

11421144
/// The bag with entries we DO NOT want to return
11431145
other: &'a HashBag<T, S>,
11441146

1145-
/// Keeps track of many times we have conceptually "consumed" an entry from
1146-
/// `other`.
1147-
removed_from_other: HashMap<&'a T, usize>,
1147+
/// For `size_hint()`
1148+
upper_bound: usize,
11481149
}
11491150

11501151
impl<'a, T: fmt::Debug> fmt::Debug for Difference<'a, T> {
11511152
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
11521153
fmt.debug_struct("Difference")
1153-
.field("base_iter", &self.base_iter)
1154+
.field("items", &self.items)
11541155
.field("other", &self.other)
11551156
.finish()
11561157
}
@@ -1161,30 +1162,22 @@ where
11611162
T: Eq + Hash,
11621163
S: BuildHasher,
11631164
{
1164-
type Item = &'a T;
1165+
type Item = (&'a T, usize);
11651166

11661167
#[inline]
1167-
fn next(&mut self) -> Option<&'a T> {
1168+
fn next(&mut self) -> Option<Self::Item> {
11681169
loop {
1169-
let next = self.base_iter.next()?;
1170-
let removal_count = self.removed_from_other.entry(next).or_insert(0);
1171-
1172-
// Keep track of how many times we have removed the current entry.
1173-
// We don't actually remove anything, we just pretend we do.
1174-
*removal_count += 1;
1175-
1176-
// If we removed MORE entries from `other`, THEN we may start
1177-
// returning entries from the base iterator.
1178-
if *removal_count > self.other.contains(next) {
1179-
return Some(next);
1170+
let (t, n) = self.items.next()?;
1171+
let other_n = self.other.contains(t);
1172+
if other_n < *n {
1173+
return Some((t, *n - other_n));
11801174
}
11811175
}
11821176
}
11831177

11841178
#[inline]
11851179
fn size_hint(&self) -> (usize, Option<usize>) {
1186-
let (_, upper_bound) = self.base_iter.size_hint();
1187-
(0, upper_bound)
1180+
(0, Some(self.upper_bound))
11881181
}
11891182
}
11901183

@@ -1284,11 +1277,11 @@ mod tests {
12841277
let this = self_entries.iter().collect::<HashBag<_>>();
12851278
let other = other_entries.iter().collect::<HashBag<_>>();
12861279
let expected = expected_entries.iter().collect::<HashBag<_>>();
1287-
assert_eq!(
1288-
this.difference(&other)
1289-
.copied()
1290-
.collect::<HashBag<&isize>>(),
1291-
expected
1292-
);
1280+
let mut actual = HashBag::new();
1281+
for (t, n) in this.difference(&other) {
1282+
actual.insert_many(*t, n);
1283+
}
1284+
1285+
assert_eq!(actual, expected);
12931286
}
12941287
}

0 commit comments

Comments
 (0)