// Copyright 2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! An unordered map and set type implemented as hash tables //! //! The tables use a keyed hash with new random keys generated for each container, so the ordering //! of a set of keys in a hash table is randomized. #[mutable_doc]; use container::{Container, Mutable, Map, MutableMap, Set, MutableSet}; use clone::Clone; use cmp::{Eq, Equiv}; use hash::Hash; use iterator::{Iterator, IteratorUtil, FromIterator, Extendable, Chain}; use num; use option::{None, Option, Some}; use rand::RngUtil; use rand; use uint; use util::{replace, unreachable}; use vec::{ImmutableVector, MutableVector, OwnedVector}; use vec; static INITIAL_CAPACITY: uint = 32u; // 2^5 struct Bucket { hash: uint, key: K, value: V, } /// A hash map implementation which uses linear probing along with the SipHash /// hash function for internal state. This means that the order of all hash maps /// is randomized by keying each hash map randomly on creation. /// /// It is required that the keys implement the `Eq` and `Hash` traits, although /// this can frequently be achieved by just implementing the `Eq` and /// `IterBytes` traits as `Hash` is automatically implemented for types that /// implement `IterBytes`. pub struct HashMap { priv k0: u64, priv k1: u64, priv resize_at: uint, priv size: uint, priv buckets: ~[Option>], } // We could rewrite FoundEntry to have type Option<&Bucket> // which would be nifty enum SearchResult { FoundEntry(uint), FoundHole(uint), TableFull } #[inline] fn resize_at(capacity: uint) -> uint { ((capacity as float) * 3. / 4.) as uint } /// Creates a new hash map with the specified capacity. pub fn linear_map_with_capacity( initial_capacity: uint) -> HashMap { let mut r = rand::task_rng(); linear_map_with_capacity_and_keys(r.gen(), r.gen(), initial_capacity) } fn linear_map_with_capacity_and_keys( k0: u64, k1: u64, initial_capacity: uint) -> HashMap { let cap = num::max(INITIAL_CAPACITY, initial_capacity); HashMap { k0: k0, k1: k1, resize_at: resize_at(cap), size: 0, buckets: vec::from_fn(cap, |_| None) } } impl HashMap { #[inline] fn to_bucket(&self, h: uint) -> uint { // A good hash function with entropy spread over all of the // bits is assumed. SipHash is more than good enough. h % self.buckets.len() } #[inline] fn next_bucket(&self, idx: uint, len_buckets: uint) -> uint { (idx + 1) % len_buckets } #[inline] fn bucket_sequence(&self, hash: uint, op: &fn(uint) -> bool) -> bool { let start_idx = self.to_bucket(hash); let len_buckets = self.buckets.len(); let mut idx = start_idx; loop { if !op(idx) { return false; } idx = self.next_bucket(idx, len_buckets); if idx == start_idx { return true; } } } #[inline] fn bucket_for_key(&self, k: &K) -> SearchResult { let hash = k.hash_keyed(self.k0, self.k1) as uint; self.bucket_for_key_with_hash(hash, k) } #[inline] fn bucket_for_key_equiv>(&self, k: &Q) -> SearchResult { let hash = k.hash_keyed(self.k0, self.k1) as uint; self.bucket_for_key_with_hash_equiv(hash, k) } #[inline] fn bucket_for_key_with_hash(&self, hash: uint, k: &K) -> SearchResult { let mut ret = TableFull; do self.bucket_sequence(hash) |i| { match self.buckets[i] { Some(ref bkt) if bkt.hash == hash && *k == bkt.key => { ret = FoundEntry(i); false }, None => { ret = FoundHole(i); false } _ => true, } }; ret } #[inline] fn bucket_for_key_with_hash_equiv>(&self, hash: uint, k: &Q) -> SearchResult { let mut ret = TableFull; do self.bucket_sequence(hash) |i| { match self.buckets[i] { Some(ref bkt) if bkt.hash == hash && k.equiv(&bkt.key) => { ret = FoundEntry(i); false }, None => { ret = FoundHole(i); false } _ => true, } }; ret } /// Expand the capacity of the array to the next power of two /// and re-insert each of the existing buckets. #[inline] fn expand(&mut self) { let new_capacity = self.buckets.len() * 2; self.resize(new_capacity); } /// Expands the capacity of the array and re-insert each of the /// existing buckets. fn resize(&mut self, new_capacity: uint) { self.resize_at = resize_at(new_capacity); let old_buckets = replace(&mut self.buckets, vec::from_fn(new_capacity, |_| None)); self.size = 0; // consume_rev_iter is more efficient foreach bucket in old_buckets.consume_rev_iter() { self.insert_opt_bucket(bucket); } } fn insert_opt_bucket(&mut self, bucket: Option>) { match bucket { Some(Bucket{hash: hash, key: key, value: value}) => { self.insert_internal(hash, key, value); } None => {} } } #[inline] fn value_for_bucket<'a>(&'a self, idx: uint) -> &'a V { match self.buckets[idx] { Some(ref bkt) => &bkt.value, None => fail!("HashMap::find: internal logic error"), } } #[inline] fn mut_value_for_bucket<'a>(&'a mut self, idx: uint) -> &'a mut V { match self.buckets[idx] { Some(ref mut bkt) => &mut bkt.value, None => unreachable() } } /// Inserts the key value pair into the buckets. /// Assumes that there will be a bucket. /// True if there was no previous entry with that key fn insert_internal(&mut self, hash: uint, k: K, v: V) -> Option { match self.bucket_for_key_with_hash(hash, &k) { TableFull => { fail!("Internal logic error"); } FoundHole(idx) => { self.buckets[idx] = Some(Bucket{hash: hash, key: k, value: v}); self.size += 1; None } FoundEntry(idx) => { match self.buckets[idx] { None => { fail!("insert_internal: Internal logic error") } Some(ref mut b) => { b.hash = hash; b.key = k; Some(replace(&mut b.value, v)) } } } } } fn pop_internal(&mut self, hash: uint, k: &K) -> Option { // Removing from an open-addressed hashtable // is, well, painful. The problem is that // the entry may lie on the probe path for other // entries, so removing it would make you think that // those probe paths are empty. // // To address this we basically have to keep walking, // re-inserting entries we find until we reach an empty // bucket. We know we will eventually reach one because // we insert one ourselves at the beginning (the removed // entry). // // I found this explanation elucidating: // http://www.maths.lse.ac.uk/Courses/MA407/del-hash.pdf let mut idx = match self.bucket_for_key_with_hash(hash, k) { TableFull | FoundHole(_) => return None, FoundEntry(idx) => idx }; let len_buckets = self.buckets.len(); let bucket = self.buckets[idx].take(); let value = do bucket.map_consume |bucket| { bucket.value }; /* re-inserting buckets may cause changes in size, so remember what our new size is ahead of time before we start insertions */ let size = self.size - 1; idx = self.next_bucket(idx, len_buckets); while self.buckets[idx].is_some() { let bucket = self.buckets[idx].take(); self.insert_opt_bucket(bucket); idx = self.next_bucket(idx, len_buckets); } self.size = size; value } } impl Container for HashMap { /// Return the number of elements in the map fn len(&self) -> uint { self.size } } impl Mutable for HashMap { /// Clear the map, removing all key-value pairs. fn clear(&mut self) { for uint::range(0, self.buckets.len()) |idx| { self.buckets[idx] = None; } self.size = 0; } } impl Map for HashMap { /// Return true if the map contains a value for the specified key fn contains_key(&self, k: &K) -> bool { match self.bucket_for_key(k) { FoundEntry(_) => {true} TableFull | FoundHole(_) => {false} } } /// Return a reference to the value corresponding to the key fn find<'a>(&'a self, k: &K) -> Option<&'a V> { match self.bucket_for_key(k) { FoundEntry(idx) => Some(self.value_for_bucket(idx)), TableFull | FoundHole(_) => None, } } } impl MutableMap for HashMap { /// Return a mutable reference to the value corresponding to the key fn find_mut<'a>(&'a mut self, k: &K) -> Option<&'a mut V> { let idx = match self.bucket_for_key(k) { FoundEntry(idx) => idx, TableFull | FoundHole(_) => return None }; Some(self.mut_value_for_bucket(idx)) } /// Insert a key-value pair from the map. If the key already had a value /// present in the map, that value is returned. Otherwise None is returned. fn swap(&mut self, k: K, v: V) -> Option { // this could be faster. if self.size >= self.resize_at { // n.b.: We could also do this after searching, so // that we do not resize if this call to insert is // simply going to update a key in place. My sense // though is that it's worse to have to search through // buckets to find the right spot twice than to just // resize in this corner case. self.expand(); } let hash = k.hash_keyed(self.k0, self.k1) as uint; self.insert_internal(hash, k, v) } /// Removes a key from the map, returning the value at the key if the key /// was previously in the map. fn pop(&mut self, k: &K) -> Option { let hash = k.hash_keyed(self.k0, self.k1) as uint; self.pop_internal(hash, k) } } impl HashMap { /// Create an empty HashMap pub fn new() -> HashMap { HashMap::with_capacity(INITIAL_CAPACITY) } /// Create an empty HashMap with space for at least `n` elements in /// the hash table. pub fn with_capacity(capacity: uint) -> HashMap { linear_map_with_capacity(capacity) } /// Reserve space for at least `n` elements in the hash table. pub fn reserve_at_least(&mut self, n: uint) { if n > self.buckets.len() { let buckets = n * 4 / 3 + 1; self.resize(uint::next_power_of_two(buckets)); } } /// Modify and return the value corresponding to the key in the map, or /// insert and return a new value if it doesn't exist. pub fn mangle<'a,A>(&'a mut self, k: K, a: A, not_found: &fn(&K, A) -> V, found: &fn(&K, &mut V, A)) -> &'a mut V { if self.size >= self.resize_at { // n.b.: We could also do this after searching, so // that we do not resize if this call to insert is // simply going to update a key in place. My sense // though is that it's worse to have to search through // buckets to find the right spot twice than to just // resize in this corner case. self.expand(); } let hash = k.hash_keyed(self.k0, self.k1) as uint; let idx = match self.bucket_for_key_with_hash(hash, &k) { TableFull => fail!("Internal logic error"), FoundEntry(idx) => { found(&k, self.mut_value_for_bucket(idx), a); idx } FoundHole(idx) => { let v = not_found(&k, a); self.buckets[idx] = Some(Bucket{hash: hash, key: k, value: v}); self.size += 1; idx } }; self.mut_value_for_bucket(idx) } /// Return the value corresponding to the key in the map, or insert /// and return the value if it doesn't exist. pub fn find_or_insert<'a>(&'a mut self, k: K, v: V) -> &'a mut V { self.mangle(k, v, |_k, a| a, |_k,_v,_a| ()) } /// Return the value corresponding to the key in the map, or create, /// insert, and return a new value if it doesn't exist. pub fn find_or_insert_with<'a>(&'a mut self, k: K, f: &fn(&K) -> V) -> &'a mut V { self.mangle(k, (), |k,_a| f(k), |_k,_v,_a| ()) } /// Insert a key-value pair into the map if the key is not already present. /// Otherwise, modify the existing value for the key. /// Returns the new or modified value for the key. pub fn insert_or_update_with<'a>(&'a mut self, k: K, v: V, f: &fn(&K, &mut V)) -> &'a mut V { self.mangle(k, v, |_k,a| a, |k,v,_a| f(k,v)) } /// Retrieves a value for the given key, failing if the key is not /// present. pub fn get<'a>(&'a self, k: &K) -> &'a V { match self.find(k) { Some(v) => v, None => fail!("No entry found for key: %?", k), } } /// Retrieves a (mutable) value for the given key, failing if the key /// is not present. pub fn get_mut<'a>(&'a mut self, k: &K) -> &'a mut V { match self.find_mut(k) { Some(v) => v, None => fail!("No entry found for key: %?", k), } } /// Return true if the map contains a value for the specified key, /// using equivalence pub fn contains_key_equiv>(&self, key: &Q) -> bool { match self.bucket_for_key_equiv(key) { FoundEntry(_) => {true} TableFull | FoundHole(_) => {false} } } /// Return the value corresponding to the key in the map, using /// equivalence pub fn find_equiv<'a, Q:Hash + Equiv>(&'a self, k: &Q) -> Option<&'a V> { match self.bucket_for_key_equiv(k) { FoundEntry(idx) => Some(self.value_for_bucket(idx)), TableFull | FoundHole(_) => None, } } /// Visit all keys pub fn each_key(&self, blk: &fn(k: &K) -> bool) -> bool { self.iter().advance(|(k, _)| blk(k)) } /// Visit all values pub fn each_value<'a>(&'a self, blk: &fn(v: &'a V) -> bool) -> bool { self.iter().advance(|(_, v)| blk(v)) } /// An iterator visiting all key-value pairs in arbitrary order. /// Iterator element type is (&'a K, &'a V). pub fn iter<'a>(&'a self) -> HashMapIterator<'a, K, V> { HashMapIterator { iter: self.buckets.iter() } } /// An iterator visiting all key-value pairs in arbitrary order, /// with mutable references to the values. /// Iterator element type is (&'a K, &'a mut V). pub fn mut_iter<'a>(&'a mut self) -> HashMapMutIterator<'a, K, V> { HashMapMutIterator { iter: self.buckets.mut_iter() } } /// Creates a consuming iterator, that is, one that moves each key-value /// pair out of the map in arbitrary order. The map cannot be used after /// calling this. pub fn consume(self) -> HashMapConsumeIterator { // `consume_rev_iter` is more efficient than `consume_iter` for vectors HashMapConsumeIterator {iter: self.buckets.consume_rev_iter()} } } impl HashMap { /// Like `find`, but returns a copy of the value. pub fn find_copy(&self, k: &K) -> Option { self.find(k).map_consume(|v| (*v).clone()) } /// Like `get`, but returns a copy of the value. pub fn get_copy(&self, k: &K) -> V { (*self.get(k)).clone() } } impl Eq for HashMap { fn eq(&self, other: &HashMap) -> bool { if self.len() != other.len() { return false; } do self.iter().all |(key, value)| { match other.find(key) { None => false, Some(v) => value == v } } } fn ne(&self, other: &HashMap) -> bool { !self.eq(other) } } impl Clone for HashMap { fn clone(&self) -> HashMap { let mut new_map = HashMap::with_capacity(self.len()); foreach (key, value) in self.iter() { new_map.insert((*key).clone(), (*value).clone()); } new_map } } /// HashMap iterator #[deriving(Clone)] pub struct HashMapIterator<'self, K, V> { priv iter: vec::VecIterator<'self, Option>>, } /// HashMap mutable values iterator pub struct HashMapMutIterator<'self, K, V> { priv iter: vec::VecMutIterator<'self, Option>>, } /// HashMap consume iterator pub struct HashMapConsumeIterator { priv iter: vec::ConsumeRevIterator>>, } /// HashSet iterator #[deriving(Clone)] pub struct HashSetIterator<'self, K> { priv iter: vec::VecIterator<'self, Option>>, } /// HashSet consume iterator pub struct HashSetConsumeIterator { priv iter: vec::ConsumeRevIterator>>, } impl<'self, K, V> Iterator<(&'self K, &'self V)> for HashMapIterator<'self, K, V> { #[inline] fn next(&mut self) -> Option<(&'self K, &'self V)> { foreach elt in self.iter { match elt { &Some(ref bucket) => return Some((&bucket.key, &bucket.value)), &None => {}, } } None } } impl<'self, K, V> Iterator<(&'self K, &'self mut V)> for HashMapMutIterator<'self, K, V> { #[inline] fn next(&mut self) -> Option<(&'self K, &'self mut V)> { foreach elt in self.iter { match elt { &Some(ref mut bucket) => return Some((&bucket.key, &mut bucket.value)), &None => {}, } } None } } impl Iterator<(K, V)> for HashMapConsumeIterator { #[inline] fn next(&mut self) -> Option<(K, V)> { foreach elt in self.iter { match elt { Some(Bucket {key, value, _}) => return Some((key, value)), None => {}, } } None } } impl<'self, K> Iterator<&'self K> for HashSetIterator<'self, K> { #[inline] fn next(&mut self) -> Option<&'self K> { foreach elt in self.iter { match elt { &Some(ref bucket) => return Some(&bucket.key), &None => {}, } } None } } impl Iterator for HashSetConsumeIterator { #[inline] fn next(&mut self) -> Option { foreach elt in self.iter { match elt { Some(bucket) => return Some(bucket.key), None => {}, } } None } } impl> FromIterator<(K, V), T> for HashMap { fn from_iterator(iter: &mut T) -> HashMap { let (lower, _) = iter.size_hint(); let mut map = HashMap::with_capacity(lower); map.extend(iter); map } } impl> Extendable<(K, V), T> for HashMap { fn extend(&mut self, iter: &mut T) { foreach (k, v) in *iter { self.insert(k, v); } } } /// An implementation of a hash set using the underlying representation of a /// HashMap where the value is (). As with the `HashMap` type, a `HashSet` /// requires that the elements implement the `Eq` and `Hash` traits. pub struct HashSet { priv map: HashMap } impl Eq for HashSet { fn eq(&self, other: &HashSet) -> bool { self.map == other.map } fn ne(&self, other: &HashSet) -> bool { self.map != other.map } } impl Container for HashSet { /// Return the number of elements in the set fn len(&self) -> uint { self.map.len() } } impl Mutable for HashSet { /// Clear the set, removing all values. fn clear(&mut self) { self.map.clear() } } impl Set for HashSet { /// Return true if the set contains a value fn contains(&self, value: &T) -> bool { self.map.contains_key(value) } /// Return true if the set has no elements in common with `other`. /// This is equivalent to checking for an empty intersection. fn is_disjoint(&self, other: &HashSet) -> bool { self.iter().all(|v| !other.contains(v)) } /// Return true if the set is a subset of another fn is_subset(&self, other: &HashSet) -> bool { self.iter().all(|v| other.contains(v)) } /// Return true if the set is a superset of another fn is_superset(&self, other: &HashSet) -> bool { other.is_subset(self) } } impl MutableSet for HashSet { /// Add a value to the set. Return true if the value was not already /// present in the set. fn insert(&mut self, value: T) -> bool { self.map.insert(value, ()) } /// Remove a value from the set. Return true if the value was /// present in the set. fn remove(&mut self, value: &T) -> bool { self.map.remove(value) } } impl HashSet { /// Create an empty HashSet pub fn new() -> HashSet { HashSet::with_capacity(INITIAL_CAPACITY) } /// Create an empty HashSet with space for at least `n` elements in /// the hash table. pub fn with_capacity(capacity: uint) -> HashSet { HashSet { map: HashMap::with_capacity(capacity) } } /// Reserve space for at least `n` elements in the hash table. pub fn reserve_at_least(&mut self, n: uint) { self.map.reserve_at_least(n) } /// Returns true if the hash set contains a value equivalent to the /// given query value. pub fn contains_equiv>(&self, value: &Q) -> bool { self.map.contains_key_equiv(value) } /// An iterator visiting all elements in arbitrary order. /// Iterator element type is &'a T. pub fn iter<'a>(&'a self) -> HashSetIterator<'a, T> { HashSetIterator { iter: self.map.buckets.iter() } } /// Creates a consuming iterator, that is, one that moves each value out /// of the set in arbitrary order. The set cannot be used after calling /// this. pub fn consume(self) -> HashSetConsumeIterator { // `consume_rev_iter` is more efficient than `consume_iter` for vectors HashSetConsumeIterator {iter: self.map.buckets.consume_rev_iter()} } /// Visit the values representing the difference pub fn difference_iter<'a>(&'a self, other: &'a HashSet) -> SetAlgebraIter<'a, T> { EnvFilterIterator{iter: self.iter(), env: other, filter: |elt, other| !other.contains(elt) } } /// Visit the values representing the symmetric difference pub fn symmetric_difference_iter<'a>(&'a self, other: &'a HashSet) -> Chain, SetAlgebraIter<'a, T>> { self.difference_iter(other).chain_(other.difference_iter(self)) } /// Visit the values representing the intersection pub fn intersection_iter<'a>(&'a self, other: &'a HashSet) -> SetAlgebraIter<'a, T> { EnvFilterIterator{iter: self.iter(), env: other, filter: |elt, other| other.contains(elt) } } /// Visit the values representing the union pub fn union_iter<'a>(&'a self, other: &'a HashSet) -> Chain, SetAlgebraIter<'a, T>> { self.iter().chain_(other.difference_iter(self)) } } impl> FromIterator for HashSet { fn from_iterator(iter: &mut T) -> HashSet { let (lower, _) = iter.size_hint(); let mut set = HashSet::with_capacity(lower); set.extend(iter); set } } impl> Extendable for HashSet { fn extend(&mut self, iter: &mut T) { foreach k in *iter { self.insert(k); } } } // FIXME #7814: use std::iterator::FilterIterator /// Building block for Set operation iterators pub struct EnvFilterIterator { priv env: Env, priv filter: &'static fn(&A, Env) -> bool, priv iter: I, } impl<'self, A, Env: Clone, I: Iterator<&'self A>> Iterator<&'self A> for EnvFilterIterator { #[inline] fn next(&mut self) -> Option<&'self A> { loop { match self.iter.next() { Some(elt) => if (self.filter)(elt, self.env.clone()) { return Some(elt) }, None => return None, } } } #[inline] fn size_hint(&self) -> (uint, Option) { let (_, upper) = self.iter.size_hint(); (0, upper) } } /// Set operations iterator pub type SetAlgebraIter<'self, T> = EnvFilterIterator, HashSetIterator<'self, T>>; #[cfg(test)] mod test_map { use container::{Container, Map}; use option::{None, Some}; use super::*; use uint; #[test] fn test_create_capacity_zero() { let mut m = HashMap::with_capacity(0); assert!(m.insert(1, 1)); } #[test] fn test_insert() { let mut m = HashMap::new(); assert!(m.insert(1, 2)); assert!(m.insert(2, 4)); assert_eq!(*m.get(&1), 2); assert_eq!(*m.get(&2), 4); } #[test] fn test_find_mut() { let mut m = HashMap::new(); assert!(m.insert(1, 12)); assert!(m.insert(2, 8)); assert!(m.insert(5, 14)); let new = 100; match m.find_mut(&5) { None => fail!(), Some(x) => *x = new } assert_eq!(m.find(&5), Some(&new)); } #[test] fn test_insert_overwrite() { let mut m = HashMap::new(); assert!(m.insert(1, 2)); assert_eq!(*m.get(&1), 2); assert!(!m.insert(1, 3)); assert_eq!(*m.get(&1), 3); } #[test] fn test_insert_conflicts() { let mut m = linear_map_with_capacity(4); assert!(m.insert(1, 2)); assert!(m.insert(5, 3)); assert!(m.insert(9, 4)); assert_eq!(*m.get(&9), 4); assert_eq!(*m.get(&5), 3); assert_eq!(*m.get(&1), 2); } #[test] fn test_conflict_remove() { let mut m = linear_map_with_capacity(4); assert!(m.insert(1, 2)); assert!(m.insert(5, 3)); assert!(m.insert(9, 4)); assert!(m.remove(&1)); assert_eq!(*m.get(&9), 4); assert_eq!(*m.get(&5), 3); } #[test] fn test_is_empty() { let mut m = linear_map_with_capacity(4); assert!(m.insert(1, 2)); assert!(!m.is_empty()); assert!(m.remove(&1)); assert!(m.is_empty()); } #[test] fn test_pop() { let mut m = HashMap::new(); m.insert(1, 2); assert_eq!(m.pop(&1), Some(2)); assert_eq!(m.pop(&1), None); } #[test] fn test_swap() { let mut m = HashMap::new(); assert_eq!(m.swap(1, 2), None); assert_eq!(m.swap(1, 3), Some(2)); assert_eq!(m.swap(1, 4), Some(3)); } #[test] fn test_find_or_insert() { let mut m = HashMap::new::(); assert_eq!(*m.find_or_insert(1, 2), 2); assert_eq!(*m.find_or_insert(1, 3), 2); } #[test] fn test_find_or_insert_with() { let mut m = HashMap::new::(); assert_eq!(*m.find_or_insert_with(1, |_| 2), 2); assert_eq!(*m.find_or_insert_with(1, |_| 3), 2); } #[test] fn test_insert_or_update_with() { let mut m = HashMap::new::(); assert_eq!(*m.insert_or_update_with(1, 2, |_,x| *x+=1), 2); assert_eq!(*m.insert_or_update_with(1, 2, |_,x| *x+=1), 3); } #[test] fn test_consume() { let hm = { let mut hm = HashMap::new(); hm.insert('a', 1); hm.insert('b', 2); hm }; let v = hm.consume().collect::<~[(char, int)]>(); assert!([('a', 1), ('b', 2)] == v || [('b', 2), ('a', 1)] == v); } #[test] fn test_iterate() { let mut m = linear_map_with_capacity(4); for uint::range(0, 32) |i| { assert!(m.insert(i, i*2)); } let mut observed = 0; foreach (k, v) in m.iter() { assert_eq!(*v, *k * 2); observed |= (1 << *k); } assert_eq!(observed, 0xFFFF_FFFF); } #[test] fn test_find() { let mut m = HashMap::new(); assert!(m.find(&1).is_none()); m.insert(1, 2); match m.find(&1) { None => fail!(), Some(v) => assert!(*v == 2) } } #[test] fn test_eq() { let mut m1 = HashMap::new(); m1.insert(1, 2); m1.insert(2, 3); m1.insert(3, 4); let mut m2 = HashMap::new(); m2.insert(1, 2); m2.insert(2, 3); assert!(m1 != m2); m2.insert(3, 4); assert_eq!(m1, m2); } #[test] fn test_expand() { let mut m = HashMap::new(); assert_eq!(m.len(), 0); assert!(m.is_empty()); let mut i = 0u; let old_resize_at = m.resize_at; while old_resize_at == m.resize_at { m.insert(i, i); i += 1; } assert_eq!(m.len(), i); assert!(!m.is_empty()); } #[test] fn test_find_equiv() { let mut m = HashMap::new(); let (foo, bar, baz) = (1,2,3); m.insert(~"foo", foo); m.insert(~"bar", bar); m.insert(~"baz", baz); assert_eq!(m.find_equiv(&("foo")), Some(&foo)); assert_eq!(m.find_equiv(&("bar")), Some(&bar)); assert_eq!(m.find_equiv(&("baz")), Some(&baz)); assert_eq!(m.find_equiv(&("qux")), None); } #[test] fn test_from_iter() { let xs = ~[(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; let map: HashMap = xs.iter().transform(|&x| x).collect(); foreach &(k, v) in xs.iter() { assert_eq!(map.find(&k), Some(&v)); } } } #[cfg(test)] mod test_set { use super::*; use prelude::*; use container::Container; use vec::ImmutableEqVector; use uint; #[test] fn test_disjoint() { let mut xs = HashSet::new(); let mut ys = HashSet::new(); assert!(xs.is_disjoint(&ys)); assert!(ys.is_disjoint(&xs)); assert!(xs.insert(5)); assert!(ys.insert(11)); assert!(xs.is_disjoint(&ys)); assert!(ys.is_disjoint(&xs)); assert!(xs.insert(7)); assert!(xs.insert(19)); assert!(xs.insert(4)); assert!(ys.insert(2)); assert!(ys.insert(-11)); assert!(xs.is_disjoint(&ys)); assert!(ys.is_disjoint(&xs)); assert!(ys.insert(7)); assert!(!xs.is_disjoint(&ys)); assert!(!ys.is_disjoint(&xs)); } #[test] fn test_subset_and_superset() { let mut a = HashSet::new(); assert!(a.insert(0)); assert!(a.insert(5)); assert!(a.insert(11)); assert!(a.insert(7)); let mut b = HashSet::new(); assert!(b.insert(0)); assert!(b.insert(7)); assert!(b.insert(19)); assert!(b.insert(250)); assert!(b.insert(11)); assert!(b.insert(200)); assert!(!a.is_subset(&b)); assert!(!a.is_superset(&b)); assert!(!b.is_subset(&a)); assert!(!b.is_superset(&a)); assert!(b.insert(5)); assert!(a.is_subset(&b)); assert!(!a.is_superset(&b)); assert!(!b.is_subset(&a)); assert!(b.is_superset(&a)); } #[test] fn test_iterate() { let mut a = HashSet::new(); for uint::range(0, 32) |i| { assert!(a.insert(i)); } let mut observed = 0; foreach k in a.iter() { observed |= (1 << *k); } assert_eq!(observed, 0xFFFF_FFFF); } #[test] fn test_intersection() { let mut a = HashSet::new(); let mut b = HashSet::new(); assert!(a.insert(11)); assert!(a.insert(1)); assert!(a.insert(3)); assert!(a.insert(77)); assert!(a.insert(103)); assert!(a.insert(5)); assert!(a.insert(-5)); assert!(b.insert(2)); assert!(b.insert(11)); assert!(b.insert(77)); assert!(b.insert(-9)); assert!(b.insert(-42)); assert!(b.insert(5)); assert!(b.insert(3)); let mut i = 0; let expected = [3, 5, 11, 77]; foreach x in a.intersection_iter(&b) { assert!(expected.contains(x)); i += 1 } assert_eq!(i, expected.len()); } #[test] fn test_difference() { let mut a = HashSet::new(); let mut b = HashSet::new(); assert!(a.insert(1)); assert!(a.insert(3)); assert!(a.insert(5)); assert!(a.insert(9)); assert!(a.insert(11)); assert!(b.insert(3)); assert!(b.insert(9)); let mut i = 0; let expected = [1, 5, 11]; foreach x in a.difference_iter(&b) { assert!(expected.contains(x)); i += 1 } assert_eq!(i, expected.len()); } #[test] fn test_symmetric_difference() { let mut a = HashSet::new(); let mut b = HashSet::new(); assert!(a.insert(1)); assert!(a.insert(3)); assert!(a.insert(5)); assert!(a.insert(9)); assert!(a.insert(11)); assert!(b.insert(-2)); assert!(b.insert(3)); assert!(b.insert(9)); assert!(b.insert(14)); assert!(b.insert(22)); let mut i = 0; let expected = [-2, 1, 5, 11, 14, 22]; foreach x in a.symmetric_difference_iter(&b) { assert!(expected.contains(x)); i += 1 } assert_eq!(i, expected.len()); } #[test] fn test_union() { let mut a = HashSet::new(); let mut b = HashSet::new(); assert!(a.insert(1)); assert!(a.insert(3)); assert!(a.insert(5)); assert!(a.insert(9)); assert!(a.insert(11)); assert!(a.insert(16)); assert!(a.insert(19)); assert!(a.insert(24)); assert!(b.insert(-2)); assert!(b.insert(1)); assert!(b.insert(5)); assert!(b.insert(9)); assert!(b.insert(13)); assert!(b.insert(19)); let mut i = 0; let expected = [-2, 1, 3, 5, 9, 11, 13, 16, 19, 24]; foreach x in a.union_iter(&b) { assert!(expected.contains(x)); i += 1 } assert_eq!(i, expected.len()); } #[test] fn test_from_iter() { let xs = ~[1, 2, 3, 4, 5, 6, 7, 8, 9]; let set: HashSet = xs.iter().transform(|&x| x).collect(); foreach x in xs.iter() { assert!(set.contains(x)); } } #[test] fn test_consume() { let hs = { let mut hs = HashSet::new(); hs.insert('a'); hs.insert('b'); hs }; let v = hs.consume().collect::<~[char]>(); assert!(['a', 'b'] == v || ['b', 'a'] == v); } }