From 44160db846f0de98b48cead04f9295e0d278d991 Mon Sep 17 00:00:00 2001 From: Odin Dutton Date: Wed, 19 Feb 2020 12:44:50 +1100 Subject: [PATCH] Implement more HashSet constructors --- src/set.rs | 101 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 99 insertions(+), 2 deletions(-) diff --git a/src/set.rs b/src/set.rs index 670027cf..1850aca7 100644 --- a/src/set.rs +++ b/src/set.rs @@ -3,7 +3,7 @@ //! See `HashSet` for details. use std::borrow::Borrow; -use std::hash::Hash; +use std::hash::{BuildHasher, Hash}; use crate::epoch::{self, Guard}; use crate::iter::Keys; @@ -48,6 +48,72 @@ where map: HashMap, } +impl Default for HashSet +where + T: Sync + Send + Clone + Hash + Eq, + S: BuildHasher + Default, +{ + fn default() -> Self { + Self::with_hasher(S::default()) + } +} + +impl HashSet +where + T: Sync + Send + Clone + Hash + Eq, + S: BuildHasher, +{ + /// Creates an empty set which will use `hash_builder` to hash values. + /// + /// The created set has the default initial capacity. + /// + /// Warning: `hash_builder` is normally randomly generated, and is designed to + /// allow the set 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. + /// + /// # Examples + /// + /// ``` + /// use flurry::{HashSet, DefaultHashBuilder}; + /// + /// let set = HashSet::with_hasher(DefaultHashBuilder::default()); + /// set.insert(1); + /// ``` + pub fn with_hasher(hash_builder: S) -> Self { + Self { + map: HashMap::with_hasher(hash_builder), + } + } + + /// Creates an empty set with the specified `capacity`, using `hash_builder` to hash the + /// values. + /// + /// The set will be sized to accommodate `capacity` elements with a low chance of reallocating + /// (assuming uniformly distributed hashes). If `capacity` is 0, the call will not allocate, + /// and is equivalent to [`HashSet::new`]. + /// + /// Warning: `hash_builder` is normally randomly generated, and is designed to allow the set + /// 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. + /// + /// # Examples + /// + /// ``` + /// use flurry::HashSet; + /// use std::collections::hash_map::RandomState; + /// + /// let s = RandomState::new(); + /// let set = HashSet::with_capacity_and_hasher(10, s); + /// set.insert(1); + /// ``` + pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> Self { + Self { + map: HashMap::with_capacity_and_hasher(capacity, hash_builder), + } + } +} + impl HashSet where T: Sync + Send + Clone + Hash + Eq, @@ -63,10 +129,41 @@ where /// ``` pub fn new() -> Self { Self { - map: HashMap::::new(), + map: HashMap::default(), } } + /// Creates an empty `HashSet` with the specified capacity. + /// + /// The hash map will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash map will not allocate. + /// + /// # Examples + /// + /// ``` + /// use flurry::HashSet; + /// + /// let map: HashSet<&str> = HashSet::with_capacity(10); + /// ``` + /// + /// # Notes + /// + /// There is no guarantee that the HashSet will not resize if `capacity` + /// elements are inserted. The set will resize based on key collision, so + /// bad key distribution may cause a resize before `capacity` is reached. + /// For more information see the [`resizing behavior`] of HashMap. + /// + /// [`resizing behavior`]: index.html#resizing-behavior + pub fn with_capacity(capacity: usize) -> Self { + Self::with_capacity_and_hasher(capacity, crate::DefaultHashBuilder::default()) + } +} + +impl HashSet +where + T: Sync + Send + Clone + Hash + Eq, + S: BuildHasher, +{ /// Adds a value to the set. /// /// If the set did not have this value present, true is returned.