|
|
@ -13,9 +13,47 @@ use std::{
|
|
|
|
fmt,
|
|
|
|
fmt,
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Map of collisions
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
|
|
|
|
|
|
pub struct CollisionMap<'a>(HashMap<hash::Sha256Hash, Vec<&'a Path>>);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl<'a> CollisionMap<'a>
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
#[inline] pub fn len(&self) -> usize
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
self.0.len()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline] pub fn full_len(&self) -> usize
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
self.0.iter().map(|(_, v)| v.len()).sum()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline] pub fn iter(&self) -> impl Iterator<Item = (&hash::Sha256Hash, &[&'a Path])>
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
self.0.iter().map(|(k, v)| (k, v.as_slice()))
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline] pub fn of_hash(&self, name: &hash::Sha256Hash) -> &[&'a Path]
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if let Some(vec) = self.0.get(name)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
&vec[..]
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
&[]
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline] pub fn hashes(&self) -> impl Iterator<Item = &hash::Sha256Hash>
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
self.0.iter().map(|(k, _)| k)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline] pub fn into_iter(self) -> impl Iterator<Item = (hash::Sha256Hash, Vec<&'a Path>)>
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
self.0.into_iter()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
|
|
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
|
|
|
pub struct DupeMap
|
|
|
|
pub struct DupeMap
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
names: HashMap<PathBuf, hash::Sha256Hash>,
|
|
|
|
iteration: HashSet<hash::Sha256Hash>, // What we calculate
|
|
|
|
iteration: HashSet<hash::Sha256Hash>, // What we calculate
|
|
|
|
table: HashMap<PathBuf, (hash::Sha256Hash, bool)>, // What we save and load, and if it's transient (ignored in calculate)
|
|
|
|
table: HashMap<PathBuf, (hash::Sha256Hash, bool)>, // What we save and load, and if it's transient (ignored in calculate)
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -53,7 +91,7 @@ impl DupeMap
|
|
|
|
/// Create a new empty dupe map
|
|
|
|
/// Create a new empty dupe map
|
|
|
|
pub fn new() -> Self
|
|
|
|
pub fn new() -> Self
|
|
|
|
{
|
|
|
|
{
|
|
|
|
Self{iteration: HashSet::new(), table: HashMap::new()}
|
|
|
|
Self{iteration: HashSet::new(), table: HashMap::new(), names: HashMap::new()}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Iterator over all hashes
|
|
|
|
/// Iterator over all hashes
|
|
|
@ -167,14 +205,32 @@ impl DupeMap
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Try to add to store. True if adding was oke, false if already exists.
|
|
|
|
/// Try to add to store. True if adding was oke, false if already exists.
|
|
|
|
pub fn try_add(&mut self, hash: hash::Sha256Hash) -> bool
|
|
|
|
pub fn try_add(&mut self, hash: hash::Sha256Hash, name: impl Into<PathBuf>) -> bool
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if self.iteration.contains(&hash) {
|
|
|
|
if self.iteration.insert(hash) {
|
|
|
|
false
|
|
|
|
self.names.insert(name.into(), hash);
|
|
|
|
} else {
|
|
|
|
|
|
|
|
self.iteration.insert(hash);
|
|
|
|
|
|
|
|
true
|
|
|
|
true
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
false
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Create a map of all collisions
|
|
|
|
|
|
|
|
pub fn get_collision_map(&self) -> CollisionMap<'_>
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
let mut cm = CollisionMap(HashMap::new());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (name, hash) in self.names.iter()
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if let Some(vec) = cm.0.get_mut(hash)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
vec.push(name);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
cm.0.insert(*hash, vec![name]);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cm
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Save this list to a file
|
|
|
|
/// Save this list to a file
|
|
|
|