diff --git a/src/libstd/collections/hashmap.rs b/src/libstd/collections/hashmap.rs index 9a53c941377e4..14027bc1f544f 100644 --- a/src/libstd/collections/hashmap.rs +++ b/src/libstd/collections/hashmap.rs @@ -1514,54 +1514,44 @@ pub type SetMoveItems = /// println!("{}", *book); /// } /// ``` +/// +/// The easiest way to use `HashSet` with a custom type is to derive +/// `Eq` and `Hash`. We must also derive `PartialEq`, this will in the +/// future be implied by `Eq`. +/// +/// ```rust +/// use std::collections::HashSet; +/// +/// #[deriving(Hash, Eq, PartialEq, Show)] +/// struct Viking<'a> { +/// name: &'a str, +/// power: uint, +/// } +/// +/// let mut vikings = HashSet::new(); +/// +/// vikings.insert(Viking { name: "Einar", power: 9u }); +/// vikings.insert(Viking { name: "Einar", power: 9u }); +/// vikings.insert(Viking { name: "Olaf", power: 4u }); +/// vikings.insert(Viking { name: "Harald", power: 8u }); +/// +/// // Use derived implementation to print the vikings. +/// for x in vikings.iter() { +/// println!("{}", x); +/// } +/// ``` #[deriving(Clone)] pub struct HashSet { map: HashMap } -impl, S, H: Hasher> PartialEq for HashSet { - fn eq(&self, other: &HashSet) -> bool { - if self.len() != other.len() { return false; } - - self.iter().all(|key| other.contains(key)) - } -} - -impl, S, H: Hasher> Eq for HashSet {} - -impl, S, H: Hasher> Collection for HashSet { - fn len(&self) -> uint { self.map.len() } -} - -impl, S, H: Hasher> Mutable for HashSet { - fn clear(&mut self) { self.map.clear() } -} - -impl, S, H: Hasher> Set for HashSet { - fn contains(&self, value: &T) -> bool { self.map.contains_key(value) } - - fn is_disjoint(&self, other: &HashSet) -> bool { - self.iter().all(|v| !other.contains(v)) - } - - fn is_subset(&self, other: &HashSet) -> bool { - self.iter().all(|v| other.contains(v)) - } -} - -impl, S, H: Hasher> MutableSet for HashSet { - fn insert(&mut self, value: T) -> bool { self.map.insert(value, ()) } - - fn remove(&mut self, value: &T) -> bool { self.map.remove(value) } -} - impl HashSet { - /// Create an empty HashSet + /// Create an empty HashSet. /// /// # Example /// /// ```rust - /// # use std::collections::HashSet; + /// use std::collections::HashSet; /// let mut set: HashSet = HashSet::new(); /// ``` #[inline] @@ -1575,7 +1565,7 @@ impl HashSet { /// # Example /// /// ```rust - /// # use std::collections::HashSet; + /// use std::collections::HashSet; /// let mut set: HashSet = HashSet::with_capacity(10); /// ``` #[inline] @@ -1589,6 +1579,17 @@ impl, S, H: Hasher> HashSet { /// keys. /// /// The hash set is also created with the default initial capacity. + /// + /// # Example + /// + /// ```rust + /// use std::collections::HashSet; + /// use std::hash::sip::SipHasher; + /// + /// let h = SipHasher::new(); + /// let mut set = HashSet::with_hasher(h); + /// set.insert(2u); + /// ``` #[inline] pub fn with_hasher(hasher: H) -> HashSet { HashSet::with_capacity_and_hasher(INITIAL_CAPACITY, hasher) @@ -1601,6 +1602,17 @@ impl, S, H: Hasher> HashSet { /// is designed to allow `HashSet`s 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. + /// + /// # Example + /// + /// ```rust + /// use std::collections::HashSet; + /// use std::hash::sip::SipHasher; + /// + /// let h = SipHasher::new(); + /// let mut set = HashSet::with_capacity_and_hasher(10u, h); + /// set.insert(1i); + /// ``` #[inline] pub fn with_capacity_and_hasher(capacity: uint, hasher: H) -> HashSet { HashSet { map: HashMap::with_capacity_and_hasher(capacity, hasher) } @@ -1611,7 +1623,7 @@ impl, S, H: Hasher> HashSet { /// # Example /// /// ```rust - /// # use std::collections::HashSet; + /// use std::collections::HashSet; /// let mut set: HashSet = HashSet::new(); /// set.reserve(10); /// ``` @@ -1621,6 +1633,45 @@ impl, S, H: Hasher> HashSet { /// Returns true if the hash set contains a value equivalent to the /// given query value. + /// + /// # Example + /// + /// This is a slightly silly example where we define the number's + /// parity as the equivilance class. It is important that the + /// values hash the same, which is why we implement `Hash`. + /// + /// ```rust + /// use std::collections::HashSet; + /// use std::hash::Hash; + /// use std::hash::sip::SipState; + /// + /// #[deriving(Eq, PartialEq)] + /// struct EvenOrOdd { + /// num: uint + /// }; + /// + /// impl Hash for EvenOrOdd { + /// fn hash(&self, state: &mut SipState) { + /// let parity = self.num % 2; + /// parity.hash(state); + /// } + /// } + /// + /// impl Equiv for EvenOrOdd { + /// fn equiv(&self, other: &EvenOrOdd) -> bool { + /// self.num % 2 == other.num % 2 + /// } + /// } + /// + /// let mut set = HashSet::new(); + /// set.insert(EvenOrOdd { num: 3u }); + /// + /// assert!(set.contains_equiv(&EvenOrOdd { num: 3u })); + /// assert!(set.contains_equiv(&EvenOrOdd { num: 5u })); + /// assert!(!set.contains_equiv(&EvenOrOdd { num: 4u })); + /// assert!(!set.contains_equiv(&EvenOrOdd { num: 2u })); + /// + /// ``` pub fn contains_equiv + Equiv>(&self, value: &Q) -> bool { self.map.contains_key_equiv(value) } @@ -1631,7 +1682,8 @@ impl, S, H: Hasher> HashSet { /// # Example /// /// ```rust - /// # use std::collections::HashSet; + /// use std::collections::HashSet; + /// /// let mut set = HashSet::new(); /// set.insert("a"); /// set.insert("b"); @@ -1652,7 +1704,8 @@ impl, S, H: Hasher> HashSet { /// # Example /// /// ```rust - /// # use std::collections::HashSet; + /// use std::collections::HashSet; + /// /// let mut set = HashSet::new(); /// set.insert("a".to_string()); /// set.insert("b".to_string()); @@ -1674,7 +1727,8 @@ impl, S, H: Hasher> HashSet { /// # Example /// /// ```rust - /// # use std::collections::HashSet; + /// use std::collections::HashSet; + /// /// let a: HashSet = [1i, 2, 3].iter().map(|&x| x).collect(); /// let b: HashSet = [4i, 2, 3, 4].iter().map(|&x| x).collect(); /// @@ -1703,7 +1757,8 @@ impl, S, H: Hasher> HashSet { /// # Example /// /// ```rust - /// # use std::collections::HashSet; + /// use std::collections::HashSet; + /// /// let a: HashSet = [1i, 2, 3].iter().map(|&x| x).collect(); /// let b: HashSet = [4i, 2, 3, 4].iter().map(|&x| x).collect(); /// @@ -1728,7 +1783,8 @@ impl, S, H: Hasher> HashSet { /// # Example /// /// ```rust - /// # use std::collections::HashSet; + /// use std::collections::HashSet; + /// /// let a: HashSet = [1i, 2, 3].iter().map(|&x| x).collect(); /// let b: HashSet = [4i, 2, 3, 4].iter().map(|&x| x).collect(); /// @@ -1753,7 +1809,8 @@ impl, S, H: Hasher> HashSet { /// # Example /// /// ```rust - /// # use std::collections::HashSet; + /// use std::collections::HashSet; + /// /// let a: HashSet = [1i, 2, 3].iter().map(|&x| x).collect(); /// let b: HashSet = [4i, 2, 3, 4].iter().map(|&x| x).collect(); /// @@ -1771,6 +1828,43 @@ impl, S, H: Hasher> HashSet { } } +impl, S, H: Hasher> PartialEq for HashSet { + fn eq(&self, other: &HashSet) -> bool { + if self.len() != other.len() { return false; } + + self.iter().all(|key| other.contains(key)) + } +} + +impl, S, H: Hasher> Eq for HashSet {} + +impl, S, H: Hasher> Collection for HashSet { + fn len(&self) -> uint { self.map.len() } +} + +impl, S, H: Hasher> Mutable for HashSet { + fn clear(&mut self) { self.map.clear() } +} + +impl, S, H: Hasher> Set for HashSet { + fn contains(&self, value: &T) -> bool { self.map.contains_key(value) } + + fn is_disjoint(&self, other: &HashSet) -> bool { + self.iter().all(|v| !other.contains(v)) + } + + fn is_subset(&self, other: &HashSet) -> bool { + self.iter().all(|v| other.contains(v)) + } +} + +impl, S, H: Hasher> MutableSet for HashSet { + fn insert(&mut self, value: T) -> bool { self.map.insert(value, ()) } + + fn remove(&mut self, value: &T) -> bool { self.map.remove(value) } +} + + impl + fmt::Show, S, H: Hasher> fmt::Show for HashSet { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { try!(write!(f, "{{"));