Skip to content

Commit

Permalink
Document replacement behavior in some collections
Browse files Browse the repository at this point in the history
{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
  • Loading branch information
steveklabnik committed Aug 18, 2015
1 parent 288edec commit 3108900
Show file tree
Hide file tree
Showing 4 changed files with 200 additions and 8 deletions.
52 changes: 50 additions & 2 deletions src/libcollections/btree/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,8 +312,12 @@ impl<K: Ord, V> BTreeMap<K, V> {
// 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
///
Expand All @@ -328,6 +332,50 @@ impl<K: Ord, V> BTreeMap<K, V> {
/// 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<H: Hasher>(&self, h: &mut H) { self.a.hash(h); }
/// }
///
/// impl PartialOrd for Foo {
/// fn partial_cmp(&self, other: &Self) -> Option<Ordering> { 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<V> {
// This is a stack of rawptrs to nodes paired with indices, respectively
Expand Down
52 changes: 50 additions & 2 deletions src/libcollections/btree/set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -417,8 +417,12 @@ impl<T: Ord> BTreeSet<T> {
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
///
Expand All @@ -431,6 +435,50 @@ impl<T: Ord> BTreeSet<T> {
/// 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<H: Hasher>(&self, h: &mut H) { self.a.hash(h); }
/// }
///
/// impl PartialOrd for Foo {
/// fn partial_cmp(&self, other: &Self) -> Option<Ordering> { 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()
Expand Down
52 changes: 50 additions & 2 deletions src/libstd/collections/hash/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1101,8 +1101,12 @@ impl<K, V, S> HashMap<K, V, S>
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
///
Expand All @@ -1117,6 +1121,50 @@ impl<K, V, S> HashMap<K, V, S>
/// 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<H: Hasher>(&self, h: &mut H) { self.a.hash(h); }
/// }
///
/// impl PartialOrd for Foo {
/// fn partial_cmp(&self, other: &Self) -> Option<Ordering> { 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<V> {
let hash = self.make_hash(&k);
Expand Down
52 changes: 50 additions & 2 deletions src/libstd/collections/hash/set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -527,8 +527,12 @@ impl<T, S> HashSet<T, S>
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
///
Expand All @@ -541,6 +545,50 @@ impl<T, S> HashSet<T, S>
/// 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<H: Hasher>(&self, h: &mut H) { self.a.hash(h); }
/// }
///
/// impl PartialOrd for Foo {
/// fn partial_cmp(&self, other: &Self) -> Option<Ordering> { 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() }

Expand Down

0 comments on commit 3108900

Please sign in to comment.