2012-07-04 16:53:12 -05:00
|
|
|
//! A map type
|
2011-10-26 13:28:23 -05:00
|
|
|
|
2012-08-02 17:42:56 -05:00
|
|
|
#[warn(deprecated_mode)];
|
|
|
|
|
2012-07-13 02:01:26 -05:00
|
|
|
import io::writer_util;
|
2012-08-13 18:20:27 -05:00
|
|
|
import to_str::ToStr;
|
2012-03-14 14:07:23 -05:00
|
|
|
export hashmap, hashfn, eqfn, set, map, chained, hashmap, str_hash;
|
2012-06-10 02:49:59 -05:00
|
|
|
export box_str_hash;
|
2012-03-14 14:07:23 -05:00
|
|
|
export bytes_hash, int_hash, uint_hash, set_add;
|
2012-03-14 21:32:19 -05:00
|
|
|
export hash_from_vec, hash_from_strs, hash_from_bytes;
|
|
|
|
export hash_from_ints, hash_from_uints;
|
2012-05-16 17:45:06 -05:00
|
|
|
export vec_from_set;
|
2012-03-07 18:48:57 -06:00
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/**
|
|
|
|
* A function that returns a hash of a value
|
|
|
|
*
|
|
|
|
* The hash should concentrate entropy in the lower bits.
|
|
|
|
*/
|
2012-08-02 17:42:56 -05:00
|
|
|
type hashfn<K> = fn~(key: &K) -> uint;
|
2011-06-15 13:19:50 -05:00
|
|
|
|
2012-08-02 17:42:56 -05:00
|
|
|
type eqfn<K> = fn~(key1: &K, key2: &K) -> bool;
|
2011-06-15 13:19:50 -05:00
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/// A convenience type to treat a hashmap as a set
|
2012-03-07 18:48:57 -06:00
|
|
|
type set<K> = hashmap<K, ()>;
|
2012-01-09 09:24:53 -06:00
|
|
|
|
2012-03-07 18:48:57 -06:00
|
|
|
type hashmap<K, V> = chained::t<K, V>;
|
2011-07-21 20:14:39 -05:00
|
|
|
|
2012-08-02 17:42:56 -05:00
|
|
|
trait map<K: copy, V: copy> {
|
2012-07-04 16:53:12 -05:00
|
|
|
/// Return the number of elements in the map
|
2011-10-26 13:28:23 -05:00
|
|
|
fn size() -> uint;
|
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/**
|
|
|
|
* Add a value to the map.
|
|
|
|
*
|
|
|
|
* If the map already contains a value for the specified key then the
|
|
|
|
* original value is replaced.
|
|
|
|
*
|
|
|
|
* Returns true if the key did not already exist in the map
|
|
|
|
*/
|
2012-06-08 16:35:11 -05:00
|
|
|
fn insert(+K, +V) -> bool;
|
2011-10-26 13:28:23 -05:00
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/// Returns true if the map contains a value for the specified key
|
2012-08-02 17:42:56 -05:00
|
|
|
fn contains_key(+key: K) -> bool;
|
|
|
|
|
|
|
|
/// Returns true if the map contains a value for the specified
|
|
|
|
/// key, taking the key by reference.
|
|
|
|
fn contains_key_ref(key: &K) -> bool;
|
2011-10-26 13:28:23 -05:00
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/**
|
|
|
|
* Get the value for the specified key. Fails if the key does not exist in
|
|
|
|
* the map.
|
|
|
|
*/
|
2012-08-02 17:42:56 -05:00
|
|
|
fn get(+key: K) -> V;
|
2012-06-27 18:34:53 -05:00
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/**
|
|
|
|
* Get the value for the specified key. If the key does not exist in
|
|
|
|
* the map then returns none.
|
|
|
|
*/
|
2012-08-02 17:42:56 -05:00
|
|
|
fn find(+key: K) -> option<V>;
|
2011-10-26 13:28:23 -05:00
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/**
|
|
|
|
* Remove and return a value from the map. If the key does not exist
|
|
|
|
* in the map then returns none.
|
|
|
|
*/
|
2012-08-02 17:42:56 -05:00
|
|
|
fn remove(+key: K) -> option<V>;
|
2011-10-26 13:28:23 -05:00
|
|
|
|
2012-07-08 18:04:57 -05:00
|
|
|
/// Clear the map, removing all key/value pairs.
|
|
|
|
fn clear();
|
|
|
|
|
2012-08-02 17:42:56 -05:00
|
|
|
/// Iterate over all the key/value pairs in the map by value
|
|
|
|
fn each(fn(+key: K, +value: V) -> bool);
|
|
|
|
|
|
|
|
/// Iterate over all the keys in the map by value
|
|
|
|
fn each_key(fn(+key: K) -> bool);
|
|
|
|
|
|
|
|
/// Iterate over all the values in the map by value
|
|
|
|
fn each_value(fn(+value: V) -> bool);
|
2011-10-26 13:28:23 -05:00
|
|
|
|
2012-08-02 17:42:56 -05:00
|
|
|
/// Iterate over all the key/value pairs in the map by reference
|
|
|
|
fn each_ref(fn(key: &K, value: &V) -> bool);
|
2012-01-27 22:39:16 -06:00
|
|
|
|
2012-08-02 17:42:56 -05:00
|
|
|
/// Iterate over all the keys in the map by reference
|
|
|
|
fn each_key_ref(fn(key: &K) -> bool);
|
|
|
|
|
|
|
|
/// Iterate over all the values in the map by reference
|
|
|
|
fn each_value_ref(fn(value: &V) -> bool);
|
2012-01-09 09:24:53 -06:00
|
|
|
}
|
2011-10-26 13:28:23 -05:00
|
|
|
|
2012-08-02 13:26:52 -05:00
|
|
|
mod util {
|
|
|
|
type rational = {num: int, den: int}; // : int::positive(*.den);
|
|
|
|
|
|
|
|
pure fn rational_leq(x: rational, y: rational) -> bool {
|
|
|
|
// NB: Uses the fact that rationals have positive denominators WLOG:
|
|
|
|
|
|
|
|
x.num * y.den <= y.num * x.den
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-06-21 18:44:10 -05:00
|
|
|
// FIXME (#2344): package this up and export it as a datatype usable for
|
|
|
|
// external code that doesn't want to pay the cost of a box.
|
2011-12-06 21:56:47 -06:00
|
|
|
mod chained {
|
2012-05-22 12:02:34 -05:00
|
|
|
export t, mk, hashmap;
|
|
|
|
|
2012-07-08 18:04:57 -05:00
|
|
|
const initial_capacity: uint = 32u; // 2^5
|
|
|
|
|
2012-08-02 17:42:56 -05:00
|
|
|
struct entry<K, V> {
|
|
|
|
hash: uint;
|
|
|
|
key: K;
|
|
|
|
value: V;
|
|
|
|
mut next: option<@entry<K, V>>;
|
2011-12-06 21:56:47 -06:00
|
|
|
}
|
|
|
|
|
2012-08-02 17:42:56 -05:00
|
|
|
struct hashmap_<K, V> {
|
|
|
|
mut count: uint;
|
|
|
|
mut chains: ~[mut option<@entry<K,V>>];
|
|
|
|
hasher: hashfn<K>;
|
|
|
|
eqer: eqfn<K>;
|
2012-07-11 17:00:40 -05:00
|
|
|
}
|
|
|
|
|
2012-08-02 17:42:56 -05:00
|
|
|
type t<K, V> = @hashmap_<K, V>;
|
2012-07-11 17:00:40 -05:00
|
|
|
|
2012-01-19 17:20:57 -06:00
|
|
|
enum search_result<K, V> {
|
2012-01-19 21:08:08 -06:00
|
|
|
not_found,
|
|
|
|
found_first(uint, @entry<K,V>),
|
2012-01-19 21:29:21 -06:00
|
|
|
found_after(@entry<K,V>, @entry<K,V>)
|
2011-12-06 21:56:47 -06:00
|
|
|
}
|
|
|
|
|
2012-08-07 20:10:06 -05:00
|
|
|
priv impl<K, V: copy> t<K, V> {
|
2012-08-02 17:42:56 -05:00
|
|
|
fn search_rem(k: &K, h: uint, idx: uint,
|
2012-05-22 12:02:34 -05:00
|
|
|
e_root: @entry<K,V>) -> search_result<K,V> {
|
|
|
|
let mut e0 = e_root;
|
|
|
|
let mut comp = 1u; // for logging
|
|
|
|
loop {
|
2012-08-06 14:34:08 -05:00
|
|
|
match copy e0.next {
|
2012-08-03 21:59:04 -05:00
|
|
|
none => {
|
2012-07-30 18:01:07 -05:00
|
|
|
debug!{"search_tbl: absent, comp %u, hash %u, idx %u",
|
|
|
|
comp, h, idx};
|
2012-08-01 19:30:05 -05:00
|
|
|
return not_found;
|
2012-05-22 12:02:34 -05:00
|
|
|
}
|
2012-08-03 21:59:04 -05:00
|
|
|
some(e1) => {
|
2012-05-22 12:02:34 -05:00
|
|
|
comp += 1u;
|
2012-08-02 17:42:56 -05:00
|
|
|
if e1.hash == h && self.eqer(&e1.key, k) {
|
2012-07-30 18:01:07 -05:00
|
|
|
debug!{"search_tbl: present, comp %u, \
|
2012-05-22 12:02:34 -05:00
|
|
|
hash %u, idx %u",
|
2012-07-30 18:01:07 -05:00
|
|
|
comp, h, idx};
|
2012-08-01 19:30:05 -05:00
|
|
|
return found_after(e0, e1);
|
2012-05-22 12:02:34 -05:00
|
|
|
} else {
|
|
|
|
e0 = e1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2012-08-02 17:42:56 -05:00
|
|
|
fn search_tbl(k: &K, h: uint) -> search_result<K,V> {
|
2012-05-22 12:02:34 -05:00
|
|
|
let idx = h % vec::len(self.chains);
|
2012-08-06 14:34:08 -05:00
|
|
|
match copy self.chains[idx] {
|
2012-08-03 21:59:04 -05:00
|
|
|
none => {
|
2012-08-02 17:42:56 -05:00
|
|
|
debug!{"search_tbl: none, comp %u, hash %u, idx %u",
|
2012-07-30 18:01:07 -05:00
|
|
|
0u, h, idx};
|
2012-08-01 19:30:05 -05:00
|
|
|
return not_found;
|
2011-12-06 21:56:47 -06:00
|
|
|
}
|
2012-08-03 21:59:04 -05:00
|
|
|
some(e) => {
|
2012-08-02 17:42:56 -05:00
|
|
|
if e.hash == h && self.eqer(&e.key, k) {
|
2012-07-30 18:01:07 -05:00
|
|
|
debug!{"search_tbl: present, comp %u, hash %u, idx %u",
|
|
|
|
1u, h, idx};
|
2012-08-01 19:30:05 -05:00
|
|
|
return found_first(idx, e);
|
2011-12-06 21:56:47 -06:00
|
|
|
} else {
|
2012-08-01 19:30:05 -05:00
|
|
|
return self.search_rem(k, h, idx, e);
|
2011-12-06 21:56:47 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-22 12:02:34 -05:00
|
|
|
fn rehash() {
|
2012-08-02 17:42:56 -05:00
|
|
|
let n_old_chains = self.chains.len();
|
2012-05-22 12:02:34 -05:00
|
|
|
let n_new_chains: uint = uint::next_power_of_two(n_old_chains+1u);
|
|
|
|
let new_chains = chains(n_new_chains);
|
2012-06-30 18:19:07 -05:00
|
|
|
for self.each_entry |entry| {
|
2012-05-22 12:02:34 -05:00
|
|
|
let idx = entry.hash % n_new_chains;
|
|
|
|
entry.next = new_chains[idx];
|
2012-08-02 17:42:56 -05:00
|
|
|
new_chains[idx] = some(entry);
|
2012-05-22 12:02:34 -05:00
|
|
|
}
|
|
|
|
self.chains = new_chains;
|
2011-12-06 21:56:47 -06:00
|
|
|
}
|
|
|
|
|
2012-05-22 12:02:34 -05:00
|
|
|
fn each_entry(blk: fn(@entry<K,V>) -> bool) {
|
2012-08-02 17:42:56 -05:00
|
|
|
// n.b. we can't use vec::iter() here because self.chains
|
|
|
|
// is stored in a mutable location.
|
|
|
|
let mut i = 0u, n = self.chains.len();
|
2012-05-22 12:02:34 -05:00
|
|
|
while i < n {
|
|
|
|
let mut chain = self.chains[i];
|
|
|
|
loop {
|
2012-08-06 14:34:08 -05:00
|
|
|
chain = match chain {
|
2012-08-03 21:59:04 -05:00
|
|
|
none => break,
|
|
|
|
some(entry) => {
|
2012-05-22 12:02:34 -05:00
|
|
|
let next = entry.next;
|
2012-08-01 19:30:05 -05:00
|
|
|
if !blk(entry) { return; }
|
2012-05-22 12:02:34 -05:00
|
|
|
next
|
|
|
|
}
|
|
|
|
}
|
2012-04-23 06:42:15 -05:00
|
|
|
}
|
2012-05-22 12:02:34 -05:00
|
|
|
i += 1u;
|
2012-04-23 06:42:15 -05:00
|
|
|
}
|
2011-12-06 21:56:47 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-07 20:10:06 -05:00
|
|
|
impl<K: copy, V: copy> t<K, V>: map<K, V> {
|
2012-03-07 18:48:57 -06:00
|
|
|
fn size() -> uint { self.count }
|
2011-12-06 21:56:47 -06:00
|
|
|
|
2012-08-02 17:42:56 -05:00
|
|
|
fn contains_key(+k: K) -> bool {
|
|
|
|
self.contains_key_ref(&k)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn contains_key_ref(k: &K) -> bool {
|
2012-05-22 12:02:34 -05:00
|
|
|
let hash = self.hasher(k);
|
2012-08-06 14:34:08 -05:00
|
|
|
match self.search_tbl(k, hash) {
|
2012-08-03 21:59:04 -05:00
|
|
|
not_found => false,
|
|
|
|
found_first(*) | found_after(*) => true
|
2012-05-22 12:02:34 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-08 16:35:11 -05:00
|
|
|
fn insert(+k: K, +v: V) -> bool {
|
2012-08-02 17:42:56 -05:00
|
|
|
let hash = self.hasher(&k);
|
2012-08-06 14:34:08 -05:00
|
|
|
match self.search_tbl(&k, hash) {
|
2012-08-03 21:59:04 -05:00
|
|
|
not_found => {
|
2012-05-22 12:02:34 -05:00
|
|
|
self.count += 1u;
|
|
|
|
let idx = hash % vec::len(self.chains);
|
|
|
|
let old_chain = self.chains[idx];
|
2012-08-02 17:42:56 -05:00
|
|
|
self.chains[idx] = some(@entry {
|
2012-05-22 12:02:34 -05:00
|
|
|
hash: hash,
|
|
|
|
key: k,
|
2012-08-02 17:42:56 -05:00
|
|
|
value: v,
|
|
|
|
next: old_chain});
|
2012-05-22 12:02:34 -05:00
|
|
|
|
|
|
|
// consider rehashing if more 3/4 full
|
2012-03-23 07:30:29 -05:00
|
|
|
let nchains = vec::len(self.chains);
|
|
|
|
let load = {num: (self.count + 1u) as int,
|
|
|
|
den: nchains as int};
|
2012-05-22 12:02:34 -05:00
|
|
|
if !util::rational_leq(load, {num:3, den:4}) {
|
|
|
|
self.rehash();
|
|
|
|
}
|
|
|
|
|
2012-08-01 19:30:05 -05:00
|
|
|
return true;
|
2012-05-22 12:02:34 -05:00
|
|
|
}
|
2012-08-03 21:59:04 -05:00
|
|
|
found_first(idx, entry) => {
|
2012-08-02 17:42:56 -05:00
|
|
|
self.chains[idx] = some(@entry {
|
|
|
|
hash: hash,
|
|
|
|
key: k,
|
|
|
|
value: v,
|
|
|
|
next: entry.next});
|
2012-08-01 19:30:05 -05:00
|
|
|
return false;
|
2012-05-22 12:02:34 -05:00
|
|
|
}
|
2012-08-03 21:59:04 -05:00
|
|
|
found_after(prev, entry) => {
|
2012-08-02 17:42:56 -05:00
|
|
|
prev.next = some(@entry {
|
|
|
|
hash: hash,
|
|
|
|
key: k,
|
|
|
|
value: v,
|
|
|
|
next: entry.next});
|
|
|
|
return false;
|
2012-05-22 12:02:34 -05:00
|
|
|
}
|
2012-03-23 07:30:29 -05:00
|
|
|
}
|
2011-12-06 21:56:47 -06:00
|
|
|
}
|
|
|
|
|
2012-08-02 17:42:56 -05:00
|
|
|
fn find(+k: K) -> option<V> {
|
2012-08-06 14:34:08 -05:00
|
|
|
match self.search_tbl(&k, self.hasher(&k)) {
|
2012-08-03 21:59:04 -05:00
|
|
|
not_found => none,
|
|
|
|
found_first(_, entry) => some(entry.value),
|
|
|
|
found_after(_, entry) => some(entry.value)
|
2012-05-22 12:02:34 -05:00
|
|
|
}
|
|
|
|
}
|
2011-12-06 21:56:47 -06:00
|
|
|
|
2012-08-02 17:42:56 -05:00
|
|
|
fn get(+k: K) -> V {
|
|
|
|
let opt_v = self.find(k);
|
|
|
|
if opt_v.is_none() {
|
|
|
|
fail fmt!{"Key not found in table: %?", k};
|
2012-07-13 20:43:47 -05:00
|
|
|
}
|
2012-08-02 17:42:56 -05:00
|
|
|
option::unwrap(opt_v)
|
2012-05-22 12:02:34 -05:00
|
|
|
}
|
2011-12-06 21:56:47 -06:00
|
|
|
|
2012-08-02 17:42:56 -05:00
|
|
|
fn remove(+k: K) -> option<V> {
|
2012-08-06 14:34:08 -05:00
|
|
|
match self.search_tbl(&k, self.hasher(&k)) {
|
2012-08-03 21:59:04 -05:00
|
|
|
not_found => none,
|
|
|
|
found_first(idx, entry) => {
|
2012-05-22 12:02:34 -05:00
|
|
|
self.count -= 1u;
|
|
|
|
self.chains[idx] = entry.next;
|
|
|
|
some(entry.value)
|
|
|
|
}
|
2012-08-03 21:59:04 -05:00
|
|
|
found_after(eprev, entry) => {
|
2012-05-22 12:02:34 -05:00
|
|
|
self.count -= 1u;
|
|
|
|
eprev.next = entry.next;
|
|
|
|
some(entry.value)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-12-06 21:56:47 -06:00
|
|
|
|
2012-07-08 18:04:57 -05:00
|
|
|
fn clear() {
|
|
|
|
self.count = 0u;
|
|
|
|
self.chains = chains(initial_capacity);
|
|
|
|
}
|
|
|
|
|
2012-08-02 17:42:56 -05:00
|
|
|
fn each(blk: fn(+key: K, +value: V) -> bool) {
|
|
|
|
self.each_ref(|k, v| blk(*k, *v))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn each_key(blk: fn(+key: K) -> bool) {
|
|
|
|
self.each_key_ref(|p| blk(*p))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn each_value(blk: fn(+value: V) -> bool) {
|
|
|
|
self.each_value_ref(|p| blk(*p))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn each_ref(blk: fn(key: &K, value: &V) -> bool) {
|
2012-06-30 18:19:07 -05:00
|
|
|
for self.each_entry |entry| {
|
2012-08-02 17:42:56 -05:00
|
|
|
if !blk(&entry.key, &entry.value) { break; }
|
2012-05-22 12:02:34 -05:00
|
|
|
}
|
|
|
|
}
|
2011-12-06 21:56:47 -06:00
|
|
|
|
2012-08-02 17:42:56 -05:00
|
|
|
fn each_key_ref(blk: fn(key: &K) -> bool) {
|
|
|
|
self.each_ref(|k, _v| blk(k))
|
|
|
|
}
|
2011-12-06 21:56:47 -06:00
|
|
|
|
2012-08-02 17:42:56 -05:00
|
|
|
fn each_value_ref(blk: fn(value: &V) -> bool) {
|
|
|
|
self.each_ref(|_k, v| blk(v))
|
|
|
|
}
|
2012-05-22 12:02:34 -05:00
|
|
|
}
|
2011-12-06 21:56:47 -06:00
|
|
|
|
2012-08-13 18:20:27 -05:00
|
|
|
impl<K: copy ToStr, V: ToStr copy> t<K, V>: ToStr {
|
2012-07-13 02:01:26 -05:00
|
|
|
fn to_writer(wr: io::writer) {
|
|
|
|
if self.count == 0u {
|
2012-08-03 13:22:35 -05:00
|
|
|
wr.write_str(~"{}");
|
2012-08-01 19:30:05 -05:00
|
|
|
return;
|
2012-07-13 02:01:26 -05:00
|
|
|
}
|
|
|
|
|
2012-08-03 13:22:35 -05:00
|
|
|
wr.write_str(~"{ ");
|
2012-07-13 02:01:26 -05:00
|
|
|
let mut first = true;
|
|
|
|
for self.each_entry |entry| {
|
|
|
|
if !first {
|
2012-08-03 13:22:35 -05:00
|
|
|
wr.write_str(~", ");
|
2012-07-13 02:01:26 -05:00
|
|
|
}
|
|
|
|
first = false;
|
|
|
|
wr.write_str(entry.key.to_str());
|
2012-08-03 13:22:35 -05:00
|
|
|
wr.write_str(~": ");
|
2012-07-13 02:01:26 -05:00
|
|
|
wr.write_str((copy entry.value).to_str());
|
|
|
|
};
|
2012-08-03 13:22:35 -05:00
|
|
|
wr.write_str(~" }");
|
2012-07-13 02:01:26 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
fn to_str() -> ~str {
|
|
|
|
do io::with_str_writer |wr| { self.to_writer(wr) }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-07 20:10:06 -05:00
|
|
|
impl<K: copy, V: copy> t<K, V>: ops::index<K, V> {
|
2012-08-02 17:42:56 -05:00
|
|
|
pure fn index(&&k: K) -> V {
|
2012-07-27 16:51:19 -05:00
|
|
|
unchecked {
|
|
|
|
self.get(k)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-02 17:42:56 -05:00
|
|
|
fn chains<K,V>(nchains: uint) -> ~[mut option<@entry<K,V>>] {
|
|
|
|
vec::to_mut(vec::from_elem(nchains, none))
|
2011-12-06 21:56:47 -06:00
|
|
|
}
|
|
|
|
|
2012-08-02 17:42:56 -05:00
|
|
|
fn mk<K, V: copy>(+hasher: hashfn<K>, +eqer: eqfn<K>) -> t<K,V> {
|
|
|
|
let slf: t<K, V> = @hashmap_ {count: 0u,
|
|
|
|
chains: chains(initial_capacity),
|
2012-07-11 17:00:40 -05:00
|
|
|
hasher: hasher,
|
2012-08-02 17:42:56 -05:00
|
|
|
eqer: eqer};
|
2012-03-07 18:48:57 -06:00
|
|
|
slf
|
2011-12-06 21:56:47 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-07 10:14:57 -06:00
|
|
|
/*
|
2012-03-14 14:07:23 -05:00
|
|
|
Function: hashmap
|
2011-12-07 10:14:57 -06:00
|
|
|
|
|
|
|
Construct a hashmap.
|
|
|
|
|
|
|
|
Parameters:
|
|
|
|
|
|
|
|
hasher - The hash function for key type K
|
|
|
|
eqer - The equality function for key type K
|
|
|
|
*/
|
2012-08-02 17:42:56 -05:00
|
|
|
fn hashmap<K: const, V: copy>(+hasher: hashfn<K>, +eqer: eqfn<K>)
|
2012-03-07 18:48:57 -06:00
|
|
|
-> hashmap<K, V> {
|
2012-01-09 09:24:53 -06:00
|
|
|
chained::mk(hasher, eqer)
|
2011-12-06 21:56:47 -06:00
|
|
|
}
|
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/// Construct a hashmap for string keys
|
2012-07-14 00:57:48 -05:00
|
|
|
fn str_hash<V: copy>() -> hashmap<~str, V> {
|
2012-08-01 19:30:05 -05:00
|
|
|
return hashmap(str::hash, str::eq);
|
2011-07-05 04:48:19 -05:00
|
|
|
}
|
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/// Construct a hashmap for boxed string keys
|
2012-07-14 00:57:48 -05:00
|
|
|
fn box_str_hash<V: copy>() -> hashmap<@~str, V> {
|
2012-08-02 17:42:56 -05:00
|
|
|
hashmap(|x: &@~str| str::hash(&**x),
|
|
|
|
|x: &@~str, y: &@~str| str::eq(&**x, &**y))
|
2012-06-10 02:49:59 -05:00
|
|
|
}
|
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/// Construct a hashmap for byte string keys
|
2012-06-29 18:26:56 -05:00
|
|
|
fn bytes_hash<V: copy>() -> hashmap<~[u8], V> {
|
2012-08-01 19:30:05 -05:00
|
|
|
return hashmap(vec::u8::hash, vec::u8::eq);
|
2012-01-06 09:36:56 -06:00
|
|
|
}
|
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/// Construct a hashmap for int keys
|
2012-03-14 14:07:23 -05:00
|
|
|
fn int_hash<V: copy>() -> hashmap<int, V> {
|
2012-08-01 19:30:05 -05:00
|
|
|
return hashmap(int::hash, int::eq);
|
2011-07-05 04:48:19 -05:00
|
|
|
}
|
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/// Construct a hashmap for uint keys
|
2012-03-14 14:07:23 -05:00
|
|
|
fn uint_hash<V: copy>() -> hashmap<uint, V> {
|
2012-08-01 19:30:05 -05:00
|
|
|
return hashmap(uint::hash, uint::eq);
|
2011-07-05 04:48:19 -05:00
|
|
|
}
|
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/// Convenience function for adding keys to a hashmap with nil type keys
|
2012-08-02 17:42:56 -05:00
|
|
|
fn set_add<K: const copy>(set: set<K>, +key: K) -> bool {
|
|
|
|
set.insert(key, ())
|
2012-05-31 12:26:05 -05:00
|
|
|
}
|
2012-01-17 21:05:07 -06:00
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/// Convert a set into a vector.
|
2012-06-29 18:26:56 -05:00
|
|
|
fn vec_from_set<T: copy>(s: set<T>) -> ~[T] {
|
|
|
|
let mut v = ~[];
|
2012-08-02 17:42:56 -05:00
|
|
|
vec::reserve(v, s.size());
|
2012-06-30 18:19:07 -05:00
|
|
|
do s.each_key() |k| {
|
2012-06-26 16:04:15 -05:00
|
|
|
vec::push(v, k);
|
2012-05-16 17:45:06 -05:00
|
|
|
true
|
|
|
|
};
|
|
|
|
v
|
|
|
|
}
|
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/// Construct a hashmap from a vector
|
2012-08-02 17:42:56 -05:00
|
|
|
fn hash_from_vec<K: const copy, V: copy>(+hasher: hashfn<K>, +eqer: eqfn<K>,
|
|
|
|
items: &[(K, V)]) -> hashmap<K, V> {
|
2012-03-14 21:32:19 -05:00
|
|
|
let map = hashmap(hasher, eqer);
|
2012-06-30 18:19:07 -05:00
|
|
|
do vec::iter(items) |item| {
|
2012-03-14 21:32:19 -05:00
|
|
|
let (key, value) = item;
|
|
|
|
map.insert(key, value);
|
|
|
|
}
|
|
|
|
map
|
|
|
|
}
|
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/// Construct a hashmap from a vector with string keys
|
2012-08-02 17:42:56 -05:00
|
|
|
fn hash_from_strs<V: copy>(items: &[(~str, V)]) -> hashmap<~str, V> {
|
2012-03-14 21:32:19 -05:00
|
|
|
hash_from_vec(str::hash, str::eq, items)
|
|
|
|
}
|
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/// Construct a hashmap from a vector with byte keys
|
2012-08-02 17:42:56 -05:00
|
|
|
fn hash_from_bytes<V: copy>(items: &[(~[u8], V)]) -> hashmap<~[u8], V> {
|
2012-03-14 21:32:19 -05:00
|
|
|
hash_from_vec(vec::u8::hash, vec::u8::eq, items)
|
|
|
|
}
|
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/// Construct a hashmap from a vector with int keys
|
2012-08-02 17:42:56 -05:00
|
|
|
fn hash_from_ints<V: copy>(items: &[(int, V)]) -> hashmap<int, V> {
|
2012-06-12 18:16:47 -05:00
|
|
|
hash_from_vec(int::hash, int::eq, items)
|
2012-03-14 21:32:19 -05:00
|
|
|
}
|
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/// Construct a hashmap from a vector with uint keys
|
2012-08-02 17:42:56 -05:00
|
|
|
fn hash_from_uints<V: copy>(items: &[(uint, V)]) -> hashmap<uint, V> {
|
2012-06-12 18:16:47 -05:00
|
|
|
hash_from_vec(uint::hash, uint::eq, items)
|
2012-03-14 21:32:19 -05:00
|
|
|
}
|
|
|
|
|
2012-01-17 21:05:07 -06:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_simple() {
|
2012-07-30 18:01:07 -05:00
|
|
|
debug!{"*** starting test_simple"};
|
2012-08-02 17:42:56 -05:00
|
|
|
pure fn eq_uint(x: &uint, y: &uint) -> bool { *x == *y }
|
|
|
|
pure fn uint_id(x: &uint) -> uint { *x }
|
2012-01-17 21:05:07 -06:00
|
|
|
let hasher_uint: map::hashfn<uint> = uint_id;
|
|
|
|
let eqer_uint: map::eqfn<uint> = eq_uint;
|
2012-07-14 00:57:48 -05:00
|
|
|
let hasher_str: map::hashfn<~str> = str::hash;
|
|
|
|
let eqer_str: map::eqfn<~str> = str::eq;
|
2012-07-30 18:01:07 -05:00
|
|
|
debug!{"uint -> uint"};
|
2012-01-17 21:05:07 -06:00
|
|
|
let hm_uu: map::hashmap<uint, uint> =
|
2012-08-02 17:42:56 -05:00
|
|
|
map::hashmap::<uint, uint>(copy hasher_uint, copy eqer_uint);
|
2012-01-17 21:05:07 -06:00
|
|
|
assert (hm_uu.insert(10u, 12u));
|
|
|
|
assert (hm_uu.insert(11u, 13u));
|
|
|
|
assert (hm_uu.insert(12u, 14u));
|
|
|
|
assert (hm_uu.get(11u) == 13u);
|
|
|
|
assert (hm_uu.get(12u) == 14u);
|
|
|
|
assert (hm_uu.get(10u) == 12u);
|
|
|
|
assert (!hm_uu.insert(12u, 14u));
|
|
|
|
assert (hm_uu.get(12u) == 14u);
|
|
|
|
assert (!hm_uu.insert(12u, 12u));
|
|
|
|
assert (hm_uu.get(12u) == 12u);
|
2012-07-14 00:57:48 -05:00
|
|
|
let ten: ~str = ~"ten";
|
|
|
|
let eleven: ~str = ~"eleven";
|
|
|
|
let twelve: ~str = ~"twelve";
|
2012-07-30 18:01:07 -05:00
|
|
|
debug!{"str -> uint"};
|
2012-07-14 00:57:48 -05:00
|
|
|
let hm_su: map::hashmap<~str, uint> =
|
2012-08-02 17:42:56 -05:00
|
|
|
map::hashmap::<~str, uint>(copy hasher_str, copy eqer_str);
|
2012-07-14 00:57:48 -05:00
|
|
|
assert (hm_su.insert(~"ten", 12u));
|
2012-01-17 21:05:07 -06:00
|
|
|
assert (hm_su.insert(eleven, 13u));
|
2012-07-14 00:57:48 -05:00
|
|
|
assert (hm_su.insert(~"twelve", 14u));
|
2012-01-17 21:05:07 -06:00
|
|
|
assert (hm_su.get(eleven) == 13u);
|
2012-07-14 00:57:48 -05:00
|
|
|
assert (hm_su.get(~"eleven") == 13u);
|
|
|
|
assert (hm_su.get(~"twelve") == 14u);
|
|
|
|
assert (hm_su.get(~"ten") == 12u);
|
|
|
|
assert (!hm_su.insert(~"twelve", 14u));
|
|
|
|
assert (hm_su.get(~"twelve") == 14u);
|
|
|
|
assert (!hm_su.insert(~"twelve", 12u));
|
|
|
|
assert (hm_su.get(~"twelve") == 12u);
|
2012-07-30 18:01:07 -05:00
|
|
|
debug!{"uint -> str"};
|
2012-07-14 00:57:48 -05:00
|
|
|
let hm_us: map::hashmap<uint, ~str> =
|
2012-08-02 17:42:56 -05:00
|
|
|
map::hashmap::<uint, ~str>(copy hasher_uint, copy eqer_uint);
|
2012-07-14 00:57:48 -05:00
|
|
|
assert (hm_us.insert(10u, ~"twelve"));
|
|
|
|
assert (hm_us.insert(11u, ~"thirteen"));
|
|
|
|
assert (hm_us.insert(12u, ~"fourteen"));
|
2012-08-02 17:42:56 -05:00
|
|
|
assert hm_us.get(11u) == ~"thirteen";
|
|
|
|
assert hm_us.get(12u) == ~"fourteen";
|
|
|
|
assert hm_us.get(10u) == ~"twelve";
|
2012-07-14 00:57:48 -05:00
|
|
|
assert (!hm_us.insert(12u, ~"fourteen"));
|
2012-08-02 17:42:56 -05:00
|
|
|
assert hm_us.get(12u) == ~"fourteen";
|
2012-07-14 00:57:48 -05:00
|
|
|
assert (!hm_us.insert(12u, ~"twelve"));
|
2012-08-02 17:42:56 -05:00
|
|
|
assert hm_us.get(12u) == ~"twelve";
|
2012-07-30 18:01:07 -05:00
|
|
|
debug!{"str -> str"};
|
2012-07-14 00:57:48 -05:00
|
|
|
let hm_ss: map::hashmap<~str, ~str> =
|
2012-08-02 17:42:56 -05:00
|
|
|
map::hashmap::<~str, ~str>(copy hasher_str, copy eqer_str);
|
2012-07-14 00:57:48 -05:00
|
|
|
assert (hm_ss.insert(ten, ~"twelve"));
|
|
|
|
assert (hm_ss.insert(eleven, ~"thirteen"));
|
|
|
|
assert (hm_ss.insert(twelve, ~"fourteen"));
|
2012-08-02 17:42:56 -05:00
|
|
|
assert hm_ss.get(~"eleven") == ~"thirteen";
|
|
|
|
assert hm_ss.get(~"twelve") == ~"fourteen";
|
|
|
|
assert hm_ss.get(~"ten") == ~"twelve";
|
2012-07-14 00:57:48 -05:00
|
|
|
assert (!hm_ss.insert(~"twelve", ~"fourteen"));
|
2012-08-02 17:42:56 -05:00
|
|
|
assert hm_ss.get(~"twelve") == ~"fourteen";
|
2012-07-14 00:57:48 -05:00
|
|
|
assert (!hm_ss.insert(~"twelve", ~"twelve"));
|
2012-08-02 17:42:56 -05:00
|
|
|
assert hm_ss.get(~"twelve") == ~"twelve";
|
2012-07-30 18:01:07 -05:00
|
|
|
debug!{"*** finished test_simple"};
|
2012-01-17 21:05:07 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Force map growth
|
|
|
|
*/
|
|
|
|
#[test]
|
|
|
|
fn test_growth() {
|
2012-07-30 18:01:07 -05:00
|
|
|
debug!{"*** starting test_growth"};
|
2012-01-17 21:05:07 -06:00
|
|
|
let num_to_insert: uint = 64u;
|
2012-08-02 17:42:56 -05:00
|
|
|
pure fn eq_uint(x: &uint, y: &uint) -> bool { *x == *y }
|
|
|
|
pure fn uint_id(x: &uint) -> uint { *x }
|
2012-07-30 18:01:07 -05:00
|
|
|
debug!{"uint -> uint"};
|
2012-01-17 21:05:07 -06:00
|
|
|
let hasher_uint: map::hashfn<uint> = uint_id;
|
|
|
|
let eqer_uint: map::eqfn<uint> = eq_uint;
|
|
|
|
let hm_uu: map::hashmap<uint, uint> =
|
2012-03-14 14:07:23 -05:00
|
|
|
map::hashmap::<uint, uint>(hasher_uint, eqer_uint);
|
2012-03-22 10:39:41 -05:00
|
|
|
let mut i: uint = 0u;
|
2012-01-17 21:05:07 -06:00
|
|
|
while i < num_to_insert {
|
|
|
|
assert (hm_uu.insert(i, i * i));
|
2012-07-30 18:01:07 -05:00
|
|
|
debug!{"inserting %u -> %u", i, i*i};
|
2012-01-17 21:05:07 -06:00
|
|
|
i += 1u;
|
|
|
|
}
|
2012-07-30 18:01:07 -05:00
|
|
|
debug!{"-----"};
|
2012-01-17 21:05:07 -06:00
|
|
|
i = 0u;
|
|
|
|
while i < num_to_insert {
|
2012-07-30 18:01:07 -05:00
|
|
|
debug!{"get(%u) = %u", i, hm_uu.get(i)};
|
2012-01-17 21:05:07 -06:00
|
|
|
assert (hm_uu.get(i) == i * i);
|
|
|
|
i += 1u;
|
|
|
|
}
|
|
|
|
assert (hm_uu.insert(num_to_insert, 17u));
|
|
|
|
assert (hm_uu.get(num_to_insert) == 17u);
|
2012-07-30 18:01:07 -05:00
|
|
|
debug!{"-----"};
|
2012-01-17 21:05:07 -06:00
|
|
|
i = 0u;
|
|
|
|
while i < num_to_insert {
|
2012-07-30 18:01:07 -05:00
|
|
|
debug!{"get(%u) = %u", i, hm_uu.get(i)};
|
2012-01-17 21:05:07 -06:00
|
|
|
assert (hm_uu.get(i) == i * i);
|
|
|
|
i += 1u;
|
|
|
|
}
|
2012-07-30 18:01:07 -05:00
|
|
|
debug!{"str -> str"};
|
2012-07-14 00:57:48 -05:00
|
|
|
let hasher_str: map::hashfn<~str> = str::hash;
|
|
|
|
let eqer_str: map::eqfn<~str> = str::eq;
|
|
|
|
let hm_ss: map::hashmap<~str, ~str> =
|
|
|
|
map::hashmap::<~str, ~str>(hasher_str, eqer_str);
|
2012-01-17 21:05:07 -06:00
|
|
|
i = 0u;
|
|
|
|
while i < num_to_insert {
|
|
|
|
assert hm_ss.insert(uint::to_str(i, 2u), uint::to_str(i * i, 2u));
|
2012-07-30 18:01:07 -05:00
|
|
|
debug!{"inserting \"%s\" -> \"%s\"",
|
2012-01-17 21:05:07 -06:00
|
|
|
uint::to_str(i, 2u),
|
2012-07-30 18:01:07 -05:00
|
|
|
uint::to_str(i*i, 2u)};
|
2012-01-17 21:05:07 -06:00
|
|
|
i += 1u;
|
|
|
|
}
|
2012-07-30 18:01:07 -05:00
|
|
|
debug!{"-----"};
|
2012-01-17 21:05:07 -06:00
|
|
|
i = 0u;
|
|
|
|
while i < num_to_insert {
|
2012-07-30 18:01:07 -05:00
|
|
|
debug!{"get(\"%s\") = \"%s\"",
|
2012-01-17 21:05:07 -06:00
|
|
|
uint::to_str(i, 2u),
|
2012-07-30 18:01:07 -05:00
|
|
|
hm_ss.get(uint::to_str(i, 2u))};
|
2012-08-02 17:42:56 -05:00
|
|
|
assert hm_ss.get(uint::to_str(i, 2u)) == uint::to_str(i * i, 2u);
|
2012-01-17 21:05:07 -06:00
|
|
|
i += 1u;
|
|
|
|
}
|
|
|
|
assert (hm_ss.insert(uint::to_str(num_to_insert, 2u),
|
|
|
|
uint::to_str(17u, 2u)));
|
2012-08-02 17:42:56 -05:00
|
|
|
assert hm_ss.get(uint::to_str(num_to_insert, 2u)) ==
|
|
|
|
uint::to_str(17u, 2u);
|
2012-07-30 18:01:07 -05:00
|
|
|
debug!{"-----"};
|
2012-01-17 21:05:07 -06:00
|
|
|
i = 0u;
|
|
|
|
while i < num_to_insert {
|
2012-07-30 18:01:07 -05:00
|
|
|
debug!{"get(\"%s\") = \"%s\"",
|
2012-01-17 21:05:07 -06:00
|
|
|
uint::to_str(i, 2u),
|
2012-07-30 18:01:07 -05:00
|
|
|
hm_ss.get(uint::to_str(i, 2u))};
|
2012-08-02 17:42:56 -05:00
|
|
|
assert hm_ss.get(uint::to_str(i, 2u)) == uint::to_str(i * i, 2u);
|
2012-01-17 21:05:07 -06:00
|
|
|
i += 1u;
|
|
|
|
}
|
2012-07-30 18:01:07 -05:00
|
|
|
debug!{"*** finished test_growth"};
|
2012-01-17 21:05:07 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_removal() {
|
2012-07-30 18:01:07 -05:00
|
|
|
debug!{"*** starting test_removal"};
|
2012-01-17 21:05:07 -06:00
|
|
|
let num_to_insert: uint = 64u;
|
2012-08-02 17:42:56 -05:00
|
|
|
fn eq(x: &uint, y: &uint) -> bool { *x == *y }
|
|
|
|
fn hash(u: &uint) -> uint {
|
2012-01-17 21:05:07 -06:00
|
|
|
// This hash function intentionally causes collisions between
|
|
|
|
// consecutive integer pairs.
|
2012-08-02 17:42:56 -05:00
|
|
|
*u / 2u * 2u
|
2012-01-17 21:05:07 -06:00
|
|
|
}
|
2012-08-02 17:42:56 -05:00
|
|
|
assert (hash(&0u) == hash(&1u));
|
|
|
|
assert (hash(&2u) == hash(&3u));
|
|
|
|
assert (hash(&0u) != hash(&2u));
|
2012-01-17 21:05:07 -06:00
|
|
|
let hasher: map::hashfn<uint> = hash;
|
|
|
|
let eqer: map::eqfn<uint> = eq;
|
|
|
|
let hm: map::hashmap<uint, uint> =
|
2012-03-14 14:07:23 -05:00
|
|
|
map::hashmap::<uint, uint>(hasher, eqer);
|
2012-03-22 10:39:41 -05:00
|
|
|
let mut i: uint = 0u;
|
2012-01-17 21:05:07 -06:00
|
|
|
while i < num_to_insert {
|
|
|
|
assert (hm.insert(i, i * i));
|
2012-07-30 18:01:07 -05:00
|
|
|
debug!{"inserting %u -> %u", i, i*i};
|
2012-01-17 21:05:07 -06:00
|
|
|
i += 1u;
|
|
|
|
}
|
|
|
|
assert (hm.size() == num_to_insert);
|
2012-07-30 18:01:07 -05:00
|
|
|
debug!{"-----"};
|
|
|
|
debug!{"removing evens"};
|
2012-01-17 21:05:07 -06:00
|
|
|
i = 0u;
|
|
|
|
while i < num_to_insert {
|
|
|
|
let v = hm.remove(i);
|
2012-08-06 14:34:08 -05:00
|
|
|
match v {
|
2012-08-03 21:59:04 -05:00
|
|
|
option::some(u) => assert (u == i * i),
|
|
|
|
option::none => fail
|
2012-01-17 21:05:07 -06:00
|
|
|
}
|
|
|
|
i += 2u;
|
|
|
|
}
|
|
|
|
assert (hm.size() == num_to_insert / 2u);
|
2012-07-30 18:01:07 -05:00
|
|
|
debug!{"-----"};
|
2012-01-17 21:05:07 -06:00
|
|
|
i = 1u;
|
|
|
|
while i < num_to_insert {
|
2012-07-30 18:01:07 -05:00
|
|
|
debug!{"get(%u) = %u", i, hm.get(i)};
|
2012-01-17 21:05:07 -06:00
|
|
|
assert (hm.get(i) == i * i);
|
|
|
|
i += 2u;
|
|
|
|
}
|
2012-07-30 18:01:07 -05:00
|
|
|
debug!{"-----"};
|
2012-01-17 21:05:07 -06:00
|
|
|
i = 1u;
|
|
|
|
while i < num_to_insert {
|
2012-07-30 18:01:07 -05:00
|
|
|
debug!{"get(%u) = %u", i, hm.get(i)};
|
2012-01-17 21:05:07 -06:00
|
|
|
assert (hm.get(i) == i * i);
|
|
|
|
i += 2u;
|
|
|
|
}
|
2012-07-30 18:01:07 -05:00
|
|
|
debug!{"-----"};
|
2012-01-17 21:05:07 -06:00
|
|
|
i = 0u;
|
|
|
|
while i < num_to_insert {
|
|
|
|
assert (hm.insert(i, i * i));
|
2012-07-30 18:01:07 -05:00
|
|
|
debug!{"inserting %u -> %u", i, i*i};
|
2012-01-17 21:05:07 -06:00
|
|
|
i += 2u;
|
|
|
|
}
|
|
|
|
assert (hm.size() == num_to_insert);
|
2012-07-30 18:01:07 -05:00
|
|
|
debug!{"-----"};
|
2012-01-17 21:05:07 -06:00
|
|
|
i = 0u;
|
|
|
|
while i < num_to_insert {
|
2012-07-30 18:01:07 -05:00
|
|
|
debug!{"get(%u) = %u", i, hm.get(i)};
|
2012-01-17 21:05:07 -06:00
|
|
|
assert (hm.get(i) == i * i);
|
|
|
|
i += 1u;
|
|
|
|
}
|
2012-07-30 18:01:07 -05:00
|
|
|
debug!{"-----"};
|
2012-01-17 21:05:07 -06:00
|
|
|
assert (hm.size() == num_to_insert);
|
|
|
|
i = 0u;
|
|
|
|
while i < num_to_insert {
|
2012-07-30 18:01:07 -05:00
|
|
|
debug!{"get(%u) = %u", i, hm.get(i)};
|
2012-01-17 21:05:07 -06:00
|
|
|
assert (hm.get(i) == i * i);
|
|
|
|
i += 1u;
|
|
|
|
}
|
2012-07-30 18:01:07 -05:00
|
|
|
debug!{"*** finished test_removal"};
|
2012-01-17 21:05:07 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_contains_key() {
|
2012-07-14 00:57:48 -05:00
|
|
|
let key = ~"k";
|
|
|
|
let map = map::hashmap::<~str, ~str>(str::hash, str::eq);
|
2012-01-17 21:05:07 -06:00
|
|
|
assert (!map.contains_key(key));
|
2012-07-14 00:57:48 -05:00
|
|
|
map.insert(key, ~"val");
|
2012-01-17 21:05:07 -06:00
|
|
|
assert (map.contains_key(key));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_find() {
|
2012-07-14 00:57:48 -05:00
|
|
|
let key = ~"k";
|
|
|
|
let map = map::hashmap::<~str, ~str>(str::hash, str::eq);
|
2012-01-17 21:05:07 -06:00
|
|
|
assert (option::is_none(map.find(key)));
|
2012-07-14 00:57:48 -05:00
|
|
|
map.insert(key, ~"val");
|
|
|
|
assert (option::get(map.find(key)) == ~"val");
|
2012-01-17 21:05:07 -06:00
|
|
|
}
|
2012-03-14 21:32:19 -05:00
|
|
|
|
2012-07-08 18:04:57 -05:00
|
|
|
#[test]
|
|
|
|
fn test_clear() {
|
2012-07-14 00:57:48 -05:00
|
|
|
let key = ~"k";
|
|
|
|
let map = map::hashmap::<~str, ~str>(str::hash, str::eq);
|
|
|
|
map.insert(key, ~"val");
|
2012-07-08 18:04:57 -05:00
|
|
|
assert (map.size() == 1);
|
|
|
|
assert (map.contains_key(key));
|
|
|
|
map.clear();
|
|
|
|
assert (map.size() == 0);
|
|
|
|
assert (!map.contains_key(key));
|
|
|
|
}
|
|
|
|
|
2012-03-14 21:32:19 -05:00
|
|
|
#[test]
|
|
|
|
fn test_hash_from_vec() {
|
2012-06-29 18:26:56 -05:00
|
|
|
let map = map::hash_from_strs(~[
|
2012-07-14 00:57:48 -05:00
|
|
|
(~"a", 1),
|
|
|
|
(~"b", 2),
|
|
|
|
(~"c", 3)
|
2012-06-29 18:26:56 -05:00
|
|
|
]);
|
2012-03-14 21:32:19 -05:00
|
|
|
assert map.size() == 3u;
|
2012-07-14 00:57:48 -05:00
|
|
|
assert map.get(~"a") == 1;
|
|
|
|
assert map.get(~"b") == 2;
|
|
|
|
assert map.get(~"c") == 3;
|
2012-03-14 21:32:19 -05:00
|
|
|
}
|
2012-01-27 22:39:16 -06:00
|
|
|
}
|