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-01-23 15:28:00 -06:00
|
|
|
//! Sendable hash maps.
|
2012-07-26 18:09:22 -05:00
|
|
|
|
2012-09-25 14:04:02 -05:00
|
|
|
// NB: transitionary, de-mode-ing.
|
|
|
|
#[forbid(deprecated_mode)];
|
|
|
|
#[forbid(deprecated_pattern)];
|
|
|
|
|
2013-01-29 16:04:25 -06:00
|
|
|
use container::{Container, Mutable, Map, Set};
|
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
|
|
|
|
|
|
|
/// Open addressing with linear probing.
|
2012-09-26 19:47:29 -05:00
|
|
|
pub mod linear {
|
2013-01-29 16:04:25 -06:00
|
|
|
use super::*;
|
2013-01-20 13:18:24 -06:00
|
|
|
use iter::BaseIter;
|
2013-01-08 21:37:25 -06:00
|
|
|
use hash::Hash;
|
2013-01-29 15:07:11 -06:00
|
|
|
use iter;
|
2013-01-08 21:37:25 -06:00
|
|
|
use kinds::Copy;
|
|
|
|
use option::{None, Option, Some};
|
2012-12-23 16:41:37 -06:00
|
|
|
use option;
|
|
|
|
use rand;
|
2013-01-08 21:37:25 -06:00
|
|
|
use to_bytes::IterBytes;
|
2012-12-23 16:41:37 -06:00
|
|
|
use uint;
|
|
|
|
use vec;
|
|
|
|
|
2012-11-06 20:41:06 -06:00
|
|
|
const INITIAL_CAPACITY: uint = 32u; // 2^5
|
2012-09-26 19:47:29 -05:00
|
|
|
|
2013-01-28 12:46:43 -06:00
|
|
|
struct Bucket<K,V> {
|
2012-09-07 16:50:47 -05:00
|
|
|
hash: uint,
|
|
|
|
key: K,
|
|
|
|
value: V,
|
2012-08-28 13:59:31 -05:00
|
|
|
}
|
2013-01-24 21:00:58 -06:00
|
|
|
|
2013-01-28 12:46:43 -06:00
|
|
|
pub struct LinearMap<K,V> {
|
2012-09-07 16:50:47 -05:00
|
|
|
k0: u64,
|
|
|
|
k1: u64,
|
|
|
|
resize_at: uint,
|
|
|
|
size: uint,
|
2013-01-24 21:00:58 -06:00
|
|
|
buckets: ~[Option<Bucket<K, V>>],
|
2012-07-26 18:09:22 -05:00
|
|
|
}
|
|
|
|
|
2013-01-24 21:00:58 -06:00
|
|
|
// FIXME(#3148) -- we could rewrite FoundEntry
|
|
|
|
// 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
|
|
|
}
|
|
|
|
|
2013-01-24 21:00:58 -06:00
|
|
|
pure fn resize_at(capacity: uint) -> uint {
|
2012-07-26 18:09:22 -05:00
|
|
|
((capacity as float) * 3. / 4.) as uint
|
|
|
|
}
|
|
|
|
|
2013-01-24 21:00:58 -06:00
|
|
|
pub fn linear_map_with_capacity<K: Eq Hash, V>(
|
|
|
|
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
|
|
|
|
2013-01-24 21:00:58 -06:00
|
|
|
pure fn linear_map_with_capacity_and_keys<K: Eq Hash, V>(
|
2012-08-30 21:01:22 -05:00
|
|
|
k0: u64, k1: u64,
|
2013-01-24 21:00:58 -06:00
|
|
|
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,
|
2013-01-24 21:00:58 -06:00
|
|
|
buckets: vec::from_fn(initial_capacity, |_| None)
|
2012-08-28 13:59:31 -05:00
|
|
|
}
|
2012-07-26 18:09:22 -05:00
|
|
|
}
|
|
|
|
|
2013-01-24 21:00:58 -06:00
|
|
|
priv impl<K: Hash IterBytes Eq, V> LinearMap<K, V> {
|
2012-07-26 18:09:22 -05:00
|
|
|
#[inline(always)]
|
2013-01-24 21:00:58 -06:00
|
|
|
pure fn to_bucket(&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)]
|
2013-01-24 21:00:58 -06:00
|
|
|
pure fn next_bucket(&self, idx: uint, len_buckets: uint) -> uint {
|
2012-07-26 18:09:22 -05:00
|
|
|
let n = (idx + 1) % len_buckets;
|
2013-01-23 15:39:09 -06:00
|
|
|
debug!("next_bucket(%?, %?) = %?", idx, len_buckets, n);
|
2013-01-24 21:00:58 -06:00
|
|
|
n
|
2012-07-26 18:09:22 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline(always)]
|
2013-01-24 21:00:58 -06:00
|
|
|
pure fn bucket_sequence(&self, hash: uint,
|
2012-08-22 23:01:30 -05:00
|
|
|
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)]
|
2013-01-24 21:00:58 -06:00
|
|
|
pure fn bucket_for_key(&self, 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)]
|
2013-01-24 21:00:58 -06:00
|
|
|
pure fn bucket_for_key_with_hash(&self,
|
|
|
|
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-09-28 15:00:07 -05:00
|
|
|
Some(ref bkt) => if bkt.hash == hash && *k == bkt.key {
|
2012-09-07 12:34:39 -05:00
|
|
|
return FoundEntry(i);
|
|
|
|
},
|
|
|
|
None => return FoundHole(i)
|
2012-07-26 18:09:22 -05:00
|
|
|
}
|
|
|
|
};
|
2013-01-24 21:00:58 -06:00
|
|
|
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;
|
|
|
|
|
2013-01-24 21:00:58 -06:00
|
|
|
let mut old_buckets = vec::from_fn(new_capacity, |_| None);
|
2012-07-26 18:09:22 -05:00
|
|
|
self.buckets <-> old_buckets;
|
|
|
|
|
2012-12-30 12:35:03 -06:00
|
|
|
self.size = 0;
|
2012-07-26 18:09:22 -05:00
|
|
|
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];
|
2013-01-24 21:00:58 -06:00
|
|
|
self.insert_opt_bucket(bucket);
|
2012-07-26 18:09:22 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-24 21:00:58 -06: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-09-07 12:34:39 -05:00
|
|
|
}
|
|
|
|
None => {}
|
2012-08-28 13:59:31 -05:00
|
|
|
}
|
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-10-02 13:37:37 -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-09-07 12:34:39 -05:00
|
|
|
TableFull => { fail ~"Internal logic error"; }
|
|
|
|
FoundHole(idx) => {
|
|
|
|
debug!("insert fresh (%?->%?) at idx %?, hash %?",
|
|
|
|
k, v, idx, hash);
|
2013-01-24 21:00:58 -06:00
|
|
|
self.buckets[idx] = Some(Bucket{hash: hash, key: k,
|
|
|
|
value: v});
|
2012-09-07 12:34:39 -05:00
|
|
|
self.size += 1;
|
|
|
|
true
|
|
|
|
}
|
|
|
|
FoundEntry(idx) => {
|
|
|
|
debug!("insert overwrite (%?->%?) at idx %?, hash %?",
|
|
|
|
k, v, idx, hash);
|
2013-01-24 21:00:58 -06:00
|
|
|
self.buckets[idx] = Some(Bucket{hash: hash, key: k,
|
|
|
|
value: v});
|
2012-09-07 12:34:39 -05:00
|
|
|
false
|
|
|
|
}
|
2012-07-26 18:09:22 -05:00
|
|
|
}
|
|
|
|
}
|
2012-08-22 23:01:30 -05:00
|
|
|
|
2012-10-08 09:05:01 -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(self.buckets,
|
|
|
|
hash, k) {
|
|
|
|
TableFull | FoundHole(_) => return None,
|
|
|
|
FoundEntry(idx) => idx
|
|
|
|
};
|
|
|
|
|
|
|
|
let len_buckets = self.buckets.len();
|
|
|
|
let mut bucket = None;
|
|
|
|
self.buckets[idx] <-> bucket;
|
|
|
|
|
2013-01-24 21:00:58 -06:00
|
|
|
let value = match bucket {
|
2012-10-08 09:05:01 -05:00
|
|
|
None => None,
|
2013-01-24 21:00:58 -06:00
|
|
|
Some(bucket) => {
|
|
|
|
let Bucket{value: value, _} = bucket;
|
|
|
|
Some(value)
|
2012-10-08 09:05:01 -05:00
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2013-01-29 13:44:46 -06:00
|
|
|
/* re-inserting buckets may cause changes in size, so remember
|
|
|
|
what our new size is ahead of time before we start insertions */
|
2013-01-29 10:16:39 -06:00
|
|
|
let size = self.size - 1;
|
2012-10-08 09:05:01 -05:00
|
|
|
idx = self.next_bucket(idx, len_buckets);
|
|
|
|
while self.buckets[idx].is_some() {
|
|
|
|
let mut bucket = None;
|
|
|
|
bucket <-> self.buckets[idx];
|
2013-01-24 21:00:58 -06:00
|
|
|
self.insert_opt_bucket(bucket);
|
2012-10-08 09:05:01 -05:00
|
|
|
idx = self.next_bucket(idx, len_buckets);
|
|
|
|
}
|
2013-01-29 10:16:39 -06:00
|
|
|
self.size = size;
|
2012-10-08 09:05:01 -05:00
|
|
|
|
2013-01-24 21:00:58 -06:00
|
|
|
value
|
2012-10-08 09:05:01 -05:00
|
|
|
}
|
|
|
|
|
2013-01-24 21:00:58 -06:00
|
|
|
fn search(&self, hash: uint,
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2013-01-21 20:59:19 -06:00
|
|
|
impl <K: Hash IterBytes Eq, V> LinearMap<K, V>: Container {
|
2013-01-23 15:47:27 -06:00
|
|
|
/// Return the number of elements in the map
|
2013-01-21 20:59:19 -06:00
|
|
|
pure fn len(&self) -> uint { self.size }
|
2013-01-23 15:47:27 -06:00
|
|
|
|
|
|
|
/// Return true if the map contains no elements
|
2013-01-21 20:59:19 -06:00
|
|
|
pure fn is_empty(&self) -> bool { self.len() == 0 }
|
|
|
|
}
|
|
|
|
|
2013-01-21 16:25:57 -06:00
|
|
|
impl <K: Hash IterBytes Eq, V> LinearMap<K, V>: Mutable {
|
2013-01-23 15:47:27 -06:00
|
|
|
/// Clear the map, removing all key-value pairs.
|
2013-01-21 16:25:57 -06:00
|
|
|
fn clear(&mut self) {
|
|
|
|
for uint::range(0, self.buckets.len()) |idx| {
|
|
|
|
self.buckets[idx] = None;
|
|
|
|
}
|
|
|
|
self.size = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-21 17:22:03 -06:00
|
|
|
impl <K: Hash IterBytes Eq, V> LinearMap<K, V>: Map<K, V> {
|
2013-01-23 15:47:27 -06:00
|
|
|
/// Return true if the map contains a value for the specified key
|
2013-01-21 17:22:03 -06:00
|
|
|
pure fn contains_key(&self, k: &K) -> bool {
|
|
|
|
match self.bucket_for_key(self.buckets, k) {
|
|
|
|
FoundEntry(_) => {true}
|
|
|
|
TableFull | FoundHole(_) => {false}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-23 15:47:27 -06:00
|
|
|
/// Visit all key-value pairs
|
2013-01-21 17:22:03 -06:00
|
|
|
pure fn each(&self, blk: fn(k: &K, v: &V) -> bool) {
|
2013-01-24 21:00:58 -06:00
|
|
|
for self.buckets.each |slot| {
|
2013-01-21 17:22:03 -06:00
|
|
|
let mut broke = false;
|
|
|
|
do slot.iter |bucket| {
|
|
|
|
if !blk(&bucket.key, &bucket.value) {
|
|
|
|
broke = true; // FIXME(#3064) just write "break;"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if broke { break; }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-23 15:47:27 -06:00
|
|
|
/// Visit all keys
|
2013-01-21 17:22:03 -06:00
|
|
|
pure fn each_key(&self, blk: fn(k: &K) -> bool) {
|
2013-01-24 21:00:58 -06:00
|
|
|
self.each(|k, _| blk(k))
|
2013-01-21 17:22:03 -06:00
|
|
|
}
|
|
|
|
|
2013-01-23 15:47:27 -06:00
|
|
|
/// Visit all values
|
2013-01-21 17:22:03 -06:00
|
|
|
pure fn each_value(&self, blk: fn(v: &V) -> bool) {
|
2013-01-24 21:00:58 -06:00
|
|
|
self.each(|_, v| blk(v))
|
2013-01-21 17:22:03 -06:00
|
|
|
}
|
|
|
|
|
2013-01-23 15:47:27 -06:00
|
|
|
/// Return the value corresponding to the key in the map
|
2013-01-23 11:21:58 -06:00
|
|
|
pure fn find(&self, k: &K) -> Option<&self/V> {
|
|
|
|
match self.bucket_for_key(self.buckets, k) {
|
|
|
|
FoundEntry(idx) => {
|
|
|
|
match self.buckets[idx] {
|
|
|
|
Some(ref bkt) => {
|
|
|
|
// FIXME(#3148)---should be inferred
|
2013-01-24 21:00:58 -06:00
|
|
|
let bkt: &self/Bucket<K, V> = bkt;
|
2013-01-23 11:21:58 -06:00
|
|
|
Some(&bkt.value)
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
fail ~"LinearMap::find: internal logic error"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
TableFull | FoundHole(_) => {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-23 15:47:27 -06: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.
|
2012-10-02 13:37:37 -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;
|
2013-01-24 21:00:58 -06:00
|
|
|
self.insert_internal(hash, k, v)
|
2012-07-26 18:09:22 -05:00
|
|
|
}
|
|
|
|
|
2013-01-23 15:47:27 -06:00
|
|
|
/// Remove a key-value pair from the map. Return true if the key
|
|
|
|
/// was present in the map, otherwise false.
|
2012-08-22 23:01:30 -05:00
|
|
|
fn remove(&mut self, k: &K) -> bool {
|
2013-01-24 21:00:58 -06:00
|
|
|
self.pop(k).is_some()
|
2012-10-08 09:05:01 -05:00
|
|
|
}
|
2013-01-21 17:22:03 -06:00
|
|
|
}
|
2012-07-26 18:09:22 -05:00
|
|
|
|
2013-01-24 21:00:58 -06:00
|
|
|
pub impl<K:Hash IterBytes Eq, V> LinearMap<K, V> {
|
2013-01-24 12:36:55 -06:00
|
|
|
/// Create an empty LinearMap
|
2013-01-23 16:06:32 -06:00
|
|
|
static fn new() -> LinearMap<K, V> {
|
|
|
|
linear_map_with_capacity(INITIAL_CAPACITY)
|
|
|
|
}
|
|
|
|
|
2012-10-08 09:05:01 -05:00
|
|
|
fn pop(&mut self, k: &K) -> Option<V> {
|
|
|
|
let hash = k.hash_keyed(self.k0, self.k1) as uint;
|
|
|
|
self.pop_internal(hash, k)
|
|
|
|
}
|
2012-07-26 18:09:22 -05:00
|
|
|
|
2012-10-08 09:05:01 -05:00
|
|
|
fn swap(&mut self, k: K, v: V) -> Option<V> {
|
|
|
|
// this could be faster.
|
|
|
|
let hash = k.hash_keyed(self.k0, self.k1) as uint;
|
|
|
|
let old_value = self.pop_internal(hash, &k);
|
|
|
|
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2013-01-24 21:00:58 -06:00
|
|
|
self.insert_internal(hash, k, v);
|
2012-10-08 09:05:01 -05:00
|
|
|
|
2013-01-24 21:00:58 -06:00
|
|
|
old_value
|
2012-10-08 09:05:01 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
fn consume(&mut self, f: fn(K, V)) {
|
|
|
|
let mut buckets = ~[];
|
|
|
|
self.buckets <-> buckets;
|
|
|
|
self.size = 0;
|
|
|
|
|
2013-01-24 21:00:58 -06:00
|
|
|
do vec::consume(buckets) |_, bucket| {
|
|
|
|
match bucket {
|
|
|
|
None => {},
|
|
|
|
Some(bucket) => {
|
|
|
|
let Bucket{key: key, value: value, _} = bucket;
|
|
|
|
f(key, value)
|
2012-10-08 09:05:01 -05:00
|
|
|
}
|
|
|
|
}
|
2012-07-26 18:09:22 -05:00
|
|
|
}
|
|
|
|
}
|
2012-08-21 17:55:17 -05:00
|
|
|
|
2013-01-23 10:47:43 -06:00
|
|
|
pure fn get(&self, k: &K) -> &self/V {
|
|
|
|
match self.find(k) {
|
2012-09-14 18:02:02 -05:00
|
|
|
Some(v) => v,
|
|
|
|
None => fail fmt!("No entry found for key: %?", k),
|
|
|
|
}
|
|
|
|
}
|
2012-07-31 16:11:57 -05:00
|
|
|
}
|
|
|
|
|
2013-01-24 21:00:58 -06:00
|
|
|
impl<K: Hash IterBytes Eq, V: Eq> LinearMap<K, V>: Eq {
|
2012-12-10 11:00:52 -06:00
|
|
|
pure fn eq(&self, other: &LinearMap<K, V>) -> bool {
|
|
|
|
if self.len() != other.len() { return false; }
|
|
|
|
|
|
|
|
for self.each |key, value| {
|
2013-01-23 10:47:43 -06:00
|
|
|
match other.find(key) {
|
2012-12-10 11:00:52 -06:00
|
|
|
None => return false,
|
|
|
|
Some(v) => if value != v { return false },
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-24 21:00:58 -06:00
|
|
|
true
|
2012-12-10 11:00:52 -06:00
|
|
|
}
|
|
|
|
|
2013-01-24 21:00:58 -06:00
|
|
|
pure fn ne(&self, other: &LinearMap<K, V>) -> bool { !self.eq(other) }
|
2012-12-10 11:00:52 -06:00
|
|
|
}
|
2013-01-20 13:18:24 -06:00
|
|
|
|
2013-01-28 12:46:43 -06:00
|
|
|
pub struct LinearSet<T> {
|
2013-01-20 13:18:24 -06:00
|
|
|
priv map: LinearMap<T, ()>
|
|
|
|
}
|
|
|
|
|
|
|
|
impl <T: Hash IterBytes Eq> LinearSet<T>: BaseIter<T> {
|
|
|
|
/// Visit all values in order
|
|
|
|
pure fn each(&self, f: fn(&T) -> bool) { self.map.each_key(f) }
|
|
|
|
pure fn size_hint(&self) -> Option<uint> { Some(self.len()) }
|
|
|
|
}
|
|
|
|
|
|
|
|
impl <T: Hash IterBytes Eq> LinearSet<T>: Eq {
|
2013-01-20 16:07:57 -06:00
|
|
|
pure fn eq(&self, other: &LinearSet<T>) -> bool {
|
|
|
|
self.map == other.map
|
|
|
|
}
|
|
|
|
pure fn ne(&self, other: &LinearSet<T>) -> bool {
|
|
|
|
self.map != other.map
|
|
|
|
}
|
2013-01-20 13:18:24 -06:00
|
|
|
}
|
|
|
|
|
2013-01-21 20:59:19 -06:00
|
|
|
impl <T: Hash IterBytes Eq> LinearSet<T>: Container {
|
2013-01-23 15:47:27 -06:00
|
|
|
/// Return the number of elements in the set
|
2013-01-21 20:59:19 -06:00
|
|
|
pure fn len(&self) -> uint { self.map.len() }
|
2013-01-23 15:47:27 -06:00
|
|
|
|
|
|
|
/// Return true if the set contains no elements
|
2013-01-21 20:59:19 -06:00
|
|
|
pure fn is_empty(&self) -> bool { self.map.is_empty() }
|
|
|
|
}
|
|
|
|
|
2013-01-21 16:25:57 -06:00
|
|
|
impl <T: Hash IterBytes Eq> LinearSet<T>: Mutable {
|
2013-01-23 15:47:27 -06:00
|
|
|
/// Clear the set, removing all values.
|
2013-01-21 16:25:57 -06:00
|
|
|
fn clear(&mut self) { self.map.clear() }
|
|
|
|
}
|
|
|
|
|
2013-01-20 13:18:24 -06:00
|
|
|
impl <T: Hash IterBytes Eq> LinearSet<T>: Set<T> {
|
|
|
|
/// Return true if the set contains a value
|
|
|
|
pure fn contains(&self, value: &T) -> bool {
|
|
|
|
self.map.contains_key(value)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 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) }
|
2013-01-29 15:07:11 -06:00
|
|
|
|
2013-01-29 16:04:25 -06:00
|
|
|
/// Return true if the set has no elements in common with `other`.
|
|
|
|
/// This is equivalent to checking for an empty intersection.
|
|
|
|
pure fn is_disjoint(&self, other: &LinearSet<T>) -> bool {
|
|
|
|
iter::all(self, |v| !other.contains(v))
|
|
|
|
}
|
|
|
|
|
2013-01-29 15:07:11 -06:00
|
|
|
/// Return true if the set is a subset of another
|
|
|
|
pure fn is_subset(&self, other: &LinearSet<T>) -> bool {
|
|
|
|
iter::all(self, |v| other.contains(v))
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Return true if the set is a superset of another
|
|
|
|
pure fn is_superset(&self, other: &LinearSet<T>) -> bool {
|
|
|
|
other.is_subset(self)
|
|
|
|
}
|
2013-01-29 18:30:26 -06:00
|
|
|
|
|
|
|
/// Visit the values representing the difference
|
|
|
|
pure fn difference(&self, other: &LinearSet<T>, f: fn(&T) -> bool) {
|
|
|
|
for self.each |v| {
|
|
|
|
if !other.contains(v) {
|
2013-01-29 20:58:47 -06:00
|
|
|
if !f(v) { return }
|
2013-01-29 18:30:26 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Visit the values representing the symmetric difference
|
|
|
|
pure fn symmetric_difference(&self, other: &LinearSet<T>,
|
|
|
|
f: fn(&T) -> bool) {
|
|
|
|
self.difference(other, f);
|
|
|
|
other.difference(self, f);
|
|
|
|
}
|
2013-01-29 20:58:47 -06:00
|
|
|
|
|
|
|
/// Visit the values representing the intersection
|
|
|
|
pure fn intersection(&self, other: &LinearSet<T>, f: fn(&T) -> bool) {
|
|
|
|
for self.each |v| {
|
|
|
|
if other.contains(v) {
|
|
|
|
if !f(v) { return }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Visit the values representing the union
|
|
|
|
pure fn union(&self, other: &LinearSet<T>, f: fn(&T) -> bool) {
|
|
|
|
for self.each |v| {
|
|
|
|
if !f(v) { return }
|
|
|
|
}
|
|
|
|
|
|
|
|
for other.each |v| {
|
|
|
|
if !self.contains(v) {
|
|
|
|
if !f(v) { return }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-01-20 13:18:24 -06:00
|
|
|
}
|
|
|
|
|
2013-01-22 20:13:06 -06:00
|
|
|
pub impl <T: Hash IterBytes Eq> LinearSet<T> {
|
2013-01-20 13:18:24 -06:00
|
|
|
/// Create an empty LinearSet
|
2013-01-24 10:47:00 -06:00
|
|
|
static fn new() -> LinearSet<T> { LinearSet{map: LinearMap::new()} }
|
2013-01-20 13:18:24 -06:00
|
|
|
}
|
2012-07-26 18:09:22 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2013-01-29 15:07:11 -06:00
|
|
|
mod test_map {
|
2013-01-25 18:57:39 -06:00
|
|
|
use container::{Container, Mutable, Map, Set};
|
2013-01-08 21:37:25 -06:00
|
|
|
use option::{None, Some};
|
2013-01-23 09:25:27 -06:00
|
|
|
use hashmap::linear::LinearMap;
|
|
|
|
use hashmap::linear;
|
2012-12-27 19:53:04 -06:00
|
|
|
use uint;
|
2012-07-26 18:09:22 -05:00
|
|
|
|
|
|
|
#[test]
|
2012-09-26 19:47:29 -05:00
|
|
|
pub fn inserts() {
|
2013-01-23 16:06:32 -06:00
|
|
|
let mut m = LinearMap::new();
|
2012-07-27 17:08:56 -05:00
|
|
|
assert m.insert(1, 2);
|
|
|
|
assert m.insert(2, 4);
|
2013-01-23 11:45:12 -06:00
|
|
|
assert *m.get(&1) == 2;
|
|
|
|
assert *m.get(&2) == 4;
|
2012-07-26 18:09:22 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2012-09-26 19:47:29 -05:00
|
|
|
pub fn overwrite() {
|
2013-01-23 16:06:32 -06:00
|
|
|
let mut m = LinearMap::new();
|
2012-07-27 17:08:56 -05:00
|
|
|
assert m.insert(1, 2);
|
2013-01-23 11:45:12 -06:00
|
|
|
assert *m.get(&1) == 2;
|
2012-07-27 17:08:56 -05:00
|
|
|
assert !m.insert(1, 3);
|
2013-01-23 11:45:12 -06:00
|
|
|
assert *m.get(&1) == 3;
|
2012-07-26 18:09:22 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2012-09-26 19:47:29 -05:00
|
|
|
pub fn conflicts() {
|
2012-09-12 08:47:28 -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);
|
2013-01-23 11:45:12 -06:00
|
|
|
assert *m.get(&9) == 4;
|
|
|
|
assert *m.get(&5) == 3;
|
|
|
|
assert *m.get(&1) == 2;
|
2012-07-26 18:09:22 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2012-09-26 19:47:29 -05:00
|
|
|
pub fn conflict_remove() {
|
2012-09-12 08:47:28 -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);
|
2013-01-23 11:45:12 -06:00
|
|
|
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]
|
2012-09-26 19:47:29 -05:00
|
|
|
pub fn empty() {
|
2012-09-12 08:47:28 -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-10-08 09:05:01 -05:00
|
|
|
#[test]
|
|
|
|
pub fn pops() {
|
2013-01-23 16:06:32 -06:00
|
|
|
let mut m = LinearMap::new();
|
2012-10-08 09:05:01 -05:00
|
|
|
m.insert(1, 2);
|
|
|
|
assert m.pop(&1) == Some(2);
|
|
|
|
assert m.pop(&1) == None;
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
pub fn swaps() {
|
2013-01-23 16:06:32 -06:00
|
|
|
let mut m = LinearMap::new();
|
2012-10-08 09:05:01 -05:00
|
|
|
assert m.swap(1, 2) == None;
|
|
|
|
assert m.swap(1, 3) == Some(2);
|
|
|
|
assert m.swap(1, 4) == Some(3);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
pub fn consumes() {
|
2013-01-23 16:06:32 -06:00
|
|
|
let mut m = LinearMap::new();
|
2012-10-08 09:05:01 -05:00
|
|
|
assert m.insert(1, 2);
|
|
|
|
assert m.insert(2, 3);
|
2013-01-23 16:06:32 -06:00
|
|
|
let mut m2 = LinearMap::new();
|
2012-10-08 09:05:01 -05:00
|
|
|
do m.consume |k, v| {
|
|
|
|
m2.insert(k, v);
|
|
|
|
}
|
|
|
|
assert m.len() == 0;
|
|
|
|
assert m2.len() == 2;
|
2013-01-28 15:06:09 -06:00
|
|
|
assert m2.get(&1) == &2;
|
|
|
|
assert m2.get(&2) == &3;
|
2012-10-08 09:05:01 -05:00
|
|
|
}
|
|
|
|
|
2012-07-31 16:11:57 -05:00
|
|
|
#[test]
|
2012-09-26 19:47:29 -05:00
|
|
|
pub 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| {
|
2012-09-12 08:47:28 -05:00
|
|
|
assert m.insert(i, i*2);
|
2012-07-31 16:11:57 -05:00
|
|
|
}
|
|
|
|
let mut observed = 0;
|
2012-09-12 08:47:28 -05:00
|
|
|
for m.each |k, v| {
|
2012-09-18 23:41:37 -05:00
|
|
|
assert *v == *k * 2;
|
|
|
|
observed |= (1 << *k);
|
2012-07-31 16:11:57 -05:00
|
|
|
}
|
|
|
|
assert observed == 0xFFFF_FFFF;
|
|
|
|
}
|
2012-09-07 12:41:07 -05:00
|
|
|
|
|
|
|
#[test]
|
2013-01-23 10:47:43 -06:00
|
|
|
pub fn find() {
|
2013-01-23 16:06:32 -06:00
|
|
|
let mut m = LinearMap::new();
|
2013-01-23 10:47:43 -06:00
|
|
|
assert m.find(&1).is_none();
|
2012-09-07 12:41:07 -05:00
|
|
|
m.insert(1, 2);
|
2013-01-23 10:47:43 -06:00
|
|
|
match m.find(&1) {
|
2012-09-14 17:19:54 -05:00
|
|
|
None => fail,
|
|
|
|
Some(v) => assert *v == 2
|
|
|
|
}
|
2012-09-07 12:41:07 -05:00
|
|
|
}
|
2012-12-10 11:00:52 -06:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
pub fn test_eq() {
|
2013-01-23 16:06:32 -06:00
|
|
|
let mut m1 = LinearMap::new();
|
2012-12-10 11:00:52 -06:00
|
|
|
m1.insert(1, 2);
|
|
|
|
m1.insert(2, 3);
|
|
|
|
m1.insert(3, 4);
|
|
|
|
|
2013-01-23 16:06:32 -06:00
|
|
|
let mut m2 = LinearMap::new();
|
2012-12-10 11:00:52 -06:00
|
|
|
m2.insert(1, 2);
|
|
|
|
m2.insert(2, 3);
|
|
|
|
|
|
|
|
assert m1 != m2;
|
|
|
|
|
|
|
|
m2.insert(3, 4);
|
|
|
|
|
|
|
|
assert m1 == m2;
|
|
|
|
}
|
2012-12-30 12:35:03 -06:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
pub fn test_expand() {
|
2013-01-23 16:06:32 -06:00
|
|
|
let mut m = LinearMap::new();
|
2012-12-30 12:35:03 -06:00
|
|
|
|
|
|
|
assert 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 m.len() == i;
|
|
|
|
assert !m.is_empty();
|
|
|
|
}
|
2012-07-31 16:00:17 -05:00
|
|
|
}
|
2013-01-29 15:07:11 -06:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
mod test_set {
|
|
|
|
use super::*;
|
2013-01-29 22:43:44 -06:00
|
|
|
use vec;
|
2013-01-29 15:07:11 -06:00
|
|
|
|
2013-01-29 16:04:25 -06:00
|
|
|
#[test]
|
|
|
|
fn test_disjoint() {
|
|
|
|
let mut xs = linear::LinearSet::new();
|
|
|
|
let mut ys = linear::LinearSet::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);
|
|
|
|
}
|
|
|
|
|
2013-01-29 15:07:11 -06:00
|
|
|
#[test]
|
|
|
|
fn test_subset_and_superset() {
|
|
|
|
let mut a = linear::LinearSet::new();
|
|
|
|
assert a.insert(0);
|
|
|
|
assert a.insert(5);
|
|
|
|
assert a.insert(11);
|
|
|
|
assert a.insert(7);
|
|
|
|
|
|
|
|
let mut b = linear::LinearSet::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);
|
|
|
|
}
|
2013-01-29 18:30:26 -06:00
|
|
|
|
2013-01-29 20:58:47 -06:00
|
|
|
#[test]
|
|
|
|
fn test_intersection() {
|
|
|
|
let mut a = linear::LinearSet::new();
|
|
|
|
let mut b = linear::LinearSet::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];
|
|
|
|
for a.intersection(&b) |x| {
|
|
|
|
assert vec::contains(expected, x);
|
|
|
|
i += 1
|
|
|
|
}
|
|
|
|
assert i == expected.len();
|
|
|
|
}
|
|
|
|
|
2013-01-29 18:30:26 -06:00
|
|
|
#[test]
|
|
|
|
fn test_difference() {
|
|
|
|
let mut a = linear::LinearSet::new();
|
|
|
|
let mut b = linear::LinearSet::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];
|
|
|
|
for a.difference(&b) |x| {
|
|
|
|
assert vec::contains(expected, x);
|
|
|
|
i += 1
|
|
|
|
}
|
|
|
|
assert i == expected.len();
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_symmetric_difference() {
|
|
|
|
let mut a = linear::LinearSet::new();
|
|
|
|
let mut b = linear::LinearSet::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];
|
|
|
|
for a.symmetric_difference(&b) |x| {
|
|
|
|
assert vec::contains(expected, x);
|
|
|
|
i += 1
|
|
|
|
}
|
|
|
|
assert i == expected.len();
|
|
|
|
}
|
2013-01-29 20:58:47 -06:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_union() {
|
|
|
|
let mut a = linear::LinearSet::new();
|
|
|
|
let mut b = linear::LinearSet::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];
|
|
|
|
for a.union(&b) |x| {
|
|
|
|
assert vec::contains(expected, x);
|
|
|
|
i += 1
|
|
|
|
}
|
|
|
|
assert i == expected.len();
|
|
|
|
}
|
2013-01-29 15:07:11 -06:00
|
|
|
}
|