Skip to content

Commit fb57217

Browse files
committed
Make insert_unique_unchecked unsafe
This is in line with the standard library guarantees that it should be impossible to create an inconsistent `HashMap` with well-defined key types.
1 parent f01e271 commit fb57217

File tree

3 files changed

+37
-23
lines changed

3 files changed

+37
-23
lines changed

benches/insert_unique_unchecked.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ fn insert_unique_unchecked(b: &mut Bencher) {
2525
b.iter(|| {
2626
let mut m = HashMap::with_capacity(1000);
2727
for k in &keys {
28-
m.insert_unique_unchecked(k, k);
28+
unsafe {
29+
m.insert_unique_unchecked(k, k);
30+
}
2931
}
3032
m
3133
});

src/map.rs

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1761,8 +1761,17 @@ where
17611761
/// Insert a key-value pair into the map without checking
17621762
/// if the key already exists in the map.
17631763
///
1764+
/// This operation is faster than regular insert, because it does not perform
1765+
/// lookup before insertion.
1766+
///
1767+
/// This operation is useful during initial population of the map.
1768+
/// For example, when constructing a map from another map, we know
1769+
/// that keys are unique.
1770+
///
17641771
/// Returns a reference to the key and value just inserted.
17651772
///
1773+
/// # Safety
1774+
///
17661775
/// This operation is safe if a key does not exist in the map.
17671776
///
17681777
/// However, if a key exists in the map already, the behavior is unspecified:
@@ -1772,12 +1781,9 @@ where
17721781
/// That said, this operation (and following operations) are guaranteed to
17731782
/// not violate memory safety.
17741783
///
1775-
/// This operation is faster than regular insert, because it does not perform
1776-
/// lookup before insertion.
1777-
///
1778-
/// This operation is useful during initial population of the map.
1779-
/// For example, when constructing a map from another map, we know
1780-
/// that keys are unique.
1784+
/// However this operation is still unsafe because the resulting `HashMap`
1785+
/// may be passed to unsafe code which does expect the map to behave
1786+
/// correctly, and would could unsoundness as a result.
17811787
///
17821788
/// # Examples
17831789
///
@@ -1793,10 +1799,12 @@ where
17931799
/// let mut map2 = HashMap::new();
17941800
///
17951801
/// for (key, value) in map1.into_iter() {
1796-
/// map2.insert_unique_unchecked(key, value);
1802+
/// unsafe {
1803+
/// map2.insert_unique_unchecked(key, value);
1804+
/// }
17971805
/// }
17981806
///
1799-
/// let (key, value) = map2.insert_unique_unchecked(4, "d");
1807+
/// let (key, value) = unsafe { map2.insert_unique_unchecked(4, "d") };
18001808
/// assert_eq!(key, &4);
18011809
/// assert_eq!(value, &mut "d");
18021810
/// *value = "e";
@@ -1808,7 +1816,7 @@ where
18081816
/// assert_eq!(map2.len(), 4);
18091817
/// ```
18101818
#[cfg_attr(feature = "inline-more", inline)]
1811-
pub fn insert_unique_unchecked(&mut self, k: K, v: V) -> (&K, &mut V) {
1819+
pub unsafe fn insert_unique_unchecked(&mut self, k: K, v: V) -> (&K, &mut V) {
18121820
let hash = make_hash::<K, S>(&self.hash_builder, &k);
18131821
let bucket = self
18141822
.table
@@ -3187,7 +3195,7 @@ impl<'a, K, V, S, A: Allocator> IntoIterator for &'a HashMap<K, V, S, A> {
31873195
///
31883196
/// for (key, value) in &map_one {
31893197
/// println!("Key: {}, Value: {}", key, value);
3190-
/// map_two.insert_unique_unchecked(*key, *value);
3198+
/// map_two.insert(*key, *value);
31913199
/// }
31923200
///
31933201
/// assert_eq!(map_one, map_two);
@@ -5710,9 +5718,9 @@ mod test_map {
57105718
#[test]
57115719
fn test_insert_unique_unchecked() {
57125720
let mut map = HashMap::new();
5713-
let (k1, v1) = map.insert_unique_unchecked(10, 11);
5721+
let (k1, v1) = unsafe { map.insert_unique_unchecked(10, 11) };
57145722
assert_eq!((&10, &mut 11), (k1, v1));
5715-
let (k2, v2) = map.insert_unique_unchecked(20, 21);
5723+
let (k2, v2) = unsafe { map.insert_unique_unchecked(20, 21) };
57165724
assert_eq!((&20, &mut 21), (k2, v2));
57175725
assert_eq!(Some(&11), map.get(&10));
57185726
assert_eq!(Some(&21), map.get(&20));

src/set.rs

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1118,25 +1118,29 @@ where
11181118

11191119
/// Insert a value the set without checking if the value already exists in the set.
11201120
///
1121-
/// Returns a reference to the value just inserted.
1121+
/// This operation is faster than regular insert, because it does not perform
1122+
/// lookup before insertion.
1123+
///
1124+
/// This operation is useful during initial population of the set.
1125+
/// For example, when constructing a set from another set, we know
1126+
/// that values are unique.
1127+
///
1128+
/// # Safety
11221129
///
1123-
/// This operation is safe if a value does not exist in the set.
1130+
/// This operation is safe if a key does not exist in the set.
11241131
///
1125-
/// However, if a value exists in the set already, the behavior is unspecified:
1132+
/// However, if a key exists in the set already, the behavior is unspecified:
11261133
/// this operation may panic, loop forever, or any following operation with the set
11271134
/// may panic, loop forever or return arbitrary result.
11281135
///
11291136
/// That said, this operation (and following operations) are guaranteed to
11301137
/// not violate memory safety.
11311138
///
1132-
/// This operation is faster than regular insert, because it does not perform
1133-
/// lookup before insertion.
1134-
///
1135-
/// This operation is useful during initial population of the set.
1136-
/// For example, when constructing a set from another set, we know
1137-
/// that values are unique.
1139+
/// However this operation is still unsafe because the resulting `HashSet`
1140+
/// may be passed to unsafe code which does expect the set to behave
1141+
/// correctly, and would could unsoundness as a result.
11381142
#[cfg_attr(feature = "inline-more", inline)]
1139-
pub fn insert_unique_unchecked(&mut self, value: T) -> &T {
1143+
pub unsafe fn insert_unique_unchecked(&mut self, value: T) -> &T {
11401144
self.map.insert_unique_unchecked(value, ()).0
11411145
}
11421146

0 commit comments

Comments
 (0)