2012-07-26 18:09:22 -05:00
|
|
|
/*!
|
|
|
|
|
|
|
|
Sendable hash maps. Very much a work in progress.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
2012-09-04 13:12:17 -05:00
|
|
|
use cmp::Eq;
|
|
|
|
use hash::Hash;
|
|
|
|
use to_bytes::IterBytes;
|
2012-07-26 18:09:22 -05:00
|
|
|
|
2012-08-30 21:01:22 -05:00
|
|
|
trait SendMap<K:Eq Hash, V: copy> {
|
2012-08-28 13:59:31 -05:00
|
|
|
// FIXME(#3148) ^^^^ once find_ref() works, we can drop V:copy
|
|
|
|
|
|
|
|
fn insert(&mut self, +k: K, +v: V) -> bool;
|
|
|
|
fn remove(&mut self, k: &K) -> bool;
|
|
|
|
fn clear(&mut self);
|
|
|
|
pure fn len(&const self) -> uint;
|
|
|
|
pure fn is_empty(&const self) -> bool;
|
|
|
|
fn contains_key(&const self, k: &K) -> bool;
|
|
|
|
fn each_ref(&self, blk: fn(k: &K, v: &V) -> bool);
|
|
|
|
fn each_key_ref(&self, blk: fn(k: &K) -> bool);
|
|
|
|
fn each_value_ref(&self, blk: fn(v: &V) -> bool);
|
|
|
|
fn find(&const self, k: &K) -> Option<V>;
|
|
|
|
fn get(&const self, k: &K) -> V;
|
|
|
|
}
|
|
|
|
|
2012-07-26 18:09:22 -05:00
|
|
|
/// Open addressing with linear probing.
|
|
|
|
mod linear {
|
2012-08-14 18:54:13 -05:00
|
|
|
export LinearMap, linear_map, linear_map_with_capacity, public_methods;
|
2012-07-26 18:09:22 -05:00
|
|
|
|
|
|
|
const initial_capacity: uint = 32u; // 2^5
|
2012-08-30 21:01:22 -05:00
|
|
|
struct Bucket<K:Eq Hash,V> {
|
2012-08-28 13:59:31 -05:00
|
|
|
hash: uint;
|
|
|
|
key: K;
|
|
|
|
value: V;
|
|
|
|
}
|
2012-08-30 21:01:22 -05:00
|
|
|
struct LinearMap<K:Eq Hash,V> {
|
|
|
|
k0: u64;
|
|
|
|
k1: u64;
|
2012-08-28 13:59:31 -05:00
|
|
|
resize_at: uint;
|
|
|
|
size: uint;
|
|
|
|
buckets: ~[Option<Bucket<K,V>>];
|
2012-07-26 18:09:22 -05:00
|
|
|
}
|
|
|
|
|
2012-08-22 16:54:57 -05:00
|
|
|
// FIXME(#3148) -- we could rewrite found_entry
|
2012-07-26 18:09:22 -05:00
|
|
|
// to have type option<&bucket<K,V>> which would be nifty
|
2012-08-22 16:54:57 -05:00
|
|
|
// However, that won't work until #3148 is fixed
|
2012-08-14 18:54:13 -05:00
|
|
|
enum SearchResult {
|
|
|
|
FoundEntry(uint), FoundHole(uint), TableFull
|
2012-07-26 18:09:22 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
fn resize_at(capacity: uint) -> uint {
|
|
|
|
((capacity as float) * 3. / 4.) as uint
|
|
|
|
}
|
|
|
|
|
2012-08-30 21:01:22 -05:00
|
|
|
fn LinearMap<K:Eq Hash,V>() -> LinearMap<K,V> {
|
|
|
|
linear_map_with_capacity(32)
|
2012-07-26 18:09:22 -05:00
|
|
|
}
|
|
|
|
|
2012-08-30 21:01:22 -05:00
|
|
|
fn linear_map_with_capacity<K:Eq Hash,V>(
|
2012-08-14 18:54:13 -05:00
|
|
|
initial_capacity: uint) -> LinearMap<K,V> {
|
2012-08-30 21:01:22 -05:00
|
|
|
let r = rand::Rng();
|
|
|
|
linear_map_with_capacity_and_keys(r.gen_u64(), r.gen_u64(),
|
|
|
|
initial_capacity)
|
|
|
|
}
|
2012-07-26 18:09:22 -05:00
|
|
|
|
2012-08-30 21:01:22 -05:00
|
|
|
fn linear_map_with_capacity_and_keys<K:Eq Hash,V> (
|
|
|
|
k0: u64, k1: u64,
|
|
|
|
initial_capacity: uint) -> LinearMap<K,V> {
|
2012-08-28 13:59:31 -05:00
|
|
|
LinearMap {
|
2012-08-30 21:01:22 -05:00
|
|
|
k0: k0, k1: k1,
|
2012-07-26 18:09:22 -05:00
|
|
|
resize_at: resize_at(initial_capacity),
|
|
|
|
size: 0,
|
2012-08-28 13:59:31 -05:00
|
|
|
buckets: vec::from_fn(initial_capacity, |_i| None)
|
|
|
|
}
|
2012-07-26 18:09:22 -05:00
|
|
|
}
|
|
|
|
|
2012-08-30 21:01:22 -05:00
|
|
|
priv impl<K:Hash IterBytes Eq, V> LinearMap<K,V> {
|
2012-07-26 18:09:22 -05:00
|
|
|
#[inline(always)]
|
2012-08-22 23:01:30 -05:00
|
|
|
pure fn to_bucket(&const self,
|
|
|
|
h: uint) -> uint {
|
2012-07-26 18:09:22 -05:00
|
|
|
// FIXME(#3041) borrow a more sophisticated technique here from
|
|
|
|
// Gecko, for example borrowing from Knuth, as Eich so
|
|
|
|
// colorfully argues for here:
|
|
|
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=743107#c22
|
|
|
|
h % self.buckets.len()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline(always)]
|
2012-08-22 23:01:30 -05:00
|
|
|
pure fn next_bucket(&const self,
|
|
|
|
idx: uint,
|
|
|
|
len_buckets: uint) -> uint {
|
2012-07-26 18:09:22 -05:00
|
|
|
let n = (idx + 1) % len_buckets;
|
|
|
|
unsafe{ // argh. log not considered pure.
|
2012-08-22 19:24:52 -05:00
|
|
|
debug!("next_bucket(%?, %?) = %?", idx, len_buckets, n);
|
2012-07-26 18:09:22 -05:00
|
|
|
}
|
2012-08-01 19:30:05 -05:00
|
|
|
return n;
|
2012-07-26 18:09:22 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline(always)]
|
2012-08-22 23:01:30 -05:00
|
|
|
pure fn bucket_sequence(&const self,
|
|
|
|
hash: uint,
|
|
|
|
op: fn(uint) -> bool) -> uint {
|
2012-07-26 18:09:22 -05:00
|
|
|
let start_idx = self.to_bucket(hash);
|
|
|
|
let len_buckets = self.buckets.len();
|
|
|
|
let mut idx = start_idx;
|
|
|
|
loop {
|
|
|
|
if !op(idx) {
|
2012-08-01 19:30:05 -05:00
|
|
|
return idx;
|
2012-07-26 18:09:22 -05:00
|
|
|
}
|
|
|
|
idx = self.next_bucket(idx, len_buckets);
|
|
|
|
if idx == start_idx {
|
2012-08-01 19:30:05 -05:00
|
|
|
return start_idx;
|
2012-07-26 18:09:22 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline(always)]
|
2012-08-22 23:01:30 -05:00
|
|
|
pure fn bucket_for_key(&const self,
|
2012-08-20 14:23:37 -05:00
|
|
|
buckets: &[Option<Bucket<K,V>>],
|
2012-08-22 23:01:30 -05:00
|
|
|
k: &K) -> SearchResult {
|
2012-08-30 21:01:22 -05:00
|
|
|
let hash = k.hash_keyed(self.k0, self.k1) as uint;
|
2012-07-26 18:09:22 -05:00
|
|
|
self.bucket_for_key_with_hash(buckets, hash, k)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline(always)]
|
2012-08-22 23:01:30 -05:00
|
|
|
pure fn bucket_for_key_with_hash(&const self,
|
2012-08-20 14:23:37 -05:00
|
|
|
buckets: &[Option<Bucket<K,V>>],
|
2012-08-22 23:01:30 -05:00
|
|
|
hash: uint,
|
|
|
|
k: &K) -> SearchResult {
|
2012-07-26 18:09:22 -05:00
|
|
|
let _ = for self.bucket_sequence(hash) |i| {
|
2012-08-06 14:34:08 -05:00
|
|
|
match buckets[i] {
|
2012-08-30 21:01:22 -05:00
|
|
|
Some(bkt) => if bkt.hash == hash && *k == bkt.key {
|
2012-08-14 18:54:13 -05:00
|
|
|
return FoundEntry(i);
|
2012-08-06 19:14:32 -05:00
|
|
|
},
|
2012-08-20 14:23:37 -05:00
|
|
|
None => return FoundHole(i)
|
2012-07-26 18:09:22 -05:00
|
|
|
}
|
|
|
|
};
|
2012-08-14 18:54:13 -05:00
|
|
|
return TableFull;
|
2012-07-26 18:09:22 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Expands the capacity of the array and re-inserts each
|
|
|
|
/// of the existing buckets.
|
2012-08-22 23:01:30 -05:00
|
|
|
fn expand(&mut self) {
|
2012-07-26 18:09:22 -05:00
|
|
|
let old_capacity = self.buckets.len();
|
|
|
|
let new_capacity = old_capacity * 2;
|
|
|
|
self.resize_at = ((new_capacity as float) * 3.0 / 4.0) as uint;
|
|
|
|
|
2012-08-20 14:23:37 -05:00
|
|
|
let mut old_buckets = vec::from_fn(new_capacity, |_i| None);
|
2012-07-26 18:09:22 -05:00
|
|
|
self.buckets <-> old_buckets;
|
|
|
|
|
|
|
|
for uint::range(0, old_capacity) |i| {
|
2012-08-20 14:23:37 -05:00
|
|
|
let mut bucket = None;
|
2012-07-26 18:09:22 -05:00
|
|
|
bucket <-> old_buckets[i];
|
2012-08-28 13:59:31 -05:00
|
|
|
self.insert_opt_bucket(bucket);
|
2012-07-26 18:09:22 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-28 13:59:31 -05:00
|
|
|
fn insert_opt_bucket(&mut self, +bucket: Option<Bucket<K,V>>) {
|
|
|
|
match move bucket {
|
|
|
|
Some(Bucket {hash: move hash,
|
|
|
|
key: move key,
|
|
|
|
value: move value}) => {
|
|
|
|
self.insert_internal(hash, key, value);
|
|
|
|
}
|
|
|
|
None => {}
|
|
|
|
}
|
2012-07-26 18:09:22 -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
|
2012-08-22 23:01:30 -05:00
|
|
|
fn insert_internal(&mut self, hash: uint, +k: K, +v: V) -> bool {
|
2012-08-21 10:10:32 -05:00
|
|
|
match self.bucket_for_key_with_hash(self.buckets, hash, &k) {
|
2012-08-14 18:54:13 -05:00
|
|
|
TableFull => {fail ~"Internal logic error";}
|
|
|
|
FoundHole(idx) => {
|
2012-08-22 19:24:52 -05:00
|
|
|
debug!("insert fresh (%?->%?) at idx %?, hash %?",
|
|
|
|
k, v, idx, hash);
|
2012-08-28 13:59:31 -05:00
|
|
|
self.buckets[idx] = Some(Bucket {hash: hash,
|
|
|
|
key: k,
|
|
|
|
value: v});
|
2012-07-26 18:09:22 -05:00
|
|
|
self.size += 1;
|
2012-08-01 19:30:05 -05:00
|
|
|
return true;
|
2012-07-26 18:09:22 -05:00
|
|
|
}
|
2012-08-14 18:54:13 -05:00
|
|
|
FoundEntry(idx) => {
|
2012-08-22 19:24:52 -05:00
|
|
|
debug!("insert overwrite (%?->%?) at idx %?, hash %?",
|
|
|
|
k, v, idx, hash);
|
2012-08-28 13:59:31 -05:00
|
|
|
self.buckets[idx] = Some(Bucket {hash: hash,
|
|
|
|
key: k,
|
|
|
|
value: v});
|
2012-08-01 19:30:05 -05:00
|
|
|
return false;
|
2012-07-26 18:09:22 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-08-22 23:01:30 -05:00
|
|
|
|
|
|
|
fn search(&self,
|
|
|
|
hash: uint,
|
2012-08-20 14:23:37 -05:00
|
|
|
op: fn(x: &Option<Bucket<K,V>>) -> bool) {
|
2012-08-22 23:01:30 -05:00
|
|
|
let _ = self.bucket_sequence(hash, |i| op(&self.buckets[i]));
|
|
|
|
}
|
2012-07-26 18:09:22 -05:00
|
|
|
}
|
|
|
|
|
2012-08-30 21:01:22 -05:00
|
|
|
impl<K:Hash IterBytes Eq,V> LinearMap<K,V> {
|
2012-08-22 23:01:30 -05:00
|
|
|
fn insert(&mut self, +k: K, +v: V) -> bool {
|
2012-07-26 18:09:22 -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();
|
|
|
|
}
|
|
|
|
|
2012-08-30 21:01:22 -05:00
|
|
|
let hash = k.hash_keyed(self.k0, self.k1) as uint;
|
2012-07-26 18:09:22 -05:00
|
|
|
self.insert_internal(hash, k, v)
|
|
|
|
}
|
|
|
|
|
2012-08-22 23:01:30 -05:00
|
|
|
fn remove(&mut self, k: &K) -> bool {
|
2012-07-26 18:09:22 -05:00
|
|
|
// 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
|
|
|
|
|
2012-08-06 14:34:08 -05:00
|
|
|
let mut idx = match self.bucket_for_key(self.buckets, k) {
|
2012-08-14 18:54:13 -05:00
|
|
|
TableFull | FoundHole(_) => {
|
2012-08-01 19:30:05 -05:00
|
|
|
return false;
|
2012-07-26 18:09:22 -05:00
|
|
|
}
|
2012-08-14 18:54:13 -05:00
|
|
|
FoundEntry(idx) => {
|
2012-07-26 18:09:22 -05:00
|
|
|
idx
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let len_buckets = self.buckets.len();
|
2012-08-20 14:23:37 -05:00
|
|
|
self.buckets[idx] = None;
|
2012-07-26 18:09:22 -05:00
|
|
|
idx = self.next_bucket(idx, len_buckets);
|
|
|
|
while self.buckets[idx].is_some() {
|
2012-08-20 14:23:37 -05:00
|
|
|
let mut bucket = None;
|
2012-07-26 18:09:22 -05:00
|
|
|
bucket <-> self.buckets[idx];
|
2012-08-28 13:59:31 -05:00
|
|
|
self.insert_opt_bucket(bucket);
|
2012-07-26 18:09:22 -05:00
|
|
|
idx = self.next_bucket(idx, len_buckets);
|
|
|
|
}
|
2012-08-01 17:52:13 -05:00
|
|
|
self.size -= 1;
|
2012-08-01 19:30:05 -05:00
|
|
|
return true;
|
2012-07-26 18:09:22 -05:00
|
|
|
}
|
2012-08-21 17:55:17 -05:00
|
|
|
|
2012-08-22 23:01:30 -05:00
|
|
|
fn clear(&mut self) {
|
2012-08-21 17:55:17 -05:00
|
|
|
for uint::range(0, self.buckets.len()) |idx| {
|
2012-08-20 14:23:37 -05:00
|
|
|
self.buckets[idx] = None;
|
2012-08-21 17:55:17 -05:00
|
|
|
}
|
|
|
|
self.size = 0;
|
|
|
|
}
|
2012-07-26 18:09:22 -05:00
|
|
|
|
2012-08-22 23:01:30 -05:00
|
|
|
pure fn len(&const self) -> uint {
|
2012-07-26 18:09:22 -05:00
|
|
|
self.size
|
|
|
|
}
|
|
|
|
|
2012-08-22 23:01:30 -05:00
|
|
|
pure fn is_empty(&const self) -> bool {
|
2012-08-01 17:52:13 -05:00
|
|
|
self.len() == 0
|
|
|
|
}
|
|
|
|
|
2012-08-22 23:01:30 -05:00
|
|
|
fn contains_key(&const self,
|
|
|
|
k: &K) -> bool {
|
2012-08-06 14:34:08 -05:00
|
|
|
match self.bucket_for_key(self.buckets, k) {
|
2012-08-14 18:54:13 -05:00
|
|
|
FoundEntry(_) => {true}
|
|
|
|
TableFull | FoundHole(_) => {false}
|
2012-07-26 18:09:22 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-31 16:00:17 -05:00
|
|
|
/*
|
2012-08-21 10:10:32 -05:00
|
|
|
FIXME(#3148)--region inference fails to capture needed deps
|
|
|
|
|
2012-08-22 23:01:30 -05:00
|
|
|
fn find_ref(&self, k: &K) -> option<&self/V> {
|
2012-08-21 10:10:32 -05:00
|
|
|
match self.bucket_for_key(self.buckets, k) {
|
|
|
|
FoundEntry(idx) => {
|
|
|
|
match check self.buckets[idx] {
|
|
|
|
some(ref bkt) => some(&bkt.value)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
TableFull | FoundHole(_) => {
|
|
|
|
none
|
|
|
|
}
|
|
|
|
}
|
2012-07-26 18:09:22 -05:00
|
|
|
}
|
2012-07-31 16:00:17 -05:00
|
|
|
*/
|
|
|
|
|
2012-08-22 23:01:30 -05:00
|
|
|
fn each_ref(&self, blk: fn(k: &K, v: &V) -> bool) {
|
2012-07-31 16:00:17 -05:00
|
|
|
for vec::each(self.buckets) |slot| {
|
|
|
|
let mut broke = false;
|
|
|
|
do slot.iter |bucket| {
|
|
|
|
if !blk(&bucket.key, &bucket.value) {
|
|
|
|
broke = true; // FIXME(#3064) just write "break;"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if broke { break; }
|
|
|
|
}
|
|
|
|
}
|
2012-08-22 23:01:30 -05:00
|
|
|
|
|
|
|
fn each_key_ref(&self, blk: fn(k: &K) -> bool) {
|
2012-07-31 16:11:57 -05:00
|
|
|
self.each_ref(|k, _v| blk(k))
|
2012-07-31 16:00:17 -05:00
|
|
|
}
|
2012-08-22 23:01:30 -05:00
|
|
|
|
|
|
|
fn each_value_ref(&self, blk: fn(v: &V) -> bool) {
|
2012-07-31 16:11:57 -05:00
|
|
|
self.each_ref(|_k, v| blk(v))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-30 21:01:22 -05:00
|
|
|
impl<K:Hash IterBytes Eq, V: copy> LinearMap<K,V> {
|
2012-08-20 14:23:37 -05:00
|
|
|
fn find(&const self, k: &K) -> Option<V> {
|
2012-08-22 23:01:30 -05:00
|
|
|
match self.bucket_for_key(self.buckets, k) {
|
|
|
|
FoundEntry(idx) => {
|
2012-08-24 23:08:33 -05:00
|
|
|
// FIXME (#3148): Once we rewrite found_entry, this
|
|
|
|
// failure case won't be necessary
|
|
|
|
match self.buckets[idx] {
|
2012-08-20 14:23:37 -05:00
|
|
|
Some(bkt) => {Some(copy bkt.value)}
|
|
|
|
None => fail ~"LinearMap::find: internal logic error"
|
2012-08-22 23:01:30 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
TableFull | FoundHole(_) => {
|
2012-08-20 14:23:37 -05:00
|
|
|
None
|
2012-08-22 23:01:30 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get(&const self, k: &K) -> V {
|
|
|
|
let value = self.find(k);
|
|
|
|
if value.is_none() {
|
2012-08-22 19:24:52 -05:00
|
|
|
fail fmt!("No entry found for key: %?", k);
|
2012-08-22 23:01:30 -05:00
|
|
|
}
|
|
|
|
option::unwrap(value)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2012-08-30 21:01:22 -05:00
|
|
|
impl<K: Hash IterBytes Eq copy, V: copy> LinearMap<K,V> {
|
2012-08-22 23:01:30 -05:00
|
|
|
fn each(&self, blk: fn(+K,+V) -> bool) {
|
2012-07-31 16:11:57 -05:00
|
|
|
self.each_ref(|k,v| blk(copy *k, copy *v));
|
|
|
|
}
|
|
|
|
}
|
2012-08-30 21:01:22 -05:00
|
|
|
impl<K: Hash IterBytes Eq copy, V> LinearMap<K,V> {
|
2012-08-22 23:01:30 -05:00
|
|
|
fn each_key(&self, blk: fn(+K) -> bool) {
|
2012-07-31 16:11:57 -05:00
|
|
|
self.each_key_ref(|k| blk(copy *k));
|
|
|
|
}
|
|
|
|
}
|
2012-08-30 21:01:22 -05:00
|
|
|
impl<K: Hash IterBytes Eq, V: copy> LinearMap<K,V> {
|
2012-08-22 23:01:30 -05:00
|
|
|
fn each_value(&self, blk: fn(+V) -> bool) {
|
2012-07-31 16:11:57 -05:00
|
|
|
self.each_value_ref(|v| blk(copy *v));
|
2012-07-31 16:00:17 -05:00
|
|
|
}
|
2012-07-26 18:09:22 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
mod test {
|
|
|
|
|
2012-08-27 16:22:25 -05:00
|
|
|
import linear::LinearMap;
|
2012-07-26 18:09:22 -05:00
|
|
|
|
2012-08-14 18:54:13 -05:00
|
|
|
fn int_linear_map<V>() -> LinearMap<uint,V> {
|
2012-08-30 21:01:22 -05:00
|
|
|
return LinearMap();
|
2012-07-26 18:09:22 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn inserts() {
|
2012-07-27 17:08:56 -05:00
|
|
|
let mut m = ~int_linear_map();
|
|
|
|
assert m.insert(1, 2);
|
|
|
|
assert m.insert(2, 4);
|
|
|
|
assert m.get(&1) == 2;
|
|
|
|
assert m.get(&2) == 4;
|
2012-07-26 18:09:22 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn overwrite() {
|
2012-07-27 17:08:56 -05:00
|
|
|
let mut m = ~int_linear_map();
|
|
|
|
assert m.insert(1, 2);
|
|
|
|
assert m.get(&1) == 2;
|
|
|
|
assert !m.insert(1, 3);
|
|
|
|
assert m.get(&1) == 3;
|
2012-07-26 18:09:22 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn conflicts() {
|
2012-08-30 21:01:22 -05:00
|
|
|
let mut m = ~linear::linear_map_with_capacity(4);
|
2012-07-27 17:08:56 -05:00
|
|
|
assert m.insert(1, 2);
|
|
|
|
assert m.insert(5, 3);
|
|
|
|
assert m.insert(9, 4);
|
|
|
|
assert m.get(&9) == 4;
|
|
|
|
assert m.get(&5) == 3;
|
|
|
|
assert m.get(&1) == 2;
|
2012-07-26 18:09:22 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn conflict_remove() {
|
2012-08-30 21:01:22 -05:00
|
|
|
let mut m = ~linear::linear_map_with_capacity(4);
|
2012-07-27 17:08:56 -05:00
|
|
|
assert m.insert(1, 2);
|
|
|
|
assert m.insert(5, 3);
|
|
|
|
assert m.insert(9, 4);
|
|
|
|
assert m.remove(&1);
|
|
|
|
assert m.get(&9) == 4;
|
|
|
|
assert m.get(&5) == 3;
|
2012-07-26 18:09:22 -05:00
|
|
|
}
|
2012-07-31 16:11:57 -05:00
|
|
|
|
2012-08-01 17:52:13 -05:00
|
|
|
#[test]
|
|
|
|
fn empty() {
|
2012-08-30 21:01:22 -05:00
|
|
|
let mut m = ~linear::linear_map_with_capacity(4);
|
2012-08-01 17:52:13 -05:00
|
|
|
assert m.insert(1, 2);
|
|
|
|
assert !m.is_empty();
|
|
|
|
assert m.remove(&1);
|
|
|
|
assert m.is_empty();
|
|
|
|
}
|
|
|
|
|
2012-07-31 16:11:57 -05:00
|
|
|
#[test]
|
|
|
|
fn iterate() {
|
2012-08-30 21:01:22 -05:00
|
|
|
let mut m = linear::linear_map_with_capacity(4);
|
2012-07-31 16:11:57 -05:00
|
|
|
for uint::range(0, 32) |i| {
|
|
|
|
assert (&mut m).insert(i, i*2);
|
|
|
|
}
|
|
|
|
let mut observed = 0;
|
|
|
|
for (&m).each |k, v| {
|
|
|
|
assert v == k*2;
|
|
|
|
observed |= (1 << k);
|
|
|
|
}
|
|
|
|
assert observed == 0xFFFF_FFFF;
|
|
|
|
}
|
2012-07-31 16:00:17 -05:00
|
|
|
}
|