Skip to content

Commit

Permalink
auto merge of #15772 : treeman/rust/hashset-doc, r=alexcrichton
Browse files Browse the repository at this point in the history
Example how to use the set with a custom type. Fill in examples for the missing methods. Also group implemented traits below `HashSet` method impl.
  • Loading branch information
bors committed Jul 19, 2014
2 parents ca38434 + 01b6fd3 commit 793b142
Showing 1 changed file with 140 additions and 46 deletions.
186 changes: 140 additions & 46 deletions src/libstd/collections/hashmap.rs
Expand Up @@ -1514,54 +1514,44 @@ 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
///
/// ```rust
/// # use std::collections::HashSet;
/// use std::collections::HashSet;
/// let mut set: HashSet<int> = HashSet::new();
/// ```
#[inline]
Expand All @@ -1575,7 +1565,7 @@ impl<T: Hash + Eq> HashSet<T, RandomSipHasher> {
/// # Example
///
/// ```rust
/// # use std::collections::HashSet;
/// use std::collections::HashSet;
/// let mut set: HashSet<int> = HashSet::with_capacity(10);
/// ```
#[inline]
Expand All @@ -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)
Expand All @@ -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) }
Expand All @@ -1611,7 +1623,7 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> {
/// # Example
///
/// ```rust
/// # use std::collections::HashSet;
/// use std::collections::HashSet;
/// let mut set: HashSet<int> = HashSet::new();
/// set.reserve(10);
/// ```
Expand All @@ -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)
}
Expand All @@ -1631,7 +1682,8 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> {
/// # Example
///
/// ```rust
/// # use std::collections::HashSet;
/// use std::collections::HashSet;
///
/// let mut set = HashSet::new();
/// set.insert("a");
/// set.insert("b");
Expand All @@ -1652,7 +1704,8 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> {
/// # 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());
Expand All @@ -1674,7 +1727,8 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> {
/// # Example
///
/// ```rust
/// # use std::collections::HashSet;
/// use std::collections::HashSet;
///
/// let a: HashSet<int> = [1i, 2, 3].iter().map(|&x| x).collect();
/// let b: HashSet<int> = [4i, 2, 3, 4].iter().map(|&x| x).collect();
///
Expand Down Expand Up @@ -1703,7 +1757,8 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> {
/// # Example
///
/// ```rust
/// # use std::collections::HashSet;
/// use std::collections::HashSet;
///
/// let a: HashSet<int> = [1i, 2, 3].iter().map(|&x| x).collect();
/// let b: HashSet<int> = [4i, 2, 3, 4].iter().map(|&x| x).collect();
///
Expand All @@ -1728,7 +1783,8 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> {
/// # Example
///
/// ```rust
/// # use std::collections::HashSet;
/// use std::collections::HashSet;
///
/// let a: HashSet<int> = [1i, 2, 3].iter().map(|&x| x).collect();
/// let b: HashSet<int> = [4i, 2, 3, 4].iter().map(|&x| x).collect();
///
Expand All @@ -1753,7 +1809,8 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> {
/// # Example
///
/// ```rust
/// # use std::collections::HashSet;
/// use std::collections::HashSet;
///
/// let a: HashSet<int> = [1i, 2, 3].iter().map(|&x| x).collect();
/// let b: HashSet<int> = [4i, 2, 3, 4].iter().map(|&x| x).collect();
///
Expand All @@ -1771,6 +1828,43 @@ 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> {
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: Eq + Hash<S> + fmt::Show, S, H: Hasher<S>> fmt::Show for HashSet<T, H> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
try!(write!(f, "{{"));
Expand Down

0 comments on commit 793b142

Please sign in to comment.