You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
67 lines
1.3 KiB
67 lines
1.3 KiB
4 years ago
|
//! Map iter
|
||
|
use super::*;
|
||
|
use std::{
|
||
|
iter,
|
||
|
collections::HashSet,
|
||
|
hash::Hash,
|
||
|
};
|
||
|
|
||
|
//TODO: Feature flag for SHA256 hashing
|
||
|
type HashOutput = u64;
|
||
|
|
||
|
fn compute<H: Hash>(what: &H) -> HashOutput
|
||
|
{
|
||
|
use std::hash::Hasher;
|
||
|
let mut hasher = std::collections::hash_map::DefaultHasher::new();
|
||
|
what.hash(&mut hasher);
|
||
|
hasher.finish()
|
||
|
}
|
||
|
|
||
|
pub struct DedupIter<I: Iterator>(I, HashSet<HashOutput>)
|
||
|
where <I as Iterator>::Item: Hash;
|
||
|
|
||
|
impl<I: Iterator> Iterator for DedupIter<I>
|
||
|
where I::Item: Hash
|
||
|
{
|
||
|
type Item = I::Item;
|
||
|
fn next(&mut self) -> Option<Self::Item>
|
||
|
{
|
||
|
if let Some(next) = self.0.next() {
|
||
|
let hash = compute(&next);
|
||
|
if self.1.insert(hash) {
|
||
|
Some(next)
|
||
|
} else {
|
||
|
return self.next();
|
||
|
}
|
||
|
} else {
|
||
|
None
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fn size_hint(&self) -> (usize, Option<usize>)
|
||
|
{
|
||
|
let (low, high) = self.0.size_hint();
|
||
|
|
||
|
(if low < 1 {0} else {1}, high)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub trait DedupIterExt: Iterator + Sized
|
||
|
where Self::Item: Hash
|
||
|
{
|
||
|
fn dedup(self) -> DedupIter<Self>;
|
||
|
}
|
||
|
|
||
|
impl<I: Iterator> DedupIterExt for I
|
||
|
where I::Item: Hash
|
||
|
{
|
||
|
fn dedup(self) -> DedupIter<Self>
|
||
|
{
|
||
|
let set = match self.size_hint() {
|
||
|
(0, Some(0)) | (0, None) => HashSet::new(),
|
||
|
(x, None) | (_, Some(x)) => HashSet::with_capacity(x),
|
||
|
};
|
||
|
DedupIter(self, set)
|
||
|
}
|
||
|
}
|