Migrate core::send_map to random, keyed hashes w/ hash::Hash trait.
This commit is contained in:
parent
3462bb6a46
commit
536cb90a21
6 changed files with 56 additions and 55 deletions
|
@ -17,7 +17,7 @@ import io::Writer;
|
||||||
import io::WriterUtil;
|
import io::WriterUtil;
|
||||||
import to_bytes::IterBytes;
|
import to_bytes::IterBytes;
|
||||||
|
|
||||||
export Streaming, State;
|
export Streaming, State, Hash, HashUtil;
|
||||||
export default_state;
|
export default_state;
|
||||||
export hash_bytes_keyed;
|
export hash_bytes_keyed;
|
||||||
export hash_str_keyed;
|
export hash_str_keyed;
|
||||||
|
|
|
@ -4,16 +4,11 @@ Sendable hash maps. Very much a work in progress.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import cmp::Eq;
|
||||||
|
import hash::Hash;
|
||||||
|
import to_bytes::IterBytes;
|
||||||
|
|
||||||
/**
|
trait SendMap<K:Eq Hash, V: copy> {
|
||||||
* 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> {
|
|
||||||
// FIXME(#3148) ^^^^ once find_ref() works, we can drop V:copy
|
// FIXME(#3148) ^^^^ once find_ref() works, we can drop V:copy
|
||||||
|
|
||||||
fn insert(&mut self, +k: K, +v: V) -> bool;
|
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;
|
export LinearMap, linear_map, linear_map_with_capacity, public_methods;
|
||||||
|
|
||||||
const initial_capacity: uint = 32u; // 2^5
|
const initial_capacity: uint = 32u; // 2^5
|
||||||
struct Bucket<K,V> {
|
struct Bucket<K:Eq Hash,V> {
|
||||||
hash: uint;
|
hash: uint;
|
||||||
key: K;
|
key: K;
|
||||||
value: V;
|
value: V;
|
||||||
}
|
}
|
||||||
struct LinearMap<K,V> {
|
struct LinearMap<K:Eq Hash,V> {
|
||||||
hashfn: pure fn~(x: &K) -> uint;
|
k0: u64;
|
||||||
eqfn: pure fn~(x: &K, y: &K) -> bool;
|
k1: u64;
|
||||||
resize_at: uint;
|
resize_at: uint;
|
||||||
size: uint;
|
size: uint;
|
||||||
buckets: ~[Option<Bucket<K,V>>];
|
buckets: ~[Option<Bucket<K,V>>];
|
||||||
|
@ -58,28 +53,29 @@ mod linear {
|
||||||
((capacity as float) * 3. / 4.) as uint
|
((capacity as float) * 3. / 4.) as uint
|
||||||
}
|
}
|
||||||
|
|
||||||
fn LinearMap<K,V>(
|
fn LinearMap<K:Eq Hash,V>() -> LinearMap<K,V> {
|
||||||
+hashfn: pure fn~(x: &K) -> uint,
|
linear_map_with_capacity(32)
|
||||||
+eqfn: pure fn~(x: &K, y: &K) -> bool) -> LinearMap<K,V> {
|
|
||||||
|
|
||||||
linear_map_with_capacity(hashfn, eqfn, 32)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn linear_map_with_capacity<K,V>(
|
fn linear_map_with_capacity<K:Eq Hash,V>(
|
||||||
+hashfn: pure fn~(x: &K) -> uint,
|
|
||||||
+eqfn: pure fn~(x: &K, y: &K) -> bool,
|
|
||||||
initial_capacity: uint) -> LinearMap<K,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 {
|
LinearMap {
|
||||||
hashfn: hashfn,
|
k0: k0, k1: k1,
|
||||||
eqfn: eqfn,
|
|
||||||
resize_at: resize_at(initial_capacity),
|
resize_at: resize_at(initial_capacity),
|
||||||
size: 0,
|
size: 0,
|
||||||
buckets: vec::from_fn(initial_capacity, |_i| None)
|
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)]
|
#[inline(always)]
|
||||||
pure fn to_bucket(&const self,
|
pure fn to_bucket(&const self,
|
||||||
h: uint) -> uint {
|
h: uint) -> uint {
|
||||||
|
@ -123,7 +119,7 @@ mod linear {
|
||||||
pure fn bucket_for_key(&const self,
|
pure fn bucket_for_key(&const self,
|
||||||
buckets: &[Option<Bucket<K,V>>],
|
buckets: &[Option<Bucket<K,V>>],
|
||||||
k: &K) -> SearchResult {
|
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)
|
self.bucket_for_key_with_hash(buckets, hash, k)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,7 +130,7 @@ mod linear {
|
||||||
k: &K) -> SearchResult {
|
k: &K) -> SearchResult {
|
||||||
let _ = for self.bucket_sequence(hash) |i| {
|
let _ = for self.bucket_sequence(hash) |i| {
|
||||||
match buckets[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);
|
return FoundEntry(i);
|
||||||
},
|
},
|
||||||
None => return FoundHole(i)
|
None => return FoundHole(i)
|
||||||
|
@ -204,7 +200,7 @@ mod linear {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<K,V> LinearMap<K,V> {
|
impl<K:Hash IterBytes Eq,V> LinearMap<K,V> {
|
||||||
fn insert(&mut self, +k: K, +v: V) -> bool {
|
fn insert(&mut self, +k: K, +v: V) -> bool {
|
||||||
if self.size >= self.resize_at {
|
if self.size >= self.resize_at {
|
||||||
// n.b.: We could also do this after searching, so
|
// n.b.: We could also do this after searching, so
|
||||||
|
@ -216,7 +212,7 @@ mod linear {
|
||||||
self.expand();
|
self.expand();
|
||||||
}
|
}
|
||||||
|
|
||||||
let hash = self.hashfn(&k);
|
let hash = k.hash_keyed(self.k0, self.k1) as uint;
|
||||||
self.insert_internal(hash, k, v)
|
self.insert_internal(hash, k, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -319,7 +315,7 @@ mod linear {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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> {
|
fn find(&const self, k: &K) -> Option<V> {
|
||||||
match self.bucket_for_key(self.buckets, k) {
|
match self.bucket_for_key(self.buckets, k) {
|
||||||
FoundEntry(idx) => {
|
FoundEntry(idx) => {
|
||||||
|
@ -346,17 +342,17 @@ mod linear {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
fn each(&self, blk: fn(+K,+V) -> bool) {
|
||||||
self.each_ref(|k,v| blk(copy *k, copy *v));
|
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) {
|
fn each_key(&self, blk: fn(+K) -> bool) {
|
||||||
self.each_key_ref(|k| blk(copy *k));
|
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) {
|
fn each_value(&self, blk: fn(+V) -> bool) {
|
||||||
self.each_value_ref(|v| blk(copy *v));
|
self.each_value_ref(|v| blk(copy *v));
|
||||||
}
|
}
|
||||||
|
@ -368,11 +364,8 @@ mod test {
|
||||||
|
|
||||||
import linear::LinearMap;
|
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> {
|
fn int_linear_map<V>() -> LinearMap<uint,V> {
|
||||||
return LinearMap(uint_hash, uint_eq);
|
return LinearMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -395,7 +388,7 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn conflicts() {
|
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(1, 2);
|
||||||
assert m.insert(5, 3);
|
assert m.insert(5, 3);
|
||||||
assert m.insert(9, 4);
|
assert m.insert(9, 4);
|
||||||
|
@ -406,7 +399,7 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn conflict_remove() {
|
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(1, 2);
|
||||||
assert m.insert(5, 3);
|
assert m.insert(5, 3);
|
||||||
assert m.insert(9, 4);
|
assert m.insert(9, 4);
|
||||||
|
@ -417,7 +410,7 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn empty() {
|
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.insert(1, 2);
|
||||||
assert !m.is_empty();
|
assert !m.is_empty();
|
||||||
assert m.remove(&1);
|
assert m.remove(&1);
|
||||||
|
@ -426,7 +419,7 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn iterate() {
|
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| {
|
for uint::range(0, 32) |i| {
|
||||||
assert (&mut m).insert(i, i*2);
|
assert (&mut m).insert(i, i*2);
|
||||||
}
|
}
|
||||||
|
|
|
@ -731,17 +731,7 @@ type rust_closure = libc::c_void;
|
||||||
type TaskSet = send_map::linear::LinearMap<*rust_task,()>;
|
type TaskSet = send_map::linear::LinearMap<*rust_task,()>;
|
||||||
|
|
||||||
fn new_taskset() -> TaskSet {
|
fn new_taskset() -> TaskSet {
|
||||||
pure fn task_hash(t: &*rust_task) -> uint {
|
send_map::linear::LinearMap()
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
fn taskset_insert(tasks: &mut TaskSet, task: *rust_task) {
|
fn taskset_insert(tasks: &mut TaskSet, task: *rust_task) {
|
||||||
let didnt_overwrite = tasks.insert(task, ());
|
let didnt_overwrite = tasks.insert(task, ());
|
||||||
|
|
|
@ -290,6 +290,19 @@ impl<A: IterBytes> ~A: IterBytes {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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 {
|
trait ToBytes {
|
||||||
fn to_le_bytes() -> ~[u8];
|
fn to_le_bytes() -> ~[u8];
|
||||||
|
|
|
@ -7,6 +7,10 @@ import to_str::ToStr;
|
||||||
import managed::Managed;
|
import managed::Managed;
|
||||||
import send_map::linear::LinearMap;
|
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 hashmap, hashfn, eqfn, set, map, chained, hashmap, str_hash;
|
||||||
export box_str_hash;
|
export box_str_hash;
|
||||||
export bytes_hash, int_hash, uint_hash, set_add;
|
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
|
// 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 {
|
pure fn size() -> uint {
|
||||||
unchecked {
|
unchecked {
|
||||||
do self.borrow_const |p| {
|
do self.borrow_const |p| {
|
||||||
|
|
|
@ -168,10 +168,10 @@ fn main(args: ~[~str]) {
|
||||||
let rng = rand::seeded_rng(copy seed);
|
let rng = rand::seeded_rng(copy seed);
|
||||||
let mut results = empty_results();
|
let mut results = empty_results();
|
||||||
int_benchmarks::<Managed<LinearMap<uint, uint>>>(
|
int_benchmarks::<Managed<LinearMap<uint, uint>>>(
|
||||||
|| Managed(LinearMap(uint::hash, uint::eq)),
|
|| Managed(LinearMap()),
|
||||||
rng, num_keys, &mut results);
|
rng, num_keys, &mut results);
|
||||||
str_benchmarks::<Managed<LinearMap<~str, uint>>>(
|
str_benchmarks::<Managed<LinearMap<~str, uint>>>(
|
||||||
|| Managed(LinearMap(str::hash, str::eq)),
|
|| Managed(LinearMap()),
|
||||||
rng, num_keys, &mut results);
|
rng, num_keys, &mut results);
|
||||||
write_results("libstd::map::hashmap", &results);
|
write_results("libstd::map::hashmap", &results);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue