From 0e72b410759a798e80fafb87dd95949e8cd0e76b Mon Sep 17 00:00:00 2001 From: Maneren <49210777+Maneren@users.noreply.github.com> Date: Sun, 4 Feb 2024 10:38:55 +0100 Subject: [PATCH] Add support for generic Hashers (#19) --- src/default_hashmap.rs | 101 +++++++++++++++++++++++++++++++++-------- 1 file changed, 83 insertions(+), 18 deletions(-) diff --git a/src/default_hashmap.rs b/src/default_hashmap.rs index 423b3c1..be452ff 100644 --- a/src/default_hashmap.rs +++ b/src/default_hashmap.rs @@ -2,26 +2,28 @@ use std::borrow::Borrow; use std::collections::{ - hash_map::{Drain, Entry, IntoKeys, IntoValues, Iter, IterMut, Keys, Values, ValuesMut}, + hash_map::{ + Drain, Entry, IntoKeys, IntoValues, Iter, IterMut, Keys, RandomState, Values, ValuesMut, + }, HashMap, }; use std::default::Default; -use std::hash::Hash; +use std::hash::{BuildHasher, Hash}; use std::ops::Index; /// This struct mimicks the behaviour of a python defaultdict. This means alongside the traitbounds /// that apply on the key and value that are inherited from the [`HashMap`], it also requires the /// [`Default`] trait be implemented on the value type. -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct DefaultHashMap +#[derive(Clone, Debug)] +pub struct DefaultHashMap where K: Eq + Hash, V: Default, { - _inner: HashMap, + _inner: HashMap, _default: V, } -impl DefaultHashMap +impl DefaultHashMap where K: Eq + Hash, V: Default, @@ -47,6 +49,42 @@ where _default: V::default(), } } +} + +impl DefaultHashMap +where + K: Eq + Hash, + V: Default, + S: BuildHasher, +{ + /// Creates an empty [`DefaultHashMap`] which will use the given hash builder to hash + /// keys. + /// + /// Warning: `hash_builder` is normally randomly generated, and + /// is designed to allow HashMaps to be resistant to attacks that + /// cause many collisions and very poor performance. Setting it + /// manually using this function can expose a DoS attack vector. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the HashMap to be useful, see its documentation for details. + /// + /// # Examples + /// + /// ``` + /// use defaultdict::DefaultHashMap; + /// use std::collections::hash_map::RandomState; + /// + /// let s = RandomState::new(); + /// let mut map = DefaultHashMap::with_hasher(s); + /// map.insert(1, 2); + /// ``` + #[inline] + pub fn with_hasher(hash_builder: S) -> Self { + DefaultHashMap { + _inner: HashMap::with_hasher(hash_builder), + _default: V::default(), + } + } /// Returns the number of elements the map can hold without reallocating. /// @@ -516,13 +554,33 @@ where } } -impl IntoIterator for DefaultHashMap +impl PartialEq for DefaultHashMap +where + K: Eq + Hash, + V: PartialEq + Default, + S: BuildHasher, +{ + fn eq(&self, other: &DefaultHashMap) -> bool { + self._inner == other._inner && self._default == other._default + } +} + +impl Eq for DefaultHashMap +where + K: Eq + Hash, + V: Eq + Default, + S: BuildHasher, +{ +} + +impl IntoIterator for DefaultHashMap where K: Eq + Hash + Ord + Clone, V: Default, + S: BuildHasher, { type Item = (K, V); - type IntoIter = DefaultHashMapIter; + type IntoIter = DefaultHashMapIter; fn into_iter(self) -> Self::IntoIter { let mut keys: Vec = vec![]; @@ -537,10 +595,11 @@ where } } -impl<'a, K, V> IntoIterator for &'a DefaultHashMap +impl<'a, K, V, S> IntoIterator for &'a DefaultHashMap where K: Eq + Hash + Ord + Clone, V: Default, + S: BuildHasher, { type Item = (&'a K, &'a V); type IntoIter = Iter<'a, K, V>; @@ -550,10 +609,11 @@ where } } -impl Index<&K> for DefaultHashMap +impl Index<&K> for DefaultHashMap where K: Eq + Hash + Ord + Clone, V: Default, + S: BuildHasher, { type Output = V; @@ -562,10 +622,11 @@ where } } -impl<'a, K, V> IntoIterator for &'a mut DefaultHashMap +impl<'a, K, V, S> IntoIterator for &'a mut DefaultHashMap where K: Eq + Hash + Ord + Clone, V: Default, + S: BuildHasher, { type Item = (&'a K, &'a mut V); type IntoIter = IterMut<'a, K, V>; @@ -575,12 +636,13 @@ where } } -impl From> for DefaultHashMap +impl From> for DefaultHashMap where K: Eq + Hash + Ord + Clone, V: Default, + S: BuildHasher, { - fn from(hashmap: HashMap) -> Self { + fn from(hashmap: HashMap) -> Self { Self { _inner: hashmap, _default: V::default(), @@ -588,20 +650,22 @@ where } } -impl From> for HashMap +impl From> for HashMap where K: Eq + Hash + Ord + Clone, V: Default, + S: BuildHasher, { - fn from(hashmap: DefaultHashMap) -> Self { + fn from(hashmap: DefaultHashMap) -> Self { hashmap._inner } } -impl Iterator for DefaultHashMapIter +impl Iterator for DefaultHashMapIter where K: Eq + Hash + Ord + Clone, V: Default, + S: BuildHasher, { type Item = (K, V); @@ -616,12 +680,13 @@ where } } -pub struct DefaultHashMapIter +pub struct DefaultHashMapIter where K: Eq + Hash + Ord, V: Default, + S: BuildHasher, { - _defaulthashmap: DefaultHashMap, + _defaulthashmap: DefaultHashMap, keys: Vec, }