2013-01-20 13:18:24 -06:00
|
|
|
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
2012-12-03 18:48:01 -06:00
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2013-03-27 02:03:10 -05:00
|
|
|
//! 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.
|
2012-07-26 18:09:22 -05:00
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
use container::{Container, Mutable, Map, Set};
|
|
|
|
use cmp::{Eq, Equiv};
|
|
|
|
use hash::Hash;
|
2013-04-24 19:35:49 -05:00
|
|
|
use old_iter::BaseIter;
|
|
|
|
use old_iter;
|
2013-04-03 07:45:14 -05:00
|
|
|
use option::{None, Option, Some};
|
|
|
|
use rand::RngUtil;
|
|
|
|
use rand;
|
|
|
|
use uint;
|
|
|
|
use vec;
|
2013-05-05 11:17:59 -05:00
|
|
|
use kinds::Copy;
|
2013-05-04 08:54:58 -05:00
|
|
|
use util::{replace, unreachable};
|
2013-04-03 07:45:14 -05:00
|
|
|
|
|
|
|
static INITIAL_CAPACITY: uint = 32u; // 2^5
|
|
|
|
|
|
|
|
struct Bucket<K,V> {
|
|
|
|
hash: uint,
|
|
|
|
key: K,
|
|
|
|
value: V,
|
|
|
|
}
|
2012-12-23 16:41:37 -06:00
|
|
|
|
2013-04-03 08:28:36 -05:00
|
|
|
pub struct HashMap<K,V> {
|
2013-04-03 07:45:14 -05:00
|
|
|
priv k0: u64,
|
|
|
|
priv k1: u64,
|
|
|
|
priv resize_at: uint,
|
|
|
|
priv size: uint,
|
|
|
|
priv buckets: ~[Option<Bucket<K, V>>],
|
|
|
|
}
|
2012-09-26 19:47:29 -05:00
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
// We could rewrite FoundEntry to have type Option<&Bucket<K, V>>
|
|
|
|
// which would be nifty
|
|
|
|
enum SearchResult {
|
|
|
|
FoundEntry(uint), FoundHole(uint), TableFull
|
|
|
|
}
|
2013-01-24 21:00:58 -06:00
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
#[inline(always)]
|
|
|
|
fn resize_at(capacity: uint) -> uint {
|
|
|
|
((capacity as float) * 3. / 4.) as uint
|
|
|
|
}
|
2012-07-26 18:09:22 -05:00
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
pub fn linear_map_with_capacity<K:Eq + Hash,V>(
|
2013-04-03 08:28:36 -05:00
|
|
|
initial_capacity: uint) -> HashMap<K, V> {
|
2013-05-03 01:09:50 -05:00
|
|
|
let mut r = rand::task_rng();
|
2013-04-24 07:29:19 -05:00
|
|
|
linear_map_with_capacity_and_keys(r.gen(), r.gen(),
|
2013-04-03 07:45:14 -05:00
|
|
|
initial_capacity)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn linear_map_with_capacity_and_keys<K:Eq + Hash,V>(
|
|
|
|
k0: u64, k1: u64,
|
2013-04-03 08:28:36 -05:00
|
|
|
initial_capacity: uint) -> HashMap<K, V> {
|
|
|
|
HashMap {
|
2013-04-03 07:45:14 -05:00
|
|
|
k0: k0, k1: k1,
|
|
|
|
resize_at: resize_at(initial_capacity),
|
|
|
|
size: 0,
|
|
|
|
buckets: vec::from_fn(initial_capacity, |_| None)
|
2012-07-26 18:09:22 -05:00
|
|
|
}
|
2013-04-03 07:45:14 -05:00
|
|
|
}
|
2012-07-26 18:09:22 -05:00
|
|
|
|
2013-04-18 17:53:29 -05:00
|
|
|
priv impl<K:Hash + Eq,V> HashMap<K, V> {
|
2013-02-15 00:35:15 -06:00
|
|
|
#[inline(always)]
|
2013-04-03 07:45:14 -05:00
|
|
|
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()
|
2012-07-26 18:09:22 -05:00
|
|
|
}
|
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
#[inline(always)]
|
|
|
|
fn next_bucket(&self, idx: uint, len_buckets: uint) -> uint {
|
|
|
|
let n = (idx + 1) % len_buckets;
|
|
|
|
debug!("next_bucket(%?, %?) = %?", idx, len_buckets, n);
|
|
|
|
n
|
2012-08-30 21:01:22 -05:00
|
|
|
}
|
2012-07-26 18:09:22 -05:00
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
#[inline(always)]
|
2013-05-02 17:33:18 -05:00
|
|
|
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; }
|
2013-04-03 07:45:14 -05:00
|
|
|
idx = self.next_bucket(idx, len_buckets);
|
|
|
|
if idx == start_idx {
|
2013-05-02 17:33:18 -05:00
|
|
|
return true;
|
2013-04-03 07:45:14 -05:00
|
|
|
}
|
2012-08-28 13:59:31 -05:00
|
|
|
}
|
2012-07-26 18:09:22 -05:00
|
|
|
}
|
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
#[inline(always)]
|
|
|
|
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)
|
|
|
|
}
|
2012-07-26 18:09:22 -05:00
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
#[inline(always)]
|
2013-04-18 17:53:29 -05:00
|
|
|
fn bucket_for_key_equiv<Q:Hash + Equiv<K>>(&self, k: &Q)
|
|
|
|
-> SearchResult {
|
2013-04-03 07:45:14 -05:00
|
|
|
let hash = k.hash_keyed(self.k0, self.k1) as uint;
|
|
|
|
self.bucket_for_key_with_hash_equiv(hash, k)
|
|
|
|
}
|
2012-07-26 18:09:22 -05:00
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
#[inline(always)]
|
|
|
|
fn bucket_for_key_with_hash(&self,
|
|
|
|
hash: uint,
|
|
|
|
k: &K)
|
|
|
|
-> SearchResult {
|
2013-05-02 17:33:18 -05:00
|
|
|
for self.bucket_sequence(hash) |i| {
|
2013-04-03 07:45:14 -05:00
|
|
|
match self.buckets[i] {
|
|
|
|
Some(ref bkt) => if bkt.hash == hash && *k == bkt.key {
|
|
|
|
return FoundEntry(i);
|
|
|
|
},
|
|
|
|
None => return FoundHole(i)
|
2012-07-26 18:09:22 -05:00
|
|
|
}
|
2013-05-02 17:33:18 -05:00
|
|
|
}
|
2013-04-03 07:45:14 -05:00
|
|
|
TableFull
|
|
|
|
}
|
2013-03-04 21:43:14 -06:00
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
#[inline(always)]
|
|
|
|
fn bucket_for_key_with_hash_equiv<Q:Equiv<K>>(&self,
|
|
|
|
hash: uint,
|
|
|
|
k: &Q)
|
|
|
|
-> SearchResult {
|
2013-05-02 17:33:18 -05:00
|
|
|
for self.bucket_sequence(hash) |i| {
|
2013-04-03 07:45:14 -05:00
|
|
|
match self.buckets[i] {
|
|
|
|
Some(ref bkt) => {
|
|
|
|
if bkt.hash == hash && k.equiv(&bkt.key) {
|
2012-09-07 12:34:39 -05:00
|
|
|
return FoundEntry(i);
|
2013-04-03 07:45:14 -05:00
|
|
|
}
|
|
|
|
},
|
|
|
|
None => return FoundHole(i)
|
|
|
|
}
|
2013-05-02 17:33:18 -05:00
|
|
|
}
|
2013-04-03 07:45:14 -05:00
|
|
|
TableFull
|
|
|
|
}
|
2013-03-04 21:43:14 -06:00
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
/// Expand the capacity of the array to the next power of two
|
|
|
|
/// and re-insert each of the existing buckets.
|
|
|
|
#[inline(always)]
|
|
|
|
fn expand(&mut self) {
|
|
|
|
let new_capacity = self.buckets.len() * 2;
|
|
|
|
self.resize(new_capacity);
|
|
|
|
}
|
2013-02-15 00:35:15 -06:00
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
/// 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);
|
2012-07-26 18:09:22 -05:00
|
|
|
|
2013-05-05 23:42:54 -05:00
|
|
|
let old_buckets = replace(&mut self.buckets,
|
|
|
|
vec::from_fn(new_capacity, |_| None));
|
2012-07-26 18:09:22 -05:00
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
self.size = 0;
|
2013-05-05 23:42:54 -05:00
|
|
|
do vec::consume(old_buckets) |_, bucket| {
|
2013-04-03 07:45:14 -05:00
|
|
|
self.insert_opt_bucket(bucket);
|
2012-07-26 18:09:22 -05:00
|
|
|
}
|
2013-04-03 07:45:14 -05:00
|
|
|
}
|
2012-07-26 18:09:22 -05:00
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
fn insert_opt_bucket(&mut self, bucket: Option<Bucket<K, V>>) {
|
|
|
|
match bucket {
|
|
|
|
Some(Bucket{hash: hash, key: key, value: value}) => {
|
|
|
|
self.insert_internal(hash, key, value);
|
2012-08-28 13:59:31 -05:00
|
|
|
}
|
2013-04-03 07:45:14 -05:00
|
|
|
None => {}
|
2012-07-26 18:09:22 -05:00
|
|
|
}
|
2013-04-03 07:45:14 -05:00
|
|
|
}
|
2012-07-26 18:09:22 -05:00
|
|
|
|
2013-04-10 15:11:35 -05:00
|
|
|
#[inline(always)]
|
|
|
|
fn value_for_bucket<'a>(&'a self, idx: uint) -> &'a V {
|
|
|
|
match self.buckets[idx] {
|
|
|
|
Some(ref bkt) => &bkt.value,
|
2013-05-05 17:18:51 -05:00
|
|
|
None => fail!("HashMap::find: internal logic error"),
|
2013-04-10 15:11:35 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline(always)]
|
|
|
|
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()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
/// 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
|
2013-05-04 08:54:58 -05:00
|
|
|
fn insert_internal(&mut self, hash: uint, k: K, v: V) -> Option<V> {
|
2013-04-03 07:45:14 -05:00
|
|
|
match self.bucket_for_key_with_hash(hash, &k) {
|
2013-05-05 17:18:51 -05:00
|
|
|
TableFull => { fail!("Internal logic error"); }
|
2013-04-03 07:45:14 -05:00
|
|
|
FoundHole(idx) => {
|
|
|
|
debug!("insert fresh (%?->%?) at idx %?, hash %?",
|
|
|
|
k, v, idx, hash);
|
|
|
|
self.buckets[idx] = Some(Bucket{hash: hash, key: k,
|
|
|
|
value: v});
|
|
|
|
self.size += 1;
|
2013-05-04 08:54:58 -05:00
|
|
|
None
|
2013-04-03 07:45:14 -05:00
|
|
|
}
|
|
|
|
FoundEntry(idx) => {
|
|
|
|
debug!("insert overwrite (%?->%?) at idx %?, hash %?",
|
|
|
|
k, v, idx, hash);
|
2013-05-04 08:54:58 -05:00
|
|
|
match self.buckets[idx] {
|
2013-05-05 17:18:51 -05:00
|
|
|
None => { fail!("insert_internal: Internal logic error") }
|
2013-05-04 08:54:58 -05:00
|
|
|
Some(ref mut b) => {
|
|
|
|
b.hash = hash;
|
|
|
|
b.key = k;
|
|
|
|
Some(replace(&mut b.value, v))
|
|
|
|
}
|
|
|
|
}
|
2012-07-26 18:09:22 -05:00
|
|
|
}
|
|
|
|
}
|
2013-04-03 07:45:14 -05:00
|
|
|
}
|
2012-08-22 23:01:30 -05:00
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
fn pop_internal(&mut self, hash: uint, k: &K) -> Option<V> {
|
|
|
|
// 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();
|
2013-05-05 23:42:54 -05:00
|
|
|
let bucket = replace(&mut self.buckets[idx], None);
|
2013-04-03 07:45:14 -05:00
|
|
|
|
|
|
|
let value = match bucket {
|
|
|
|
None => None,
|
2013-05-05 23:42:54 -05:00
|
|
|
Some(Bucket{value, _}) => {
|
2013-04-03 07:45:14 -05:00
|
|
|
Some(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() {
|
2013-05-05 23:42:54 -05:00
|
|
|
let bucket = replace(&mut self.buckets[idx], None);
|
2013-04-03 07:45:14 -05:00
|
|
|
self.insert_opt_bucket(bucket);
|
2012-10-08 09:05:01 -05:00
|
|
|
idx = self.next_bucket(idx, len_buckets);
|
|
|
|
}
|
2013-04-03 07:45:14 -05:00
|
|
|
self.size = size;
|
2012-10-08 09:05:01 -05:00
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
value
|
2012-07-26 18:09:22 -05:00
|
|
|
}
|
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
fn search(&self, hash: uint,
|
|
|
|
op: &fn(x: &Option<Bucket<K, V>>) -> bool) {
|
|
|
|
let _ = self.bucket_sequence(hash, |i| op(&self.buckets[i]));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-18 17:53:29 -05:00
|
|
|
impl<K:Hash + Eq,V> Container for HashMap<K, V> {
|
2013-04-03 07:45:14 -05:00
|
|
|
/// Return the number of elements in the map
|
|
|
|
fn len(&const self) -> uint { self.size }
|
2013-01-23 15:47:27 -06:00
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
/// Return true if the map contains no elements
|
|
|
|
fn is_empty(&const self) -> bool { self.len() == 0 }
|
|
|
|
}
|
2013-01-21 20:59:19 -06:00
|
|
|
|
2013-04-18 17:53:29 -05:00
|
|
|
impl<K:Hash + Eq,V> Mutable for HashMap<K, V> {
|
2013-04-03 07:45:14 -05:00
|
|
|
/// Clear the map, removing all key-value pairs.
|
|
|
|
fn clear(&mut self) {
|
|
|
|
for uint::range(0, self.buckets.len()) |idx| {
|
|
|
|
self.buckets[idx] = None;
|
2013-01-21 16:25:57 -06:00
|
|
|
}
|
2013-04-03 07:45:14 -05:00
|
|
|
self.size = 0;
|
2013-01-21 16:25:57 -06:00
|
|
|
}
|
2013-04-03 07:45:14 -05:00
|
|
|
}
|
2013-01-21 16:25:57 -06:00
|
|
|
|
2013-04-18 17:53:29 -05:00
|
|
|
impl<K:Hash + Eq,V> Map<K, V> for HashMap<K, V> {
|
2013-04-03 07:45:14 -05:00
|
|
|
/// 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}
|
2013-01-21 17:22:03 -06:00
|
|
|
}
|
2013-04-03 07:45:14 -05:00
|
|
|
}
|
2013-01-21 17:22:03 -06:00
|
|
|
|
2013-04-06 10:22:36 -05:00
|
|
|
/// Visit all key-value pairs
|
2013-05-02 17:33:18 -05:00
|
|
|
fn each<'a>(&'a self, blk: &fn(&K, &'a V) -> bool) -> bool {
|
2013-05-20 11:40:29 -05:00
|
|
|
for self.buckets.each |bucket| {
|
|
|
|
for bucket.each |pair| {
|
|
|
|
if !blk(&pair.key, &pair.value) {
|
2013-05-02 17:33:18 -05:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
/// Visit all keys
|
2013-05-02 17:33:18 -05:00
|
|
|
fn each_key(&self, blk: &fn(k: &K) -> bool) -> bool {
|
|
|
|
self.each(|k, _| blk(k))
|
|
|
|
}
|
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
/// Visit all values
|
2013-05-02 17:33:18 -05:00
|
|
|
fn each_value<'a>(&'a self, blk: &fn(v: &'a V) -> bool) -> bool {
|
|
|
|
self.each(|_, v| blk(v))
|
|
|
|
}
|
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
/// Iterate over the map and mutate the contained values
|
2013-05-02 17:33:18 -05:00
|
|
|
fn mutate_values(&mut self, blk: &fn(&K, &mut V) -> bool) -> bool {
|
|
|
|
for uint::range(0, self.buckets.len()) |i| {
|
|
|
|
match self.buckets[i] {
|
|
|
|
Some(Bucket{key: ref key, value: ref mut value, _}) => {
|
|
|
|
if !blk(key, value) { return false; }
|
|
|
|
}
|
|
|
|
None => ()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
/// Return a reference to the value corresponding to the key
|
2013-04-10 15:11:35 -05:00
|
|
|
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,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
/// Return a mutable reference to the value corresponding to the key
|
2013-05-06 22:29:54 -05:00
|
|
|
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))
|
|
|
|
}
|
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
/// Insert a key-value pair into the map. An existing value for a
|
|
|
|
/// key is replaced by the new value. Return true if the key did
|
|
|
|
/// not already exist in the map.
|
|
|
|
fn insert(&mut self, k: K, v: V) -> bool {
|
2013-05-04 08:54:58 -05:00
|
|
|
self.swap(k, v).is_none()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Remove a key-value pair from the map. Return true if the key
|
|
|
|
/// was present in the map, otherwise false.
|
|
|
|
fn remove(&mut self, k: &K) -> bool {
|
|
|
|
self.pop(k).is_some()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 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<V> {
|
|
|
|
// this could be faster.
|
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
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)
|
2013-01-21 17:22:03 -06:00
|
|
|
}
|
2012-07-26 18:09:22 -05:00
|
|
|
|
2013-05-04 08:54:58 -05:00
|
|
|
/// 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<V> {
|
|
|
|
let hash = k.hash_keyed(self.k0, self.k1) as uint;
|
|
|
|
self.pop_internal(hash, k)
|
2013-04-03 07:45:14 -05:00
|
|
|
}
|
|
|
|
}
|
2013-03-28 22:30:50 -05:00
|
|
|
|
2013-04-18 17:53:29 -05:00
|
|
|
pub impl<K: Hash + Eq, V> HashMap<K, V> {
|
2013-04-03 08:28:36 -05:00
|
|
|
/// Create an empty HashMap
|
|
|
|
fn new() -> HashMap<K, V> {
|
|
|
|
HashMap::with_capacity(INITIAL_CAPACITY)
|
2013-04-03 07:45:14 -05:00
|
|
|
}
|
2013-01-23 16:06:32 -06:00
|
|
|
|
2013-04-03 08:28:36 -05:00
|
|
|
/// Create an empty HashMap with space for at least `n` elements in
|
2013-04-03 07:45:14 -05:00
|
|
|
/// the hash table.
|
2013-04-03 08:28:36 -05:00
|
|
|
fn with_capacity(capacity: uint) -> HashMap<K, V> {
|
2013-04-03 07:45:14 -05:00
|
|
|
linear_map_with_capacity(capacity)
|
|
|
|
}
|
2013-02-15 00:35:15 -06:00
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
/// Reserve space for at least `n` elements in the hash table.
|
|
|
|
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));
|
2012-10-08 09:05:01 -05:00
|
|
|
}
|
2013-04-03 07:45:14 -05:00
|
|
|
}
|
2012-07-26 18:09:22 -05:00
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
/// Return the value corresponding to the key in the map, or insert
|
|
|
|
/// and return the value if it doesn't exist.
|
2013-05-06 22:29:54 -05:00
|
|
|
fn find_or_insert<'a>(&'a mut self, k: K, v: V) -> &'a 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) {
|
2013-05-05 17:18:51 -05:00
|
|
|
TableFull => fail!("Internal logic error"),
|
2013-05-06 22:29:54 -05:00
|
|
|
FoundEntry(idx) => idx,
|
|
|
|
FoundHole(idx) => {
|
|
|
|
self.buckets[idx] = Some(Bucket{hash: hash, key: k,
|
|
|
|
value: v});
|
|
|
|
self.size += 1;
|
|
|
|
idx
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
self.value_for_bucket(idx)
|
|
|
|
}
|
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
/// Return the value corresponding to the key in the map, or create,
|
|
|
|
/// insert, and return a new value if it doesn't exist.
|
2013-05-06 22:29:54 -05:00
|
|
|
fn find_or_insert_with<'a>(&'a mut self, k: K, f: &fn(&K) -> V) -> &'a 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) {
|
2013-05-05 17:18:51 -05:00
|
|
|
TableFull => fail!("Internal logic error"),
|
2013-05-06 22:29:54 -05:00
|
|
|
FoundEntry(idx) => idx,
|
|
|
|
FoundHole(idx) => {
|
|
|
|
let v = f(&k);
|
|
|
|
self.buckets[idx] = Some(Bucket{hash: hash, key: k,
|
|
|
|
value: v});
|
|
|
|
self.size += 1;
|
|
|
|
idx
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
self.value_for_bucket(idx)
|
|
|
|
}
|
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
fn consume(&mut self, f: &fn(K, V)) {
|
2013-05-05 23:42:54 -05:00
|
|
|
let buckets = replace(&mut self.buckets, ~[]);
|
2013-04-03 07:45:14 -05:00
|
|
|
self.size = 0;
|
|
|
|
|
|
|
|
do vec::consume(buckets) |_, bucket| {
|
|
|
|
match bucket {
|
|
|
|
None => {},
|
2013-05-05 23:42:54 -05:00
|
|
|
Some(Bucket{key, value, _}) => {
|
2013-04-03 07:45:14 -05:00
|
|
|
f(key, value)
|
2012-10-08 09:05:01 -05:00
|
|
|
}
|
2012-07-26 18:09:22 -05:00
|
|
|
}
|
|
|
|
}
|
2013-04-03 07:45:14 -05:00
|
|
|
}
|
2012-08-21 17:55:17 -05:00
|
|
|
|
2013-04-10 15:11:35 -05:00
|
|
|
fn get<'a>(&'a self, k: &K) -> &'a V {
|
|
|
|
match self.find(k) {
|
|
|
|
Some(v) => v,
|
2013-05-05 17:18:51 -05:00
|
|
|
None => fail!("No entry found for key: %?", k),
|
2013-04-10 15:11:35 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
/// Return true if the map contains a value for the specified key,
|
|
|
|
/// using equivalence
|
2013-04-18 17:53:29 -05:00
|
|
|
fn contains_key_equiv<Q:Hash + Equiv<K>>(&self, key: &Q) -> bool {
|
2013-04-03 07:45:14 -05:00
|
|
|
match self.bucket_for_key_equiv(key) {
|
|
|
|
FoundEntry(_) => {true}
|
|
|
|
TableFull | FoundHole(_) => {false}
|
2013-03-04 21:43:14 -06:00
|
|
|
}
|
2013-04-03 07:45:14 -05:00
|
|
|
}
|
2013-03-04 21:43:14 -06:00
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
/// Return the value corresponding to the key in the map, using
|
|
|
|
/// equivalence
|
2013-04-18 17:53:29 -05:00
|
|
|
fn find_equiv<'a, Q:Hash + Equiv<K>>(&'a self, k: &Q) -> Option<&'a V> {
|
2013-04-10 15:11:35 -05:00
|
|
|
match self.bucket_for_key_equiv(k) {
|
|
|
|
FoundEntry(idx) => Some(self.value_for_bucket(idx)),
|
|
|
|
TableFull | FoundHole(_) => None,
|
|
|
|
}
|
|
|
|
}
|
2013-04-03 07:45:14 -05:00
|
|
|
}
|
2012-07-31 16:11:57 -05:00
|
|
|
|
2013-05-05 11:17:59 -05:00
|
|
|
pub impl<K: Hash + Eq, V: Copy> HashMap<K, V> {
|
|
|
|
/// Like `find`, but returns a copy of the value.
|
|
|
|
fn find_copy(&self, k: &K) -> Option<V> {
|
|
|
|
self.find(k).map_consume(|v| copy *v)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Like `get`, but returns a copy of the value.
|
|
|
|
fn get_copy(&self, k: &K) -> V {
|
|
|
|
copy *self.get(k)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-18 17:53:29 -05:00
|
|
|
impl<K:Hash + Eq,V:Eq> Eq for HashMap<K, V> {
|
2013-04-03 08:28:36 -05:00
|
|
|
fn eq(&self, other: &HashMap<K, V>) -> bool {
|
2013-04-03 07:45:14 -05:00
|
|
|
if self.len() != other.len() { return false; }
|
2012-12-10 11:00:52 -06:00
|
|
|
|
2013-04-06 10:22:36 -05:00
|
|
|
for self.each |key, value| {
|
2013-04-03 07:45:14 -05:00
|
|
|
match other.find(key) {
|
|
|
|
None => return false,
|
|
|
|
Some(v) => if value != v { return false },
|
2012-12-10 11:00:52 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
true
|
2012-12-10 11:00:52 -06:00
|
|
|
}
|
2013-01-20 13:18:24 -06:00
|
|
|
|
2013-04-03 08:28:36 -05:00
|
|
|
fn ne(&self, other: &HashMap<K, V>) -> bool { !self.eq(other) }
|
2013-04-03 07:45:14 -05:00
|
|
|
}
|
2013-01-20 13:18:24 -06:00
|
|
|
|
2013-04-03 08:28:36 -05:00
|
|
|
pub struct HashSet<T> {
|
|
|
|
priv map: HashMap<T, ()>
|
2013-04-03 07:45:14 -05:00
|
|
|
}
|
2013-01-20 13:18:24 -06:00
|
|
|
|
2013-04-18 17:53:29 -05:00
|
|
|
impl<T:Hash + Eq> BaseIter<T> for HashSet<T> {
|
2013-04-03 07:45:14 -05:00
|
|
|
/// Visit all values in order
|
2013-05-02 17:33:18 -05:00
|
|
|
fn each(&self, f: &fn(&T) -> bool) -> bool { self.map.each_key(f) }
|
2013-04-03 07:45:14 -05:00
|
|
|
fn size_hint(&self) -> Option<uint> { Some(self.len()) }
|
|
|
|
}
|
2013-01-20 13:18:24 -06:00
|
|
|
|
2013-04-18 17:53:29 -05:00
|
|
|
impl<T:Hash + Eq> Eq for HashSet<T> {
|
2013-04-03 08:28:36 -05:00
|
|
|
fn eq(&self, other: &HashSet<T>) -> bool { self.map == other.map }
|
|
|
|
fn ne(&self, other: &HashSet<T>) -> bool { self.map != other.map }
|
2013-04-03 07:45:14 -05:00
|
|
|
}
|
2013-01-23 15:47:27 -06:00
|
|
|
|
2013-04-18 17:53:29 -05:00
|
|
|
impl<T:Hash + Eq> Container for HashSet<T> {
|
2013-04-03 07:45:14 -05:00
|
|
|
/// Return the number of elements in the set
|
|
|
|
fn len(&const self) -> uint { self.map.len() }
|
2013-01-21 20:59:19 -06:00
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
/// Return true if the set contains no elements
|
|
|
|
fn is_empty(&const self) -> bool { self.map.is_empty() }
|
|
|
|
}
|
2013-01-21 16:25:57 -06:00
|
|
|
|
2013-04-18 17:53:29 -05:00
|
|
|
impl<T:Hash + Eq> Mutable for HashSet<T> {
|
2013-04-03 07:45:14 -05:00
|
|
|
/// Clear the set, removing all values.
|
|
|
|
fn clear(&mut self) { self.map.clear() }
|
|
|
|
}
|
2013-01-20 13:18:24 -06:00
|
|
|
|
2013-04-18 17:53:29 -05:00
|
|
|
impl<T:Hash + Eq> Set<T> for HashSet<T> {
|
2013-04-03 07:45:14 -05:00
|
|
|
/// Return true if the set contains a value
|
|
|
|
fn contains(&self, value: &T) -> bool { self.map.contains_key(value) }
|
2013-01-20 13:18:24 -06:00
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
/// 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, ()) }
|
2013-01-29 15:07:11 -06:00
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
/// 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) }
|
2013-01-29 16:04:25 -06:00
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
/// Return true if the set has no elements in common with `other`.
|
|
|
|
/// This is equivalent to checking for an empty intersection.
|
2013-04-03 08:28:36 -05:00
|
|
|
fn is_disjoint(&self, other: &HashSet<T>) -> bool {
|
2013-04-24 19:35:49 -05:00
|
|
|
old_iter::all(self, |v| !other.contains(v))
|
2013-04-03 07:45:14 -05:00
|
|
|
}
|
2013-01-29 15:07:11 -06:00
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
/// Return true if the set is a subset of another
|
2013-04-03 08:28:36 -05:00
|
|
|
fn is_subset(&self, other: &HashSet<T>) -> bool {
|
2013-04-24 19:35:49 -05:00
|
|
|
old_iter::all(self, |v| other.contains(v))
|
2013-04-03 07:45:14 -05:00
|
|
|
}
|
2013-01-29 18:30:26 -06:00
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
/// Return true if the set is a superset of another
|
2013-04-03 08:28:36 -05:00
|
|
|
fn is_superset(&self, other: &HashSet<T>) -> bool {
|
2013-04-03 07:45:14 -05:00
|
|
|
other.is_subset(self)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Visit the values representing the difference
|
2013-05-02 17:33:18 -05:00
|
|
|
fn difference(&self, other: &HashSet<T>, f: &fn(&T) -> bool) -> bool {
|
|
|
|
self.each(|v| other.contains(v) || f(v))
|
|
|
|
}
|
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
/// Visit the values representing the symmetric difference
|
2013-05-02 17:33:18 -05:00
|
|
|
fn symmetric_difference(&self,
|
|
|
|
other: &HashSet<T>,
|
|
|
|
f: &fn(&T) -> bool) -> bool {
|
|
|
|
self.difference(other, f) && other.difference(self, f)
|
|
|
|
}
|
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
/// Visit the values representing the intersection
|
2013-05-02 17:33:18 -05:00
|
|
|
fn intersection(&self, other: &HashSet<T>, f: &fn(&T) -> bool) -> bool {
|
|
|
|
self.each(|v| !other.contains(v) || f(v))
|
|
|
|
}
|
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
/// Visit the values representing the union
|
2013-05-02 17:33:18 -05:00
|
|
|
fn union(&self, other: &HashSet<T>, f: &fn(&T) -> bool) -> bool {
|
|
|
|
self.each(f) && other.each(|v| self.contains(v) || f(v))
|
|
|
|
}
|
2013-04-03 07:45:14 -05:00
|
|
|
}
|
2013-01-20 13:18:24 -06:00
|
|
|
|
2013-04-18 17:53:29 -05:00
|
|
|
pub impl <T:Hash + Eq> HashSet<T> {
|
2013-04-03 08:28:36 -05:00
|
|
|
/// Create an empty HashSet
|
|
|
|
fn new() -> HashSet<T> {
|
|
|
|
HashSet::with_capacity(INITIAL_CAPACITY)
|
2013-04-03 07:45:14 -05:00
|
|
|
}
|
2013-03-28 22:30:50 -05:00
|
|
|
|
2013-04-03 08:28:36 -05:00
|
|
|
/// Create an empty HashSet with space for at least `n` elements in
|
2013-04-03 07:45:14 -05:00
|
|
|
/// the hash table.
|
2013-04-03 08:28:36 -05:00
|
|
|
fn with_capacity(capacity: uint) -> HashSet<T> {
|
|
|
|
HashSet { map: HashMap::with_capacity(capacity) }
|
2013-04-03 07:45:14 -05:00
|
|
|
}
|
2013-02-15 00:35:15 -06:00
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
/// Reserve space for at least `n` elements in the hash table.
|
|
|
|
fn reserve_at_least(&mut self, n: uint) {
|
|
|
|
self.map.reserve_at_least(n)
|
|
|
|
}
|
2013-03-21 14:41:37 -05:00
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
/// Consumes all of the elements in the set, emptying it out
|
|
|
|
fn consume(&mut self, f: &fn(T)) {
|
|
|
|
self.map.consume(|k, _| f(k))
|
2013-01-20 13:18:24 -06:00
|
|
|
}
|
2013-05-11 10:42:59 -05:00
|
|
|
|
|
|
|
fn contains_equiv<Q:Hash + Equiv<T>>(&self, value: &Q) -> bool {
|
|
|
|
self.map.contains_key_equiv(value)
|
|
|
|
}
|
2013-04-03 07:45:14 -05:00
|
|
|
}
|
|
|
|
|
2013-04-30 06:02:29 -05:00
|
|
|
#[cfg(test)]
|
2013-04-03 07:45:14 -05:00
|
|
|
mod test_map {
|
|
|
|
use container::{Container, Map, Set};
|
|
|
|
use option::{None, Some};
|
|
|
|
use super::*;
|
|
|
|
use uint;
|
2013-02-10 17:30:44 -06:00
|
|
|
|
2012-10-08 09:05:01 -05:00
|
|
|
#[test]
|
2013-04-15 10:08:52 -05:00
|
|
|
fn test_insert() {
|
2013-04-03 08:28:36 -05:00
|
|
|
let mut m = HashMap::new();
|
2013-04-03 07:45:14 -05:00
|
|
|
assert!(m.insert(1, 2));
|
|
|
|
assert!(m.insert(2, 4));
|
2013-05-18 21:02:45 -05:00
|
|
|
assert_eq!(*m.get(&1), 2);
|
|
|
|
assert_eq!(*m.get(&2), 4);
|
2013-04-03 07:45:14 -05:00
|
|
|
}
|
2013-03-02 04:09:36 -06:00
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
#[test]
|
|
|
|
fn test_find_mut() {
|
2013-04-03 08:28:36 -05:00
|
|
|
let mut m = HashMap::new();
|
2013-04-03 07:45:14 -05:00
|
|
|
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));
|
|
|
|
}
|
2013-03-24 18:07:36 -05:00
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
#[test]
|
2013-04-15 10:08:52 -05:00
|
|
|
fn test_insert_overwrite() {
|
2013-04-03 08:28:36 -05:00
|
|
|
let mut m = HashMap::new();
|
2013-04-03 07:45:14 -05:00
|
|
|
assert!(m.insert(1, 2));
|
2013-05-18 21:02:45 -05:00
|
|
|
assert_eq!(*m.get(&1), 2);
|
2013-04-03 07:45:14 -05:00
|
|
|
assert!(!m.insert(1, 3));
|
2013-05-18 21:02:45 -05:00
|
|
|
assert_eq!(*m.get(&1), 3);
|
2013-04-03 07:45:14 -05:00
|
|
|
}
|
2013-03-02 04:09:36 -06:00
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
#[test]
|
2013-04-15 10:08:52 -05:00
|
|
|
fn test_insert_conflicts() {
|
2013-04-03 07:45:14 -05:00
|
|
|
let mut m = linear_map_with_capacity(4);
|
|
|
|
assert!(m.insert(1, 2));
|
|
|
|
assert!(m.insert(5, 3));
|
|
|
|
assert!(m.insert(9, 4));
|
2013-05-18 21:02:45 -05:00
|
|
|
assert_eq!(*m.get(&9), 4);
|
|
|
|
assert_eq!(*m.get(&5), 3);
|
|
|
|
assert_eq!(*m.get(&1), 2);
|
2013-04-03 07:45:14 -05:00
|
|
|
}
|
2013-03-02 04:09:36 -06:00
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
#[test]
|
2013-04-15 10:08:52 -05:00
|
|
|
fn test_conflict_remove() {
|
2013-04-03 07:45:14 -05:00
|
|
|
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));
|
2013-05-18 21:02:45 -05:00
|
|
|
assert_eq!(*m.get(&9), 4);
|
|
|
|
assert_eq!(*m.get(&5), 3);
|
2013-04-03 07:45:14 -05:00
|
|
|
}
|
2013-03-02 04:09:36 -06:00
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
#[test]
|
2013-04-15 10:08:52 -05:00
|
|
|
fn test_is_empty() {
|
2013-04-03 07:45:14 -05:00
|
|
|
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());
|
|
|
|
}
|
2013-03-02 04:09:36 -06:00
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
#[test]
|
2013-04-15 10:08:52 -05:00
|
|
|
fn test_pop() {
|
2013-04-03 08:28:36 -05:00
|
|
|
let mut m = HashMap::new();
|
2013-04-03 07:45:14 -05:00
|
|
|
m.insert(1, 2);
|
2013-05-18 21:02:45 -05:00
|
|
|
assert_eq!(m.pop(&1), Some(2));
|
|
|
|
assert_eq!(m.pop(&1), None);
|
2013-04-03 07:45:14 -05:00
|
|
|
}
|
2013-03-02 04:09:36 -06:00
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
#[test]
|
2013-04-15 10:08:52 -05:00
|
|
|
fn test_swap() {
|
2013-04-03 08:28:36 -05:00
|
|
|
let mut m = HashMap::new();
|
2013-05-18 21:02:45 -05:00
|
|
|
assert_eq!(m.swap(1, 2), None);
|
|
|
|
assert_eq!(m.swap(1, 3), Some(2));
|
|
|
|
assert_eq!(m.swap(1, 4), Some(3));
|
2013-04-03 07:45:14 -05:00
|
|
|
}
|
2013-03-02 04:09:36 -06:00
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
#[test]
|
2013-04-15 10:08:52 -05:00
|
|
|
fn test_find_or_insert() {
|
2013-04-03 08:28:36 -05:00
|
|
|
let mut m = HashMap::new::<int, int>();
|
2013-05-18 21:02:45 -05:00
|
|
|
assert_eq!(m.find_or_insert(1, 2), &2);
|
|
|
|
assert_eq!(m.find_or_insert(1, 3), &2);
|
2013-04-03 07:45:14 -05:00
|
|
|
}
|
2013-03-02 04:09:36 -06:00
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
#[test]
|
2013-04-15 10:08:52 -05:00
|
|
|
fn test_find_or_insert_with() {
|
2013-04-03 08:28:36 -05:00
|
|
|
let mut m = HashMap::new::<int, int>();
|
2013-05-18 21:02:45 -05:00
|
|
|
assert_eq!(m.find_or_insert_with(1, |_| 2), &2);
|
|
|
|
assert_eq!(m.find_or_insert_with(1, |_| 3), &2);
|
2013-04-03 07:45:14 -05:00
|
|
|
}
|
2013-03-02 04:09:36 -06:00
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
#[test]
|
2013-04-15 10:08:52 -05:00
|
|
|
fn test_consume() {
|
2013-04-03 08:28:36 -05:00
|
|
|
let mut m = HashMap::new();
|
2013-04-03 07:45:14 -05:00
|
|
|
assert!(m.insert(1, 2));
|
|
|
|
assert!(m.insert(2, 3));
|
2013-04-03 08:28:36 -05:00
|
|
|
let mut m2 = HashMap::new();
|
2013-04-03 07:45:14 -05:00
|
|
|
do m.consume |k, v| {
|
|
|
|
m2.insert(k, v);
|
|
|
|
}
|
2013-05-18 21:02:45 -05:00
|
|
|
assert_eq!(m.len(), 0);
|
|
|
|
assert_eq!(m2.len(), 2);
|
|
|
|
assert_eq!(m2.get(&1), &2);
|
|
|
|
assert_eq!(m2.get(&2), &3);
|
2013-04-03 07:45:14 -05:00
|
|
|
}
|
2013-03-02 04:09:36 -06:00
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
#[test]
|
2013-04-15 10:08:52 -05:00
|
|
|
fn test_iterate() {
|
2013-04-03 07:45:14 -05:00
|
|
|
let mut m = linear_map_with_capacity(4);
|
|
|
|
for uint::range(0, 32) |i| {
|
|
|
|
assert!(m.insert(i, i*2));
|
2012-07-31 16:11:57 -05:00
|
|
|
}
|
2013-04-03 07:45:14 -05:00
|
|
|
let mut observed = 0;
|
2013-04-06 10:22:36 -05:00
|
|
|
for m.each |k, v| {
|
2013-05-18 21:02:45 -05:00
|
|
|
assert_eq!(*v, *k * 2);
|
2013-04-03 07:45:14 -05:00
|
|
|
observed |= (1 << *k);
|
2012-09-14 17:19:54 -05:00
|
|
|
}
|
2013-05-18 21:02:45 -05:00
|
|
|
assert_eq!(observed, 0xFFFF_FFFF);
|
2013-04-03 07:45:14 -05:00
|
|
|
}
|
2012-12-10 11:00:52 -06:00
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
#[test]
|
2013-04-15 10:08:52 -05:00
|
|
|
fn test_find() {
|
2013-04-03 08:28:36 -05:00
|
|
|
let mut m = HashMap::new();
|
2013-04-03 07:45:14 -05:00
|
|
|
assert!(m.find(&1).is_none());
|
|
|
|
m.insert(1, 2);
|
|
|
|
match m.find(&1) {
|
|
|
|
None => fail!(),
|
|
|
|
Some(v) => assert!(*v == 2)
|
|
|
|
}
|
|
|
|
}
|
2012-12-10 11:00:52 -06:00
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
#[test]
|
2013-04-15 10:08:52 -05:00
|
|
|
fn test_eq() {
|
2013-04-03 08:28:36 -05:00
|
|
|
let mut m1 = HashMap::new();
|
2013-04-03 07:45:14 -05:00
|
|
|
m1.insert(1, 2);
|
|
|
|
m1.insert(2, 3);
|
|
|
|
m1.insert(3, 4);
|
2012-12-10 11:00:52 -06:00
|
|
|
|
2013-04-03 08:28:36 -05:00
|
|
|
let mut m2 = HashMap::new();
|
2013-04-03 07:45:14 -05:00
|
|
|
m2.insert(1, 2);
|
|
|
|
m2.insert(2, 3);
|
2012-12-10 11:00:52 -06:00
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
assert!(m1 != m2);
|
2012-12-10 11:00:52 -06:00
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
m2.insert(3, 4);
|
2012-12-30 12:35:03 -06:00
|
|
|
|
2013-05-18 21:02:45 -05:00
|
|
|
assert_eq!(m1, m2);
|
2013-04-03 07:45:14 -05:00
|
|
|
}
|
2012-12-30 12:35:03 -06:00
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
#[test]
|
2013-04-15 10:08:52 -05:00
|
|
|
fn test_expand() {
|
2013-04-03 08:28:36 -05:00
|
|
|
let mut m = HashMap::new();
|
2012-12-30 12:35:03 -06:00
|
|
|
|
2013-05-18 21:02:45 -05:00
|
|
|
assert_eq!(m.len(), 0);
|
2013-04-03 07:45:14 -05:00
|
|
|
assert!(m.is_empty());
|
2012-12-30 12:35:03 -06:00
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
let mut i = 0u;
|
|
|
|
let old_resize_at = m.resize_at;
|
|
|
|
while old_resize_at == m.resize_at {
|
|
|
|
m.insert(i, i);
|
|
|
|
i += 1;
|
2013-03-02 04:09:36 -06:00
|
|
|
}
|
2013-04-03 07:45:14 -05:00
|
|
|
|
2013-05-18 21:02:45 -05:00
|
|
|
assert_eq!(m.len(), i);
|
2013-04-03 07:45:14 -05:00
|
|
|
assert!(!m.is_empty());
|
2012-12-30 12:35:03 -06:00
|
|
|
}
|
2013-04-03 07:45:14 -05:00
|
|
|
}
|
2013-01-29 15:07:11 -06:00
|
|
|
|
2013-04-30 06:02:29 -05:00
|
|
|
#[cfg(test)]
|
2013-04-03 07:45:14 -05:00
|
|
|
mod test_set {
|
|
|
|
use super::*;
|
|
|
|
use container::{Container, Map, Set};
|
|
|
|
use vec;
|
2013-03-02 04:09:36 -06:00
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
#[test]
|
|
|
|
fn test_disjoint() {
|
2013-04-03 08:28:36 -05:00
|
|
|
let mut xs = HashSet::new();
|
|
|
|
let mut ys = HashSet::new();
|
2013-04-03 07:45:14 -05:00
|
|
|
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));
|
|
|
|
}
|
2013-03-02 04:09:36 -06:00
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
#[test]
|
|
|
|
fn test_subset_and_superset() {
|
2013-04-03 08:28:36 -05:00
|
|
|
let mut a = HashSet::new();
|
2013-04-03 07:45:14 -05:00
|
|
|
assert!(a.insert(0));
|
|
|
|
assert!(a.insert(5));
|
|
|
|
assert!(a.insert(11));
|
|
|
|
assert!(a.insert(7));
|
|
|
|
|
2013-04-03 08:28:36 -05:00
|
|
|
let mut b = HashSet::new();
|
2013-04-03 07:45:14 -05:00
|
|
|
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));
|
|
|
|
}
|
2013-01-29 18:30:26 -06:00
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
#[test]
|
|
|
|
fn test_intersection() {
|
2013-04-03 08:28:36 -05:00
|
|
|
let mut a = HashSet::new();
|
|
|
|
let mut b = HashSet::new();
|
2013-04-03 07:45:14 -05:00
|
|
|
|
|
|
|
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];
|
|
|
|
for a.intersection(&b) |x| {
|
|
|
|
assert!(vec::contains(expected, x));
|
|
|
|
i += 1
|
|
|
|
}
|
2013-05-18 21:02:45 -05:00
|
|
|
assert_eq!(i, expected.len());
|
2013-04-03 07:45:14 -05:00
|
|
|
}
|
2013-03-02 04:09:36 -06:00
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
#[test]
|
|
|
|
fn test_difference() {
|
2013-04-03 08:28:36 -05:00
|
|
|
let mut a = HashSet::new();
|
|
|
|
let mut b = HashSet::new();
|
2013-04-03 07:45:14 -05:00
|
|
|
|
|
|
|
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];
|
|
|
|
for a.difference(&b) |x| {
|
|
|
|
assert!(vec::contains(expected, x));
|
|
|
|
i += 1
|
|
|
|
}
|
2013-05-18 21:02:45 -05:00
|
|
|
assert_eq!(i, expected.len());
|
2013-04-03 07:45:14 -05:00
|
|
|
}
|
2013-03-02 04:09:36 -06:00
|
|
|
|
2013-04-03 07:45:14 -05:00
|
|
|
#[test]
|
|
|
|
fn test_symmetric_difference() {
|
2013-04-03 08:28:36 -05:00
|
|
|
let mut a = HashSet::new();
|
|
|
|
let mut b = HashSet::new();
|
2013-04-03 07:45:14 -05:00
|
|
|
|
|
|
|
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];
|
|
|
|
for a.symmetric_difference(&b) |x| {
|
|
|
|
assert!(vec::contains(expected, x));
|
|
|
|
i += 1
|
|
|
|
}
|
2013-05-18 21:02:45 -05:00
|
|
|
assert_eq!(i, expected.len());
|
2013-04-03 07:45:14 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_union() {
|
2013-04-03 08:28:36 -05:00
|
|
|
let mut a = HashSet::new();
|
|
|
|
let mut b = HashSet::new();
|
2013-04-03 07:45:14 -05:00
|
|
|
|
|
|
|
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];
|
|
|
|
for a.union(&b) |x| {
|
|
|
|
assert!(vec::contains(expected, x));
|
|
|
|
i += 1
|
|
|
|
}
|
2013-05-18 21:02:45 -05:00
|
|
|
assert_eq!(i, expected.len());
|
2013-01-29 20:58:47 -06:00
|
|
|
}
|
2013-01-29 15:07:11 -06:00
|
|
|
}
|