aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRoy Frostig <[email protected]>2010-07-16 18:14:52 -0700
committerRoy Frostig <[email protected]>2010-07-16 18:14:52 -0700
commitfb68286700525b5bcd2d44d05d1d53f53b702af6 (patch)
tree63b0a5b61eed209c0210f133258ef85554e4ebb4 /src
parentFix IL translation of pattern-alt to allow a value of mutable/constrained typ... (diff)
downloadrust-fb68286700525b5bcd2d44d05d1d53f53b702af6.tar.xz
rust-fb68286700525b5bcd2d44d05d1d53f53b702af6.zip
Add incomplete hashmap implementation to stdlib.
Diffstat (limited to 'src')
-rw-r--r--src/lib/map.rs160
-rw-r--r--src/lib/std.rc9
2 files changed, 169 insertions, 0 deletions
diff --git a/src/lib/map.rs b/src/lib/map.rs
new file mode 100644
index 00000000..8df2cba0
--- /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 80d21fb0..4bdad5bd 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;