Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement with_hasher adaptors #1007

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
60 changes: 38 additions & 22 deletions src/duplicates_impl.rs
Original file line number Diff line number Diff line change
@@ -1,31 +1,37 @@
use std::hash::Hash;
use core::hash::BuildHasher;
use std::hash::{Hash, RandomState};

mod private {
use core::hash::BuildHasher;
use std::collections::HashMap;
use std::fmt;
use std::hash::Hash;
use std::hash::{Hash, RandomState};

#[derive(Clone)]
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct DuplicatesBy<I: Iterator, Key, F> {
pub struct DuplicatesBy<I: Iterator, Key, F, S = RandomState>
where
S: BuildHasher,
{
pub(crate) iter: I,
pub(crate) meta: Meta<Key, F>,
pub(crate) meta: Meta<Key, F, S>,
}

impl<I, V, F> fmt::Debug for DuplicatesBy<I, V, F>
impl<I, V, F, S> fmt::Debug for DuplicatesBy<I, V, F, S>
where
I: Iterator + fmt::Debug,
V: fmt::Debug + Hash + Eq,
S: BuildHasher,
{
debug_fmt_fields!(DuplicatesBy, iter, meta.used);
}

impl<I: Iterator, Key: Eq + Hash, F> DuplicatesBy<I, Key, F> {
pub(crate) fn new(iter: I, key_method: F) -> Self {
impl<I: Iterator, Key: Eq + Hash, F, S: BuildHasher> DuplicatesBy<I, Key, F, S> {
pub(crate) fn new(iter: I, key_method: F, hash_builder: S) -> Self {
Self {
iter,
meta: Meta {
used: HashMap::new(),
used: HashMap::with_hasher(hash_builder),
pending: 0,
key_method,
},
Expand All @@ -34,15 +40,16 @@ mod private {
}

#[derive(Clone)]
pub struct Meta<Key, F> {
used: HashMap<Key, bool>,
pub struct Meta<Key, F, S> {
used: HashMap<Key, bool, S>,
pending: usize,
key_method: F,
}

impl<Key, F> Meta<Key, F>
impl<Key, F, S> Meta<Key, F, S>
where
Key: Eq + Hash,
S: BuildHasher,
{
/// Takes an item and returns it back to the caller if it's the second time we see it.
/// Otherwise the item is consumed and None is returned
Expand All @@ -68,11 +75,12 @@ mod private {
}
}

impl<I, Key, F> Iterator for DuplicatesBy<I, Key, F>
impl<I, Key, F, S> Iterator for DuplicatesBy<I, Key, F, S>
where
I: Iterator,
Key: Eq + Hash,
F: KeyMethod<Key, I::Item>,
S: BuildHasher,
{
type Item = I::Item;

Expand Down Expand Up @@ -102,11 +110,12 @@ mod private {
}
}

impl<I, Key, F> DoubleEndedIterator for DuplicatesBy<I, Key, F>
impl<I, Key, F, S> DoubleEndedIterator for DuplicatesBy<I, Key, F, S>
where
I: DoubleEndedIterator,
Key: Eq + Hash,
F: KeyMethod<Key, I::Item>,
S: BuildHasher,
{
fn next_back(&mut self) -> Option<Self::Item> {
let Self { iter, meta } = self;
Expand Down Expand Up @@ -189,28 +198,35 @@ mod private {
/// An iterator adapter to filter for duplicate elements.
///
/// See [`.duplicates_by()`](crate::Itertools::duplicates_by) for more information.
pub type DuplicatesBy<I, V, F> = private::DuplicatesBy<I, V, private::ByFn<F>>;

/// Create a new `DuplicatesBy` iterator.
pub fn duplicates_by<I, Key, F>(iter: I, f: F) -> DuplicatesBy<I, Key, F>
pub type DuplicatesBy<I, V, F, S = RandomState> = private::DuplicatesBy<I, V, private::ByFn<F>, S>;

/// Create a new `DuplicatesBy` iterator with a specified hash builder.
pub fn duplicates_by_with_hasher<I, Key, F, S>(
iter: I,
f: F,
hash_builder: S,
) -> DuplicatesBy<I, Key, F, S>
where
Key: Eq + Hash,
F: FnMut(&I::Item) -> Key,
I: Iterator,
S: BuildHasher,
{
DuplicatesBy::new(iter, private::ByFn(f))
DuplicatesBy::new(iter, private::ByFn(f), hash_builder)
}

/// An iterator adapter to filter out duplicate elements.
///
/// See [`.duplicates()`](crate::Itertools::duplicates) for more information.
pub type Duplicates<I> = private::DuplicatesBy<I, <I as Iterator>::Item, private::ById>;
pub type Duplicates<I, S = RandomState> =
private::DuplicatesBy<I, <I as Iterator>::Item, private::ById, S>;

/// Create a new `Duplicates` iterator.
pub fn duplicates<I>(iter: I) -> Duplicates<I>
/// Create a new `Duplicates` iterator with a specified hash builder.
pub fn duplicates_with_hasher<I, S>(iter: I, hash_builder: S) -> Duplicates<I, S>
where
I: Iterator,
I::Item: Eq + Hash,
S: BuildHasher,
{
Duplicates::new(iter, private::ById)
Duplicates::new(iter, private::ById, hash_builder)
}
15 changes: 11 additions & 4 deletions src/group_map.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#![cfg(feature = "use_std")]

use core::hash::BuildHasher;
use std::collections::HashMap;
use std::hash::Hash;
use std::iter::Iterator;
Expand All @@ -8,12 +9,13 @@ use std::iter::Iterator;
///
/// See [`.into_group_map()`](crate::Itertools::into_group_map)
/// for more information.
pub fn into_group_map<I, K, V>(iter: I) -> HashMap<K, Vec<V>>
pub fn into_group_map_with_hasher<I, K, V, S>(iter: I, hash_builder: S) -> HashMap<K, Vec<V>, S>
where
I: Iterator<Item = (K, V)>,
K: Hash + Eq,
S: BuildHasher,
{
let mut lookup = HashMap::new();
let mut lookup = HashMap::with_hasher(hash_builder);

iter.for_each(|(key, val)| {
lookup.entry(key).or_insert_with(Vec::new).push(val);
Expand All @@ -22,11 +24,16 @@ where
lookup
}

pub fn into_group_map_by<I, K, V, F>(iter: I, mut f: F) -> HashMap<K, Vec<V>>
pub fn into_group_map_by_with_hasher<I, K, V, F, S>(
iter: I,
mut f: F,
hash_builder: S,
) -> HashMap<K, Vec<V>, S>
where
I: Iterator<Item = V>,
K: Hash + Eq,
F: FnMut(&V) -> K,
S: BuildHasher,
{
into_group_map(iter.map(|v| (f(&v), v)))
into_group_map_with_hasher(iter.map(|v| (f(&v), v)), hash_builder)
}
Loading