about summary refs log tree commit diff
path: root/src/libstd/map.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstd/map.rs')
-rw-r--r--src/libstd/map.rs289
1 files changed, 158 insertions, 131 deletions
diff --git a/src/libstd/map.rs b/src/libstd/map.rs
index 902fe5aaf6e..dd99c9945e1 100644
--- a/src/libstd/map.rs
+++ b/src/libstd/map.rs
@@ -1,5 +1,7 @@
 //! A map type
 
+#[warn(deprecated_mode)];
+
 import chained::hashmap;
 import io::writer_util;
 import to_str::to_str;
@@ -15,16 +17,16 @@ export vec_from_set;
  *
  * The hash should concentrate entropy in the lower bits.
  */
-type hashfn<K> = fn@(K) -> uint;
+type hashfn<K> = fn~(key: &K) -> uint;
 
-type eqfn<K> = fn@(K, K) -> bool;
+type eqfn<K> = fn~(key1: &K, key2: &K) -> bool;
 
 /// A convenience type to treat a hashmap as a set
 type set<K> = hashmap<K, ()>;
 
 type hashmap<K, V> = chained::t<K, V>;
 
-trait map<K, V: copy> {
+trait map<K: copy, V: copy> {
     /// Return the number of elements in the map
     fn size() -> uint;
 
@@ -39,40 +41,50 @@ trait map<K, V: copy> {
     fn insert(+K, +V) -> bool;
 
     /// Returns true if the map contains a value for the specified key
-    fn contains_key(K) -> bool;
+    fn contains_key(+key: K) -> bool;
+
+    /// Returns true if the map contains a value for the specified
+    /// key, taking the key by reference.
+    fn contains_key_ref(key: &K) -> bool;
 
     /**
      * Get the value for the specified key. Fails if the key does not exist in
      * the map.
      */
-    fn get(K) -> V;
-
-    /// Like get, but as an operator.
-    fn [](K) -> V;
+    fn get(+key: K) -> V;
 
     /**
      * Get the value for the specified key. If the key does not exist in
      * the map then returns none.
      */
-    fn find(K) -> option<V>;
+    fn find(+key: K) -> option<V>;
 
     /**
      * Remove and return a value from the map. If the key does not exist
      * in the map then returns none.
      */
-    fn remove(K) -> option<V>;
+    fn remove(+key: K) -> option<V>;
 
     /// Clear the map, removing all key/value pairs.
     fn clear();
 
-    /// Iterate over all the key/value pairs in the map
-    fn each(fn(K, V) -> bool);
+    /// Iterate over all the key/value pairs in the map by value
+    fn each(fn(+key: K, +value: V) -> bool);
+
+    /// Iterate over all the keys in the map by value
+    fn each_key(fn(+key: K) -> bool);
+
+    /// Iterate over all the values in the map by value
+    fn each_value(fn(+value: V) -> bool);
 
-    /// Iterate over all the keys in the map
-    fn each_key(fn(K) -> bool);
+    /// Iterate over all the key/value pairs in the map by reference
+    fn each_ref(fn(key: &K, value: &V) -> bool);
 
-    /// Iterate over all the values in the map
-    fn each_value(fn(V) -> bool);
+    /// Iterate over all the keys in the map by reference
+    fn each_key_ref(fn(key: &K) -> bool);
+
+    /// Iterate over all the values in the map by reference
+    fn each_value_ref(fn(value: &V) -> bool);
 }
 
 mod util {
@@ -93,31 +105,21 @@ mod chained {
 
     const initial_capacity: uint = 32u; // 2^5
 
-    type entry<K, V> = {
-        hash: uint,
-        key: K,
-        mut value: V,
-        mut next: chain<K, V>
-    };
-
-    enum chain<K, V> {
-        present(@entry<K, V>),
-        absent
+    struct entry<K, V> {
+        hash: uint;
+        key: K;
+        value: V;
+        mut next: option<@entry<K, V>>;
     }
 
-    type hashmap__<K, V> = {
-        mut count: uint,
-        mut chains: ~[mut chain<K,V>],
-        hasher: hashfn<K>,
-        eqer: eqfn<K>
-    };
-    type t<K, V> = @hashmap_<K, V>;
-
-    enum hashmap_<K, V> {
-        hashmap_(@hashmap__<K, V>)
+    struct hashmap_<K, V> {
+        mut count: uint;
+        mut chains: ~[mut option<@entry<K,V>>];
+        hasher: hashfn<K>;
+        eqer: eqfn<K>;
     }
 
-    type t<K, V> = hashmap_<K, V>;
+    type t<K, V> = @hashmap_<K, V>;
 
     enum search_result<K, V> {
         not_found,
@@ -125,21 +127,21 @@ mod chained {
         found_after(@entry<K,V>, @entry<K,V>)
     }
 
-    impl private_methods<K, V: copy> for hashmap_<K, V> {
-        fn search_rem(k: K, h: uint, idx: uint,
+    impl private_methods<K, V: copy> for t<K, V> {
+        fn search_rem(k: &K, h: uint, idx: uint,
                       e_root: @entry<K,V>) -> search_result<K,V> {
             let mut e0 = e_root;
             let mut comp = 1u;   // for logging
             loop {
                 alt copy e0.next {
-                  absent {
+                  none {
                     debug!{"search_tbl: absent, comp %u, hash %u, idx %u",
                            comp, h, idx};
                     return not_found;
                   }
-                  present(e1) {
+                  some(e1) {
                     comp += 1u;
-                    if e1.hash == h && self.eqer(e1.key, k) {
+                    if e1.hash == h && self.eqer(&e1.key, k) {
                         debug!{"search_tbl: present, comp %u, \
                                 hash %u, idx %u",
                                comp, h, idx};
@@ -152,16 +154,16 @@ mod chained {
             };
         }
 
-        fn search_tbl(k: K, h: uint) -> search_result<K,V> {
+        fn search_tbl(k: &K, h: uint) -> search_result<K,V> {
             let idx = h % vec::len(self.chains);
             alt copy self.chains[idx] {
-              absent {
-                debug!{"search_tbl: absent, comp %u, hash %u, idx %u",
+              none {
+                debug!{"search_tbl: none, comp %u, hash %u, idx %u",
                        0u, h, idx};
                 return not_found;
               }
-              present(e) {
-                if e.hash == h && self.eqer(e.key, k) {
+              some(e) {
+                if e.hash == h && self.eqer(&e.key, k) {
                     debug!{"search_tbl: present, comp %u, hash %u, idx %u",
                            1u, h, idx};
                     return found_first(idx, e);
@@ -173,25 +175,27 @@ mod chained {
         }
 
         fn rehash() {
-            let n_old_chains = vec::len(self.chains);
+            let n_old_chains = self.chains.len();
             let n_new_chains: uint = uint::next_power_of_two(n_old_chains+1u);
             let new_chains = chains(n_new_chains);
             for self.each_entry |entry| {
                 let idx = entry.hash % n_new_chains;
                 entry.next = new_chains[idx];
-                new_chains[idx] = present(entry);
+                new_chains[idx] = some(entry);
             }
             self.chains = new_chains;
         }
 
         fn each_entry(blk: fn(@entry<K,V>) -> bool) {
-            let mut i = 0u, n = vec::len(self.chains);
+            // n.b. we can't use vec::iter() here because self.chains
+            // is stored in a mutable location.
+            let mut i = 0u, n = self.chains.len();
             while i < n {
                 let mut chain = self.chains[i];
                 loop {
                     chain = alt chain {
-                      absent { break; }
-                      present(entry) {
+                      none { break; }
+                      some(entry) {
                         let next = entry.next;
                         if !blk(entry) { return; }
                         next
@@ -203,10 +207,14 @@ mod chained {
         }
     }
 
-    impl hashmap<K, V: copy> of map<K, V> for t<K, V> {
+    impl hashmap<K: copy, V: copy> of map<K, V> for t<K, V> {
         fn size() -> uint { self.count }
 
-        fn contains_key(k: K) -> bool {
+        fn contains_key(+k: K) -> bool {
+            self.contains_key_ref(&k)
+        }
+
+        fn contains_key_ref(k: &K) -> bool {
             let hash = self.hasher(k);
             alt self.search_tbl(k, hash) {
               not_found {false}
@@ -215,17 +223,17 @@ mod chained {
         }
 
         fn insert(+k: K, +v: V) -> bool {
-            let hash = self.hasher(k);
-            alt self.search_tbl(k, hash) {
+            let hash = self.hasher(&k);
+            alt self.search_tbl(&k, hash) {
               not_found {
                 self.count += 1u;
                 let idx = hash % vec::len(self.chains);
                 let old_chain = self.chains[idx];
-                self.chains[idx] = present(@{
+                self.chains[idx] = some(@entry {
                     hash: hash,
                     key: k,
-                    mut value: v,
-                    mut next: old_chain});
+                    value: v,
+                    next: old_chain});
 
                 // consider rehashing if more 3/4 full
                 let nchains = vec::len(self.chains);
@@ -237,38 +245,43 @@ mod chained {
 
                 return true;
               }
-              found_first(_, entry) {
-                entry.value = v;
+              found_first(idx, entry) {
+                self.chains[idx] = some(@entry {
+                    hash: hash,
+                    key: k,
+                    value: v,
+                    next: entry.next});
                 return false;
               }
-              found_after(_, entry) {
-                entry.value = v;
-                return false
+              found_after(prev, entry) {
+                prev.next = some(@entry {
+                    hash: hash,
+                    key: k,
+                    value: v,
+                    next: entry.next});
+                return false;
               }
             }
         }
 
-        fn find(k: K) -> option<V> {
-            alt self.search_tbl(k, self.hasher(k)) {
+        fn find(+k: K) -> option<V> {
+            alt self.search_tbl(&k, self.hasher(&k)) {
               not_found {none}
               found_first(_, entry) {some(entry.value)}
               found_after(_, entry) {some(entry.value)}
             }
         }
 
-        fn get(k: K) -> V {
-            alt self.find(k) {
-              some(v) => {v}
-              none => {fail fmt!{"Key not found in table: %?", k}}
+        fn get(+k: K) -> V {
+            let opt_v = self.find(k);
+            if opt_v.is_none() {
+                fail fmt!{"Key not found in table: %?", k};
             }
+            option::unwrap(opt_v)
         }
 
-        fn [](k: K) -> V {
-            self.get(k)
-        }
-
-        fn remove(k: K) -> option<V> {
-            alt self.search_tbl(k, self.hasher(k)) {
+        fn remove(+k: K) -> option<V> {
+            alt self.search_tbl(&k, self.hasher(&k)) {
               not_found {none}
               found_first(idx, entry) {
                 self.count -= 1u;
@@ -288,18 +301,34 @@ mod chained {
             self.chains = chains(initial_capacity);
         }
 
-        fn each(blk: fn(K,V) -> bool) {
+        fn each(blk: fn(+key: K, +value: V) -> bool) {
+            self.each_ref(|k, v| blk(*k, *v))
+        }
+
+        fn each_key(blk: fn(+key: K) -> bool) {
+            self.each_key_ref(|p| blk(*p))
+        }
+
+        fn each_value(blk: fn(+value: V) -> bool) {
+            self.each_value_ref(|p| blk(*p))
+        }
+
+        fn each_ref(blk: fn(key: &K, value: &V) -> bool) {
             for self.each_entry |entry| {
-                if !blk(entry.key, copy entry.value) { break; }
+                if !blk(&entry.key, &entry.value) { break; }
             }
         }
 
-        fn each_key(blk: fn(K) -> bool) { self.each(|k, _v| blk(k)) }
+        fn each_key_ref(blk: fn(key: &K) -> bool) {
+            self.each_ref(|k, _v| blk(k))
+        }
 
-        fn each_value(blk: fn(V) -> bool) { self.each(|_k, v| blk(v)) }
+        fn each_value_ref(blk: fn(value: &V) -> bool) {
+            self.each_ref(|_k, v| blk(v))
+        }
     }
 
-    impl hashmap<K: to_str, V: to_str copy> of to_str for hashmap_<K, V> {
+    impl hashmap<K: copy to_str, V: to_str copy> of to_str for t<K, V> {
         fn to_writer(wr: io::writer) {
             if self.count == 0u {
                 wr.write_str("{}");
@@ -325,24 +354,23 @@ mod chained {
         }
     }
 
-    impl hashmap<K, V: copy> of ops::index<K, V> for t<K, V> {
-        pure fn index(k: K) -> V {
+    impl hashmap<K: copy, V: copy> of ops::index<K, V> for t<K, V> {
+        pure fn index(&&k: K) -> V {
             unchecked {
                 self.get(k)
             }
         }
     }
 
-
-    fn chains<K,V>(nchains: uint) -> ~[mut chain<K,V>] {
-        return vec::to_mut(vec::from_elem(nchains, absent));
+    fn chains<K,V>(nchains: uint) -> ~[mut option<@entry<K,V>>] {
+        vec::to_mut(vec::from_elem(nchains, none))
     }
 
-    fn mk<K, V: copy>(hasher: hashfn<K>, eqer: eqfn<K>) -> t<K,V> {
-        let slf: t<K, V> = hashmap_(@{mut count: 0u,
-                                      mut chains: chains(initial_capacity),
+    fn mk<K, V: copy>(+hasher: hashfn<K>, +eqer: eqfn<K>) -> t<K,V> {
+        let slf: t<K, V> = @hashmap_ {count: 0u,
+                                      chains: chains(initial_capacity),
                                       hasher: hasher,
-                                      eqer: eqer});
+                                      eqer: eqer};
         slf
     }
 }
@@ -357,7 +385,7 @@ Parameters:
 hasher - The hash function for key type K
 eqer - The equality function for key type K
 */
-fn hashmap<K: const, V: copy>(hasher: hashfn<K>, eqer: eqfn<K>)
+fn hashmap<K: const, V: copy>(+hasher: hashfn<K>, +eqer: eqfn<K>)
         -> hashmap<K, V> {
     chained::mk(hasher, eqer)
 }
@@ -369,7 +397,8 @@ fn str_hash<V: copy>() -> hashmap<~str, V> {
 
 /// Construct a hashmap for boxed string keys
 fn box_str_hash<V: copy>() -> hashmap<@~str, V> {
-    return hashmap(|x: @~str| str::hash(*x), |x,y| str::eq(*x,*y));
+    hashmap(|x: &@~str| str::hash(&**x),
+            |x: &@~str, y: &@~str| str::eq(&**x, &**y))
 }
 
 /// Construct a hashmap for byte string keys
@@ -388,13 +417,14 @@ fn uint_hash<V: copy>() -> hashmap<uint, V> {
 }
 
 /// Convenience function for adding keys to a hashmap with nil type keys
-fn set_add<K: const copy>(set: set<K>, key: K) -> bool {
-    return set.insert(key, ());
+fn set_add<K: const copy>(set: set<K>, +key: K) -> bool {
+    set.insert(key, ())
 }
 
 /// Convert a set into a vector.
 fn vec_from_set<T: copy>(s: set<T>) -> ~[T] {
     let mut v = ~[];
+    vec::reserve(v, s.size());
     do s.each_key() |k| {
         vec::push(v, k);
         true
@@ -403,8 +433,8 @@ fn vec_from_set<T: copy>(s: set<T>) -> ~[T] {
 }
 
 /// Construct a hashmap from a vector
-fn hash_from_vec<K: const copy, V: copy>(hasher: hashfn<K>, eqer: eqfn<K>,
-                                         items: ~[(K, V)]) -> hashmap<K, V> {
+fn hash_from_vec<K: const copy, V: copy>(+hasher: hashfn<K>, +eqer: eqfn<K>,
+                                         items: &[(K, V)]) -> hashmap<K, V> {
     let map = hashmap(hasher, eqer);
     do vec::iter(items) |item| {
         let (key, value) = item;
@@ -414,22 +444,22 @@ fn hash_from_vec<K: const copy, V: copy>(hasher: hashfn<K>, eqer: eqfn<K>,
 }
 
 /// Construct a hashmap from a vector with string keys
-fn hash_from_strs<V: copy>(items: ~[(~str, V)]) -> hashmap<~str, V> {
+fn hash_from_strs<V: copy>(items: &[(~str, V)]) -> hashmap<~str, V> {
     hash_from_vec(str::hash, str::eq, items)
 }
 
 /// Construct a hashmap from a vector with byte keys
-fn hash_from_bytes<V: copy>(items: ~[(~[u8], V)]) -> hashmap<~[u8], V> {
+fn hash_from_bytes<V: copy>(items: &[(~[u8], V)]) -> hashmap<~[u8], V> {
     hash_from_vec(vec::u8::hash, vec::u8::eq, items)
 }
 
 /// Construct a hashmap from a vector with int keys
-fn hash_from_ints<V: copy>(items: ~[(int, V)]) -> hashmap<int, V> {
+fn hash_from_ints<V: copy>(items: &[(int, V)]) -> hashmap<int, V> {
     hash_from_vec(int::hash, int::eq, items)
 }
 
 /// Construct a hashmap from a vector with uint keys
-fn hash_from_uints<V: copy>(items: ~[(uint, V)]) -> hashmap<uint, V> {
+fn hash_from_uints<V: copy>(items: &[(uint, V)]) -> hashmap<uint, V> {
     hash_from_vec(uint::hash, uint::eq, items)
 }
 
@@ -439,15 +469,15 @@ mod tests {
     #[test]
     fn test_simple() {
         debug!{"*** starting test_simple"};
-        fn eq_uint(&&x: uint, &&y: uint) -> bool { return x == y; }
-        fn uint_id(&&x: uint) -> uint { x }
+        pure fn eq_uint(x: &uint, y: &uint) -> bool { *x == *y }
+        pure fn uint_id(x: &uint) -> uint { *x }
         let hasher_uint: map::hashfn<uint> = uint_id;
         let eqer_uint: map::eqfn<uint> = eq_uint;
         let hasher_str: map::hashfn<~str> = str::hash;
         let eqer_str: map::eqfn<~str> = str::eq;
         debug!{"uint -> uint"};
         let hm_uu: map::hashmap<uint, uint> =
-            map::hashmap::<uint, uint>(hasher_uint, eqer_uint);
+            map::hashmap::<uint, uint>(copy hasher_uint, copy eqer_uint);
         assert (hm_uu.insert(10u, 12u));
         assert (hm_uu.insert(11u, 13u));
         assert (hm_uu.insert(12u, 14u));
@@ -463,7 +493,7 @@ mod tests {
         let twelve: ~str = ~"twelve";
         debug!{"str -> uint"};
         let hm_su: map::hashmap<~str, uint> =
-            map::hashmap::<~str, uint>(hasher_str, eqer_str);
+            map::hashmap::<~str, uint>(copy hasher_str, copy eqer_str);
         assert (hm_su.insert(~"ten", 12u));
         assert (hm_su.insert(eleven, 13u));
         assert (hm_su.insert(~"twelve", 14u));
@@ -477,30 +507,30 @@ mod tests {
         assert (hm_su.get(~"twelve") == 12u);
         debug!{"uint -> str"};
         let hm_us: map::hashmap<uint, ~str> =
-            map::hashmap::<uint, ~str>(hasher_uint, eqer_uint);
+            map::hashmap::<uint, ~str>(copy hasher_uint, copy eqer_uint);
         assert (hm_us.insert(10u, ~"twelve"));
         assert (hm_us.insert(11u, ~"thirteen"));
         assert (hm_us.insert(12u, ~"fourteen"));
-        assert (str::eq(hm_us.get(11u), ~"thirteen"));
-        assert (str::eq(hm_us.get(12u), ~"fourteen"));
-        assert (str::eq(hm_us.get(10u), ~"twelve"));
+        assert hm_us.get(11u) == ~"thirteen";
+        assert hm_us.get(12u) == ~"fourteen";
+        assert hm_us.get(10u) == ~"twelve";
         assert (!hm_us.insert(12u, ~"fourteen"));
-        assert (str::eq(hm_us.get(12u), ~"fourteen"));
+        assert hm_us.get(12u) == ~"fourteen";
         assert (!hm_us.insert(12u, ~"twelve"));
-        assert (str::eq(hm_us.get(12u), ~"twelve"));
+        assert hm_us.get(12u) == ~"twelve";
         debug!{"str -> str"};
         let hm_ss: map::hashmap<~str, ~str> =
-            map::hashmap::<~str, ~str>(hasher_str, eqer_str);
+            map::hashmap::<~str, ~str>(copy hasher_str, copy eqer_str);
         assert (hm_ss.insert(ten, ~"twelve"));
         assert (hm_ss.insert(eleven, ~"thirteen"));
         assert (hm_ss.insert(twelve, ~"fourteen"));
-        assert (str::eq(hm_ss.get(~"eleven"), ~"thirteen"));
-        assert (str::eq(hm_ss.get(~"twelve"), ~"fourteen"));
-        assert (str::eq(hm_ss.get(~"ten"), ~"twelve"));
+        assert hm_ss.get(~"eleven") == ~"thirteen";
+        assert hm_ss.get(~"twelve") == ~"fourteen";
+        assert hm_ss.get(~"ten") == ~"twelve";
         assert (!hm_ss.insert(~"twelve", ~"fourteen"));
-        assert (str::eq(hm_ss.get(~"twelve"), ~"fourteen"));
+        assert hm_ss.get(~"twelve") == ~"fourteen";
         assert (!hm_ss.insert(~"twelve", ~"twelve"));
-        assert (str::eq(hm_ss.get(~"twelve"), ~"twelve"));
+        assert hm_ss.get(~"twelve") == ~"twelve";
         debug!{"*** finished test_simple"};
     }
 
@@ -512,8 +542,8 @@ mod tests {
     fn test_growth() {
         debug!{"*** starting test_growth"};
         let num_to_insert: uint = 64u;
-        fn eq_uint(&&x: uint, &&y: uint) -> bool { return x == y; }
-        fn uint_id(&&x: uint) -> uint { x }
+        pure fn eq_uint(x: &uint, y: &uint) -> bool { *x == *y }
+        pure fn uint_id(x: &uint) -> uint { *x }
         debug!{"uint -> uint"};
         let hasher_uint: map::hashfn<uint> = uint_id;
         let eqer_uint: map::eqfn<uint> = eq_uint;
@@ -560,22 +590,20 @@ mod tests {
             debug!{"get(\"%s\") = \"%s\"",
                    uint::to_str(i, 2u),
                    hm_ss.get(uint::to_str(i, 2u))};
-            assert (str::eq(hm_ss.get(uint::to_str(i, 2u)),
-                            uint::to_str(i * i, 2u)));
+            assert hm_ss.get(uint::to_str(i, 2u)) == uint::to_str(i * i, 2u);
             i += 1u;
         }
         assert (hm_ss.insert(uint::to_str(num_to_insert, 2u),
                              uint::to_str(17u, 2u)));
-        assert (str::eq(hm_ss.get(uint::to_str(num_to_insert, 2u)),
-                        uint::to_str(17u, 2u)));
+        assert hm_ss.get(uint::to_str(num_to_insert, 2u)) ==
+            uint::to_str(17u, 2u);
         debug!{"-----"};
         i = 0u;
         while i < num_to_insert {
             debug!{"get(\"%s\") = \"%s\"",
                    uint::to_str(i, 2u),
                    hm_ss.get(uint::to_str(i, 2u))};
-            assert (str::eq(hm_ss.get(uint::to_str(i, 2u)),
-                            uint::to_str(i * i, 2u)));
+            assert hm_ss.get(uint::to_str(i, 2u)) == uint::to_str(i * i, 2u);
             i += 1u;
         }
         debug!{"*** finished test_growth"};
@@ -585,16 +613,15 @@ mod tests {
     fn test_removal() {
         debug!{"*** starting test_removal"};
         let num_to_insert: uint = 64u;
-        fn eq(&&x: uint, &&y: uint) -> bool { return x == y; }
-        fn hash(&&u: uint) -> uint {
+        fn eq(x: &uint, y: &uint) -> bool { *x == *y }
+        fn hash(u: &uint) -> uint {
             // This hash function intentionally causes collisions between
             // consecutive integer pairs.
-
-            return u / 2u * 2u;
+            *u / 2u * 2u
         }
-        assert (hash(0u) == hash(1u));
-        assert (hash(2u) == hash(3u));
-        assert (hash(0u) != hash(2u));
+        assert (hash(&0u) == hash(&1u));
+        assert (hash(&2u) == hash(&3u));
+        assert (hash(&0u) != hash(&2u));
         let hasher: map::hashfn<uint> = hash;
         let eqer: map::eqfn<uint> = eq;
         let hm: map::hashmap<uint, uint> =