From b2a02b580d4193a75e4aacdd58e87805437480c5 Mon Sep 17 00:00:00 2001 From: Jonas Hietala Date: Thu, 17 Jul 2014 20:40:39 +0200 Subject: [PATCH 1/2] Fill in documentation for HashSet. Example how to use the set with a custom type. Fill in examples for the missing methods. --- src/libstd/collections/hashmap.rs | 304 ++++++++++++++++++++++++++---- 1 file changed, 267 insertions(+), 37 deletions(-) diff --git a/src/libstd/collections/hashmap.rs b/src/libstd/collections/hashmap.rs index 9a53c941377e4..12b80d1b4674d 100644 --- a/src/libstd/collections/hashmap.rs +++ b/src/libstd/collections/hashmap.rs @@ -1514,49 +1514,39 @@ 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 /// @@ -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) } @@ -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) } @@ -1771,7 +1822,154 @@ impl, S, H: Hasher> HashSet { } } +impl, S, H: Hasher> PartialEq for HashSet { + /// Partial equality between sets. + /// + /// # Example + /// + /// ```rust + /// # use std::collections::HashSet; + /// let a: HashSet = [1i, 2, 3].iter().map(|&x| x).collect(); + /// let b: HashSet = [1i, 2, 3, 4].iter().map(|&x| x).collect(); + /// let c: HashSet = [1i, 2, 3].iter().map(|&x| x).collect(); + /// + /// assert!(a.eq(&c)); + /// + /// // eq and ne defines the == and != operators + /// assert!(a == c); + /// assert!(a != b); + /// ``` + 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 { + /// Return the number of elements in the set. + /// + /// # Example + /// + /// ```rust + /// # use std::collections::HashSet; + /// let set: HashSet = [1i, 2, 3, 2].iter().map(|&x| x).collect(); + /// assert_eq!(set.len(), 3); + /// ``` + fn len(&self) -> uint { self.map.len() } +} + +impl, S, H: Hasher> Mutable for HashSet { + /// Clear the set. Keeps the allocated memory for reuse. + /// + /// # Example + /// + /// ```rust + /// # use std::collections::HashSet; + /// let mut set: HashSet = [1i, 2, 3].iter().map(|&x| x).collect(); + /// set.clear(); + /// assert!(set.is_empty()); + /// ``` + fn clear(&mut self) { self.map.clear() } +} + +impl, S, H: Hasher> Set for HashSet { + /// Return true if `value` is contained by the set. + /// + /// # Example + /// + /// ```rust + /// # use std::collections::HashSet; + /// let set: HashSet = [1i, 2, 3].iter().map(|&x| x).collect(); + /// assert_eq!(set.contains(&1), true); + /// assert_eq!(set.contains(&4), false); + /// ``` + fn contains(&self, value: &T) -> bool { self.map.contains_key(value) } + + /// Return true if the set is disjoint with `other`. + /// + /// # Example + /// + /// ```rust + /// # use std::collections::HashSet; + /// let a: HashSet = [1i, 2, 3].iter().map(|&x| x).collect(); + /// let mut b: HashSet = HashSet::new(); + /// + /// assert_eq!(a.is_disjoint(&b), true); + /// b.insert(4); + /// assert_eq!(a.is_disjoint(&b), true); + /// b.insert(1); + /// assert_eq!(a.is_disjoint(&b), false); + /// ``` + fn is_disjoint(&self, other: &HashSet) -> bool { + self.iter().all(|v| !other.contains(v)) + } + + /// Return true if the set is a subset of `other`. + /// + /// # Example + /// + /// ```rust + /// # use std::collections::HashSet; + /// let sup: HashSet = [1i, 2, 3].iter().map(|&x| x).collect(); + /// let mut set: HashSet = HashSet::new(); + /// + /// assert_eq!(set.is_subset(&sup), true); + /// set.insert(2); + /// assert_eq!(set.is_subset(&sup), true); + /// set.insert(4); + /// assert_eq!(set.is_subset(&sup), false); + /// ``` + fn is_subset(&self, other: &HashSet) -> bool { + self.iter().all(|v| other.contains(v)) + } +} + +impl, S, H: Hasher> MutableSet for HashSet { + /// Insert an element. + /// + /// # Example + /// + /// ```rust + /// # use std::collections::HashSet; + /// let mut set = HashSet::new(); + /// set.insert(2i); + /// set.insert(2i); + /// assert_eq!(set.len(), 1); + /// ``` + fn insert(&mut self, value: T) -> bool { self.map.insert(value, ()) } + + /// Remove an element. + /// + /// # Example + /// + /// ```rust + /// # use std::collections::HashSet; + /// let mut set = HashSet::new(); + /// set.insert(2i); + /// + /// // Return boolean success flag. + /// assert_eq!(set.remove(&2), true); + /// assert_eq!(set.remove(&2), false); + /// ``` + fn remove(&mut self, value: &T) -> bool { self.map.remove(value) } +} + + impl + fmt::Show, S, H: Hasher> fmt::Show for HashSet { + /// Implement the `Show` trait for easy output format. The values in the + /// set must also implement `Show`. + /// + /// # Example + /// + /// ```rust + /// # use std::collections::HashSet; + /// let a: HashSet = [1i, 2, 3].iter().map(|&x| x).collect(); + /// // Will call .fmt() to print, in some order. + /// println!("{}", a); + /// ``` fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { try!(write!(f, "{{")); @@ -1785,6 +1983,17 @@ impl + fmt::Show, S, H: Hasher> fmt::Show for HashSet { } impl, S, H: Hasher + Default> FromIterator for HashSet { + /// Build a set from an external iterator. + /// + /// # Example + /// + /// ```rust + /// # use std::collections::HashSet; + /// let values = vec!(1i, 2, 3); + /// let set: HashSet = values.move_iter().collect(); + /// let another_set: HashSet = [1i, 2, 3].iter().map(|&x| x).collect(); + /// assert_eq!(set, another_set); + /// ``` fn from_iter>(iter: I) -> HashSet { let (lower, _) = iter.size_hint(); let mut set = HashSet::with_capacity_and_hasher(lower, Default::default()); @@ -1794,6 +2003,18 @@ impl, S, H: Hasher + Default> FromIterator for HashSet, S, H: Hasher + Default> Extendable for HashSet { + /// Extend the set with the values yielded by an iterator. + /// + /// # Example + /// + /// ```rust + /// # use std::collections::HashSet; + /// let values = vec!(1i, 2, 3); + /// let mut set = HashSet::new(); + /// set.insert(0i); + /// set.extend(values.move_iter()); + /// assert_eq!(set.len(), 4); + /// ``` fn extend>(&mut self, mut iter: I) { for k in iter { self.insert(k); @@ -1802,6 +2023,15 @@ impl, S, H: Hasher + Default> Extendable for HashSet } impl, S, H: Hasher + Default> Default for HashSet { + /// Create a default set. + /// + /// # Example + /// + /// ```rust + /// # use std::collections::HashSet; + /// use std::default::Default; + /// let mut set: HashSet = Default::default(); + /// ``` fn default() -> HashSet { HashSet::with_hasher(Default::default()) } From 01b6fd3e82f84a504f37597152c39da9929fbfbf Mon Sep 17 00:00:00 2001 From: Jonas Hietala Date: Fri, 18 Jul 2014 16:34:07 +0200 Subject: [PATCH 2/2] Remove examples from trait implementations. Unhide imports. --- src/libstd/collections/hashmap.rs | 172 ++++-------------------------- 1 file changed, 18 insertions(+), 154 deletions(-) diff --git a/src/libstd/collections/hashmap.rs b/src/libstd/collections/hashmap.rs index 12b80d1b4674d..14027bc1f544f 100644 --- a/src/libstd/collections/hashmap.rs +++ b/src/libstd/collections/hashmap.rs @@ -1551,7 +1551,7 @@ impl HashSet { /// # Example /// /// ```rust - /// # use std::collections::HashSet; + /// use std::collections::HashSet; /// let mut set: HashSet = HashSet::new(); /// ``` #[inline] @@ -1565,7 +1565,7 @@ impl HashSet { /// # Example /// /// ```rust - /// # use std::collections::HashSet; + /// use std::collections::HashSet; /// let mut set: HashSet = HashSet::with_capacity(10); /// ``` #[inline] @@ -1583,7 +1583,7 @@ impl, S, H: Hasher> HashSet { /// # Example /// /// ```rust - /// # use std::collections::HashSet; + /// use std::collections::HashSet; /// use std::hash::sip::SipHasher; /// /// let h = SipHasher::new(); @@ -1606,7 +1606,7 @@ impl, S, H: Hasher> HashSet { /// # Example /// /// ```rust - /// # use std::collections::HashSet; + /// use std::collections::HashSet; /// use std::hash::sip::SipHasher; /// /// let h = SipHasher::new(); @@ -1623,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); /// ``` @@ -1641,7 +1641,7 @@ impl, S, H: Hasher> HashSet { /// values hash the same, which is why we implement `Hash`. /// /// ```rust - /// # use std::collections::HashSet; + /// use std::collections::HashSet; /// use std::hash::Hash; /// use std::hash::sip::SipState; /// @@ -1682,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"); @@ -1703,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()); @@ -1725,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(); /// @@ -1754,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(); /// @@ -1779,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(); /// @@ -1804,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(); /// @@ -1823,22 +1829,6 @@ impl, S, H: Hasher> HashSet { } impl, S, H: Hasher> PartialEq for HashSet { - /// Partial equality between sets. - /// - /// # Example - /// - /// ```rust - /// # use std::collections::HashSet; - /// let a: HashSet = [1i, 2, 3].iter().map(|&x| x).collect(); - /// let b: HashSet = [1i, 2, 3, 4].iter().map(|&x| x).collect(); - /// let c: HashSet = [1i, 2, 3].iter().map(|&x| x).collect(); - /// - /// assert!(a.eq(&c)); - /// - /// // eq and ne defines the == and != operators - /// assert!(a == c); - /// assert!(a != b); - /// ``` fn eq(&self, other: &HashSet) -> bool { if self.len() != other.len() { return false; } @@ -1849,127 +1839,33 @@ impl, S, H: Hasher> PartialEq for HashSet { impl, S, H: Hasher> Eq for HashSet {} impl, S, H: Hasher> Collection for HashSet { - /// Return the number of elements in the set. - /// - /// # Example - /// - /// ```rust - /// # use std::collections::HashSet; - /// let set: HashSet = [1i, 2, 3, 2].iter().map(|&x| x).collect(); - /// assert_eq!(set.len(), 3); - /// ``` fn len(&self) -> uint { self.map.len() } } impl, S, H: Hasher> Mutable for HashSet { - /// Clear the set. Keeps the allocated memory for reuse. - /// - /// # Example - /// - /// ```rust - /// # use std::collections::HashSet; - /// let mut set: HashSet = [1i, 2, 3].iter().map(|&x| x).collect(); - /// set.clear(); - /// assert!(set.is_empty()); - /// ``` fn clear(&mut self) { self.map.clear() } } impl, S, H: Hasher> Set for HashSet { - /// Return true if `value` is contained by the set. - /// - /// # Example - /// - /// ```rust - /// # use std::collections::HashSet; - /// let set: HashSet = [1i, 2, 3].iter().map(|&x| x).collect(); - /// assert_eq!(set.contains(&1), true); - /// assert_eq!(set.contains(&4), false); - /// ``` fn contains(&self, value: &T) -> bool { self.map.contains_key(value) } - /// Return true if the set is disjoint with `other`. - /// - /// # Example - /// - /// ```rust - /// # use std::collections::HashSet; - /// let a: HashSet = [1i, 2, 3].iter().map(|&x| x).collect(); - /// let mut b: HashSet = HashSet::new(); - /// - /// assert_eq!(a.is_disjoint(&b), true); - /// b.insert(4); - /// assert_eq!(a.is_disjoint(&b), true); - /// b.insert(1); - /// assert_eq!(a.is_disjoint(&b), false); - /// ``` fn is_disjoint(&self, other: &HashSet) -> bool { self.iter().all(|v| !other.contains(v)) } - /// Return true if the set is a subset of `other`. - /// - /// # Example - /// - /// ```rust - /// # use std::collections::HashSet; - /// let sup: HashSet = [1i, 2, 3].iter().map(|&x| x).collect(); - /// let mut set: HashSet = HashSet::new(); - /// - /// assert_eq!(set.is_subset(&sup), true); - /// set.insert(2); - /// assert_eq!(set.is_subset(&sup), true); - /// set.insert(4); - /// assert_eq!(set.is_subset(&sup), false); - /// ``` fn is_subset(&self, other: &HashSet) -> bool { self.iter().all(|v| other.contains(v)) } } impl, S, H: Hasher> MutableSet for HashSet { - /// Insert an element. - /// - /// # Example - /// - /// ```rust - /// # use std::collections::HashSet; - /// let mut set = HashSet::new(); - /// set.insert(2i); - /// set.insert(2i); - /// assert_eq!(set.len(), 1); - /// ``` fn insert(&mut self, value: T) -> bool { self.map.insert(value, ()) } - /// Remove an element. - /// - /// # Example - /// - /// ```rust - /// # use std::collections::HashSet; - /// let mut set = HashSet::new(); - /// set.insert(2i); - /// - /// // Return boolean success flag. - /// assert_eq!(set.remove(&2), true); - /// assert_eq!(set.remove(&2), false); - /// ``` fn remove(&mut self, value: &T) -> bool { self.map.remove(value) } } impl + fmt::Show, S, H: Hasher> fmt::Show for HashSet { - /// Implement the `Show` trait for easy output format. The values in the - /// set must also implement `Show`. - /// - /// # Example - /// - /// ```rust - /// # use std::collections::HashSet; - /// let a: HashSet = [1i, 2, 3].iter().map(|&x| x).collect(); - /// // Will call .fmt() to print, in some order. - /// println!("{}", a); - /// ``` fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { try!(write!(f, "{{")); @@ -1983,17 +1879,6 @@ impl + fmt::Show, S, H: Hasher> fmt::Show for HashSet { } impl, S, H: Hasher + Default> FromIterator for HashSet { - /// Build a set from an external iterator. - /// - /// # Example - /// - /// ```rust - /// # use std::collections::HashSet; - /// let values = vec!(1i, 2, 3); - /// let set: HashSet = values.move_iter().collect(); - /// let another_set: HashSet = [1i, 2, 3].iter().map(|&x| x).collect(); - /// assert_eq!(set, another_set); - /// ``` fn from_iter>(iter: I) -> HashSet { let (lower, _) = iter.size_hint(); let mut set = HashSet::with_capacity_and_hasher(lower, Default::default()); @@ -2003,18 +1888,6 @@ impl, S, H: Hasher + Default> FromIterator for HashSet, S, H: Hasher + Default> Extendable for HashSet { - /// Extend the set with the values yielded by an iterator. - /// - /// # Example - /// - /// ```rust - /// # use std::collections::HashSet; - /// let values = vec!(1i, 2, 3); - /// let mut set = HashSet::new(); - /// set.insert(0i); - /// set.extend(values.move_iter()); - /// assert_eq!(set.len(), 4); - /// ``` fn extend>(&mut self, mut iter: I) { for k in iter { self.insert(k); @@ -2023,15 +1896,6 @@ impl, S, H: Hasher + Default> Extendable for HashSet } impl, S, H: Hasher + Default> Default for HashSet { - /// Create a default set. - /// - /// # Example - /// - /// ```rust - /// # use std::collections::HashSet; - /// use std::default::Default; - /// let mut set: HashSet = Default::default(); - /// ``` fn default() -> HashSet { HashSet::with_hasher(Default::default()) }