rust/src/libstd/map.rs

693 lines
21 KiB
Rust
Raw Normal View History

//! A map type
2011-10-26 13:28:23 -05:00
import chained::hashmap;
2012-07-13 02:01:26 -05:00
import io::writer_util;
import to_str::to_str;
export hashmap, hashfn, eqfn, set, map, chained, hashmap, str_hash;
2012-06-10 02:49:59 -05:00
export box_str_hash;
export bytes_hash, int_hash, uint_hash, set_add;
export hash_from_vec, hash_from_strs, hash_from_bytes;
export hash_from_ints, hash_from_uints;
export vec_from_set;
/**
* A function that returns a hash of a value
*
* The hash should concentrate entropy in the lower bits.
*/
type hashfn<K> = fn@(K) -> uint;
type eqfn<K> = fn@(K, K) -> bool;
/// A convenience type to treat a hashmap as a set
type set<K> = hashmap<K, ()>;
type hashmap<K, V> = chained::t<K, V>;
trait map<K, V: copy> {
/// Return the number of elements in the map
2011-10-26 13:28:23 -05:00
fn size() -> uint;
/**
* 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
*/
fn insert(+K, +V) -> bool;
2011-10-26 13:28:23 -05:00
/// Returns true if the map contains a value for the specified key
2011-10-26 13:28:23 -05:00
fn contains_key(K) -> bool;
/**
* Get the value for the specified key. Fails if the key does not exist in
* the map.
*/
2011-10-26 13:28:23 -05:00
fn get(K) -> V;
/// Like get, but as an operator.
fn [](K) -> V;
/**
* Get the value for the specified key. If the key does not exist in
* the map then returns none.
*/
fn find(K) -> option<V>;
2011-10-26 13:28:23 -05:00
/**
* Remove and return a value from the map. If the key does not exist
* in the map then returns none.
*/
fn remove(K) -> option<V>;
2011-10-26 13:28:23 -05:00
/// Clear the map, removing all key/value pairs.
fn clear();
/// Iterate over all the key/value pairs in the map
fn each(fn(K, V) -> bool);
2011-10-26 13:28:23 -05:00
/// Iterate over all the keys in the map
fn each_key(fn(K) -> bool);
2012-01-27 22:39:16 -06:00
/// Iterate over all the values in the map
fn each_value(fn(V) -> bool);
}
2011-10-26 13:28:23 -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;
const initial_capacity: uint = 32u; // 2^5
type entry<K, V> = {
2011-12-06 21:56:47 -06:00
hash: uint,
key: K,
2012-03-26 20:35:18 -05:00
mut value: V,
mut next: chain<K, V>
2011-12-06 21:56:47 -06:00
};
2012-01-19 17:20:57 -06:00
enum chain<K, V> {
present(@entry<K, V>),
absent
2011-12-06 21:56:47 -06:00
}
type hashmap__<K, V> = {
2012-03-26 20:35:18 -05:00
mut count: uint,
mut chains: ~[mut chain<K,V>],
2011-12-06 21:56:47 -06:00
hasher: hashfn<K>,
eqer: eqfn<K>
};
2012-07-13 02:01:26 -05:00
type t<K, V> = @hashmap_<K, V>;
2011-12-06 21:56:47 -06:00
enum hashmap_<K, V> {
hashmap_(@hashmap__<K, V>)
}
type t<K, V> = hashmap_<K, V>;
2012-01-19 17:20:57 -06:00
enum search_result<K, V> {
not_found,
found_first(uint, @entry<K,V>),
found_after(@entry<K,V>, @entry<K,V>)
2011-12-06 21:56:47 -06:00
}
2012-07-13 02:01:26 -05:00
impl private_methods<K, V: copy> for hashmap_<K, V> {
2012-05-22 12:02:34 -05:00
fn search_rem(k: K, h: uint, idx: uint,
e_root: @entry<K,V>) -> search_result<K,V> {
let mut e0 = e_root;
let mut comp = 1u; // for logging
loop {
2012-05-23 19:18:31 -05:00
alt copy e0.next {
2012-05-22 12:02:34 -05:00
absent {
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
}
present(e1) {
comp += 1u;
2012-05-23 19:18:31 -05:00
if e1.hash == h && self.eqer(e1.key, k) {
debug!{"search_tbl: present, comp %u, \
2012-05-22 12:02:34 -05:00
hash %u, idx %u",
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;
}
}
}
};
}
fn search_tbl(k: K, h: uint) -> search_result<K,V> {
let idx = h % vec::len(self.chains);
2012-05-23 19:18:31 -05:00
alt copy self.chains[idx] {
absent {
debug!{"search_tbl: absent, comp %u, hash %u, idx %u",
0u, h, idx};
2012-08-01 19:30:05 -05:00
return not_found;
2011-12-06 21:56:47 -06:00
}
2012-05-22 12:02:34 -05:00
present(e) {
2012-05-23 19:18:31 -05:00
if e.hash == h && self.eqer(e.key, k) {
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() {
let n_old_chains = vec::len(self.chains);
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];
new_chains[idx] = present(entry);
}
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) {
let mut i = 0u, n = vec::len(self.chains);
while i < n {
let mut chain = self.chains[i];
loop {
chain = alt chain {
absent { break; }
present(entry) {
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-05-22 12:02:34 -05:00
i += 1u;
}
2011-12-06 21:56:47 -06:00
}
}
impl hashmap<K, V: copy> of map<K, V> for t<K, V> {
fn size() -> uint { self.count }
2011-12-06 21:56:47 -06:00
2012-05-22 12:02:34 -05:00
fn contains_key(k: K) -> bool {
let hash = self.hasher(k);
alt self.search_tbl(k, hash) {
not_found {false}
found_first(*) | found_after(*) {true}
}
}
fn insert(+k: K, +v: V) -> bool {
2012-05-22 12:02:34 -05:00
let hash = self.hasher(k);
alt self.search_tbl(k, hash) {
not_found {
self.count += 1u;
let idx = hash % vec::len(self.chains);
let old_chain = self.chains[idx];
self.chains[idx] = present(@{
hash: hash,
key: k,
mut value: v,
mut next: old_chain});
// consider rehashing if more 3/4 full
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
}
found_first(_, entry) {
entry.value = v;
2012-08-01 19:30:05 -05:00
return false;
2012-05-22 12:02:34 -05:00
}
found_after(_, entry) {
entry.value = v;
2012-08-01 19:30:05 -05:00
return false
2012-05-22 12:02:34 -05:00
}
}
2011-12-06 21:56:47 -06:00
}
2012-05-22 12:02:34 -05:00
fn find(k: K) -> option<V> {
alt self.search_tbl(k, self.hasher(k)) {
not_found {none}
found_first(_, entry) {some(entry.value)}
found_after(_, entry) {some(entry.value)}
}
}
2011-12-06 21:56:47 -06:00
2012-05-22 12:02:34 -05:00
fn get(k: K) -> V {
alt self.find(k) {
some(v) => {v}
none => {fail fmt!{"Key not found in table: %?", k}}
}
2012-05-22 12:02:34 -05:00
}
2011-12-06 21:56:47 -06:00
fn [](k: K) -> V {
self.get(k)
}
2012-05-22 12:02:34 -05:00
fn remove(k: K) -> option<V> {
alt self.search_tbl(k, self.hasher(k)) {
not_found {none}
found_first(idx, entry) {
self.count -= 1u;
self.chains[idx] = entry.next;
some(entry.value)
}
found_after(eprev, entry) {
self.count -= 1u;
eprev.next = entry.next;
some(entry.value)
}
}
}
2011-12-06 21:56:47 -06:00
fn clear() {
self.count = 0u;
self.chains = chains(initial_capacity);
}
2012-05-22 12:02:34 -05:00
fn each(blk: fn(K,V) -> bool) {
2012-06-30 18:19:07 -05:00
for self.each_entry |entry| {
if !blk(entry.key, copy entry.value) { break; }
2012-05-22 12:02:34 -05:00
}
}
2011-12-06 21:56:47 -06:00
2012-06-30 18:19:07 -05:00
fn each_key(blk: fn(K) -> bool) { self.each(|k, _v| blk(k)) }
2011-12-06 21:56:47 -06:00
2012-06-30 18:19:07 -05:00
fn each_value(blk: fn(V) -> bool) { self.each(|_k, v| blk(v)) }
2012-05-22 12:02:34 -05:00
}
2011-12-06 21:56:47 -06:00
2012-07-13 02:01:26 -05:00
impl hashmap<K: to_str, V: to_str copy> of to_str for hashmap_<K, V> {
fn to_writer(wr: io::writer) {
if self.count == 0u {
wr.write_str("{}");
2012-08-01 19:30:05 -05:00
return;
2012-07-13 02:01:26 -05:00
}
wr.write_str("{ ");
let mut first = true;
for self.each_entry |entry| {
if !first {
wr.write_str(", ");
}
first = false;
wr.write_str(entry.key.to_str());
wr.write_str(": ");
wr.write_str((copy entry.value).to_str());
};
wr.write_str(" }");
}
fn to_str() -> ~str {
do io::with_str_writer |wr| { self.to_writer(wr) }
}
}
impl hashmap<K, V: copy> of ops::index<K, V> for t<K, V> {
pure fn index(k: K) -> V {
unchecked {
self.get(k)
}
}
}
2012-07-13 02:01:26 -05:00
fn chains<K,V>(nchains: uint) -> ~[mut chain<K,V>] {
2012-08-01 19:30:05 -05:00
return vec::to_mut(vec::from_elem(nchains, absent));
2011-12-06 21:56:47 -06:00
}
fn mk<K, V: copy>(hasher: hashfn<K>, eqer: eqfn<K>) -> t<K,V> {
let slf: t<K, V> = hashmap_(@{mut count: 0u,
mut chains: chains(initial_capacity),
hasher: hasher,
eqer: eqer});
slf
2011-12-06 21:56:47 -06:00
}
}
2011-12-07 10:14:57 -06: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
*/
fn hashmap<K: const, V: copy>(hasher: hashfn<K>, eqer: eqfn<K>)
-> hashmap<K, V> {
chained::mk(hasher, eqer)
2011-12-06 21:56:47 -06:00
}
/// Construct a hashmap for string keys
fn str_hash<V: copy>() -> hashmap<~str, V> {
2012-08-01 19:30:05 -05:00
return hashmap(str::hash, str::eq);
}
/// Construct a hashmap for boxed string keys
fn box_str_hash<V: copy>() -> hashmap<@~str, V> {
2012-08-01 19:30:05 -05:00
return hashmap(|x: @~str| str::hash(*x), |x,y| str::eq(*x,*y));
2012-06-10 02:49:59 -05:00
}
/// Construct a hashmap for byte string keys
fn bytes_hash<V: copy>() -> hashmap<~[u8], V> {
2012-08-01 19:30:05 -05:00
return hashmap(vec::u8::hash, vec::u8::eq);
}
/// Construct a hashmap for int keys
fn int_hash<V: copy>() -> hashmap<int, V> {
2012-08-01 19:30:05 -05:00
return hashmap(int::hash, int::eq);
}
/// Construct a hashmap for uint keys
fn uint_hash<V: copy>() -> hashmap<uint, V> {
2012-08-01 19:30:05 -05:00
return hashmap(uint::hash, uint::eq);
}
/// Convenience function for adding keys to a hashmap with nil type keys
2012-05-31 12:26:05 -05:00
fn set_add<K: const copy>(set: set<K>, key: K) -> bool {
2012-08-01 19:30:05 -05:00
return set.insert(key, ());
2012-05-31 12:26:05 -05:00
}
2012-01-17 21:05:07 -06:00
/// Convert a set into a vector.
fn vec_from_set<T: copy>(s: set<T>) -> ~[T] {
let mut v = ~[];
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);
true
};
v
}
/// Construct a hashmap from a vector
2012-05-31 12:26:05 -05:00
fn hash_from_vec<K: const copy, V: copy>(hasher: hashfn<K>, eqer: eqfn<K>,
items: ~[(K, V)]) -> hashmap<K, V> {
let map = hashmap(hasher, eqer);
2012-06-30 18:19:07 -05:00
do vec::iter(items) |item| {
let (key, value) = item;
map.insert(key, value);
}
map
}
/// Construct a hashmap from a vector with string keys
fn hash_from_strs<V: copy>(items: ~[(~str, V)]) -> hashmap<~str, V> {
hash_from_vec(str::hash, str::eq, items)
}
/// Construct a hashmap from a vector with byte keys
fn hash_from_bytes<V: copy>(items: ~[(~[u8], V)]) -> hashmap<~[u8], V> {
hash_from_vec(vec::u8::hash, vec::u8::eq, items)
}
/// Construct a hashmap from a vector with int keys
fn hash_from_ints<V: copy>(items: ~[(int, V)]) -> hashmap<int, V> {
hash_from_vec(int::hash, int::eq, items)
}
/// Construct a hashmap from a vector with uint keys
fn hash_from_uints<V: copy>(items: ~[(uint, V)]) -> hashmap<uint, V> {
hash_from_vec(uint::hash, uint::eq, items)
}
2012-01-17 21:05:07 -06:00
#[cfg(test)]
mod tests {
#[test]
fn test_simple() {
debug!{"*** starting test_simple"};
2012-08-01 19:30:05 -05:00
fn eq_uint(&&x: uint, &&y: uint) -> bool { return x == y; }
2012-01-17 21:05:07 -06:00
fn uint_id(&&x: uint) -> uint { x }
let hasher_uint: map::hashfn<uint> = uint_id;
let eqer_uint: map::eqfn<uint> = eq_uint;
let hasher_str: map::hashfn<~str> = str::hash;
let eqer_str: map::eqfn<~str> = str::eq;
debug!{"uint -> uint"};
2012-01-17 21:05:07 -06:00
let hm_uu: map::hashmap<uint, uint> =
map::hashmap::<uint, uint>(hasher_uint, 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);
let ten: ~str = ~"ten";
let eleven: ~str = ~"eleven";
let twelve: ~str = ~"twelve";
debug!{"str -> uint"};
let hm_su: map::hashmap<~str, uint> =
map::hashmap::<~str, uint>(hasher_str, eqer_str);
assert (hm_su.insert(~"ten", 12u));
2012-01-17 21:05:07 -06:00
assert (hm_su.insert(eleven, 13u));
assert (hm_su.insert(~"twelve", 14u));
2012-01-17 21:05:07 -06:00
assert (hm_su.get(eleven) == 13u);
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);
debug!{"uint -> str"};
let hm_us: map::hashmap<uint, ~str> =
map::hashmap::<uint, ~str>(hasher_uint, eqer_uint);
assert (hm_us.insert(10u, ~"twelve"));
assert (hm_us.insert(11u, ~"thirteen"));
assert (hm_us.insert(12u, ~"fourteen"));
assert (str::eq(hm_us.get(11u), ~"thirteen"));
assert (str::eq(hm_us.get(12u), ~"fourteen"));
assert (str::eq(hm_us.get(10u), ~"twelve"));
assert (!hm_us.insert(12u, ~"fourteen"));
assert (str::eq(hm_us.get(12u), ~"fourteen"));
assert (!hm_us.insert(12u, ~"twelve"));
assert (str::eq(hm_us.get(12u), ~"twelve"));
debug!{"str -> str"};
let hm_ss: map::hashmap<~str, ~str> =
map::hashmap::<~str, ~str>(hasher_str, eqer_str);
assert (hm_ss.insert(ten, ~"twelve"));
assert (hm_ss.insert(eleven, ~"thirteen"));
assert (hm_ss.insert(twelve, ~"fourteen"));
assert (str::eq(hm_ss.get(~"eleven"), ~"thirteen"));
assert (str::eq(hm_ss.get(~"twelve"), ~"fourteen"));
assert (str::eq(hm_ss.get(~"ten"), ~"twelve"));
assert (!hm_ss.insert(~"twelve", ~"fourteen"));
assert (str::eq(hm_ss.get(~"twelve"), ~"fourteen"));
assert (!hm_ss.insert(~"twelve", ~"twelve"));
assert (str::eq(hm_ss.get(~"twelve"), ~"twelve"));
debug!{"*** finished test_simple"};
2012-01-17 21:05:07 -06:00
}
/**
* Force map growth
*/
#[test]
fn test_growth() {
debug!{"*** starting test_growth"};
2012-01-17 21:05:07 -06:00
let num_to_insert: uint = 64u;
2012-08-01 19:30:05 -05:00
fn eq_uint(&&x: uint, &&y: uint) -> bool { return x == y; }
2012-01-17 21:05:07 -06:00
fn uint_id(&&x: uint) -> uint { x }
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> =
map::hashmap::<uint, uint>(hasher_uint, eqer_uint);
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));
debug!{"inserting %u -> %u", i, i*i};
2012-01-17 21:05:07 -06:00
i += 1u;
}
debug!{"-----"};
2012-01-17 21:05:07 -06:00
i = 0u;
while i < num_to_insert {
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);
debug!{"-----"};
2012-01-17 21:05:07 -06:00
i = 0u;
while i < num_to_insert {
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;
}
debug!{"str -> str"};
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));
debug!{"inserting \"%s\" -> \"%s\"",
2012-01-17 21:05:07 -06:00
uint::to_str(i, 2u),
uint::to_str(i*i, 2u)};
2012-01-17 21:05:07 -06:00
i += 1u;
}
debug!{"-----"};
2012-01-17 21:05:07 -06:00
i = 0u;
while i < num_to_insert {
debug!{"get(\"%s\") = \"%s\"",
2012-01-17 21:05:07 -06:00
uint::to_str(i, 2u),
hm_ss.get(uint::to_str(i, 2u))};
2012-01-17 21:05:07 -06:00
assert (str::eq(hm_ss.get(uint::to_str(i, 2u)),
uint::to_str(i * i, 2u)));
i += 1u;
}
assert (hm_ss.insert(uint::to_str(num_to_insert, 2u),
uint::to_str(17u, 2u)));
assert (str::eq(hm_ss.get(uint::to_str(num_to_insert, 2u)),
uint::to_str(17u, 2u)));
debug!{"-----"};
2012-01-17 21:05:07 -06:00
i = 0u;
while i < num_to_insert {
debug!{"get(\"%s\") = \"%s\"",
2012-01-17 21:05:07 -06:00
uint::to_str(i, 2u),
hm_ss.get(uint::to_str(i, 2u))};
2012-01-17 21:05:07 -06:00
assert (str::eq(hm_ss.get(uint::to_str(i, 2u)),
uint::to_str(i * i, 2u)));
i += 1u;
}
debug!{"*** finished test_growth"};
2012-01-17 21:05:07 -06:00
}
#[test]
fn test_removal() {
debug!{"*** starting test_removal"};
2012-01-17 21:05:07 -06:00
let num_to_insert: uint = 64u;
2012-08-01 19:30:05 -05:00
fn eq(&&x: uint, &&y: uint) -> bool { return x == y; }
2012-01-17 21:05:07 -06:00
fn hash(&&u: uint) -> uint {
// This hash function intentionally causes collisions between
// consecutive integer pairs.
2012-08-01 19:30:05 -05:00
return u / 2u * 2u;
2012-01-17 21:05:07 -06:00
}
assert (hash(0u) == hash(1u));
assert (hash(2u) == hash(3u));
assert (hash(0u) != hash(2u));
let hasher: map::hashfn<uint> = hash;
let eqer: map::eqfn<uint> = eq;
let hm: map::hashmap<uint, uint> =
map::hashmap::<uint, uint>(hasher, eqer);
let mut i: uint = 0u;
2012-01-17 21:05:07 -06:00
while i < num_to_insert {
assert (hm.insert(i, i * i));
debug!{"inserting %u -> %u", i, i*i};
2012-01-17 21:05:07 -06:00
i += 1u;
}
assert (hm.size() == num_to_insert);
debug!{"-----"};
debug!{"removing evens"};
2012-01-17 21:05:07 -06:00
i = 0u;
while i < num_to_insert {
let v = hm.remove(i);
alt v {
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);
debug!{"-----"};
2012-01-17 21:05:07 -06:00
i = 1u;
while i < num_to_insert {
debug!{"get(%u) = %u", i, hm.get(i)};
2012-01-17 21:05:07 -06:00
assert (hm.get(i) == i * i);
i += 2u;
}
debug!{"-----"};
2012-01-17 21:05:07 -06:00
i = 1u;
while i < num_to_insert {
debug!{"get(%u) = %u", i, hm.get(i)};
2012-01-17 21:05:07 -06:00
assert (hm.get(i) == i * i);
i += 2u;
}
debug!{"-----"};
2012-01-17 21:05:07 -06:00
i = 0u;
while i < num_to_insert {
assert (hm.insert(i, i * i));
debug!{"inserting %u -> %u", i, i*i};
2012-01-17 21:05:07 -06:00
i += 2u;
}
assert (hm.size() == num_to_insert);
debug!{"-----"};
2012-01-17 21:05:07 -06:00
i = 0u;
while i < num_to_insert {
debug!{"get(%u) = %u", i, hm.get(i)};
2012-01-17 21:05:07 -06:00
assert (hm.get(i) == i * i);
i += 1u;
}
debug!{"-----"};
2012-01-17 21:05:07 -06:00
assert (hm.size() == num_to_insert);
i = 0u;
while i < num_to_insert {
debug!{"get(%u) = %u", i, hm.get(i)};
2012-01-17 21:05:07 -06:00
assert (hm.get(i) == i * i);
i += 1u;
}
debug!{"*** finished test_removal"};
2012-01-17 21:05:07 -06:00
}
#[test]
fn test_contains_key() {
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));
map.insert(key, ~"val");
2012-01-17 21:05:07 -06:00
assert (map.contains_key(key));
}
#[test]
fn test_find() {
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)));
map.insert(key, ~"val");
assert (option::get(map.find(key)) == ~"val");
2012-01-17 21:05:07 -06:00
}
#[test]
fn test_clear() {
let key = ~"k";
let map = map::hashmap::<~str, ~str>(str::hash, str::eq);
map.insert(key, ~"val");
assert (map.size() == 1);
assert (map.contains_key(key));
map.clear();
assert (map.size() == 0);
assert (!map.contains_key(key));
}
#[test]
fn test_hash_from_vec() {
let map = map::hash_from_strs(~[
(~"a", 1),
(~"b", 2),
(~"c", 3)
]);
assert map.size() == 3u;
assert map.get(~"a") == 1;
assert map.get(~"b") == 2;
assert map.get(~"c") == 3;
}
2012-01-27 22:39:16 -06:00
}