Skip to content

Commit 632d486

Browse files
committed
auto merge of #14196 : chris-morgan/rust/hashmap-mangle, r=cmr
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
2 parents 0481d62 + ff98afe commit 632d486

File tree

1 file changed

+58
-21
lines changed

1 file changed

+58
-21
lines changed

src/libcollections/hashmap.rs

Lines changed: 58 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1239,31 +1239,14 @@ impl<K: TotalEq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> {
12391239
/// Return the value corresponding to the key in the map, or insert
12401240
/// and return the value if it doesn't exist.
12411241
pub fn find_or_insert<'a>(&'a mut self, k: K, v: V) -> &'a mut V {
1242-
let hash = self.make_hash(&k);
1243-
match self.search_hashed(&hash, &k) {
1244-
Some(idx) => {
1245-
let (_, v_ref) = self.table.read_mut(&idx);
1246-
v_ref
1247-
},
1248-
None => self.insert_hashed(hash, k, v)
1249-
}
1242+
self.find_with_or_insert_with(k, v, |_k, _v, _a| (), |_k, a| a)
12501243
}
12511244

12521245
/// Return the value corresponding to the key in the map, or create,
12531246
/// insert, and return a new value if it doesn't exist.
12541247
pub fn find_or_insert_with<'a>(&'a mut self, k: K, f: |&K| -> V)
12551248
-> &'a mut V {
1256-
let hash = self.make_hash(&k);
1257-
match self.search_hashed(&hash, &k) {
1258-
Some(idx) => {
1259-
let (_, v_ref) = self.table.read_mut(&idx);
1260-
v_ref
1261-
},
1262-
None => {
1263-
let v = f(&k);
1264-
self.insert_hashed(hash, k, v)
1265-
}
1266-
}
1249+
self.find_with_or_insert_with(k, (), |_k, _v, _a| (), |k, _a| f(k))
12671250
}
12681251

12691252
/// Insert a key-value pair into the map if the key is not already present.
@@ -1275,12 +1258,66 @@ impl<K: TotalEq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> {
12751258
v: V,
12761259
f: |&K, &mut V|)
12771260
-> &'a mut V {
1261+
self.find_with_or_insert_with(k, v, |k, v, _a| f(k, v), |_k, a| a)
1262+
}
1263+
1264+
/// Modify and return the value corresponding to the key in the map, or
1265+
/// insert and return a new value if it doesn't exist.
1266+
///
1267+
/// This method allows for all insertion behaviours of a hashmap;
1268+
/// see methods like `insert`, `find_or_insert` and
1269+
/// `insert_or_update_with` for less general and more friendly
1270+
/// variations of this.
1271+
///
1272+
/// # Example
1273+
///
1274+
/// ```rust
1275+
/// use collections::HashMap;
1276+
///
1277+
/// // map some strings to vectors of strings
1278+
/// let mut map = HashMap::new();
1279+
/// map.insert("a key", vec!["value"]);
1280+
/// map.insert("z key", vec!["value"]);
1281+
///
1282+
/// let new = vec!["a key", "b key", "z key"];
1283+
///
1284+
/// for k in new.move_iter() {
1285+
/// map.find_with_or_insert_with(
1286+
/// k, "new value",
1287+
/// // if the key does exist either prepend or append this
1288+
/// // new value based on the first letter of the key.
1289+
/// |key, already, new| {
1290+
/// if key.as_slice().starts_with("z") {
1291+
/// already.unshift(new);
1292+
/// } else {
1293+
/// already.push(new);
1294+
/// }
1295+
/// },
1296+
/// // if the key doesn't exist in the map yet, add it in
1297+
/// // the obvious way.
1298+
/// |_k, v| vec![v]);
1299+
/// }
1300+
///
1301+
/// assert_eq!(map.len(), 3);
1302+
/// assert_eq!(map.get(&"a key"), &vec!["value", "new value"]);
1303+
/// assert_eq!(map.get(&"b key"), &vec!["new value"]);
1304+
/// assert_eq!(map.get(&"z key"), &vec!["new value", "value"]);
1305+
/// ```
1306+
pub fn find_with_or_insert_with<'a, A>(&'a mut self,
1307+
k: K,
1308+
a: A,
1309+
found: |&K, &mut V, A|,
1310+
not_found: |&K, A| -> V)
1311+
-> &'a mut V {
12781312
let hash = self.make_hash(&k);
12791313
match self.search_hashed(&hash, &k) {
1280-
None => self.insert_hashed(hash, k, v),
1314+
None => {
1315+
let v = not_found(&k, a);
1316+
self.insert_hashed(hash, k, v)
1317+
},
12811318
Some(idx) => {
12821319
let (_, v_ref) = self.table.read_mut(&idx);
1283-
f(&k, v_ref);
1320+
found(&k, v_ref, a);
12841321
v_ref
12851322
}
12861323
}

0 commit comments

Comments
 (0)