Skip to content

Commit d2b5aec

Browse files
authored
Merge pull request #202 from cuviper/safer-raw-access
Add more safe methods to RawTable
2 parents 298f675 + 20cdb93 commit d2b5aec

File tree

2 files changed

+101
-49
lines changed

2 files changed

+101
-49
lines changed

src/map.rs

Lines changed: 48 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -807,8 +807,8 @@ where
807807
Q: Hash + Eq,
808808
{
809809
// Avoid `Option::map` because it bloats LLVM IR.
810-
match self.get_key_value(k) {
811-
Some((_, v)) => Some(v),
810+
match self.get_inner(k) {
811+
Some(&(_, ref v)) => Some(v),
812812
None => None,
813813
}
814814
}
@@ -838,17 +838,23 @@ where
838838
K: Borrow<Q>,
839839
Q: Hash + Eq,
840840
{
841-
let hash = make_hash(&self.hash_builder, k);
842841
// Avoid `Option::map` because it bloats LLVM IR.
843-
match self.table.find(hash, |x| k.eq(x.0.borrow())) {
844-
Some(item) => unsafe {
845-
let &(ref key, ref value) = item.as_ref();
846-
Some((key, value))
847-
},
842+
match self.get_inner(k) {
843+
Some(&(ref key, ref value)) => Some((key, value)),
848844
None => None,
849845
}
850846
}
851847

848+
#[inline]
849+
fn get_inner<Q: ?Sized>(&self, k: &Q) -> Option<&(K, V)>
850+
where
851+
K: Borrow<Q>,
852+
Q: Hash + Eq,
853+
{
854+
let hash = make_hash(&self.hash_builder, k);
855+
self.table.get(hash, |x| k.eq(x.0.borrow()))
856+
}
857+
852858
/// Returns the key-value pair corresponding to the supplied key, with a mutable reference to value.
853859
///
854860
/// The supplied key may be any borrowed form of the map's key type, but
@@ -878,13 +884,9 @@ where
878884
K: Borrow<Q>,
879885
Q: Hash + Eq,
880886
{
881-
let hash = make_hash(&self.hash_builder, k);
882887
// Avoid `Option::map` because it bloats LLVM IR.
883-
match self.table.find(hash, |x| k.eq(x.0.borrow())) {
884-
Some(item) => unsafe {
885-
let &mut (ref key, ref mut value) = item.as_mut();
886-
Some((key, value))
887-
},
888+
match self.get_inner_mut(k) {
889+
Some(&mut (ref key, ref mut value)) => Some((key, value)),
888890
None => None,
889891
}
890892
}
@@ -914,7 +916,7 @@ where
914916
K: Borrow<Q>,
915917
Q: Hash + Eq,
916918
{
917-
self.get(k).is_some()
919+
self.get_inner(k).is_some()
918920
}
919921

920922
/// Returns a mutable reference to the value corresponding to the key.
@@ -944,14 +946,23 @@ where
944946
K: Borrow<Q>,
945947
Q: Hash + Eq,
946948
{
947-
let hash = make_hash(&self.hash_builder, k);
948949
// Avoid `Option::map` because it bloats LLVM IR.
949-
match self.table.find(hash, |x| k.eq(x.0.borrow())) {
950-
Some(item) => Some(unsafe { &mut item.as_mut().1 }),
950+
match self.get_inner_mut(k) {
951+
Some(&mut (_, ref mut v)) => Some(v),
951952
None => None,
952953
}
953954
}
954955

956+
#[inline]
957+
fn get_inner_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut (K, V)>
958+
where
959+
K: Borrow<Q>,
960+
Q: Hash + Eq,
961+
{
962+
let hash = make_hash(&self.hash_builder, k);
963+
self.table.get_mut(hash, |x| k.eq(x.0.borrow()))
964+
}
965+
955966
/// Inserts a key-value pair into the map.
956967
///
957968
/// If the map did not have this key present, [`None`] is returned.
@@ -979,16 +990,14 @@ where
979990
/// ```
980991
#[cfg_attr(feature = "inline-more", inline)]
981992
pub fn insert(&mut self, k: K, v: V) -> Option<V> {
982-
unsafe {
983-
let hash = make_hash(&self.hash_builder, &k);
984-
if let Some(item) = self.table.find(hash, |x| k.eq(&x.0)) {
985-
Some(mem::replace(&mut item.as_mut().1, v))
986-
} else {
987-
let hash_builder = &self.hash_builder;
988-
self.table
989-
.insert(hash, (k, v), |x| make_hash(hash_builder, &x.0));
990-
None
991-
}
993+
let hash = make_hash(&self.hash_builder, &k);
994+
if let Some((_, item)) = self.table.get_mut(hash, |x| k.eq(&x.0)) {
995+
Some(mem::replace(item, v))
996+
} else {
997+
let hash_builder = &self.hash_builder;
998+
self.table
999+
.insert(hash, (k, v), |x| make_hash(hash_builder, &x.0));
1000+
None
9921001
}
9931002
}
9941003

@@ -1051,14 +1060,8 @@ where
10511060
K: Borrow<Q>,
10521061
Q: Hash + Eq,
10531062
{
1054-
unsafe {
1055-
let hash = make_hash(&self.hash_builder, &k);
1056-
if let Some(item) = self.table.find(hash, |x| k.eq(x.0.borrow())) {
1057-
Some(self.table.remove(item))
1058-
} else {
1059-
None
1060-
}
1061-
}
1063+
let hash = make_hash(&self.hash_builder, &k);
1064+
self.table.remove_entry(hash, |x| k.eq(x.0.borrow()))
10621065
}
10631066
}
10641067

@@ -1590,11 +1593,8 @@ impl<'a, K, V, S> RawEntryBuilder<'a, K, V, S> {
15901593
where
15911594
F: FnMut(&K) -> bool,
15921595
{
1593-
match self.map.table.find(hash, |(k, _)| is_match(k)) {
1594-
Some(item) => unsafe {
1595-
let &(ref key, ref value) = item.as_ref();
1596-
Some((key, value))
1597-
},
1596+
match self.map.table.get(hash, |(k, _)| is_match(k)) {
1597+
Some(&(ref key, ref value)) => Some((key, value)),
15981598
None => None,
15991599
}
16001600
}
@@ -1961,11 +1961,10 @@ impl<'a, K, V, S> RawVacantEntryMut<'a, K, V, S> {
19611961
where
19621962
H: Fn(&K) -> u64,
19631963
{
1964-
unsafe {
1965-
let elem = self.table.insert(hash, (key, value), |x| hasher(&x.0));
1966-
let &mut (ref mut k, ref mut v) = elem.as_mut();
1967-
(k, v)
1968-
}
1964+
let &mut (ref mut k, ref mut v) = self
1965+
.table
1966+
.insert_entry(hash, (key, value), |x| hasher(&x.0));
1967+
(k, v)
19691968
}
19701969

19711970
#[cfg_attr(feature = "inline-more", inline)]
@@ -2974,10 +2973,11 @@ impl<'a, K, V, S> VacantEntry<'a, K, V, S> {
29742973
S: BuildHasher,
29752974
{
29762975
let hash_builder = &self.table.hash_builder;
2977-
let bucket = self.table.table.insert(self.hash, (self.key, value), |x| {
2976+
let table = &mut self.table.table;
2977+
let entry = table.insert_entry(self.hash, (self.key, value), |x| {
29782978
make_hash(hash_builder, &x.0)
29792979
});
2980-
unsafe { &mut bucket.as_mut().1 }
2980+
&mut entry.1
29812981
}
29822982

29832983
#[cfg_attr(feature = "inline-more", inline)]

src/raw/mod.rs

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,20 @@ impl<T> RawTable<T> {
545545
item.drop();
546546
}
547547

548+
/// Finds and erases an element from the table, dropping it in place.
549+
/// Returns true if an element was found.
550+
#[cfg(feature = "raw")]
551+
#[cfg_attr(feature = "inline-more", inline)]
552+
pub fn erase_entry(&mut self, hash: u64, eq: impl FnMut(&T) -> bool) -> bool {
553+
// Avoid `Option::map` because it bloats LLVM IR.
554+
if let Some(bucket) = self.find(hash, eq) {
555+
unsafe { self.erase(bucket) };
556+
true
557+
} else {
558+
false
559+
}
560+
}
561+
548562
/// Removes an element from the table, returning it.
549563
#[cfg_attr(feature = "inline-more", inline)]
550564
#[allow(clippy::needless_pass_by_value)]
@@ -554,6 +568,16 @@ impl<T> RawTable<T> {
554568
item.read()
555569
}
556570

571+
/// Finds and removes an element from the table, returning it.
572+
#[cfg_attr(feature = "inline-more", inline)]
573+
pub fn remove_entry(&mut self, hash: u64, eq: impl FnMut(&T) -> bool) -> Option<T> {
574+
// Avoid `Option::map` because it bloats LLVM IR.
575+
match self.find(hash, eq) {
576+
Some(bucket) => Some(unsafe { self.remove(bucket) }),
577+
None => None,
578+
}
579+
}
580+
557581
/// Returns an iterator for a probe sequence on the table.
558582
///
559583
/// This iterator never terminates, but is guaranteed to visit each bucket
@@ -910,7 +934,7 @@ impl<T> RawTable<T> {
910934
}
911935
}
912936

913-
/// Inserts a new element into the table.
937+
/// Inserts a new element into the table, and returns its raw bucket.
914938
///
915939
/// This does not check if the given element already exists in the table.
916940
#[cfg_attr(feature = "inline-more", inline)]
@@ -936,6 +960,14 @@ impl<T> RawTable<T> {
936960
}
937961
}
938962

963+
/// Inserts a new element into the table, and returns a mutable reference to it.
964+
///
965+
/// This does not check if the given element already exists in the table.
966+
#[cfg_attr(feature = "inline-more", inline)]
967+
pub fn insert_entry(&mut self, hash: u64, value: T, hasher: impl Fn(&T) -> u64) -> &mut T {
968+
unsafe { self.insert(hash, value, hasher).as_mut() }
969+
}
970+
939971
/// Inserts a new element into the table, without growing the table.
940972
///
941973
/// There must be enough space in the table to insert the new element.
@@ -1001,6 +1033,26 @@ impl<T> RawTable<T> {
10011033
}
10021034
}
10031035

1036+
/// Gets a reference to an element in the table.
1037+
#[inline]
1038+
pub fn get(&self, hash: u64, eq: impl FnMut(&T) -> bool) -> Option<&T> {
1039+
// Avoid `Option::map` because it bloats LLVM IR.
1040+
match self.find(hash, eq) {
1041+
Some(bucket) => Some(unsafe { bucket.as_ref() }),
1042+
None => None,
1043+
}
1044+
}
1045+
1046+
/// Gets a mutable reference to an element in the table.
1047+
#[inline]
1048+
pub fn get_mut(&mut self, hash: u64, eq: impl FnMut(&T) -> bool) -> Option<&mut T> {
1049+
// Avoid `Option::map` because it bloats LLVM IR.
1050+
match self.find(hash, eq) {
1051+
Some(bucket) => Some(unsafe { bucket.as_mut() }),
1052+
None => None,
1053+
}
1054+
}
1055+
10041056
/// Returns the number of elements the map can hold without reallocating.
10051057
///
10061058
/// This number is a lower bound; the table might be able to hold

0 commit comments

Comments
 (0)