Purge old map impl: more collisions, not clear it is safe on 64bit
This commit is contained in:
parent
4b704ac69b
commit
1ff8994fce
@ -353,211 +353,6 @@ fn mk<copy K, copy V>(hasher: hashfn<K>, eqer: eqfn<K>) -> hashmap<K,V> {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user