diff --git a/src/libextra/smallintmap.rs b/src/libextra/smallintmap.rs index 0ca0ff66039d8..d7316d70d9240 100644 --- a/src/libextra/smallintmap.rs +++ b/src/libextra/smallintmap.rs @@ -23,6 +23,7 @@ use std::vec; #[allow(missing_doc)] pub struct SmallIntMap { priv v: ~[Option], + priv last_key: uint, } impl Container for SmallIntMap { @@ -69,17 +70,19 @@ impl MutableMap for SmallIntMap { } } - /// Insert a key-value pair into the map. An existing value for a - /// key is replaced by the new value. Return true if the key did - /// not already exist in the map. - fn insert(&mut self, key: uint, value: V) -> bool { - let exists = self.contains_key(&key); + /// Return the value corresponding to the key in the map, or create, + /// insert, and return a new value if it doesn't exist. + fn find_or_insert_with<'a>(&'a mut self, key: uint, f: &fn(&uint) -> V) + -> (&'a uint, &'a mut V) { let len = self.v.len(); if len <= key { self.v.grow_fn(key - len + 1, |_| None); } - self.v[key] = Some(value); - !exists + self.last_key = key; + if self.v[key].is_none() { + self.v[key] = Some(f(&key)); + } + (&self.last_key, self.v[key].get_mut_ref()) } /// Remove a key-value pair from the map. Return true if the key @@ -88,17 +91,6 @@ impl MutableMap for SmallIntMap { self.pop(key).is_some() } - /// Insert a key-value pair from the map. If the key already had a value - /// present in the map, that value is returned. Otherwise None is returned. - fn swap(&mut self, key: uint, value: V) -> Option { - match self.find_mut(&key) { - Some(loc) => { return Some(replace(loc, value)); } - None => () - } - self.insert(key, value); - return None; - } - /// Removes a key from the map, returning the value at the key if the key /// was previously in the map. fn pop(&mut self, key: &uint) -> Option { @@ -107,11 +99,15 @@ impl MutableMap for SmallIntMap { } self.v[*key].take() } + + /// Does nothing for this implementation. + fn reserve_at_least(&mut self, _: uint) { + } } impl SmallIntMap { /// Create an empty SmallIntMap - pub fn new() -> SmallIntMap { SmallIntMap{v: ~[]} } + pub fn new() -> SmallIntMap { SmallIntMap{v: ~[], last_key: 0} } pub fn get<'a>(&'a self, key: &uint) -> &'a V { self.find(key).expect("key not present") @@ -337,6 +333,39 @@ mod test_map { assert_eq!(m.swap(1, 4), Some(3)); } + #[test] + fn test_find_or_insert() { + let mut m = SmallIntMap::new(); + { + let (k, v) = m.find_or_insert(1, 2); + assert_eq!((*k, *v), (1, 2)); + } + { + let (k, v) = m.find_or_insert(1, 3); + assert_eq!((*k, *v), (1, 2)); + } + } + + #[test] + fn test_find_or_insert_with() { + let mut m = SmallIntMap::new(); + { + let (k, v) = m.find_or_insert_with(1, |_| 2); + assert_eq!((*k, *v), (1, 2)); + } + { + let (k, v) = m.find_or_insert_with(1, |_| 3); + assert_eq!((*k, *v), (1, 2)); + } + } + + #[test] + fn test_insert_or_update_with() { + let mut m = SmallIntMap::new(); + assert_eq!(*m.insert_or_update_with(1, 2, |_,x| *x+=1), 2); + assert_eq!(*m.insert_or_update_with(1, 2, |_,x| *x+=1), 3); + } + #[test] fn test_pop() { let mut m = SmallIntMap::new(); diff --git a/src/libextra/treemap.rs b/src/libextra/treemap.rs index db5b12f021e5f..b4fc7c671fa52 100644 --- a/src/libextra/treemap.rs +++ b/src/libextra/treemap.rs @@ -16,6 +16,7 @@ use std::util::{swap, replace}; use std::iter::{Peekable}; use std::cmp::Ordering; +use std::cell::Cell; // This is implemented as an AA tree, which is a simplified variation of // a red-black tree where red (horizontal) nodes can only be added @@ -116,12 +117,41 @@ impl MutableMap for TreeMap { /// Insert a key-value pair from the map. If the key already had a value /// present in the map, that value is returned. Otherwise None is returned. - fn swap(&mut self, key: K, value: V) -> Option { - let ret = insert(&mut self.root, key, value); - if ret.is_none() { self.length += 1 } + fn swap(&mut self, k: K, v: V) -> Option { + let cell = Cell::new(v); + let mut ret = None; + insert_helper(&mut self.root, + k, + |_| { self.length += 1; cell.take() }, + |old| { ret = Some(replace(old, cell.take()))}, + |_| {}); ret } + + /// Return the value corresponding to the key in the map, or create, + /// insert, and return a new value if it doesn't exist. + fn find_or_insert_with<'a>(&'a mut self, k: K, f: &fn(&K) -> V) + -> (&'a K, &'a mut V) { + // since insert_helper needs to rebalance the tree on the + // way back up the stack, it can't safely hold a reference + // to the found or newly inserted node. Instead we will + // build a trail back to the node we want to find. + let mut trail = ~[]; + insert_helper(&mut self.root, k, + |k| { self.length += 1; f(k) }, + |_| {}, + |o| { trail.push(o) }); + let node = trail.rev_iter().fold(self.root.get_mut_ref(), |node, dir| { + match *dir { + Less => &mut node.left, + Greater => &mut node.right, + Equal => unreachable!(), + }.get_mut_ref() + }); + (&node.key, &mut node.value) + } + /// Removes a key from the map, returning the value at the key if the key /// was previously in the map. fn pop(&mut self, key: &K) -> Option { @@ -129,6 +159,10 @@ impl MutableMap for TreeMap { if ret.is_some() { self.length -= 1 } ret } + + /// Does nothing for this implementation. + fn reserve_at_least(&mut self, _: uint) { + } } impl TreeMap { @@ -694,18 +728,21 @@ fn mutate_values<'r, K: TotalOrd, V>(node: &'r mut Option<~TreeNode>, } // Remove left horizontal link by rotating right -fn skew(node: &mut ~TreeNode) { +fn skew(node: &mut ~TreeNode) -> bool { if node.left.as_ref().map_default(false, |x| x.level == node.level) { let mut save = node.left.take_unwrap(); swap(&mut node.left, &mut save.right); // save.right now None swap(node, &mut save); node.right = Some(save); + true + } else { + false } } // Remove dual horizontal link by rotating left and increasing level of // the parent -fn split(node: &mut ~TreeNode) { +fn split(node: &mut ~TreeNode) -> bool { if node.right.as_ref().map_default(false, |x| x.right.as_ref().map_default(false, |y| y.level == node.level)) { let mut save = node.right.take_unwrap(); @@ -713,6 +750,9 @@ fn split(node: &mut ~TreeNode) { save.level += 1; swap(node, &mut save); node.left = Some(save); + true + } else { + false } } @@ -731,33 +771,43 @@ fn find_mut<'r, K: TotalOrd, V>(node: &'r mut Option<~TreeNode>, } } -fn insert(node: &mut Option<~TreeNode>, - key: K, value: V) -> Option { +fn insert_helper(node: &mut Option<~TreeNode>, + key: K, + insert: &fn(&K) -> V, + update: &fn(&mut V), + build_trail: &fn(Ordering)) { match *node { - Some(ref mut save) => { - match key.cmp(&save.key) { - Less => { - let inserted = insert(&mut save.left, key, value); - skew(save); - split(save); - inserted - } - Greater => { - let inserted = insert(&mut save.right, key, value); - skew(save); - split(save); - inserted - } - Equal => { - save.key = key; - Some(replace(&mut save.value, value)) - } + Some(ref mut save) => { + match key.cmp(&save.key) { + Less => { + insert_helper(&mut save.left, key, insert, update, + |o| build_trail(o)); + if !skew(save) { + build_trail(Less); + } + if split(save) { + build_trail(Less); + } + } + Greater => { + insert_helper(&mut save.right, key, insert, update, + |o| build_trail(o)); + if skew(save) { + build_trail(Greater); + } + if !split(save) { + build_trail(Greater); + } + } + Equal => { + update(&mut save.value); + } + } + } + None => { + let value = insert(&key); + *node = Some(~TreeNode::new(key, value)); } - } - None => { - *node = Some(~TreeNode::new(key, value)); - None - } } } @@ -828,11 +878,11 @@ fn remove(node: &mut Option<~TreeNode>, for right in save.right.mut_iter() { skew(right); - for x in right.right.mut_iter() { skew(x) } + for x in right.right.mut_iter() { skew(x); } } split(save); - for x in save.right.mut_iter() { split(x) } + for x in save.right.mut_iter() { split(x); } } return ret; @@ -923,6 +973,47 @@ mod test_treemap { assert_eq!(m.find(&2).unwrap(), &11); } + #[test] + fn test_find_or_insert_with() { + let mut m = TreeMap::new(); + { + let (k, v) = m.find_or_insert_with(1, |_| 2); + assert_eq!((*k, *v), (1, 2)); + } + { + let (k, v) = m.find_or_insert_with(1, |_| 3); + assert_eq!((*k, *v), (1, 2)); + } + } + + #[test] + fn test_find_or_insert() { + let mut m = TreeMap::new(); + for i in range(0, 10) { + let (k, v) = m.find_or_insert(i, i + 1); + assert_eq!((*k, *v), (i, i + 1)) + } + for i in range(0, 10) { + let (k, v) = m.find_or_insert(-i, i + 1); + assert_eq!((*k, *v), (-i, i + 1)) + } + for i in range(0, 10) { + let (k, v) = m.find_or_insert(i, i + 2); + assert_eq!((*k, *v), (i, i + 1)) + } + for i in range(0, 10) { + let (k, v) = m.find_or_insert(-i, i + 2); + assert_eq!((*k, *v), (-i, i + 1)) + } + } + + #[test] + fn test_insert_or_update_with() { + let mut m = TreeMap::new(); + assert_eq!(*m.insert_or_update_with(1, 2, |_,x| *x+=1), 2); + assert_eq!(*m.insert_or_update_with(1, 2, |_,x| *x+=1), 3); + } + #[test] fn test_clear() { let mut m = TreeMap::new(); diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs index 6b46da0621127..4393ca759018d 100644 --- a/src/librustc/middle/dataflow.rs +++ b/src/librustc/middle/dataflow.rs @@ -208,7 +208,7 @@ impl DataFlowContext { fn compute_id_range(&mut self, id: ast::NodeId) -> (uint, uint) { let mut expanded = false; let len = self.nodeid_to_bitset.len(); - let n = do self.nodeid_to_bitset.find_or_insert_with(id) |_| { + let (_, n) = do self.nodeid_to_bitset.find_or_insert_with(id) |_| { expanded = true; len }; diff --git a/src/librustc/middle/typeck/check/regionmanip.rs b/src/librustc/middle/typeck/check/regionmanip.rs index ec11adbfa3dab..12aba520fdb46 100644 --- a/src/librustc/middle/typeck/check/regionmanip.rs +++ b/src/librustc/middle/typeck/check/regionmanip.rs @@ -36,7 +36,8 @@ pub fn replace_bound_regions_in_fn_sig( debug!("region r={}", r.to_str()); match r { ty::ReLateBound(s, br) if s == fn_sig.binder_id => { - *map.find_or_insert_with(br, |_| mapf(br)) + let (_, v) = map.find_or_insert_with(br, |_| mapf(br)); + *v } _ => r }}); diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 1b514f10af049..18b96af0b0cc0 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -491,7 +491,7 @@ impl DocFolder for Cache { clean::ImplItem(ref i) => { match i.trait_ { Some(clean::ResolvedPath{ id, _ }) => { - let v = do self.implementors.find_or_insert_with(id) |_|{ + let (_, v) = do self.implementors.find_or_insert_with(id) |_|{ ~[] }; match i.for_ { @@ -594,7 +594,7 @@ impl DocFolder for Cache { clean::Item{ attrs, inner: clean::ImplItem(i), _ } => { match i.for_ { clean::ResolvedPath { id, _ } => { - let v = do self.impls.find_or_insert_with(id) |_| { + let (_, v) = do self.impls.find_or_insert_with(id) |_| { ~[] }; // extract relevant documentation for this impl @@ -1607,7 +1607,7 @@ fn build_sidebar(m: &clean::Module) -> HashMap<~str, ~[~str]> { None => continue, Some(ref s) => s.to_owned(), }; - let v = map.find_or_insert_with(short.to_owned(), |_| ~[]); + let (_, v) = map.find_or_insert_with(short.to_owned(), |_| ~[]); v.push(myname); } diff --git a/src/libstd/container.rs b/src/libstd/container.rs index c91a53f966388..aeaee4df887ff 100644 --- a/src/libstd/container.rs +++ b/src/libstd/container.rs @@ -10,7 +10,9 @@ //! Container traits +use cell::Cell; use option::Option; +use util; /// A trait to represent the abstract idea of a container. The only concrete /// knowledge known is the number of elements contained within. @@ -63,7 +65,12 @@ pub trait MutableMap: Map + Mutable { /// Insert a key-value pair from the map. If the key already had a value /// present in the map, that value is returned. Otherwise None is returned. - fn swap(&mut self, k: K, v: V) -> Option; + #[inline] + fn swap(&mut self, k: K, v: V) -> Option { + let cell = Cell::new(v); + let (_, r) = self.find_or_insert_with(k, |_| cell.take()); + cell.take_opt().map(|v| util::replace(r, v)) + } /// Removes a key from the map, returning the value at the key if the key /// was previously in the map. @@ -71,6 +78,38 @@ pub trait MutableMap: Map + Mutable { /// Return a mutable reference to the value corresponding to the key fn find_mut<'a>(&'a mut self, key: &K) -> Option<&'a mut V>; + + /// Return the value corresponding to the key in the map, or insert + /// and return the value if it doesn't exist. + #[inline] + fn find_or_insert<'a>(&'a mut self, k: K, v: V) -> (&'a K, &'a mut V) { + let cell = Cell::new(v); + self.find_or_insert_with(k, |_| cell.take()) + } + + /// Return the value corresponding to the key in the map, or create, + /// insert, and return a new value if it doesn't exist. + fn find_or_insert_with<'a>(&'a mut self, k: K, f: &fn(&K) -> V) + -> (&'a K, &'a mut V); + + /// Insert a key-value pair into the map if the key is not already present. + /// Otherwise, modify the existing value for the key. + /// Returns the new or modified value for the key. + #[inline] + fn insert_or_update_with<'a>(&'a mut self, k: K, v: V, + f: &fn(&K, &mut V)) -> &'a mut V { + let cell = Cell::new(v); + let (k, v) = self.find_or_insert_with(k, |_| cell.take()); + if !cell.is_empty() { + f(k, v); + } + v + } + + /// Reserve space for at least `n` elements in the data structure + /// if applicable. Does nothing if not pre-allocating space doesn't + /// make sense for the underlying data structure. + fn reserve_at_least(&mut self, n: uint); } /// A set is a group of objects which are each distinct from one another. This diff --git a/src/libstd/hashmap.rs b/src/libstd/hashmap.rs index edefd39ebb4d1..34aa03e49c603 100644 --- a/src/libstd/hashmap.rs +++ b/src/libstd/hashmap.rs @@ -293,11 +293,10 @@ impl MutableMap for HashMap { Some(self.mut_value_for_bucket(idx)) } - /// Insert a key-value pair from the map. If the key already had a value - /// present in the map, that value is returned. Otherwise None is returned. - fn swap(&mut self, k: K, v: V) -> Option { - // this could be faster. - + /// Return the value corresponding to the key in the map, or create, + /// insert, and return a new value if it doesn't exist. + fn find_or_insert_with<'a>(&'a mut self, k: K, f: &fn(&K) -> V) + -> (&'a K, &'a mut V) { if self.size >= self.resize_at { // n.b.: We could also do this after searching, so // that we do not resize if this call to insert is @@ -309,7 +308,21 @@ impl MutableMap for HashMap { } let hash = k.hash_keyed(self.k0, self.k1) as uint; - self.insert_internal(hash, k, v) + let idx = match self.bucket_for_key_with_hash(hash, &k) { + TableFull => fail!("Internal logic error"), + FoundEntry(idx) => { idx } + FoundHole(idx) => { + let v = f(&k); + self.buckets[idx] = Some(Bucket{hash: hash, key: k, value: v}); + self.size += 1; + idx + } + }; + + match self.buckets[idx] { + Some(ref mut bkt) => (&bkt.key, &mut bkt.value), + None => unreachable!() + } } /// Removes a key from the map, returning the value at the key if the key @@ -318,6 +331,14 @@ impl MutableMap for HashMap { let hash = k.hash_keyed(self.k0, self.k1) as uint; self.pop_internal(hash, k) } + + /// Reserve space for at least `n` elements in the hash table. + fn reserve_at_least(&mut self, n: uint) { + if n > self.buckets.len() { + let buckets = n * 4 / 3 + 1; + self.resize(uint::next_power_of_two(buckets)); + } + } } impl HashMap { @@ -350,64 +371,6 @@ impl HashMap { } } - /// Reserve space for at least `n` elements in the hash table. - pub fn reserve_at_least(&mut self, n: uint) { - if n > self.buckets.len() { - let buckets = n * 4 / 3 + 1; - self.resize(uint::next_power_of_two(buckets)); - } - } - - /// Modify and return the value corresponding to the key in the map, or - /// insert and return a new value if it doesn't exist. - pub fn mangle<'a,A>(&'a mut self, k: K, a: A, not_found: &fn(&K, A) -> V, - found: &fn(&K, &mut V, A)) -> &'a mut V { - if self.size >= self.resize_at { - // n.b.: We could also do this after searching, so - // that we do not resize if this call to insert is - // simply going to update a key in place. My sense - // though is that it's worse to have to search through - // buckets to find the right spot twice than to just - // resize in this corner case. - self.expand(); - } - - let hash = k.hash_keyed(self.k0, self.k1) as uint; - let idx = match self.bucket_for_key_with_hash(hash, &k) { - TableFull => fail!("Internal logic error"), - FoundEntry(idx) => { found(&k, self.mut_value_for_bucket(idx), a); idx } - FoundHole(idx) => { - let v = not_found(&k, a); - self.buckets[idx] = Some(Bucket{hash: hash, key: k, value: v}); - self.size += 1; - idx - } - }; - - self.mut_value_for_bucket(idx) - } - - /// 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 { - self.mangle(k, v, |_k, a| a, |_k,_v,_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: &fn(&K) -> V) - -> &'a mut V { - self.mangle(k, (), |k,_a| f(k), |_k,_v,_a| ()) - } - - /// Insert a key-value pair into the map if the key is not already present. - /// Otherwise, modify the existing value for the key. - /// Returns the new or modified value for the key. - pub fn insert_or_update_with<'a>(&'a mut self, k: K, v: V, - f: &fn(&K, &mut V)) -> &'a mut V { - self.mangle(k, v, |_k,a| a, |k,v,_a| f(k,v)) - } - /// Retrieves a value for the given key, failing if the key is not /// present. pub fn get<'a>(&'a self, k: &K) -> &'a V { @@ -890,15 +853,27 @@ mod test_map { #[test] fn test_find_or_insert() { let mut m: HashMap = HashMap::new(); - assert_eq!(*m.find_or_insert(1, 2), 2); - assert_eq!(*m.find_or_insert(1, 3), 2); + { + let (k, v) = m.find_or_insert(1, 2); + assert_eq!((*k, *v), (1, 2)); + } + { + let (k, v) = m.find_or_insert(1, 3); + assert_eq!((*k, *v), (1, 2)); + } } #[test] fn test_find_or_insert_with() { let mut m: HashMap = HashMap::new(); - assert_eq!(*m.find_or_insert_with(1, |_| 2), 2); - assert_eq!(*m.find_or_insert_with(1, |_| 3), 2); + { + let (k, v) = m.find_or_insert_with(1, |_| 2); + assert_eq!((*k, *v), (1, 2)); + } + { + let (k, v) = m.find_or_insert_with(1, |_| 3); + assert_eq!((*k, *v), (1, 2)); + } } #[test] diff --git a/src/libstd/trie.rs b/src/libstd/trie.rs index c561fb6cc8a45..d23f08fc0f732 100644 --- a/src/libstd/trie.rs +++ b/src/libstd/trie.rs @@ -10,6 +10,7 @@ //! An ordered map and set for integer keys implemented as a radix trie +use cell::Cell; use prelude::*; use uint; use util::{swap, replace}; @@ -77,14 +78,13 @@ impl MutableMap for TrieMap { find_mut(&mut self.root.children[chunk(*key, 0)], *key, 1) } - /// Insert a key-value pair from the map. If the key already had a value - /// present in the map, that value is returned. Otherwise None is returned. - fn swap(&mut self, key: uint, value: T) -> Option { - let ret = insert(&mut self.root.count, - &mut self.root.children[chunk(key, 0)], - key, value, 1); - if ret.is_none() { self.length += 1 } - ret + /// Return the value corresponding to the key in the map, or create, + /// insert, and return a new value if it doesn't exist. + fn find_or_insert_with<'a>(&'a mut self, k: uint, f: &fn(&uint) -> T) + -> (&'a uint, &'a mut T) { + find_or_insert_with(&mut self.root.count, + &mut self.root.children[chunk(k, 0)], + k, |k| { self.length += 1; f(k) }, 1) } /// Removes a key from the map, returning the value at the key if the key @@ -96,6 +96,10 @@ impl MutableMap for TrieMap { if ret.is_some() { self.length -= 1 } ret } + + /// Does nothing for this implementation. + fn reserve_at_least(&mut self, _: uint) { + } } impl TrieMap { @@ -379,41 +383,45 @@ fn find_mut<'r, T>(child: &'r mut Child, key: uint, idx: uint) -> Option<&'r } } -fn insert(count: &mut uint, child: &mut Child, key: uint, value: T, - idx: uint) -> Option { +fn find_or_insert_with<'a, T>(count: &mut uint, child: &'a mut Child, + key: uint, f: &fn(&uint) -> T, idx: uint) -> (&'a uint, &'a mut T) { let mut tmp = Nothing; - let ret; - swap(&mut tmp, child); + swap(child, &mut tmp); *child = match tmp { - External(stored_key, stored_value) => { - if stored_key == key { - ret = Some(stored_value); - External(stored_key, value) - } else { - // conflict - split the node - let mut new = ~TrieNode::new(); - insert(&mut new.count, - &mut new.children[chunk(stored_key, idx)], - stored_key, stored_value, idx + 1); - ret = insert(&mut new.count, &mut new.children[chunk(key, idx)], - key, value, idx + 1); - Internal(new) - } - } - Internal(x) => { - let mut x = x; - ret = insert(&mut x.count, &mut x.children[chunk(key, idx)], key, - value, idx + 1); - Internal(x) - } - Nothing => { - *count += 1; - ret = None; - External(key, value) - } + Nothing => { + *count += 1; + External(key, f(&key)) + } + External(stored_key, stored_value) => { + if stored_key == key { + External(stored_key, stored_value) + } + else { + let mut new = ~TrieNode::new(); + let cell = Cell::new(stored_value); + find_or_insert_with(&mut new.count, + &mut new.children[chunk(stored_key, idx)], + stored_key, |_| cell.take(), idx + 1); + Internal(new) + } + } + Internal(node) => { + Internal(node) + } }; - return ret; + + match *child { + Internal(ref mut node) => { + find_or_insert_with(&mut node.count, + &mut node.children[chunk(key, idx)], + key, f, idx + 1) + } + External(ref stored_key, ref mut stored_value) => { + (stored_key, stored_value) + } + Nothing => unreachable!(), + } } fn remove(count: &mut uint, child: &mut Child, key: uint, @@ -660,6 +668,39 @@ mod test_map { assert_eq!(m.swap(1, 4), Some(3)); } + #[test] + fn test_find_or_insert() { + let mut m = TrieMap::new(); + { + let (k, v) = m.find_or_insert(1, 2); + assert_eq!((*k, *v), (1, 2)); + } + { + let (k, v) = m.find_or_insert(1, 3); + assert_eq!((*k, *v), (1, 2)); + } + } + + #[test] + fn test_find_or_insert_with() { + let mut m = TrieMap::new(); + { + let (k, v) = m.find_or_insert_with(1, |_| 2); + assert_eq!((*k, *v), (1, 2)); + } + { + let (k, v) = m.find_or_insert_with(1, |_| 3); + assert_eq!((*k, *v), (1, 2)); + } + } + + #[test] + fn test_insert_or_update_with() { + let mut m = TrieMap::new(); + assert_eq!(*m.insert_or_update_with(1, 2, |_,x| *x+=1), 2); + assert_eq!(*m.insert_or_update_with(1, 2, |_,x| *x+=1), 3); + } + #[test] fn test_pop() { let mut m = TrieMap::new(); diff --git a/src/test/run-pass/class-impl-very-parameterized-trait.rs b/src/test/run-pass/class-impl-very-parameterized-trait.rs index 918547a3a2bab..f0517e3111a9d 100644 --- a/src/test/run-pass/class-impl-very-parameterized-trait.rs +++ b/src/test/run-pass/class-impl-very-parameterized-trait.rs @@ -70,9 +70,11 @@ impl Map for cat { } impl MutableMap for cat { - fn insert(&mut self, k: int, _: T) -> bool { + fn find_or_insert_with<'a>(&'a mut self, k: int, f: &fn(&int) -> T) + -> (&'a int, &'a mut T) { + self.name = f(&k); self.meows += k; - true + (&self.meows, &mut self.name) } fn find_mut<'a>(&'a mut self, _k: &int) -> Option<&'a mut T> { fail!() } @@ -88,6 +90,9 @@ impl MutableMap for cat { fn pop(&mut self, _k: &int) -> Option { fail!() } fn swap(&mut self, _k: int, _v: T) -> Option { fail!() } + + fn reserve_at_least(&mut self, n: uint) { + } } impl cat {