Migrate core::send_map to random, keyed hashes w/ hash::Hash trait.

This commit is contained in:
Graydon Hoare 2012-08-30 19:01:22 -07:00
parent 3462bb6a46
commit 536cb90a21
6 changed files with 56 additions and 55 deletions

View File

@ -17,7 +17,7 @@
import io::WriterUtil;
import to_bytes::IterBytes;
export Streaming, State;
export Streaming, State, Hash, HashUtil;
export default_state;
export hash_bytes_keyed;
export hash_str_keyed;

View File

@ -4,16 +4,11 @@
*/
import cmp::Eq;
import hash::Hash;
import to_bytes::IterBytes;
/**
* A function that returns a hash of a value
*
* The hash should concentrate entropy in the lower bits.
*/
type HashFn<K> = pure fn~(K) -> uint;
type EqFn<K> = pure fn~(K, K) -> bool;
trait SendMap<K, V: copy> {
trait SendMap<K:Eq Hash, V: copy> {
// FIXME(#3148) ^^^^ once find_ref() works, we can drop V:copy
fn insert(&mut self, +k: K, +v: V) -> bool;
@ -34,14 +29,14 @@ mod linear {
export LinearMap, linear_map, linear_map_with_capacity, public_methods;
const initial_capacity: uint = 32u; // 2^5
struct Bucket<K,V> {
struct Bucket<K:Eq Hash,V> {
hash: uint;
key: K;
value: V;
}
struct LinearMap<K,V> {
hashfn: pure fn~(x: &K) -> uint;
eqfn: pure fn~(x: &K, y: &K) -> bool;
struct LinearMap<K:Eq Hash,V> {
k0: u64;
k1: u64;
resize_at: uint;
size: uint;
buckets: ~[Option<Bucket<K,V>>];
@ -58,28 +53,29 @@ fn resize_at(capacity: uint) -> uint {
((capacity as float) * 3. / 4.) as uint
}
fn LinearMap<K,V>(
+hashfn: pure fn~(x: &K) -> uint,
+eqfn: pure fn~(x: &K, y: &K) -> bool) -> LinearMap<K,V> {
linear_map_with_capacity(hashfn, eqfn, 32)
fn LinearMap<K:Eq Hash,V>() -> LinearMap<K,V> {
linear_map_with_capacity(32)
}
fn linear_map_with_capacity<K,V>(
+hashfn: pure fn~(x: &K) -> uint,
+eqfn: pure fn~(x: &K, y: &K) -> bool,
fn linear_map_with_capacity<K:Eq Hash,V>(
initial_capacity: uint) -> LinearMap<K,V> {
let r = rand::Rng();
linear_map_with_capacity_and_keys(r.gen_u64(), r.gen_u64(),
initial_capacity)
}
fn linear_map_with_capacity_and_keys<K:Eq Hash,V> (
k0: u64, k1: u64,
initial_capacity: uint) -> LinearMap<K,V> {
LinearMap {
hashfn: hashfn,
eqfn: eqfn,
k0: k0, k1: k1,
resize_at: resize_at(initial_capacity),
size: 0,
buckets: vec::from_fn(initial_capacity, |_i| None)
}
}
priv impl<K, V> LinearMap<K,V> {
priv impl<K:Hash IterBytes Eq, V> LinearMap<K,V> {
#[inline(always)]
pure fn to_bucket(&const self,
h: uint) -> uint {
@ -123,7 +119,7 @@ fn linear_map_with_capacity<K,V>(
pure fn bucket_for_key(&const self,
buckets: &[Option<Bucket<K,V>>],
k: &K) -> SearchResult {
let hash = self.hashfn(k);
let hash = k.hash_keyed(self.k0, self.k1) as uint;
self.bucket_for_key_with_hash(buckets, hash, k)
}
@ -134,7 +130,7 @@ fn linear_map_with_capacity<K,V>(
k: &K) -> SearchResult {
let _ = for self.bucket_sequence(hash) |i| {
match buckets[i] {
Some(bkt) => if bkt.hash == hash && self.eqfn(k, &bkt.key) {
Some(bkt) => if bkt.hash == hash && *k == bkt.key {
return FoundEntry(i);
},
None => return FoundHole(i)
@ -204,7 +200,7 @@ fn search(&self,
}
}
impl<K,V> LinearMap<K,V> {
impl<K:Hash IterBytes Eq,V> LinearMap<K,V> {
fn insert(&mut self, +k: K, +v: V) -> bool {
if self.size >= self.resize_at {
// n.b.: We could also do this after searching, so
@ -216,7 +212,7 @@ fn insert(&mut self, +k: K, +v: V) -> bool {
self.expand();
}
let hash = self.hashfn(&k);
let hash = k.hash_keyed(self.k0, self.k1) as uint;
self.insert_internal(hash, k, v)
}
@ -319,7 +315,7 @@ fn each_value_ref(&self, blk: fn(v: &V) -> bool) {
}
}
impl<K,V: copy> LinearMap<K,V> {
impl<K:Hash IterBytes Eq, V: copy> LinearMap<K,V> {
fn find(&const self, k: &K) -> Option<V> {
match self.bucket_for_key(self.buckets, k) {
FoundEntry(idx) => {
@ -346,17 +342,17 @@ fn get(&const self, k: &K) -> V {
}
impl<K: copy, V: copy> LinearMap<K,V> {
impl<K: Hash IterBytes Eq copy, V: copy> LinearMap<K,V> {
fn each(&self, blk: fn(+K,+V) -> bool) {
self.each_ref(|k,v| blk(copy *k, copy *v));
}
}
impl<K: copy, V> LinearMap<K,V> {
impl<K: Hash IterBytes Eq copy, V> LinearMap<K,V> {
fn each_key(&self, blk: fn(+K) -> bool) {
self.each_key_ref(|k| blk(copy *k));
}
}
impl<K, V: copy> LinearMap<K,V> {
impl<K: Hash IterBytes Eq, V: copy> LinearMap<K,V> {
fn each_value(&self, blk: fn(+V) -> bool) {
self.each_value_ref(|v| blk(copy *v));
}
@ -368,11 +364,8 @@ mod test {
import linear::LinearMap;
pure fn uint_hash(x: &uint) -> uint { *x }
pure fn uint_eq(x: &uint, y: &uint) -> bool { *x == *y }
fn int_linear_map<V>() -> LinearMap<uint,V> {
return LinearMap(uint_hash, uint_eq);
return LinearMap();
}
#[test]
@ -395,7 +388,7 @@ fn overwrite() {
#[test]
fn conflicts() {
let mut m = ~linear::linear_map_with_capacity(uint_hash, uint_eq, 4);
let mut m = ~linear::linear_map_with_capacity(4);
assert m.insert(1, 2);
assert m.insert(5, 3);
assert m.insert(9, 4);
@ -406,7 +399,7 @@ fn conflicts() {
#[test]
fn conflict_remove() {
let mut m = ~linear::linear_map_with_capacity(uint_hash, uint_eq, 4);
let mut m = ~linear::linear_map_with_capacity(4);
assert m.insert(1, 2);
assert m.insert(5, 3);
assert m.insert(9, 4);
@ -417,7 +410,7 @@ fn conflict_remove() {
#[test]
fn empty() {
let mut m = ~linear::linear_map_with_capacity(uint_hash, uint_eq, 4);
let mut m = ~linear::linear_map_with_capacity(4);
assert m.insert(1, 2);
assert !m.is_empty();
assert m.remove(&1);
@ -426,7 +419,7 @@ fn empty() {
#[test]
fn iterate() {
let mut m = linear::linear_map_with_capacity(uint_hash, uint_eq, 4);
let mut m = linear::linear_map_with_capacity(4);
for uint::range(0, 32) |i| {
assert (&mut m).insert(i, i*2);
}

View File

@ -731,17 +731,7 @@ struct DeferInterrupts {
type TaskSet = send_map::linear::LinearMap<*rust_task,()>;
fn new_taskset() -> TaskSet {
pure fn task_hash(t: &*rust_task) -> uint {
let task: *rust_task = *t;
hash::hash_uint(task as uint) as uint
}
pure fn task_eq(t1: &*rust_task, t2: &*rust_task) -> bool {
let task1: *rust_task = *t1;
let task2: *rust_task = *t2;
task1 == task2
}
send_map::linear::LinearMap(task_hash, task_eq)
send_map::linear::LinearMap()
}
fn taskset_insert(tasks: &mut TaskSet, task: *rust_task) {
let didnt_overwrite = tasks.insert(task, ());

View File

@ -290,6 +290,19 @@ fn iter_be_bytes(f: Cb) {
}
}
// NB: raw-pointer IterBytes does _not_ dereference
// to the target; it just gives you the pointer-bytes.
impl<A> *A: IterBytes {
#[inline(always)]
fn iter_le_bytes(f: Cb) {
(self as uint).iter_le_bytes(f);
}
#[inline(always)]
fn iter_be_bytes(f: Cb) {
(self as uint).iter_be_bytes(f);
}
}
trait ToBytes {
fn to_le_bytes() -> ~[u8];

View File

@ -7,6 +7,10 @@
import managed::Managed;
import send_map::linear::LinearMap;
import core::cmp::Eq;
import hash::Hash;
import to_bytes::IterBytes;
export hashmap, hashfn, eqfn, set, map, chained, hashmap, str_hash;
export box_str_hash;
export bytes_hash, int_hash, uint_hash, set_add;
@ -478,7 +482,8 @@ fn hash_from_uints<V: copy>(items: &[(uint, V)]) -> hashmap<uint, V> {
}
// XXX Transitionary
impl<K: copy, V: copy> Managed<LinearMap<K, V>>: map<K, V> {
impl<K: Eq IterBytes Hash copy, V: copy> Managed<LinearMap<K, V>>:
map<K, V> {
pure fn size() -> uint {
unchecked {
do self.borrow_const |p| {

View File

@ -168,10 +168,10 @@ fn main(args: ~[~str]) {
let rng = rand::seeded_rng(copy seed);
let mut results = empty_results();
int_benchmarks::<Managed<LinearMap<uint, uint>>>(
|| Managed(LinearMap(uint::hash, uint::eq)),
|| Managed(LinearMap()),
rng, num_keys, &mut results);
str_benchmarks::<Managed<LinearMap<~str, uint>>>(
|| Managed(LinearMap(str::hash, str::eq)),
|| Managed(LinearMap()),
rng, num_keys, &mut results);
write_results("libstd::map::hashmap", &results);
}