2012-12-03 18:48:01 -06:00
|
|
|
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
// 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-02-01 01:13:36 -06:00
|
|
|
//! A map type - **deprecated**, use `core::hashmap` instead
|
2012-08-02 17:42:56 -05:00
|
|
|
|
2013-02-02 01:52:01 -06:00
|
|
|
use core::container::{Container, Mutable, Map};
|
2012-09-04 13:23:53 -05:00
|
|
|
use core::cmp::Eq;
|
2012-12-23 16:41:37 -06:00
|
|
|
use core::hash::Hash;
|
|
|
|
use core::io::WriterUtil;
|
|
|
|
use core::io;
|
|
|
|
use core::ops;
|
|
|
|
use core::to_str::ToStr;
|
2013-01-08 21:37:25 -06:00
|
|
|
use core::prelude::*;
|
2012-12-23 16:41:37 -06:00
|
|
|
use core::to_bytes::IterBytes;
|
|
|
|
use core::uint;
|
|
|
|
use core::vec;
|
2012-08-30 21:01:22 -05:00
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/// A convenience type to treat a hashmap as a set
|
2013-01-28 12:46:43 -06:00
|
|
|
pub type Set<K> = HashMap<K, ()>;
|
2012-01-09 09:24:53 -06:00
|
|
|
|
2013-01-28 12:46:43 -06:00
|
|
|
pub type HashMap<K, V> = chained::T<K, V>;
|
2011-07-21 20:14:39 -05:00
|
|
|
|
2012-12-23 16:41:37 -06:00
|
|
|
pub mod util {
|
2013-01-22 10:44:24 -06:00
|
|
|
pub struct Rational {
|
|
|
|
// : int::positive(*.den);
|
|
|
|
num: int,
|
|
|
|
den: int,
|
|
|
|
}
|
2012-08-02 13:26:52 -05:00
|
|
|
|
2012-10-02 14:02:59 -05:00
|
|
|
pub pure fn rational_leq(x: Rational, y: Rational) -> bool {
|
2012-08-02 13:26:52 -05:00
|
|
|
// 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.
|
2012-10-02 14:02:59 -05:00
|
|
|
pub mod chained {
|
2013-02-01 01:13:36 -06:00
|
|
|
use super::util;
|
2012-12-23 16:41:37 -06:00
|
|
|
|
|
|
|
use core::io;
|
|
|
|
use core::ops;
|
|
|
|
use core::option;
|
2013-01-08 21:37:25 -06:00
|
|
|
use core::prelude::*;
|
2012-12-23 16:41:37 -06:00
|
|
|
use core::uint;
|
|
|
|
use core::vec;
|
2012-05-22 12:02:34 -05:00
|
|
|
|
2012-07-08 18:04:57 -05:00
|
|
|
const initial_capacity: uint = 32u; // 2^5
|
|
|
|
|
2012-09-10 17:38:28 -05:00
|
|
|
struct Entry<K, V> {
|
2012-09-07 16:50:47 -05:00
|
|
|
hash: uint,
|
|
|
|
key: K,
|
|
|
|
value: V,
|
2012-09-10 17:38:28 -05:00
|
|
|
mut next: Option<@Entry<K, V>>
|
2011-12-06 21:56:47 -06:00
|
|
|
}
|
|
|
|
|
2013-01-28 12:46:43 -06:00
|
|
|
struct HashMap_<K, V> {
|
2012-09-07 16:50:47 -05:00
|
|
|
mut count: uint,
|
2013-01-29 21:12:36 -06:00
|
|
|
mut chains: ~[Option<@Entry<K,V>>]
|
2012-07-11 17:00:40 -05:00
|
|
|
}
|
|
|
|
|
2013-01-28 12:46:43 -06:00
|
|
|
pub type T<K, V> = @HashMap_<K, V>;
|
2012-07-11 17:00:40 -05:00
|
|
|
|
2012-09-10 17:38:28 -05:00
|
|
|
enum SearchResult<K, V> {
|
|
|
|
NotFound,
|
|
|
|
FoundFirst(uint, @Entry<K,V>),
|
|
|
|
FoundAfter(@Entry<K,V>, @Entry<K,V>)
|
2011-12-06 21:56:47 -06:00
|
|
|
}
|
|
|
|
|
2013-02-08 18:20:36 -06:00
|
|
|
priv impl<K:Eq IterBytes Hash, V> T<K, V> {
|
2012-08-27 18:26:35 -05:00
|
|
|
pure fn search_rem(k: &K, h: uint, idx: uint,
|
2012-09-10 17:38:28 -05:00
|
|
|
e_root: @Entry<K,V>) -> SearchResult<K,V> {
|
2012-05-22 12:02:34 -05:00
|
|
|
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-20 14:23:37 -05:00
|
|
|
None => {
|
2012-08-22 19:24:52 -05:00
|
|
|
debug!("search_tbl: absent, comp %u, hash %u, idx %u",
|
|
|
|
comp, h, idx);
|
2012-09-10 17:38:28 -05:00
|
|
|
return NotFound;
|
2012-05-22 12:02:34 -05:00
|
|
|
}
|
2012-08-20 14:23:37 -05:00
|
|
|
Some(e1) => {
|
2012-05-22 12:02:34 -05:00
|
|
|
comp += 1u;
|
2013-02-08 18:28:37 -06:00
|
|
|
if e1.hash == h && e1.key == *k {
|
|
|
|
debug!(
|
|
|
|
"search_tbl: present, comp %u, hash %u, idx %u",
|
|
|
|
comp, h, idx);
|
|
|
|
return FoundAfter(e0, e1);
|
|
|
|
} else {
|
|
|
|
e0 = e1;
|
2012-05-22 12:02:34 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2012-09-10 17:38:28 -05:00
|
|
|
pure fn search_tbl(k: &K, h: uint) -> SearchResult<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-20 14:23:37 -05:00
|
|
|
None => {
|
2012-08-22 19:24:52 -05:00
|
|
|
debug!("search_tbl: none, comp %u, hash %u, idx %u",
|
|
|
|
0u, h, idx);
|
2012-09-10 17:38:28 -05:00
|
|
|
return NotFound;
|
2011-12-06 21:56:47 -06:00
|
|
|
}
|
2012-08-20 14:23:37 -05:00
|
|
|
Some(e) => {
|
2013-02-08 18:28:37 -06:00
|
|
|
if e.hash == h && e.key == *k {
|
|
|
|
debug!("search_tbl: present, comp %u, hash %u, \
|
|
|
|
idx %u", 1u, h, idx);
|
|
|
|
return FoundFirst(idx, e);
|
|
|
|
} else {
|
|
|
|
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);
|
2013-01-29 22:23:35 -06:00
|
|
|
let mut 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-20 14:23:37 -05:00
|
|
|
new_chains[idx] = Some(entry);
|
2012-05-22 12:02:34 -05:00
|
|
|
}
|
2013-02-15 01:30:30 -06:00
|
|
|
self.chains = new_chains;
|
2011-12-06 21:56:47 -06:00
|
|
|
}
|
|
|
|
|
2012-09-10 17:38:28 -05:00
|
|
|
pure 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-20 14:23:37 -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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-14 13:47:00 -06:00
|
|
|
impl<K: Eq IterBytes Hash, V> Container for T<K, V> {
|
2013-02-02 01:52:01 -06:00
|
|
|
pure fn len(&self) -> uint { self.count }
|
|
|
|
pure fn is_empty(&self) -> bool { self.count == 0 }
|
|
|
|
}
|
2011-12-06 21:56:47 -06:00
|
|
|
|
2013-02-14 13:47:00 -06:00
|
|
|
impl<K: Eq IterBytes Hash, V> Mutable for T<K, V> {
|
2013-02-02 02:37:13 -06:00
|
|
|
fn clear(&mut self) {
|
|
|
|
self.count = 0u;
|
|
|
|
self.chains = chains(initial_capacity);
|
2012-08-02 17:42:56 -05:00
|
|
|
}
|
2013-02-02 02:37:13 -06:00
|
|
|
}
|
2012-08-02 17:42:56 -05:00
|
|
|
|
2013-02-08 18:20:36 -06:00
|
|
|
impl<K: Eq IterBytes Hash, V> T<K, V> {
|
2013-02-08 16:08:02 -06:00
|
|
|
pure fn contains_key(&self, k: &K) -> bool {
|
2012-09-07 19:24:02 -05:00
|
|
|
let hash = k.hash_keyed(0,0) as uint;
|
2012-08-06 14:34:08 -05:00
|
|
|
match self.search_tbl(k, hash) {
|
2012-09-10 17:38:28 -05:00
|
|
|
NotFound => false,
|
|
|
|
FoundFirst(*) | FoundAfter(*) => true
|
2012-05-22 12:02:34 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-04 21:58:31 -05:00
|
|
|
fn insert(k: K, v: V) -> bool {
|
2012-09-07 19:24:02 -05:00
|
|
|
let hash = k.hash_keyed(0,0) as uint;
|
2012-08-06 14:34:08 -05:00
|
|
|
match self.search_tbl(&k, hash) {
|
2012-09-10 17:38:28 -05:00
|
|
|
NotFound => {
|
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-09-10 17:38:28 -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);
|
2013-01-22 10:44:24 -06:00
|
|
|
let load = util::Rational {
|
|
|
|
num: (self.count + 1u) as int,
|
|
|
|
den: nchains as int,
|
|
|
|
};
|
|
|
|
if !util::rational_leq(load, util::Rational {num:3, den:4}) {
|
2012-05-22 12:02:34 -05:00
|
|
|
self.rehash();
|
|
|
|
}
|
|
|
|
|
2012-08-01 19:30:05 -05:00
|
|
|
return true;
|
2012-05-22 12:02:34 -05:00
|
|
|
}
|
2012-09-10 17:38:28 -05:00
|
|
|
FoundFirst(idx, entry) => {
|
|
|
|
self.chains[idx] = Some(@Entry {
|
2012-08-02 17:42:56 -05:00
|
|
|
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-09-10 17:38:28 -05:00
|
|
|
FoundAfter(prev, entry) => {
|
|
|
|
prev.next = Some(@Entry {
|
2012-08-02 17:42:56 -05:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2013-02-08 18:20:36 -06:00
|
|
|
fn remove(k: &K) -> bool {
|
|
|
|
match self.search_tbl(k, k.hash_keyed(0,0) as uint) {
|
|
|
|
NotFound => false,
|
|
|
|
FoundFirst(idx, entry) => {
|
|
|
|
self.count -= 1u;
|
|
|
|
self.chains[idx] = entry.next;
|
|
|
|
true
|
|
|
|
}
|
|
|
|
FoundAfter(eprev, entry) => {
|
|
|
|
self.count -= 1u;
|
|
|
|
eprev.next = entry.next;
|
|
|
|
true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pure fn each(&self, blk: fn(key: &K, value: &V) -> bool) {
|
|
|
|
for self.each_entry |entry| {
|
|
|
|
if !blk(&entry.key, &entry.value) { break; }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pure fn each_key(&self, blk: fn(key: &K) -> bool) {
|
|
|
|
self.each(|k, _v| blk(k))
|
|
|
|
}
|
|
|
|
|
|
|
|
pure fn each_value(&self, blk: fn(value: &V) -> bool) {
|
|
|
|
self.each(|_k, v| blk(v))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<K: Eq IterBytes Hash Copy, V: Copy> T<K, V> {
|
2013-02-05 21:41:45 -06:00
|
|
|
pure fn find(&self, k: &K) -> Option<V> {
|
2013-02-08 18:28:37 -06:00
|
|
|
match self.search_tbl(k, k.hash_keyed(0,0) as uint) {
|
|
|
|
NotFound => None,
|
|
|
|
FoundFirst(_, entry) => Some(entry.value),
|
|
|
|
FoundAfter(_, entry) => Some(entry.value)
|
2012-05-22 12:02:34 -05:00
|
|
|
}
|
|
|
|
}
|
2011-12-06 21:56:47 -06:00
|
|
|
|
2012-11-25 14:45:18 -06:00
|
|
|
fn update_with_key(key: K, newval: V, ff: fn(K, V, V) -> V) -> bool {
|
2012-11-21 01:33:31 -06:00
|
|
|
/*
|
2012-11-11 03:01:37 -06:00
|
|
|
match self.find(key) {
|
|
|
|
None => return self.insert(key, val),
|
|
|
|
Some(copy orig) => return self.insert(key, ff(key, orig, val))
|
|
|
|
}
|
2012-11-21 01:33:31 -06:00
|
|
|
*/
|
|
|
|
|
|
|
|
let hash = key.hash_keyed(0,0) as uint;
|
|
|
|
match self.search_tbl(&key, hash) {
|
|
|
|
NotFound => {
|
|
|
|
self.count += 1u;
|
|
|
|
let idx = hash % vec::len(self.chains);
|
|
|
|
let old_chain = self.chains[idx];
|
|
|
|
self.chains[idx] = Some(@Entry {
|
|
|
|
hash: hash,
|
|
|
|
key: key,
|
|
|
|
value: newval,
|
|
|
|
next: old_chain});
|
|
|
|
|
|
|
|
// consider rehashing if more 3/4 full
|
|
|
|
let nchains = vec::len(self.chains);
|
2013-01-22 10:44:24 -06:00
|
|
|
let load = util::Rational {
|
|
|
|
num: (self.count + 1u) as int,
|
|
|
|
den: nchains as int,
|
|
|
|
};
|
|
|
|
if !util::rational_leq(load, util::Rational {num:3, den:4}) {
|
2012-11-21 01:33:31 -06:00
|
|
|
self.rehash();
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
FoundFirst(idx, entry) => {
|
|
|
|
self.chains[idx] = Some(@Entry {
|
|
|
|
hash: hash,
|
|
|
|
key: key,
|
|
|
|
value: ff(key, entry.value, newval),
|
|
|
|
next: entry.next});
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
FoundAfter(prev, entry) => {
|
|
|
|
prev.next = Some(@Entry {
|
|
|
|
hash: hash,
|
|
|
|
key: key,
|
|
|
|
value: ff(key, entry.value, newval),
|
|
|
|
next: entry.next});
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-25 14:45:18 -06:00
|
|
|
fn update(key: K, newval: V, ff: fn(V, V) -> V) -> bool {
|
|
|
|
return self.update_with_key(key, newval, |_k, v, v1| ff(v,v1));
|
2012-11-11 03:01:37 -06:00
|
|
|
}
|
|
|
|
|
2013-02-05 21:41:45 -06:00
|
|
|
pure fn get(&self, k: &K) -> V {
|
2012-08-02 17:42:56 -05:00
|
|
|
let opt_v = self.find(k);
|
|
|
|
if opt_v.is_none() {
|
2013-02-11 21:26:38 -06:00
|
|
|
fail!(fmt!("Key not found in table: %?", k));
|
2012-07-13 20:43:47 -05:00
|
|
|
}
|
2013-02-15 01:30:30 -06:00
|
|
|
option::unwrap(opt_v)
|
2012-05-22 12:02:34 -05:00
|
|
|
}
|
|
|
|
}
|
2011-12-06 21:56:47 -06:00
|
|
|
|
2012-11-29 20:37:33 -06:00
|
|
|
impl<K:Eq IterBytes Hash Copy ToStr, V: ToStr Copy> T<K, V> {
|
2012-08-14 15:38:35 -05:00
|
|
|
fn to_writer(wr: io::Writer) {
|
2012-07-13 02:01:26 -05:00
|
|
|
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
|
|
|
}
|
2012-11-29 20:37:33 -06:00
|
|
|
}
|
2012-07-13 02:01:26 -05:00
|
|
|
|
2013-02-14 13:47:00 -06:00
|
|
|
impl<K:Eq IterBytes Hash Copy ToStr, V: ToStr Copy> ToStr for T<K, V> {
|
2013-02-03 22:47:26 -06:00
|
|
|
pure fn to_str(&self) -> ~str {
|
2013-01-23 13:43:58 -06:00
|
|
|
unsafe {
|
|
|
|
// Meh -- this should be safe
|
|
|
|
do io::with_str_writer |wr| { self.to_writer(wr) }
|
|
|
|
}
|
2012-07-13 02:01:26 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-14 13:47:00 -06:00
|
|
|
impl<K:Eq IterBytes Hash Copy, V: Copy> ops::Index<K, V> for T<K, V> {
|
2012-11-28 15:51:50 -06:00
|
|
|
pure fn index(&self, k: K) -> V {
|
2013-02-08 18:28:37 -06:00
|
|
|
self.get(&k)
|
2012-11-28 15:51:50 -06:00
|
|
|
}
|
|
|
|
}
|
2012-07-27 16:51:19 -05:00
|
|
|
|
2013-01-29 21:19:41 -06:00
|
|
|
fn chains<K,V>(nchains: uint) -> ~[Option<@Entry<K,V>>] {
|
2013-01-29 22:23:35 -06:00
|
|
|
vec::from_elem(nchains, None)
|
2011-12-06 21:56:47 -06:00
|
|
|
}
|
|
|
|
|
2012-10-02 14:02:59 -05:00
|
|
|
pub fn mk<K:Eq IterBytes Hash, V: Copy>() -> T<K,V> {
|
2012-09-10 17:38:28 -05:00
|
|
|
let slf: T<K, V> = @HashMap_ {count: 0u,
|
2012-09-07 19:24:02 -05:00
|
|
|
chains: chains(initial_capacity)};
|
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.
|
|
|
|
*/
|
2012-10-02 14:02:59 -05:00
|
|
|
pub fn HashMap<K:Eq IterBytes Hash Const, V: Copy>()
|
2012-09-10 17:38:28 -05:00
|
|
|
-> HashMap<K, V> {
|
2012-09-07 19:24:02 -05:00
|
|
|
chained::mk()
|
2011-12-06 21:56:47 -06:00
|
|
|
}
|
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/// Convenience function for adding keys to a hashmap with nil type keys
|
2012-10-03 14:21:48 -05:00
|
|
|
pub fn set_add<K:Eq IterBytes Hash Const Copy>(set: Set<K>, key: K) -> bool {
|
2012-08-02 17:42:56 -05:00
|
|
|
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-10-03 21:25:24 -05:00
|
|
|
pub pure fn vec_from_set<T:Eq IterBytes Hash Copy>(s: Set<T>) -> ~[T] {
|
2013-02-02 01:52:01 -06:00
|
|
|
do vec::build_sized(s.len()) |push| {
|
2013-02-08 16:08:02 -06:00
|
|
|
for s.each_key() |&k| {
|
2012-09-21 20:43:30 -05:00
|
|
|
push(k);
|
|
|
|
}
|
|
|
|
}
|
2012-05-16 17:45:06 -05:00
|
|
|
}
|
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/// Construct a hashmap from a vector
|
2012-10-02 14:02:59 -05:00
|
|
|
pub fn hash_from_vec<K: Eq IterBytes Hash Const Copy, V: Copy>(
|
2012-09-10 17:38:28 -05:00
|
|
|
items: &[(K, V)]) -> HashMap<K, V> {
|
|
|
|
let map = HashMap();
|
2012-09-18 23:41:37 -05:00
|
|
|
for vec::each(items) |item| {
|
|
|
|
match *item {
|
2012-09-28 02:22:18 -05:00
|
|
|
(copy key, copy value) => {
|
2012-09-18 23:41:37 -05:00
|
|
|
map.insert(key, value);
|
|
|
|
}
|
|
|
|
}
|
2012-03-14 21:32:19 -05:00
|
|
|
}
|
|
|
|
map
|
|
|
|
}
|
|
|
|
|
2012-01-17 21:05:07 -06:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2013-01-08 21:37:25 -06:00
|
|
|
use core::option::None;
|
2012-12-27 20:24:18 -06:00
|
|
|
use core::uint;
|
2012-01-17 21:05:07 -06:00
|
|
|
|
2013-02-01 01:13:36 -06:00
|
|
|
use super::*;
|
|
|
|
|
2012-01-17 21:05:07 -06:00
|
|
|
#[test]
|
|
|
|
fn test_simple() {
|
2012-08-22 19:24:52 -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-08-22 19:24:52 -05:00
|
|
|
debug!("uint -> uint");
|
2013-02-01 01:13:36 -06:00
|
|
|
let hm_uu: HashMap<uint, uint> =
|
|
|
|
HashMap::<uint, 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));
|
2013-02-05 21:41:45 -06:00
|
|
|
assert (hm_uu.get(&11) == 13u);
|
|
|
|
assert (hm_uu.get(&12) == 14u);
|
|
|
|
assert (hm_uu.get(&10) == 12u);
|
2012-01-17 21:05:07 -06:00
|
|
|
assert (!hm_uu.insert(12u, 14u));
|
2013-02-05 21:41:45 -06:00
|
|
|
assert (hm_uu.get(&12) == 14u);
|
2012-01-17 21:05:07 -06:00
|
|
|
assert (!hm_uu.insert(12u, 12u));
|
2013-02-05 21:41:45 -06:00
|
|
|
assert (hm_uu.get(&12) == 12u);
|
2012-07-14 00:57:48 -05:00
|
|
|
let ten: ~str = ~"ten";
|
|
|
|
let eleven: ~str = ~"eleven";
|
|
|
|
let twelve: ~str = ~"twelve";
|
2012-08-22 19:24:52 -05:00
|
|
|
debug!("str -> uint");
|
2013-02-01 01:13:36 -06:00
|
|
|
let hm_su: HashMap<~str, uint> =
|
|
|
|
HashMap::<~str, uint>();
|
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));
|
2013-02-05 21:41:45 -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);
|
2012-07-14 00:57:48 -05:00
|
|
|
assert (!hm_su.insert(~"twelve", 14u));
|
2013-02-05 21:41:45 -06:00
|
|
|
assert (hm_su.get(&~"twelve") == 14u);
|
2012-07-14 00:57:48 -05:00
|
|
|
assert (!hm_su.insert(~"twelve", 12u));
|
2013-02-05 21:41:45 -06:00
|
|
|
assert (hm_su.get(&~"twelve") == 12u);
|
2012-08-22 19:24:52 -05:00
|
|
|
debug!("uint -> str");
|
2013-02-01 01:13:36 -06:00
|
|
|
let hm_us: HashMap<uint, ~str> =
|
|
|
|
HashMap::<uint, ~str>();
|
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"));
|
2013-02-05 21:41:45 -06:00
|
|
|
assert hm_us.get(&11) == ~"thirteen";
|
|
|
|
assert hm_us.get(&12) == ~"fourteen";
|
|
|
|
assert hm_us.get(&10) == ~"twelve";
|
2012-07-14 00:57:48 -05:00
|
|
|
assert (!hm_us.insert(12u, ~"fourteen"));
|
2013-02-05 21:41:45 -06:00
|
|
|
assert hm_us.get(&12) == ~"fourteen";
|
2012-07-14 00:57:48 -05:00
|
|
|
assert (!hm_us.insert(12u, ~"twelve"));
|
2013-02-05 21:41:45 -06:00
|
|
|
assert hm_us.get(&12) == ~"twelve";
|
2012-08-22 19:24:52 -05:00
|
|
|
debug!("str -> str");
|
2013-02-01 01:13:36 -06:00
|
|
|
let hm_ss: HashMap<~str, ~str> =
|
|
|
|
HashMap::<~str, ~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"));
|
2013-02-05 21:41:45 -06: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"));
|
2013-02-05 21:41:45 -06:00
|
|
|
assert hm_ss.get(&~"twelve") == ~"fourteen";
|
2012-07-14 00:57:48 -05:00
|
|
|
assert (!hm_ss.insert(~"twelve", ~"twelve"));
|
2013-02-05 21:41:45 -06:00
|
|
|
assert hm_ss.get(&~"twelve") == ~"twelve";
|
2012-08-22 19:24:52 -05:00
|
|
|
debug!("*** finished test_simple");
|
2012-01-17 21:05:07 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Force map growth
|
|
|
|
*/
|
|
|
|
#[test]
|
|
|
|
fn test_growth() {
|
2012-08-22 19:24:52 -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-08-22 19:24:52 -05:00
|
|
|
debug!("uint -> uint");
|
2013-02-01 01:13:36 -06:00
|
|
|
let hm_uu: HashMap<uint, uint> =
|
|
|
|
HashMap::<uint, 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-08-22 19:24:52 -05:00
|
|
|
debug!("inserting %u -> %u", i, i*i);
|
2012-01-17 21:05:07 -06:00
|
|
|
i += 1u;
|
|
|
|
}
|
2012-08-22 19:24:52 -05:00
|
|
|
debug!("-----");
|
2012-01-17 21:05:07 -06:00
|
|
|
i = 0u;
|
|
|
|
while i < num_to_insert {
|
2013-02-05 21:41:45 -06:00
|
|
|
debug!("get(%u) = %u", i, hm_uu.get(&i));
|
|
|
|
assert (hm_uu.get(&i) == i * i);
|
2012-01-17 21:05:07 -06:00
|
|
|
i += 1u;
|
|
|
|
}
|
|
|
|
assert (hm_uu.insert(num_to_insert, 17u));
|
2013-02-05 21:41:45 -06:00
|
|
|
assert (hm_uu.get(&num_to_insert) == 17u);
|
2012-08-22 19:24:52 -05:00
|
|
|
debug!("-----");
|
2012-01-17 21:05:07 -06:00
|
|
|
i = 0u;
|
|
|
|
while i < num_to_insert {
|
2013-02-05 21:41:45 -06:00
|
|
|
debug!("get(%u) = %u", i, hm_uu.get(&i));
|
|
|
|
assert (hm_uu.get(&i) == i * i);
|
2012-01-17 21:05:07 -06:00
|
|
|
i += 1u;
|
|
|
|
}
|
2012-08-22 19:24:52 -05:00
|
|
|
debug!("str -> str");
|
2013-02-01 01:13:36 -06:00
|
|
|
let hm_ss: HashMap<~str, ~str> =
|
|
|
|
HashMap::<~str, ~str>();
|
2012-01-17 21:05:07 -06:00
|
|
|
i = 0u;
|
|
|
|
while i < num_to_insert {
|
2013-01-26 20:21:37 -06:00
|
|
|
assert hm_ss.insert(uint::to_str_radix(i, 2u),
|
|
|
|
uint::to_str_radix(i * i, 2u));
|
2012-08-22 19:24:52 -05:00
|
|
|
debug!("inserting \"%s\" -> \"%s\"",
|
2013-01-26 20:21:37 -06:00
|
|
|
uint::to_str_radix(i, 2u),
|
|
|
|
uint::to_str_radix(i*i, 2u));
|
2012-01-17 21:05:07 -06:00
|
|
|
i += 1u;
|
|
|
|
}
|
2012-08-22 19:24:52 -05:00
|
|
|
debug!("-----");
|
2012-01-17 21:05:07 -06:00
|
|
|
i = 0u;
|
|
|
|
while i < num_to_insert {
|
2012-08-22 19:24:52 -05:00
|
|
|
debug!("get(\"%s\") = \"%s\"",
|
2013-01-26 20:21:37 -06:00
|
|
|
uint::to_str_radix(i, 2u),
|
2013-02-05 21:41:45 -06:00
|
|
|
hm_ss.get(&uint::to_str_radix(i, 2u)));
|
|
|
|
assert hm_ss.get(&uint::to_str_radix(i, 2u)) ==
|
2013-01-26 20:21:37 -06:00
|
|
|
uint::to_str_radix(i * i, 2u);
|
2012-01-17 21:05:07 -06:00
|
|
|
i += 1u;
|
|
|
|
}
|
2013-01-26 20:21:37 -06:00
|
|
|
assert (hm_ss.insert(uint::to_str_radix(num_to_insert, 2u),
|
|
|
|
uint::to_str_radix(17u, 2u)));
|
2013-02-05 21:41:45 -06:00
|
|
|
assert hm_ss.get(&uint::to_str_radix(num_to_insert, 2u)) ==
|
2013-01-26 20:21:37 -06:00
|
|
|
uint::to_str_radix(17u, 2u);
|
2012-08-22 19:24:52 -05:00
|
|
|
debug!("-----");
|
2012-01-17 21:05:07 -06:00
|
|
|
i = 0u;
|
|
|
|
while i < num_to_insert {
|
2012-08-22 19:24:52 -05:00
|
|
|
debug!("get(\"%s\") = \"%s\"",
|
2013-01-26 20:21:37 -06:00
|
|
|
uint::to_str_radix(i, 2u),
|
2013-02-05 21:41:45 -06:00
|
|
|
hm_ss.get(&uint::to_str_radix(i, 2u)));
|
|
|
|
assert hm_ss.get(&uint::to_str_radix(i, 2u)) ==
|
2013-01-26 20:21:37 -06:00
|
|
|
uint::to_str_radix(i * i, 2u);
|
2012-01-17 21:05:07 -06:00
|
|
|
i += 1u;
|
|
|
|
}
|
2012-08-22 19:24:52 -05:00
|
|
|
debug!("*** finished test_growth");
|
2012-01-17 21:05:07 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_removal() {
|
2012-08-22 19:24:52 -05:00
|
|
|
debug!("*** starting test_removal");
|
2012-01-17 21:05:07 -06:00
|
|
|
let num_to_insert: uint = 64u;
|
2013-02-01 01:13:36 -06:00
|
|
|
let hm: HashMap<uint, uint> =
|
|
|
|
HashMap::<uint, 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.insert(i, i * i));
|
2012-08-22 19:24:52 -05:00
|
|
|
debug!("inserting %u -> %u", i, i*i);
|
2012-01-17 21:05:07 -06:00
|
|
|
i += 1u;
|
|
|
|
}
|
2013-02-02 01:52:01 -06:00
|
|
|
assert (hm.len() == num_to_insert);
|
2012-08-22 19:24:52 -05:00
|
|
|
debug!("-----");
|
|
|
|
debug!("removing evens");
|
2012-01-17 21:05:07 -06:00
|
|
|
i = 0u;
|
|
|
|
while i < num_to_insert {
|
2013-02-03 16:12:33 -06:00
|
|
|
let v = hm.remove(&i);
|
2012-08-21 19:02:40 -05:00
|
|
|
assert v;
|
2012-01-17 21:05:07 -06:00
|
|
|
i += 2u;
|
|
|
|
}
|
2013-02-02 01:52:01 -06:00
|
|
|
assert (hm.len() == num_to_insert / 2u);
|
2012-08-22 19:24:52 -05:00
|
|
|
debug!("-----");
|
2012-01-17 21:05:07 -06:00
|
|
|
i = 1u;
|
|
|
|
while i < num_to_insert {
|
2013-02-05 21:41:45 -06:00
|
|
|
debug!("get(%u) = %u", i, hm.get(&i));
|
|
|
|
assert (hm.get(&i) == i * i);
|
2012-01-17 21:05:07 -06:00
|
|
|
i += 2u;
|
|
|
|
}
|
2012-08-22 19:24:52 -05:00
|
|
|
debug!("-----");
|
2012-01-17 21:05:07 -06:00
|
|
|
i = 1u;
|
|
|
|
while i < num_to_insert {
|
2013-02-05 21:41:45 -06:00
|
|
|
debug!("get(%u) = %u", i, hm.get(&i));
|
|
|
|
assert (hm.get(&i) == i * i);
|
2012-01-17 21:05:07 -06:00
|
|
|
i += 2u;
|
|
|
|
}
|
2012-08-22 19:24:52 -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-08-22 19:24:52 -05:00
|
|
|
debug!("inserting %u -> %u", i, i*i);
|
2012-01-17 21:05:07 -06:00
|
|
|
i += 2u;
|
|
|
|
}
|
2013-02-02 01:52:01 -06:00
|
|
|
assert (hm.len() == num_to_insert);
|
2012-08-22 19:24:52 -05:00
|
|
|
debug!("-----");
|
2012-01-17 21:05:07 -06:00
|
|
|
i = 0u;
|
|
|
|
while i < num_to_insert {
|
2013-02-05 21:41:45 -06:00
|
|
|
debug!("get(%u) = %u", i, hm.get(&i));
|
|
|
|
assert (hm.get(&i) == i * i);
|
2012-01-17 21:05:07 -06:00
|
|
|
i += 1u;
|
|
|
|
}
|
2012-08-22 19:24:52 -05:00
|
|
|
debug!("-----");
|
2013-02-02 01:52:01 -06:00
|
|
|
assert (hm.len() == num_to_insert);
|
2012-01-17 21:05:07 -06:00
|
|
|
i = 0u;
|
|
|
|
while i < num_to_insert {
|
2013-02-05 21:41:45 -06:00
|
|
|
debug!("get(%u) = %u", i, hm.get(&i));
|
|
|
|
assert (hm.get(&i) == i * i);
|
2012-01-17 21:05:07 -06:00
|
|
|
i += 1u;
|
|
|
|
}
|
2012-08-22 19:24:52 -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";
|
2013-02-01 01:13:36 -06:00
|
|
|
let map = HashMap::<~str, ~str>();
|
2013-02-08 16:08:02 -06:00
|
|
|
assert (!map.contains_key(&key));
|
2012-07-14 00:57:48 -05:00
|
|
|
map.insert(key, ~"val");
|
2013-02-08 16:08:02 -06:00
|
|
|
assert (map.contains_key(&key));
|
2012-01-17 21:05:07 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_find() {
|
2012-07-14 00:57:48 -05:00
|
|
|
let key = ~"k";
|
2013-02-01 01:13:36 -06:00
|
|
|
let map = HashMap::<~str, ~str>();
|
2013-02-05 21:41:45 -06:00
|
|
|
assert map.find(&key).is_none();
|
2012-07-14 00:57:48 -05:00
|
|
|
map.insert(key, ~"val");
|
2013-02-05 21:41:45 -06:00
|
|
|
assert map.find(&key).get() == ~"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";
|
2013-02-02 02:37:13 -06:00
|
|
|
let mut map = HashMap::<~str, ~str>();
|
2012-07-14 00:57:48 -05:00
|
|
|
map.insert(key, ~"val");
|
2013-02-02 01:52:01 -06:00
|
|
|
assert (map.len() == 1);
|
2013-02-08 16:08:02 -06:00
|
|
|
assert (map.contains_key(&key));
|
2012-07-08 18:04:57 -05:00
|
|
|
map.clear();
|
2013-02-02 01:52:01 -06:00
|
|
|
assert (map.len() == 0);
|
2013-02-08 16:08:02 -06:00
|
|
|
assert (!map.contains_key(&key));
|
2012-07-08 18:04:57 -05:00
|
|
|
}
|
|
|
|
|
2012-03-14 21:32:19 -05:00
|
|
|
#[test]
|
|
|
|
fn test_hash_from_vec() {
|
2013-02-01 01:13:36 -06:00
|
|
|
let map = hash_from_vec(~[
|
2012-07-14 00:57:48 -05:00
|
|
|
(~"a", 1),
|
|
|
|
(~"b", 2),
|
|
|
|
(~"c", 3)
|
2012-06-29 18:26:56 -05:00
|
|
|
]);
|
2013-02-02 01:52:01 -06:00
|
|
|
assert map.len() == 3u;
|
2013-02-05 21:41:45 -06: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-11-14 23:33:32 -06:00
|
|
|
|
|
|
|
#[test]
|
2012-11-25 14:45:18 -06:00
|
|
|
fn test_update_with_key() {
|
2013-02-01 01:13:36 -06:00
|
|
|
let map = HashMap::<~str, uint>();
|
2012-11-14 23:33:32 -06:00
|
|
|
|
2012-11-21 01:33:31 -06:00
|
|
|
// given a new key, initialize it with this new count, given
|
|
|
|
// given an existing key, add more to its count
|
|
|
|
fn addMoreToCount(_k: ~str, v0: uint, v1: uint) -> uint {
|
|
|
|
v0 + v1
|
|
|
|
}
|
|
|
|
|
|
|
|
fn addMoreToCount_simple(v0: uint, v1: uint) -> uint {
|
2012-11-14 23:33:32 -06:00
|
|
|
v0 + v1
|
|
|
|
}
|
|
|
|
|
2012-11-21 01:33:31 -06:00
|
|
|
// count the number of several types of animal,
|
|
|
|
// adding in groups as we go
|
2012-11-25 14:45:18 -06:00
|
|
|
map.update(~"cat", 1, addMoreToCount_simple);
|
|
|
|
map.update_with_key(~"mongoose", 1, addMoreToCount);
|
|
|
|
map.update(~"cat", 7, addMoreToCount_simple);
|
|
|
|
map.update_with_key(~"ferret", 3, addMoreToCount);
|
|
|
|
map.update_with_key(~"cat", 2, addMoreToCount);
|
2012-11-14 23:33:32 -06:00
|
|
|
|
2012-11-21 01:33:31 -06:00
|
|
|
// check the total counts
|
2013-02-05 21:41:45 -06:00
|
|
|
assert map.find(&~"cat").get() == 10;
|
|
|
|
assert map.find(&~"ferret").get() == 3;
|
|
|
|
assert map.find(&~"mongoose").get() == 1;
|
2012-11-14 23:33:32 -06:00
|
|
|
|
2012-11-21 01:33:31 -06:00
|
|
|
// sadly, no mythical animals were counted!
|
2013-02-05 21:41:45 -06:00
|
|
|
assert map.find(&~"unicorn").is_none();
|
2012-11-14 23:33:32 -06:00
|
|
|
}
|
2012-01-27 22:39:16 -06:00
|
|
|
}
|