diff options
| author | Jonas Hietala <tradet.h@gmail.com> | 2014-07-17 20:40:39 +0200 |
|---|---|---|
| committer | Jonas Hietala <tradet.h@gmail.com> | 2014-07-18 14:10:39 +0200 |
| commit | b2a02b580d4193a75e4aacdd58e87805437480c5 (patch) | |
| tree | 336048da5188805dc5068420d4e6569e1c346300 /src/libstd | |
| parent | d9f1d6b7f69f293ba5f060fd9e179de228d9497b (diff) | |
| download | rust-b2a02b580d4193a75e4aacdd58e87805437480c5.tar.gz rust-b2a02b580d4193a75e4aacdd58e87805437480c5.zip | |
Fill in documentation for HashSet.
Example how to use the set with a custom type. Fill in examples for the missing methods.
Diffstat (limited to 'src/libstd')
| -rw-r--r-- | src/libstd/collections/hashmap.rs | 304 |
1 files changed, 267 insertions, 37 deletions
diff --git a/src/libstd/collections/hashmap.rs b/src/libstd/collections/hashmap.rs index 9a53c941377..12b80d1b467 100644 --- a/src/libstd/collections/hashmap.rs +++ b/src/libstd/collections/hashmap.rs @@ -1514,49 +1514,39 @@ pub type SetMoveItems<K> = /// 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<T, H = RandomSipHasher> { map: HashMap<T, (), H> } -impl<T: Eq + Hash<S>, S, H: Hasher<S>> PartialEq for HashSet<T, H> { - fn eq(&self, other: &HashSet<T, H>) -> bool { - if self.len() != other.len() { return false; } - - self.iter().all(|key| other.contains(key)) - } -} - -impl<T: Eq + Hash<S>, S, H: Hasher<S>> Eq for HashSet<T, H> {} - -impl<T: Eq + Hash<S>, S, H: Hasher<S>> Collection for HashSet<T, H> { - fn len(&self) -> uint { self.map.len() } -} - -impl<T: Eq + Hash<S>, S, H: Hasher<S>> Mutable for HashSet<T, H> { - fn clear(&mut self) { self.map.clear() } -} - -impl<T: Eq + Hash<S>, S, H: Hasher<S>> Set<T> for HashSet<T, H> { - fn contains(&self, value: &T) -> bool { self.map.contains_key(value) } - - fn is_disjoint(&self, other: &HashSet<T, H>) -> bool { - self.iter().all(|v| !other.contains(v)) - } - - fn is_subset(&self, other: &HashSet<T, H>) -> bool { - self.iter().all(|v| other.contains(v)) - } -} - -impl<T: Eq + Hash<S>, S, H: Hasher<S>> MutableSet<T> for HashSet<T, H> { - fn insert(&mut self, value: T) -> bool { self.map.insert(value, ()) } - - fn remove(&mut self, value: &T) -> bool { self.map.remove(value) } -} - impl<T: Hash + Eq> HashSet<T, RandomSipHasher> { - /// Create an empty HashSet + /// Create an empty HashSet. /// /// # Example /// @@ -1589,6 +1579,17 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> { /// 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<T, H> { HashSet::with_capacity_and_hasher(INITIAL_CAPACITY, hasher) @@ -1601,6 +1602,17 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> { /// 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<T, H> { HashSet { map: HashMap::with_capacity_and_hasher(capacity, hasher) } @@ -1621,6 +1633,45 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> { /// 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<EvenOrOdd> 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<Q: Hash<S> + Equiv<T>>(&self, value: &Q) -> bool { self.map.contains_key_equiv(value) } @@ -1771,7 +1822,154 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> { } } +impl<T: Eq + Hash<S>, S, H: Hasher<S>> PartialEq for HashSet<T, H> { + /// Partial equality between sets. + /// + /// # Example + /// + /// ```rust + /// # use std::collections::HashSet; + /// let a: HashSet<int> = [1i, 2, 3].iter().map(|&x| x).collect(); + /// let b: HashSet<int> = [1i, 2, 3, 4].iter().map(|&x| x).collect(); + /// let c: HashSet<int> = [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<T, H>) -> bool { + if self.len() != other.len() { return false; } + + self.iter().all(|key| other.contains(key)) + } +} + +impl<T: Eq + Hash<S>, S, H: Hasher<S>> Eq for HashSet<T, H> {} + +impl<T: Eq + Hash<S>, S, H: Hasher<S>> Collection for HashSet<T, H> { + /// Return the number of elements in the set. + /// + /// # Example + /// + /// ```rust + /// # use std::collections::HashSet; + /// let set: HashSet<int> = [1i, 2, 3, 2].iter().map(|&x| x).collect(); + /// assert_eq!(set.len(), 3); + /// ``` + fn len(&self) -> uint { self.map.len() } +} + +impl<T: Eq + Hash<S>, S, H: Hasher<S>> Mutable for HashSet<T, H> { + /// Clear the set. Keeps the allocated memory for reuse. + /// + /// # Example + /// + /// ```rust + /// # use std::collections::HashSet; + /// let mut set: HashSet<int> = [1i, 2, 3].iter().map(|&x| x).collect(); + /// set.clear(); + /// assert!(set.is_empty()); + /// ``` + fn clear(&mut self) { self.map.clear() } +} + +impl<T: Eq + Hash<S>, S, H: Hasher<S>> Set<T> for HashSet<T, H> { + /// Return true if `value` is contained by the set. + /// + /// # Example + /// + /// ```rust + /// # use std::collections::HashSet; + /// let set: HashSet<int> = [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<int> = [1i, 2, 3].iter().map(|&x| x).collect(); + /// let mut b: HashSet<int> = 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<T, H>) -> 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<int> = [1i, 2, 3].iter().map(|&x| x).collect(); + /// let mut set: HashSet<int> = 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<T, H>) -> bool { + self.iter().all(|v| other.contains(v)) + } +} + +impl<T: Eq + Hash<S>, S, H: Hasher<S>> MutableSet<T> for HashSet<T, H> { + /// 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<T: Eq + Hash<S> + fmt::Show, S, H: Hasher<S>> fmt::Show for HashSet<T, H> { + /// 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<int> = [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<T: Eq + Hash<S> + fmt::Show, S, H: Hasher<S>> fmt::Show for HashSet<T, H> { } impl<T: Eq + Hash<S>, S, H: Hasher<S> + Default> FromIterator<T> for HashSet<T, H> { + /// Build a set from an external iterator. + /// + /// # Example + /// + /// ```rust + /// # use std::collections::HashSet; + /// let values = vec!(1i, 2, 3); + /// let set: HashSet<int> = values.move_iter().collect(); + /// let another_set: HashSet<int> = [1i, 2, 3].iter().map(|&x| x).collect(); + /// assert_eq!(set, another_set); + /// ``` fn from_iter<I: Iterator<T>>(iter: I) -> HashSet<T, H> { let (lower, _) = iter.size_hint(); let mut set = HashSet::with_capacity_and_hasher(lower, Default::default()); @@ -1794,6 +2003,18 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S> + Default> FromIterator<T> for HashSet<T, } impl<T: Eq + Hash<S>, S, H: Hasher<S> + Default> Extendable<T> for HashSet<T, H> { + /// 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<I: Iterator<T>>(&mut self, mut iter: I) { for k in iter { self.insert(k); @@ -1802,6 +2023,15 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S> + Default> Extendable<T> for HashSet<T, H> } impl<T: Eq + Hash<S>, S, H: Hasher<S> + Default> Default for HashSet<T, H> { + /// Create a default set. + /// + /// # Example + /// + /// ```rust + /// # use std::collections::HashSet; + /// use std::default::Default; + /// let mut set: HashSet<int> = Default::default(); + /// ``` fn default() -> HashSet<T, H> { HashSet::with_hasher(Default::default()) } |
