Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fill in documentation for HashSet. #15772

Merged
merged 2 commits into from
Jul 19, 2014
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
186 changes: 140 additions & 46 deletions src/libstd/collections/hashmap.rs
Original file line number Diff line number Diff line change
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