Purge old map impl: more collisions, not clear it is safe on 64bit

This commit is contained in:
Niko Matsakis 2011-12-07 08:34:43 -08:00
parent 4b704ac69b
commit 1ff8994fce

View file

@ -353,211 +353,6 @@ mod chained {
}
}
/*
Function: mk_flat_hashmap
Construct a "flat" hashmap, meaning that there are
not chains per buckets, but rather we search a sequence
of buckets for each key.
Warning: it is unclear to me that this code is correct
on 32-bit processors. Check out the 'hash-tearing' code
in hash() and the comment surrounding it. - Niko
Parameters:
hasher - The hash function for key type K
eqer - The equality function for key type K
*/
fn mk_flat_hashmap<copy K, copy V>(hasher: hashfn<K>, eqer: eqfn<K>)
-> hashmap<K, V> {
let initial_capacity: uint = 32u; // 2^5
let load_factor: util::rational = {num: 3, den: 4};
tag bucket<copy K, copy V> { nil; deleted; some(K, V); }
fn make_buckets<copy K, copy V>(nbkts: uint) -> [mutable bucket<K, V>] {
ret vec::init_elt_mut::<bucket<K, V>>(nil::<K, V>, nbkts);
}
// Derive two hash functions from the one given by taking the upper
// half and lower half of the uint bits. Our bucket probing
// sequence is then defined by
//
// hash(key, i) := hashl(key) * i + hashr(key) for i = 0, 1, 2, ...
//
// Tearing the hash function apart this way is kosher in practice
// as, assuming 32-bit uints, the table would have to be at 2^32
// buckets before the resulting pair of hash functions no longer
// probes all buckets for a fixed key. Note that hashl is made to
// output odd numbers (hence coprime to the number of nbkts, which
// is always a power? of 2), so that all buckets are probed for a
// fixed key.
fn hashl(n: uint) -> uint { ret (n >>> 16u) * 2u + 1u; }
fn hashr(n: uint) -> uint { ret 0x0000_ffff_u & n; }
fn hash(h: uint, nbkts: uint, i: uint) -> uint {
ret (hashl(h) * i + hashr(h)) % nbkts;
}
/**
* We attempt to never call this with a full table. If we do, it
* will fail.
*/
fn insert_common<copy K, copy V>(hasher: hashfn<K>, eqer: eqfn<K>,
bkts: [mutable bucket<K, V>],
nbkts: uint, key: K, val: V) -> bool {
let i: uint = 0u;
let h = hasher(key);
while i < nbkts {
let j: uint = hash(h, nbkts, i);
alt bkts[j] {
some(k, _) {
// Copy key to please alias analysis.
let k_ = k;
if eqer(key, k_) {
log("map updated", "i", i, "h", h, "nbkts", nbkts);
bkts[j] = some(k_, val);
ret false;
}
i += 1u;
}
_ {
log("map inserted", "i", i, "h", h, "nbkts", nbkts);
bkts[j] = some(key, val);
ret true;
}
}
}
fail; // full table
}
fn find_common<copy K, copy V>(hasher: hashfn<K>, eqer: eqfn<K>,
bkts: [mutable bucket<K, V>],
nbkts: uint, key: K) -> option::t<V> {
let i: uint = 0u;
let h = hasher(key);
while i < nbkts {
let j: uint = hash(h, nbkts, i);
alt bkts[j] {
some(k, v) {
// Copy to please alias analysis.
let k_ = k;
let v_ = v;
if eqer(key, k_) {
log("map present", "i", i, "h", h, "nbkts", nbkts);
ret option::some(v_);
}
}
nil. {
log("map absent", "i", i, "h", h, "nbkts", nbkts);
ret option::none;
}
deleted. { }
}
i += 1u;
}
ret option::none;
}
fn rehash<copy K, copy V>(hasher: hashfn<K>, eqer: eqfn<K>,
oldbkts: [mutable bucket<K, V>],
_noldbkts: uint,
newbkts: [mutable bucket<K, V>],
nnewbkts: uint) {
for b: bucket<K, V> in oldbkts {
alt b {
some(k_, v_) {
let k = k_;
let v = v_;
insert_common(hasher, eqer, newbkts, nnewbkts, k, v);
}
_ { }
}
}
}
obj hashmap<copy K, copy V>(hasher: hashfn<K>,
eqer: eqfn<K>,
mutable bkts: [mutable bucket<K, V>],
mutable nbkts: uint,
mutable nelts: uint,
lf: util::rational) {
fn size() -> uint { ret nelts; }
fn insert(key: K, val: V) -> bool {
let load: util::rational =
{num: nelts + 1u as int, den: nbkts as int};
if !util::rational_leq(load, lf) {
let nnewbkts: uint = uint::next_power_of_two(nbkts + 1u);
let newbkts = make_buckets(nnewbkts);
rehash(hasher, eqer, bkts, nbkts, newbkts, nnewbkts);
bkts = newbkts;
nbkts = nnewbkts;
}
if insert_common(hasher, eqer, bkts, nbkts, key, val) {
nelts += 1u;
ret true;
}
ret false;
}
fn contains_key(key: K) -> bool {
ret alt find_common(hasher, eqer, bkts, nbkts, key) {
option::some(_) { true }
_ { false }
};
}
fn get(key: K) -> V {
ret alt find_common(hasher, eqer, bkts, nbkts, key) {
option::some(val) { val }
_ { fail }
};
}
fn find(key: K) -> option::t<V> {
be find_common(hasher, eqer, bkts, nbkts, key);
}
fn remove(key: K) -> option::t<V> {
let i: uint = 0u;
let h = hasher(key);
while i < nbkts {
let j: uint = hash(h, nbkts, i);
alt bkts[j] {
some(k, v) {
let k_ = k;
let vo = option::some(v);
if eqer(key, k_) {
bkts[j] = deleted;
nelts -= 1u;
ret vo;
}
}
deleted. { }
nil. { ret option::none; }
}
i += 1u;
}
ret option::none;
}
fn rehash() {
let newbkts = make_buckets(nbkts);
rehash(hasher, eqer, bkts, nbkts, newbkts, nbkts);
bkts = newbkts;
}
fn items(it: block(K, V)) {
for b in bkts {
alt b { some(k, v) { it(copy k, copy v); } _ { } }
}
}
fn keys(it: block(K)) {
for b in bkts {
alt b { some(k, _) { it(copy k); } _ { } }
}
}
fn values(it: block(V)) {
for b in bkts {
alt b { some(_, v) { it(copy v); } _ { } }
}
}
}
let bkts = make_buckets(initial_capacity);
ret hashmap(hasher, eqer, bkts, initial_capacity, 0u, load_factor);
}
/*
Function: mk_hashmap