]> git.lizzy.rs Git - rust.git/commitdiff
auto merge of #14196 : chris-morgan/rust/hashmap-mangle, r=cmr
authorbors <bors@rust-lang.org>
Fri, 16 May 2014 00:36:27 +0000 (17:36 -0700)
committerbors <bors@rust-lang.org>
Fri, 16 May 2014 00:36:27 +0000 (17:36 -0700)
This used to be called `mangle` and was removed when the Robin Hood hash map came along, but it is a useful thing to have in certain situations (I just hit it with my Teepee header representation), so I want it back.

The method is renamed to `find_with_or_insert_with`, also with the parameters swapped to make sense—find and then insert, not insert and then find.

/cc @cgaebel

src/libcollections/hashmap.rs

index 3cffea46fecbf545aa9949b86b455039b0b27724..4b9c8ccadd2475629911767321643bc82a63a4b7 100644 (file)
@@ -1239,31 +1239,14 @@ fn insert_hashed<'a>(&'a mut self, hash: table::SafeHash, k: K, v: V) -> &'a mut
     /// Return the value corresponding to the key in the map, or insert
     /// and return the value if it doesn't exist.
     pub fn find_or_insert<'a>(&'a mut self, k: K, v: V) -> &'a mut V {
-        let hash = self.make_hash(&k);
-        match self.search_hashed(&hash, &k) {
-            Some(idx) => {
-                let (_, v_ref) = self.table.read_mut(&idx);
-                v_ref
-            },
-            None => self.insert_hashed(hash, k, v)
-        }
+        self.find_with_or_insert_with(k, v, |_k, _v, _a| (), |_k, a| a)
     }
 
     /// Return the value corresponding to the key in the map, or create,
     /// insert, and return a new value if it doesn't exist.
     pub fn find_or_insert_with<'a>(&'a mut self, k: K, f: |&K| -> V)
                                -> &'a mut V {
-        let hash = self.make_hash(&k);
-        match self.search_hashed(&hash, &k) {
-            Some(idx) => {
-                let (_, v_ref) = self.table.read_mut(&idx);
-                v_ref
-            },
-            None => {
-                let v = f(&k);
-                self.insert_hashed(hash, k, v)
-            }
-        }
+        self.find_with_or_insert_with(k, (), |_k, _v, _a| (), |k, _a| f(k))
     }
 
     /// Insert a key-value pair into the map if the key is not already present.
@@ -1275,12 +1258,66 @@ pub fn insert_or_update_with<'a>(
                                  v: V,
                                  f: |&K, &mut V|)
                                  -> &'a mut V {
+        self.find_with_or_insert_with(k, v, |k, v, _a| f(k, v), |_k, a| a)
+    }
+
+    /// Modify and return the value corresponding to the key in the map, or
+    /// insert and return a new value if it doesn't exist.
+    ///
+    /// This method allows for all insertion behaviours of a hashmap;
+    /// see methods like `insert`, `find_or_insert` and
+    /// `insert_or_update_with` for less general and more friendly
+    /// variations of this.
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// use collections::HashMap;
+    ///
+    /// // map some strings to vectors of strings
+    /// let mut map = HashMap::new();
+    /// map.insert("a key", vec!["value"]);
+    /// map.insert("z key", vec!["value"]);
+    ///
+    /// let new = vec!["a key", "b key", "z key"];
+    ///
+    /// for k in new.move_iter() {
+    ///     map.find_with_or_insert_with(
+    ///         k, "new value",
+    ///         // if the key does exist either prepend or append this
+    ///         // new value based on the first letter of the key.
+    ///         |key, already, new| {
+    ///             if key.as_slice().starts_with("z") {
+    ///                 already.unshift(new);
+    ///             } else {
+    ///                 already.push(new);
+    ///             }
+    ///         },
+    ///         // if the key doesn't exist in the map yet, add it in
+    ///         // the obvious way.
+    ///         |_k, v| vec![v]);
+    /// }
+    ///
+    /// assert_eq!(map.len(), 3);
+    /// assert_eq!(map.get(&"a key"), &vec!["value", "new value"]);
+    /// assert_eq!(map.get(&"b key"), &vec!["new value"]);
+    /// assert_eq!(map.get(&"z key"), &vec!["new value", "value"]);
+    /// ```
+    pub fn find_with_or_insert_with<'a, A>(&'a mut self,
+                                           k: K,
+                                           a: A,
+                                           found: |&K, &mut V, A|,
+                                           not_found: |&K, A| -> V)
+                                          -> &'a mut V {
         let hash = self.make_hash(&k);
         match self.search_hashed(&hash, &k) {
-            None      => self.insert_hashed(hash, k, v),
+            None => {
+                let v = not_found(&k, a);
+                self.insert_hashed(hash, k, v)
+            },
             Some(idx) => {
                 let (_, v_ref) = self.table.read_mut(&idx);
-                f(&k, v_ref);
+                found(&k, v_ref, a);
                 v_ref
             }
         }