From 31089008eb3802939ca4700d2cd15f63d4e534c9 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Tue, 18 Aug 2015 18:38:07 -0400 Subject: [PATCH] Document replacement behavior in some collections {BTree,Hash}{Map,Set} will not update their key if it already exists, which can matter with more complex keys. This behavior is now documented. Fixes #26888 --- src/libcollections/btree/map.rs | 52 ++++++++++++++++++++++++++++-- src/libcollections/btree/set.rs | 52 ++++++++++++++++++++++++++++-- src/libstd/collections/hash/map.rs | 52 ++++++++++++++++++++++++++++-- src/libstd/collections/hash/set.rs | 52 ++++++++++++++++++++++++++++-- 4 files changed, 200 insertions(+), 8 deletions(-) diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index 2835e28a9462c..0bb3a3ff24ec3 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -312,8 +312,12 @@ impl BTreeMap { // 2) While ODS may potentially return the pair we *just* inserted after // the split, we will never do this. Again, this shouldn't effect the analysis. - /// Inserts a key-value pair into the map. If the key already had a value - /// present in the map, that value is returned. Otherwise, `None` is returned. + /// Inserts a key-value pair into the map. + /// + /// If the map did not have this key present, `None` is returned. + /// + /// If the map did have this key present, that value is returned, and the + /// entry is not updated. See the examples below for more. /// /// # Examples /// @@ -328,6 +332,50 @@ impl BTreeMap { /// assert_eq!(map.insert(37, "c"), Some("b")); /// assert_eq!(map[&37], "c"); /// ``` + /// + /// If we have a more complex key, calls to `insert()` will + /// not update the value of the key. For example: + /// + /// ``` + /// use std::cmp::Ordering; + /// use std::collections::BTreeMap; + /// use std::hash::{Hash, Hasher}; + /// + /// #[derive(Debug)] + /// struct Foo { + /// a: u32, + /// b: &'static str, + /// } + /// + /// // we will compare `Foo`s by their `a` value only. + /// impl PartialEq for Foo { + /// fn eq(&self, other: &Self) -> bool { self.a == other.a } + /// } + /// + /// impl Eq for Foo {} + /// + /// // we will hash `Foo`s by their `a` value only. + /// impl Hash for Foo { + /// fn hash(&self, h: &mut H) { self.a.hash(h); } + /// } + /// + /// impl PartialOrd for Foo { + /// fn partial_cmp(&self, other: &Self) -> Option { self.a.partial_cmp(&other.a) } + /// } + /// + /// impl Ord for Foo { + /// fn cmp(&self, other: &Self) -> Ordering { self.a.cmp(&other.a) } + /// } + /// + /// let mut map = BTreeMap::new(); + /// map.insert(Foo { a: 1, b: "baz" }, ()); + /// + /// // We already have a Foo with an a of 1, so this will be updating the value. + /// map.insert(Foo { a: 1, b: "xyz" }, ()); + /// + /// // ... but the key hasn't changed. b is still "baz", not "xyz" + /// assert_eq!(map.keys().next().unwrap().b, "baz"); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn insert(&mut self, mut key: K, mut value: V) -> Option { // This is a stack of rawptrs to nodes paired with indices, respectively diff --git a/src/libcollections/btree/set.rs b/src/libcollections/btree/set.rs index a942d6aa6696a..b927e43531fc4 100644 --- a/src/libcollections/btree/set.rs +++ b/src/libcollections/btree/set.rs @@ -417,8 +417,12 @@ impl BTreeSet { other.is_subset(self) } - /// Adds a value to the set. Returns `true` if the value was not already - /// present in the set. + /// Adds a value to the set. + /// + /// If the set did not have a value present, `true` is returned. + /// + /// If the set already had a value present, that value is + /// returned, and the entry is not updated. See the examples below for more. /// /// # Examples /// @@ -431,6 +435,50 @@ impl BTreeSet { /// assert_eq!(set.insert(2), false); /// assert_eq!(set.len(), 1); /// ``` + /// + /// If we have a more complex key, calls to `insert()` will + /// not update the value of the key. For example: + /// + /// ``` + /// use std::cmp::Ordering; + /// use std::collections::BTreeSet; + /// use std::hash::{Hash, Hasher}; + /// + /// #[derive(Debug)] + /// struct Foo { + /// a: u32, + /// b: &'static str, + /// } + /// + /// // we will compare `Foo`s by their `a` value only. + /// impl PartialEq for Foo { + /// fn eq(&self, other: &Self) -> bool { self.a == other.a } + /// } + /// + /// impl Eq for Foo {} + /// + /// // we will hash `Foo`s by their `a` value only. + /// impl Hash for Foo { + /// fn hash(&self, h: &mut H) { self.a.hash(h); } + /// } + /// + /// impl PartialOrd for Foo { + /// fn partial_cmp(&self, other: &Self) -> Option { self.a.partial_cmp(&other.a) } + /// } + /// + /// impl Ord for Foo { + /// fn cmp(&self, other: &Self) -> Ordering { self.a.cmp(&other.a) } + /// } + /// + /// let mut set = BTreeSet::new(); + /// set.insert(Foo { a: 1, b: "baz" }); + /// + /// // We already have a Foo with an a of 1, so this will be updating the value. + /// set.insert(Foo { a: 1, b: "xyz" }); + /// + /// // ... but the key hasn't changed. b is still "baz", not "xyz" + /// assert_eq!(set.iter().next().unwrap().b, "baz"); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn insert(&mut self, value: T) -> bool { self.map.insert(value, ()).is_none() diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index d5638bdac6912..31ff61ba8ae87 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1101,8 +1101,12 @@ impl HashMap self.search_mut(k).map(|bucket| bucket.into_mut_refs().1) } - /// Inserts a key-value pair into the map. If the key already had a value - /// present in the map, that value is returned. Otherwise, `None` is returned. + /// Inserts a key-value pair into the map. + /// + /// If the map did not have this key present, `None` is returned. + /// + /// If the map did have this key present, that value is returned, and the + /// entry is not updated. See the examples below for more. /// /// # Examples /// @@ -1117,6 +1121,50 @@ impl HashMap /// assert_eq!(map.insert(37, "c"), Some("b")); /// assert_eq!(map[&37], "c"); /// ``` + /// + /// If we have a more complex key, calls to `insert()` will + /// not update the value of the key. For example: + /// + /// ``` + /// use std::cmp::Ordering; + /// use std::collections::HashMap; + /// use std::hash::{Hash, Hasher}; + /// + /// #[derive(Debug)] + /// struct Foo { + /// a: u32, + /// b: &'static str, + /// } + /// + /// // we will compare `Foo`s by their `a` value only. + /// impl PartialEq for Foo { + /// fn eq(&self, other: &Self) -> bool { self.a == other.a } + /// } + /// + /// impl Eq for Foo {} + /// + /// // we will hash `Foo`s by their `a` value only. + /// impl Hash for Foo { + /// fn hash(&self, h: &mut H) { self.a.hash(h); } + /// } + /// + /// impl PartialOrd for Foo { + /// fn partial_cmp(&self, other: &Self) -> Option { self.a.partial_cmp(&other.a) } + /// } + /// + /// impl Ord for Foo { + /// fn cmp(&self, other: &Self) -> Ordering { self.a.cmp(&other.a) } + /// } + /// + /// let mut map = HashMap::new(); + /// map.insert(Foo { a: 1, b: "baz" }, ()); + /// + /// // We already have a Foo with an a of 1, so this will be updating the value. + /// map.insert(Foo { a: 1, b: "xyz" }, ()); + /// + /// // ... but the key hasn't changed. b is still "baz", not "xyz" + /// assert_eq!(map.keys().next().unwrap().b, "baz"); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn insert(&mut self, k: K, v: V) -> Option { let hash = self.make_hash(&k); diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index ccad088a2982f..6acd349e8c798 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -527,8 +527,12 @@ impl HashSet other.is_subset(self) } - /// Adds a value to the set. Returns `true` if the value was not already - /// present in the set. + /// Adds a value to the set. + /// + /// If the set did not have a value present, `true` is returned. + /// + /// If the set already had a value present, that value is + /// returned, and the entry is not updated. See the examples below for more. /// /// # Examples /// @@ -541,6 +545,50 @@ impl HashSet /// assert_eq!(set.insert(2), false); /// assert_eq!(set.len(), 1); /// ``` + /// + /// If we have a more complex key, calls to `insert()` will + /// not update the value of the key. For example: + /// + /// ``` + /// use std::cmp::Ordering; + /// use std::collections::HashSet; + /// use std::hash::{Hash, Hasher}; + /// + /// #[derive(Debug)] + /// struct Foo { + /// a: u32, + /// b: &'static str, + /// } + /// + /// // we will compare `Foo`s by their `a` value only. + /// impl PartialEq for Foo { + /// fn eq(&self, other: &Self) -> bool { self.a == other.a } + /// } + /// + /// impl Eq for Foo {} + /// + /// // we will hash `Foo`s by their `a` value only. + /// impl Hash for Foo { + /// fn hash(&self, h: &mut H) { self.a.hash(h); } + /// } + /// + /// impl PartialOrd for Foo { + /// fn partial_cmp(&self, other: &Self) -> Option { self.a.partial_cmp(&other.a) } + /// } + /// + /// impl Ord for Foo { + /// fn cmp(&self, other: &Self) -> Ordering { self.a.cmp(&other.a) } + /// } + /// + /// let mut set = HashSet::new(); + /// set.insert(Foo { a: 1, b: "baz" }); + /// + /// // We already have a Foo with an a of 1, so this will be updating the value. + /// set.insert(Foo { a: 1, b: "xyz" }); + /// + /// // ... but the key hasn't changed. b is still "baz", not "xyz" + /// assert_eq!(set.iter().next().unwrap().b, "baz"); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn insert(&mut self, value: T) -> bool { self.map.insert(value, ()).is_none() }