Skip to content

Commit a25cd3b

Browse files
committed
Auto merge of #556 - Amanieu:api-changes, r=cuviper
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.
2 parents cd9a955 + e774b7d commit a25cd3b

File tree

3 files changed

+35
-21
lines changed

3 files changed

+35
-21
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
@@ -1771,8 +1771,17 @@ where
17711771
/// Insert a key-value pair into the map without checking
17721772
/// if the key already exists in the map.
17731773
///
1774+
/// This operation is faster than regular insert, because it does not perform
1775+
/// lookup before insertion.
1776+
///
1777+
/// This operation is useful during initial population of the map.
1778+
/// For example, when constructing a map from another map, we know
1779+
/// that keys are unique.
1780+
///
17741781
/// Returns a reference to the key and value just inserted.
17751782
///
1783+
/// # Safety
1784+
///
17761785
/// This operation is safe if a key does not exist in the map.
17771786
///
17781787
/// However, if a key exists in the map already, the behavior is unspecified:
@@ -1782,12 +1791,9 @@ where
17821791
/// That said, this operation (and following operations) are guaranteed to
17831792
/// not violate memory safety.
17841793
///
1785-
/// This operation is faster than regular insert, because it does not perform
1786-
/// lookup before insertion.
1787-
///
1788-
/// This operation is useful during initial population of the map.
1789-
/// For example, when constructing a map from another map, we know
1790-
/// that keys are unique.
1794+
/// However this operation is still unsafe because the resulting `HashMap`
1795+
/// may be passed to unsafe code which does expect the map to behave
1796+
/// correctly, and would cause unsoundness as a result.
17911797
///
17921798
/// # Examples
17931799
///
@@ -1803,10 +1809,12 @@ where
18031809
/// let mut map2 = HashMap::new();
18041810
///
18051811
/// for (key, value) in map1.into_iter() {
1806-
/// map2.insert_unique_unchecked(key, value);
1812+
/// unsafe {
1813+
/// map2.insert_unique_unchecked(key, value);
1814+
/// }
18071815
/// }
18081816
///
1809-
/// let (key, value) = map2.insert_unique_unchecked(4, "d");
1817+
/// let (key, value) = unsafe { map2.insert_unique_unchecked(4, "d") };
18101818
/// assert_eq!(key, &4);
18111819
/// assert_eq!(value, &mut "d");
18121820
/// *value = "e";
@@ -1818,7 +1826,7 @@ where
18181826
/// assert_eq!(map2.len(), 4);
18191827
/// ```
18201828
#[cfg_attr(feature = "inline-more", inline)]
1821-
pub fn insert_unique_unchecked(&mut self, k: K, v: V) -> (&K, &mut V) {
1829+
pub unsafe fn insert_unique_unchecked(&mut self, k: K, v: V) -> (&K, &mut V) {
18221830
let hash = make_hash::<K, S>(&self.hash_builder, &k);
18231831
let bucket = self
18241832
.table
@@ -3021,7 +3029,7 @@ impl<'a, K, V, S, A: Allocator> IntoIterator for &'a HashMap<K, V, S, A> {
30213029
///
30223030
/// for (key, value) in &map_one {
30233031
/// println!("Key: {}, Value: {}", key, value);
3024-
/// map_two.insert_unique_unchecked(*key, *value);
3032+
/// map_two.insert(*key, *value);
30253033
/// }
30263034
///
30273035
/// assert_eq!(map_one, map_two);
@@ -5040,9 +5048,9 @@ mod test_map {
50405048
#[test]
50415049
fn test_insert_unique_unchecked() {
50425050
let mut map = HashMap::new();
5043-
let (k1, v1) = map.insert_unique_unchecked(10, 11);
5051+
let (k1, v1) = unsafe { map.insert_unique_unchecked(10, 11) };
50445052
assert_eq!((&10, &mut 11), (k1, v1));
5045-
let (k2, v2) = map.insert_unique_unchecked(20, 21);
5053+
let (k2, v2) = unsafe { map.insert_unique_unchecked(20, 21) };
50465054
assert_eq!((&20, &mut 21), (k2, v2));
50475055
assert_eq!(Some(&11), map.get(&10));
50485056
assert_eq!(Some(&21), map.get(&20));

src/set.rs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1093,7 +1093,14 @@ where
10931093

10941094
/// Insert a value the set without checking if the value already exists in the set.
10951095
///
1096-
/// Returns a reference to the value just inserted.
1096+
/// This operation is faster than regular insert, because it does not perform
1097+
/// lookup before insertion.
1098+
///
1099+
/// This operation is useful during initial population of the set.
1100+
/// For example, when constructing a set from another set, we know
1101+
/// that values are unique.
1102+
///
1103+
/// # Safety
10971104
///
10981105
/// This operation is safe if a value does not exist in the set.
10991106
///
@@ -1104,14 +1111,11 @@ where
11041111
/// That said, this operation (and following operations) are guaranteed to
11051112
/// not violate memory safety.
11061113
///
1107-
/// This operation is faster than regular insert, because it does not perform
1108-
/// lookup before insertion.
1109-
///
1110-
/// This operation is useful during initial population of the set.
1111-
/// For example, when constructing a set from another set, we know
1112-
/// that values are unique.
1114+
/// However this operation is still unsafe because the resulting `HashSet`
1115+
/// may be passed to unsafe code which does expect the set to behave
1116+
/// correctly, and would cause unsoundness as a result.
11131117
#[cfg_attr(feature = "inline-more", inline)]
1114-
pub fn insert_unique_unchecked(&mut self, value: T) -> &T {
1118+
pub unsafe fn insert_unique_unchecked(&mut self, value: T) -> &T {
11151119
self.map.insert_unique_unchecked(value, ()).0
11161120
}
11171121

0 commit comments

Comments
 (0)