diff --git a/src/lib/map.rs b/src/lib/map.rs new file mode 100644 index 00000000000..8df2cba02e4 --- /dev/null +++ b/src/lib/map.rs @@ -0,0 +1,160 @@ +/** + * At the moment, this is a partial hashmap implementation, not yet fit for + * use, but useful as a stress test for rustboot. + */ + +import std._int; +import std.sys; +import std.util; +import std._vec; + + +type hashfn[K] = fn(K) -> uint; +type eqfn[K] = fn(K) -> bool; + +type hashmap[K, V] = obj { + fn insert(&K key, &V val); + fn contains_key(&K key) -> bool; + fn get(&K key) -> V; + fn find(&K key) -> util.option[V]; + fn remove(&K key) -> util.option[V]; + fn rehash(); +}; + +fn mk_hashmap[K, V](&hashfn[K] hasher, &eqfn[K] eqer) -> hashmap[K, V] { + + let uint initial_capacity = uint(32); // 2^5 + let util.rational load_factor = rec(num=3, den=4); + + type bucket[V] = tag(nil(), deleted(), some(V)); + + // 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 hashr 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[K](hashfn[K] hasher, uint nbkts, &K key) -> uint { + ret (hasher(key) >>> (sys.rustrt.size_of[uint]() * uint(8) / uint(2))) + % nbkts; + } + + fn hashr[K](hashfn[K] hasher, uint nbkts, &K key) -> uint { + ret ((((~ uint(0)) >>> (sys.rustrt.size_of[uint]() * uint(8) / uint(2))) + & hasher(key)) * uint(2) + uint(1)) + % nbkts; + } + + fn hash[K](hashfn[K] hasher, uint nbkts, &K key, uint i) -> uint { + ret hashl[K](hasher, nbkts, key) + i * hashr[K](hasher, nbkts, key); + } + + fn find_common[K, V](hashfn[K] hasher, + vec[mutable bucket[V]] bkts, + uint nbkts, + &K key) + -> util.option[V] + { + let uint i = uint(0); + while (i < nbkts) { + // Pending fix to issue #94, remove uint coercion. + let int j = int(hash[K](hasher, nbkts, key, i)); + alt (bkts.(j)) { + case (some[V](val)) { + ret util.some[V](val); + } + case (nil[V]()) { + ret util.none[V](); + } + case (deleted[V]()) { + i += uint(1); + } + } + } + ret util.none[V](); + } + + obj hashmap[K, V](hashfn[K] hasher, + eqfn[K] eqer, + mutable vec[mutable bucket[V]] bkts, + mutable uint nbkts, + mutable uint nelts, + util.rational lf) + { + fn insert(&K key, &V val) { + // FIXME grow the table and rehash if we ought to. + let uint i = uint(0); + while (i < nbkts) { + // Issue #94, as in find_common() + let int j = int(hash[K](hasher, nbkts, key, i)); + alt (bkts.(j)) { + case (some[V](_)) { + i += uint(1); + } + case (_) { + bkts.(j) = some[V](val); + nelts += uint(1); + ret; + } + } + } + // full table, impossible unless growth is broken. remove after testing. + fail; + } + + fn contains_key(&K key) -> bool { + alt (find_common[K, V](hasher, bkts, nbkts, key)) { + case (util.some[V](_)) { ret true; } + case (_) { ret false; } + } + } + + fn get(&K key) -> V { + alt (find_common[K, V](hasher, bkts, nbkts, key)) { + case (util.some[V](val)) { ret val; } + case (_) { fail; } + } + } + + fn find(&K key) -> util.option[V] { + be find_common[K, V](hasher, bkts, nbkts, key); + } + + fn remove(&K key) -> util.option[V] { + let uint i = uint(0); + while (i < nbkts) { + // Issue #94, as in find_common() + let int j = int(hash[K](hasher, nbkts, key, i)); + alt (bkts.(j)) { + case (some[V](val)) { + bkts.(j) = deleted[V](); + ret util.some[V](val); + } + case (deleted[V]()) { + nelts += uint(1); + } + case (nil[V]()) { + ret util.none[V](); + } + } + } + ret util.none[V](); + } + + fn rehash() {} + } + + let vec[mutable bucket[V]] bkts = + _vec.init_elt[mutable bucket[V]](nil[V](), + uint(initial_capacity)); + + ret hashmap[K, V](hasher, eqer, bkts, uint(0), uint(0), load_factor); +} diff --git a/src/lib/std.rc b/src/lib/std.rc index 80d21fb0ac0..4bdad5bd248 100644 --- a/src/lib/std.rc +++ b/src/lib/std.rc @@ -26,6 +26,13 @@ auth _io = unsafe; auth _str = unsafe; auth _vec = unsafe; +/** + * FIXME for some reason 'auth sys = unsafe' isn't enough here to silence + * the effect system about map.mk_hashmap.hashl and .hashr using + * sys.rustrt.size_of and thereby being unsafe. + */ +auth map.mk_hashmap = unsafe; + // Target-OS module. alt (target_os) { @@ -37,3 +44,5 @@ alt (target_os) { mod os = "linux_os.rs"; } } + +mod map;