diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index 27b10213ecd7c..bbf632d97fbdf 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -213,10 +213,32 @@ impl BTreeMap { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn get(&self, key: &Q) -> Option<&V> where K: Borrow, Q: Ord { + self.keyed_get(key).map(|x| x.1) + } + + /// Returns a reference to the key and the value corresponding to the key. + /// + /// The key may be any borrowed form of the map's key type, but the ordering + /// on the borrowed form *must* match the ordering on the key type. + /// + /// # Examples + /// + /// ``` + /// # #![feature(collection_keyed)] + /// use std::collections::BTreeMap; + /// + /// let mut map = BTreeMap::new(); + /// map.insert(1, "a"); + /// assert_eq!(map.keyed_get(&1), Some((&1, &"a"))); + /// assert_eq!(map.get(&2), None); + /// ``` + #[unstable(feature = "collection_keyed", + reason="keyed was recently added")] + pub fn keyed_get(&self, key: &Q) -> Option<(&K, &V)> where K: Borrow, Q: Ord { let mut cur_node = &self.root; loop { match Node::search(cur_node, key) { - Found(handle) => return Some(handle.into_kv().1), + Found(handle) => return Some(handle.into_kv()), GoDown(handle) => match handle.force() { Leaf(_) => return None, Internal(internal_handle) => { @@ -268,12 +290,42 @@ impl BTreeMap { // See `get` for implementation notes, this is basically a copy-paste with mut's added #[stable(feature = "rust1", since = "1.0.0")] pub fn get_mut(&mut self, key: &Q) -> Option<&mut V> where K: Borrow, Q: Ord { + self.keyed_get_mut(key).map(|x| x.1) + } + + /// Returns a mutable reference to the value corresponding to the key. + /// + /// The key may be any borrowed form of the map's key type, but the ordering + /// on the borrowed form *must* match the ordering on the key type. + /// + /// # Examples + /// + /// ``` + /// # #![feature(collection_keyed)] + /// use std::collections::BTreeMap; + /// + /// let mut map = BTreeMap::new(); + /// map.insert(1, "a"); + /// if let Some((key, x)) = map.keyed_get_mut(&1) { + /// assert_eq!(key, &1); + /// *x = "b"; + /// } + /// assert_eq!(map[&1], "b"); + /// ``` + // See `keyed_get` for implementation notes, this is basically a copy-paste with mut's added + #[unstable(feature = "collection_keyed", + reason="keyed was recently added")] + pub fn keyed_get_mut(&mut self, key: &Q) -> Option<(&K, &mut V)> where + K: Borrow, Q: Ord { // temp_node is a Borrowck hack for having a mutable value outlive a loop iteration let mut temp_node = &mut self.root; loop { let cur_node = temp_node; match Node::search(cur_node, key) { - Found(handle) => return Some(handle.into_kv_mut().1), + Found(handle) => { + let (key, value) = handle.into_kv_mut(); + return Some((&*key, value)); + }, GoDown(handle) => match handle.force() { Leaf(_) => return None, Internal(internal_handle) => { @@ -328,7 +380,31 @@ impl BTreeMap { /// assert_eq!(map[&37], "c"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn insert(&mut self, mut key: K, mut value: V) -> Option { + pub fn insert(&mut self, key: K, value: V) -> Option { + self.keyed_insert(key, value).map(|x| x.1) + } + + /// Inserts a key-value pair into the map. If the key already had a value + /// present in the map, that key and value are returned. Otherwise, + /// `None` is returned. + /// + /// # Examples + /// + /// ``` + /// # #![feature(collection_keyed)] + /// use std::collections::BTreeMap; + /// + /// let mut map = BTreeMap::new(); + /// assert_eq!(map.keyed_insert(37, "a"), None); + /// assert_eq!(map.is_empty(), false); + /// + /// map.insert(37, "b"); + /// assert_eq!(map.keyed_insert(37, "c"), Some((37, "b"))); + /// assert_eq!(map[&37], "c"); + /// ``` + #[unstable(feature = "collection_keyed", + reason="keyed was recently added")] + pub fn keyed_insert(&mut self, mut key: K, mut value: V) -> Option<(K, V)> { // This is a stack of rawptrs to nodes paired with indices, respectively // representing the nodes and edges of our search path. We have to store rawptrs // because as far as Rust is concerned, we can mutate aliased data with such a @@ -354,7 +430,8 @@ impl BTreeMap { Found(mut handle) => { // Perfect match, swap the values and return the old one mem::swap(handle.val_mut(), &mut value); - Finished(Some(value)) + mem::swap(handle.key_mut(), &mut key); + Finished(Some((key, value))) }, GoDown(handle) => { // We need to keep searching, try to get the search stack @@ -438,6 +515,30 @@ impl BTreeMap { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn remove(&mut self, key: &Q) -> Option where K: Borrow, Q: Ord { + self.keyed_remove(key).map(|x| x.1) + } + + /// Removes a key from the map, returning the key and the value at the key + /// if the key was previously in the map. + /// + /// The key may be any borrowed form of the map's key type, but the ordering + /// on the borrowed form *must* match the ordering on the key type. + /// + /// # Examples + /// + /// ``` + /// # #![feature(collection_keyed)] + /// use std::collections::BTreeMap; + /// + /// let mut map = BTreeMap::new(); + /// map.insert(1, "a"); + /// assert_eq!(map.keyed_remove(&1), Some((1, "a"))); + /// assert_eq!(map.keyed_remove(&1), None); + /// ``` + #[unstable(feature = "collection_keyed", + reason="keyed was recently added")] + pub fn keyed_remove(&mut self, key: &Q) -> Option<(K, V)> where + K: Borrow, Q: Ord { // See `swap` for a more thorough description of the stuff going on in here let mut stack = stack::PartialSearchStack::new(self); loop { @@ -445,7 +546,7 @@ impl BTreeMap { match Node::search(node, key) { Found(handle) => { // Perfect match. Terminate the stack here, and remove the entry - Finished(Some(pusher.seal(handle).remove())) + Finished(Some(pusher.seal(handle).keyed_remove())) }, GoDown(handle) => { // We need to keep searching, try to go down the next edge @@ -693,16 +794,16 @@ mod stack { impl<'a, K, V> SearchStack<'a, K, V, handle::KV, handle::Leaf> { /// Removes the key and value in the top element of the stack, then handles underflows as /// described in BTree's pop function. - fn remove_leaf(mut self) -> V { + fn remove_leaf(mut self) -> (K, V) { self.map.length -= 1; // Remove the key-value pair from the leaf that this search stack points to. // Then, note if the leaf is underfull, and promptly forget the leaf and its ptr // to avoid ownership issues. - let (value, mut underflow) = unsafe { - let (_, value) = self.top.from_raw_mut().remove_as_leaf(); + let (key, value, mut underflow) = unsafe { + let (key, value) = self.top.from_raw_mut().remove_as_leaf(); let underflow = self.top.from_raw().node().is_underfull(); - (value, underflow) + (key, value, underflow) }; loop { @@ -717,7 +818,7 @@ mod stack { self.map.depth -= 1; self.map.root.hoist_lone_child(); } - return value; + return (key, value); } Some(mut handle) => { if underflow { @@ -728,7 +829,7 @@ mod stack { } } else { // All done! - return value; + return (key, value); } } } @@ -740,6 +841,16 @@ mod stack { /// Removes the key and value in the top element of the stack, then handles underflows as /// described in BTree's pop function. pub fn remove(self) -> V { + // Ensure that the search stack goes to a leaf. This is necessary to perform deletion + // in a BTree. Note that this may put the tree in an inconsistent state (further + // described in into_leaf's comments), but this is immediately fixed by the + // removing the value we want to remove + self.into_leaf().remove_leaf().1 + } + + /// Removes the key and value in the top element of the stack, then handles underflows as + /// described in BTree's pop function. + pub fn keyed_remove(self) -> (K, V) { // Ensure that the search stack goes to a leaf. This is necessary to perform deletion // in a BTree. Note that this may put the tree in an inconsistent state (further // described in into_leaf's comments), but this is immediately fixed by the diff --git a/src/libcollections/vec_map.rs b/src/libcollections/vec_map.rs index 685bb5dc4b4f3..bb6076d152083 100644 --- a/src/libcollections/vec_map.rs +++ b/src/libcollections/vec_map.rs @@ -490,9 +490,29 @@ impl VecMap { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn get(&self, key: &usize) -> Option<&V> { + self.keyed_get(key).map(|x| x.1) + } + + /// Returns a reference to the key and the value corresponding to the key. + /// + /// # Examples + /// + /// ``` + /// # #![feature(vecmap)] + /// # #![feature(collection_keyed)] + /// use std::collections::VecMap; + /// + /// let mut map = VecMap::new(); + /// map.insert(1, "a"); + /// assert_eq!(map.keyed_get(&1), Some((&1, &"a"))); + /// assert_eq!(map.keyed_get(&2), None); + /// ``` + #[unstable(feature = "collection_keyed", + reason="keyed was recently added")] + pub fn keyed_get<'a>(&self, key: &'a usize) -> Option<(&'a usize, &V)> { if *key < self.v.len() { match self.v[*key] { - Some(ref value) => Some(value), + Some(ref value) => Some((key, value)), None => None } } else { @@ -536,9 +556,32 @@ impl VecMap { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn get_mut(&mut self, key: &usize) -> Option<&mut V> { + self.keyed_get_mut(key).map(|x| x.1) + } + + /// Returns a mutable reference to the value corresponding to the key. + /// + /// # Examples + /// + /// ``` + /// # #![feature(collection_keyed)] + /// # #![feature(vecmap)] + /// use std::collections::VecMap; + /// + /// let mut map = VecMap::new(); + /// map.insert(1, "a"); + /// if let Some((key, x)) = map.keyed_get_mut(&1) { + /// assert_eq!(key, &1); + /// *x = "b"; + /// } + /// assert_eq!(map[1], "b"); + /// ``` + #[unstable(feature = "collection_keyed", + reason="keyed was recently added")] + pub fn keyed_get_mut<'a>(&mut self, key: &'a usize) -> Option<(&'a usize, &mut V)> { if *key < self.v.len() { match *(&mut self.v[*key]) { - Some(ref mut value) => Some(value), + Some(ref mut value) => Some((key, value)), None => None } } else { @@ -565,11 +608,36 @@ impl VecMap { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn insert(&mut self, key: usize, value: V) -> Option { + self.keyed_insert(key, value).map(|x| x.1) + } + + /// Inserts a key-value pair into the map. If the key already had a value + /// present in the map, that key and value are returned. Otherwise, + /// `None` is returned. + /// + /// # Examples + /// + /// ``` + /// # #![feature(vecmap)] + /// # #![feature(collection_keyed)] + /// use std::collections::VecMap; + /// + /// let mut map = VecMap::new(); + /// assert_eq!(map.keyed_insert(37, "a"), None); + /// assert_eq!(map.is_empty(), false); + /// + /// map.insert(37, "b"); + /// assert_eq!(map.keyed_insert(37, "c"), Some((37, "b"))); + /// assert_eq!(map[37], "c"); + /// ``` + #[unstable(feature = "collection_keyed", + reason="keyed was recently added")] + pub fn keyed_insert(&mut self, key: usize, value: V) -> Option<(usize, V)> { let len = self.v.len(); if len <= key { self.v.extend((0..key - len + 1).map(|_| None)); } - replace(&mut self.v[key], Some(value)) + replace(&mut self.v[key], Some(value)).map(|x| (key, x)) } /// Removes a key from the map, returning the value at the key if the key @@ -588,11 +656,31 @@ impl VecMap { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn remove(&mut self, key: &usize) -> Option { + self.keyed_remove(key).map(|x| x.1) + } + + /// Removes a key from the map, returning the key and value at the key if + /// it was previously in the map. + /// + /// # Examples + /// + /// ``` + /// # #![feature(vecmap)] + /// # #![feature(collection_keyed)] + /// use std::collections::VecMap; + /// + /// let mut map = VecMap::new(); + /// map.insert(1, "a"); + /// assert_eq!(map.keyed_remove(&1), Some((1, "a"))); + /// assert_eq!(map.keyed_remove(&1), None); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn keyed_remove(&mut self, key: &usize) -> Option<(usize, V)> { if *key >= self.v.len() { return None; } let result = &mut self.v[*key]; - result.take() + result.take().map(|x| (*key, x)) } /// Gets the given key's corresponding entry in the map for in-place manipulation. diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 1dca3b77f3880..8ef3624c13a20 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -765,7 +765,7 @@ impl HashMap /// If the key already exists, the hashtable will be returned untouched /// and a reference to the existing element will be returned. fn insert_hashed_nocheck(&mut self, hash: SafeHash, k: K, v: V) -> &mut V { - self.insert_or_replace_with(hash, k, v, |_, _, _| ()) + self.insert_or_replace_with(hash, k, v, |_, _, _, _| ()) } fn insert_or_replace_with<'a, F>(&'a mut self, @@ -774,7 +774,7 @@ impl HashMap v: V, mut found_existing: F) -> &'a mut V where - F: FnMut(&mut K, &mut V, V), + F: FnMut(&mut K, K, &mut V, V), { // Worst case, we'll find one empty bucket among `size + 1` buckets. let size = self.table.size(); @@ -797,7 +797,7 @@ impl HashMap let (bucket_k, bucket_v) = bucket.into_mut_refs(); debug_assert!(k == *bucket_k); // Key already exists. Get its reference. - found_existing(bucket_k, bucket_v, v); + found_existing(bucket_k, k, bucket_v, v); return bucket_v; } } @@ -1024,6 +1024,31 @@ impl HashMap self.drain(); } + /// Returns a reference to the key and value value corresponding to the key. + /// + /// The key may be any borrowed form of the map's key type, but + /// `Hash` and `Eq` on the borrowed form *must* match those for + /// the key type. + /// + /// # Examples + /// + /// ``` + /// # #![feature(collection_keyed)] + /// use std::collections::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, "a"); + /// assert_eq!(map.keyed_get(&1), Some((&1, &"a"))); + /// assert_eq!(map.keyed_get(&2), None); + /// ``` + #[unstable(feature = "collection_keyed", + reason="keyed was recently added")] + pub fn keyed_get(&self, k: &Q) -> Option<(&K, &V)> + where K: Borrow, Q: Hash + Eq + { + self.search(k).map(|bucket| bucket.into_refs()) + } + /// Returns a reference to the value corresponding to the key. /// /// The key may be any borrowed form of the map's key type, but @@ -1044,7 +1069,7 @@ impl HashMap pub fn get(&self, k: &Q) -> Option<&V> where K: Borrow, Q: Hash + Eq { - self.search(k).map(|bucket| bucket.into_refs().1) + self.keyed_get(k).map(|x| x.1) } /// Returns true if the map contains a value for the specified key. @@ -1092,7 +1117,38 @@ impl HashMap pub fn get_mut(&mut self, k: &Q) -> Option<&mut V> where K: Borrow, Q: Hash + Eq { - self.search_mut(k).map(|bucket| bucket.into_mut_refs().1) + self.keyed_get_mut(k).map(|x| x.1) + } + + /// Returns a mutable reference to the value corresponding to the key. + /// + /// The key may be any borrowed form of the map's key type, but + /// `Hash` and `Eq` on the borrowed form *must* match those for + /// the key type. + /// + /// # Examples + /// + /// ``` + /// # #![feature(collection_keyed)] + /// use std::collections::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, "a"); + /// if let Some((key, x)) = map.keyed_get_mut(&1) { + /// assert_eq!(key, &1); + /// *x = "b"; + /// } + /// assert_eq!(map[&1], "b"); + /// ``` + #[unstable(feature = "collection_keyed", + reason="keyed was recently added")] + pub fn keyed_get_mut(&mut self, k: &Q) -> Option<(&K, &mut V)> + where K: Borrow, Q: Hash + Eq + { + self.search_mut(k).map(|bucket| { + let (k, v) = bucket.into_mut_refs(); + (&*k, v) + }) } /// Inserts a key-value pair into the map. If the key already had a value @@ -1113,12 +1169,36 @@ impl HashMap /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn insert(&mut self, k: K, v: V) -> Option { + self.keyed_insert(k, v).map(|x| x.1) + } + + /// Inserts a key-value pair into the map. If the key already had a value + /// present in the map, that old key and value are returned. Otherwise, + /// `None` is returned. + /// + /// # Examples + /// + /// ``` + /// # #![feature(collection_keyed)] + /// use std::collections::HashMap; + /// + /// let mut map = HashMap::new(); + /// assert_eq!(map.keyed_insert(37, "a"), None); + /// assert_eq!(map.is_empty(), false); + /// + /// map.insert(37, "b"); + /// assert_eq!(map.keyed_insert(37, "c"), Some((37, "b"))); + /// assert_eq!(map[&37], "c"); + /// ``` + #[unstable(feature = "collection_keyed", + reason="keyed was recently added")] + pub fn keyed_insert(&mut self, k: K, v: V) -> Option<(K, V)> { let hash = self.make_hash(&k); self.reserve(1); let mut retval = None; - self.insert_or_replace_with(hash, k, v, |_, val_ref, val| { - retval = Some(replace(val_ref, val)); + self.insert_or_replace_with(hash, k, v, |key_ref, key, val_ref, val| { + retval = Some((replace(key_ref, key), replace(val_ref, val))); }); retval } @@ -1143,12 +1223,38 @@ impl HashMap #[stable(feature = "rust1", since = "1.0.0")] pub fn remove(&mut self, k: &Q) -> Option where K: Borrow, Q: Hash + Eq + { + self.keyed_remove(k).map(|x| x.1) + } + + /// Removes a key from the map, returning the key and the value at the key + /// if the key was previously in the map. + /// + /// The key may be any borrowed form of the map's key type, but + /// `Hash` and `Eq` on the borrowed form *must* match those for + /// the key type. + /// + /// # Examples + /// + /// ``` + /// # #![feature(collection_keyed)] + /// use std::collections::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, "a"); + /// assert_eq!(map.keyed_remove(&1), Some((1, "a"))); + /// assert_eq!(map.keyed_remove(&1), None); + /// ``` + #[unstable(feature = "collection_keyed", + reason="keyed was recently added")] + pub fn keyed_remove(&mut self, k: &Q) -> Option<(K, V)> + where K: Borrow, Q: Hash + Eq { if self.table.size() == 0 { return None } - self.search_mut(k).map(|bucket| pop_internal(bucket).1) + self.search_mut(k).map(|bucket| pop_internal(bucket)) } } diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index ba50b156ab230..fce3bc38a4adf 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -454,6 +454,25 @@ impl HashSet self.map.contains_key(value) } + /// Gets a value from a set. + /// + /// # Examples + /// + /// ``` + /// # #![feature(collection_keyed)] + /// use std::collections::HashSet; + /// + /// let mut set = HashSet::new(); + /// + /// assert_eq!(set.insert(2), true); + /// assert_eq!(set.get(&2), Some(&2)); + /// ``` + #[unstable(feature = "collection_keyed", + reason="keyed was recently added")] + pub fn get(&mut self, value: &T) -> Option<&T> { + self.map.keyed_get(value).map(|x| x.0) + } + /// Returns `true` if the set has no elements in common with `other`. /// This is equivalent to checking for an empty intersection. /// @@ -539,6 +558,27 @@ impl HashSet #[stable(feature = "rust1", since = "1.0.0")] pub fn insert(&mut self, value: T) -> bool { self.map.insert(value, ()).is_none() } + /// Adds a value to the set. Returns the value that was already in the set, + /// if any. + /// + /// # Examples + /// + /// ``` + /// # #![feature(collection_keyed)] + /// use std::collections::HashSet; + /// + /// let mut set = HashSet::new(); + /// + /// assert_eq!(set.insert_item(2), None); + /// assert_eq!(set.insert_item(2), Some(2)); + /// assert_eq!(set.len(), 1); + /// ``` + #[unstable(feature = "collection_keyed", + reason="keyed was recently added")] + pub fn insert_item(&mut self, value: T) -> Option { + self.map.keyed_insert(value, ()).map(|x| x.0) + } + /// Removes a value from the set. Returns `true` if the value was /// present in the set. /// @@ -563,6 +603,33 @@ impl HashSet { self.map.remove(value).is_some() } + + /// Removes a value from the set. Returns the value if it was + /// present in the set. + /// + /// The value may be any borrowed form of the set's value type, but + /// `Hash` and `Eq` on the borrowed form *must* match those for + /// the value type. + /// + /// # Examples + /// + /// ``` + /// # #![feature(collection_keyed)] + /// use std::collections::HashSet; + /// + /// let mut set = HashSet::new(); + /// + /// set.insert(2); + /// assert_eq!(set.remove_item(&2), Some(2)); + /// assert_eq!(set.remove_item(&2), None); + /// ``` + #[unstable(feature = "collection_keyed", + reason="keyed was recently added")] + pub fn remove_item(&mut self, value: &Q) -> Option + where T: Borrow, Q: Hash + Eq + { + self.map.keyed_remove(value).map(|x| x.0) + } } #[stable(feature = "rust1", since = "1.0.0")]