Skip to content

Commit 3108900

Browse files
committed
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
1 parent 288edec commit 3108900

File tree

4 files changed

+200
-8
lines changed

4 files changed

+200
-8
lines changed

src/libcollections/btree/map.rs

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -312,8 +312,12 @@ impl<K: Ord, V> BTreeMap<K, V> {
312312
// 2) While ODS may potentially return the pair we *just* inserted after
313313
// the split, we will never do this. Again, this shouldn't effect the analysis.
314314

315-
/// Inserts a key-value pair into the map. If the key already had a value
316-
/// present in the map, that value is returned. Otherwise, `None` is returned.
315+
/// Inserts a key-value pair into the map.
316+
///
317+
/// If the map did not have this key present, `None` is returned.
318+
///
319+
/// If the map did have this key present, that value is returned, and the
320+
/// entry is not updated. See the examples below for more.
317321
///
318322
/// # Examples
319323
///
@@ -328,6 +332,50 @@ impl<K: Ord, V> BTreeMap<K, V> {
328332
/// assert_eq!(map.insert(37, "c"), Some("b"));
329333
/// assert_eq!(map[&37], "c");
330334
/// ```
335+
///
336+
/// If we have a more complex key, calls to `insert()` will
337+
/// not update the value of the key. For example:
338+
///
339+
/// ```
340+
/// use std::cmp::Ordering;
341+
/// use std::collections::BTreeMap;
342+
/// use std::hash::{Hash, Hasher};
343+
///
344+
/// #[derive(Debug)]
345+
/// struct Foo {
346+
/// a: u32,
347+
/// b: &'static str,
348+
/// }
349+
///
350+
/// // we will compare `Foo`s by their `a` value only.
351+
/// impl PartialEq for Foo {
352+
/// fn eq(&self, other: &Self) -> bool { self.a == other.a }
353+
/// }
354+
///
355+
/// impl Eq for Foo {}
356+
///
357+
/// // we will hash `Foo`s by their `a` value only.
358+
/// impl Hash for Foo {
359+
/// fn hash<H: Hasher>(&self, h: &mut H) { self.a.hash(h); }
360+
/// }
361+
///
362+
/// impl PartialOrd for Foo {
363+
/// fn partial_cmp(&self, other: &Self) -> Option<Ordering> { self.a.partial_cmp(&other.a) }
364+
/// }
365+
///
366+
/// impl Ord for Foo {
367+
/// fn cmp(&self, other: &Self) -> Ordering { self.a.cmp(&other.a) }
368+
/// }
369+
///
370+
/// let mut map = BTreeMap::new();
371+
/// map.insert(Foo { a: 1, b: "baz" }, ());
372+
///
373+
/// // We already have a Foo with an a of 1, so this will be updating the value.
374+
/// map.insert(Foo { a: 1, b: "xyz" }, ());
375+
///
376+
/// // ... but the key hasn't changed. b is still "baz", not "xyz"
377+
/// assert_eq!(map.keys().next().unwrap().b, "baz");
378+
/// ```
331379
#[stable(feature = "rust1", since = "1.0.0")]
332380
pub fn insert(&mut self, mut key: K, mut value: V) -> Option<V> {
333381
// This is a stack of rawptrs to nodes paired with indices, respectively

src/libcollections/btree/set.rs

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -417,8 +417,12 @@ impl<T: Ord> BTreeSet<T> {
417417
other.is_subset(self)
418418
}
419419

420-
/// Adds a value to the set. Returns `true` if the value was not already
421-
/// present in the set.
420+
/// Adds a value to the set.
421+
///
422+
/// If the set did not have a value present, `true` is returned.
423+
///
424+
/// If the set already had a value present, that value is
425+
/// returned, and the entry is not updated. See the examples below for more.
422426
///
423427
/// # Examples
424428
///
@@ -431,6 +435,50 @@ impl<T: Ord> BTreeSet<T> {
431435
/// assert_eq!(set.insert(2), false);
432436
/// assert_eq!(set.len(), 1);
433437
/// ```
438+
///
439+
/// If we have a more complex key, calls to `insert()` will
440+
/// not update the value of the key. For example:
441+
///
442+
/// ```
443+
/// use std::cmp::Ordering;
444+
/// use std::collections::BTreeSet;
445+
/// use std::hash::{Hash, Hasher};
446+
///
447+
/// #[derive(Debug)]
448+
/// struct Foo {
449+
/// a: u32,
450+
/// b: &'static str,
451+
/// }
452+
///
453+
/// // we will compare `Foo`s by their `a` value only.
454+
/// impl PartialEq for Foo {
455+
/// fn eq(&self, other: &Self) -> bool { self.a == other.a }
456+
/// }
457+
///
458+
/// impl Eq for Foo {}
459+
///
460+
/// // we will hash `Foo`s by their `a` value only.
461+
/// impl Hash for Foo {
462+
/// fn hash<H: Hasher>(&self, h: &mut H) { self.a.hash(h); }
463+
/// }
464+
///
465+
/// impl PartialOrd for Foo {
466+
/// fn partial_cmp(&self, other: &Self) -> Option<Ordering> { self.a.partial_cmp(&other.a) }
467+
/// }
468+
///
469+
/// impl Ord for Foo {
470+
/// fn cmp(&self, other: &Self) -> Ordering { self.a.cmp(&other.a) }
471+
/// }
472+
///
473+
/// let mut set = BTreeSet::new();
474+
/// set.insert(Foo { a: 1, b: "baz" });
475+
///
476+
/// // We already have a Foo with an a of 1, so this will be updating the value.
477+
/// set.insert(Foo { a: 1, b: "xyz" });
478+
///
479+
/// // ... but the key hasn't changed. b is still "baz", not "xyz"
480+
/// assert_eq!(set.iter().next().unwrap().b, "baz");
481+
/// ```
434482
#[stable(feature = "rust1", since = "1.0.0")]
435483
pub fn insert(&mut self, value: T) -> bool {
436484
self.map.insert(value, ()).is_none()

src/libstd/collections/hash/map.rs

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1101,8 +1101,12 @@ impl<K, V, S> HashMap<K, V, S>
11011101
self.search_mut(k).map(|bucket| bucket.into_mut_refs().1)
11021102
}
11031103

1104-
/// Inserts a key-value pair into the map. If the key already had a value
1105-
/// present in the map, that value is returned. Otherwise, `None` is returned.
1104+
/// Inserts a key-value pair into the map.
1105+
///
1106+
/// If the map did not have this key present, `None` is returned.
1107+
///
1108+
/// If the map did have this key present, that value is returned, and the
1109+
/// entry is not updated. See the examples below for more.
11061110
///
11071111
/// # Examples
11081112
///
@@ -1117,6 +1121,50 @@ impl<K, V, S> HashMap<K, V, S>
11171121
/// assert_eq!(map.insert(37, "c"), Some("b"));
11181122
/// assert_eq!(map[&37], "c");
11191123
/// ```
1124+
///
1125+
/// If we have a more complex key, calls to `insert()` will
1126+
/// not update the value of the key. For example:
1127+
///
1128+
/// ```
1129+
/// use std::cmp::Ordering;
1130+
/// use std::collections::HashMap;
1131+
/// use std::hash::{Hash, Hasher};
1132+
///
1133+
/// #[derive(Debug)]
1134+
/// struct Foo {
1135+
/// a: u32,
1136+
/// b: &'static str,
1137+
/// }
1138+
///
1139+
/// // we will compare `Foo`s by their `a` value only.
1140+
/// impl PartialEq for Foo {
1141+
/// fn eq(&self, other: &Self) -> bool { self.a == other.a }
1142+
/// }
1143+
///
1144+
/// impl Eq for Foo {}
1145+
///
1146+
/// // we will hash `Foo`s by their `a` value only.
1147+
/// impl Hash for Foo {
1148+
/// fn hash<H: Hasher>(&self, h: &mut H) { self.a.hash(h); }
1149+
/// }
1150+
///
1151+
/// impl PartialOrd for Foo {
1152+
/// fn partial_cmp(&self, other: &Self) -> Option<Ordering> { self.a.partial_cmp(&other.a) }
1153+
/// }
1154+
///
1155+
/// impl Ord for Foo {
1156+
/// fn cmp(&self, other: &Self) -> Ordering { self.a.cmp(&other.a) }
1157+
/// }
1158+
///
1159+
/// let mut map = HashMap::new();
1160+
/// map.insert(Foo { a: 1, b: "baz" }, ());
1161+
///
1162+
/// // We already have a Foo with an a of 1, so this will be updating the value.
1163+
/// map.insert(Foo { a: 1, b: "xyz" }, ());
1164+
///
1165+
/// // ... but the key hasn't changed. b is still "baz", not "xyz"
1166+
/// assert_eq!(map.keys().next().unwrap().b, "baz");
1167+
/// ```
11201168
#[stable(feature = "rust1", since = "1.0.0")]
11211169
pub fn insert(&mut self, k: K, v: V) -> Option<V> {
11221170
let hash = self.make_hash(&k);

src/libstd/collections/hash/set.rs

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -527,8 +527,12 @@ impl<T, S> HashSet<T, S>
527527
other.is_subset(self)
528528
}
529529

530-
/// Adds a value to the set. Returns `true` if the value was not already
531-
/// present in the set.
530+
/// Adds a value to the set.
531+
///
532+
/// If the set did not have a value present, `true` is returned.
533+
///
534+
/// If the set already had a value present, that value is
535+
/// returned, and the entry is not updated. See the examples below for more.
532536
///
533537
/// # Examples
534538
///
@@ -541,6 +545,50 @@ impl<T, S> HashSet<T, S>
541545
/// assert_eq!(set.insert(2), false);
542546
/// assert_eq!(set.len(), 1);
543547
/// ```
548+
///
549+
/// If we have a more complex key, calls to `insert()` will
550+
/// not update the value of the key. For example:
551+
///
552+
/// ```
553+
/// use std::cmp::Ordering;
554+
/// use std::collections::HashSet;
555+
/// use std::hash::{Hash, Hasher};
556+
///
557+
/// #[derive(Debug)]
558+
/// struct Foo {
559+
/// a: u32,
560+
/// b: &'static str,
561+
/// }
562+
///
563+
/// // we will compare `Foo`s by their `a` value only.
564+
/// impl PartialEq for Foo {
565+
/// fn eq(&self, other: &Self) -> bool { self.a == other.a }
566+
/// }
567+
///
568+
/// impl Eq for Foo {}
569+
///
570+
/// // we will hash `Foo`s by their `a` value only.
571+
/// impl Hash for Foo {
572+
/// fn hash<H: Hasher>(&self, h: &mut H) { self.a.hash(h); }
573+
/// }
574+
///
575+
/// impl PartialOrd for Foo {
576+
/// fn partial_cmp(&self, other: &Self) -> Option<Ordering> { self.a.partial_cmp(&other.a) }
577+
/// }
578+
///
579+
/// impl Ord for Foo {
580+
/// fn cmp(&self, other: &Self) -> Ordering { self.a.cmp(&other.a) }
581+
/// }
582+
///
583+
/// let mut set = HashSet::new();
584+
/// set.insert(Foo { a: 1, b: "baz" });
585+
///
586+
/// // We already have a Foo with an a of 1, so this will be updating the value.
587+
/// set.insert(Foo { a: 1, b: "xyz" });
588+
///
589+
/// // ... but the key hasn't changed. b is still "baz", not "xyz"
590+
/// assert_eq!(set.iter().next().unwrap().b, "baz");
591+
/// ```
544592
#[stable(feature = "rust1", since = "1.0.0")]
545593
pub fn insert(&mut self, value: T) -> bool { self.map.insert(value, ()).is_none() }
546594

0 commit comments

Comments
 (0)