Skip to content

Commit 20cdb93

Browse files
committed
Add more safe methods to RawTable
These methods combine lookup and bucket operations so the caller doesn't have to deal with unsafe bucket methods. - `get`: `find` and `as_ref` - `get_mut`: `find` and `as_mut` - `insert_entry`: `insert` and `as_mut` - `remove_entry`: `find` and `remove` - `erase_entry`: `find` and `erase`
1 parent 0f38616 commit 20cdb93

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
@@ -810,8 +810,8 @@ where
810810
Q: Hash + Eq,
811811
{
812812
// Avoid `Option::map` because it bloats LLVM IR.
813-
match self.get_key_value(k) {
814-
Some((_, v)) => Some(v),
813+
match self.get_inner(k) {
814+
Some(&(_, ref v)) => Some(v),
815815
None => None,
816816
}
817817
}
@@ -841,17 +841,23 @@ where
841841
K: Borrow<Q>,
842842
Q: Hash + Eq,
843843
{
844-
let hash = make_hash(&self.hash_builder, k);
845844
// Avoid `Option::map` because it bloats LLVM IR.
846-
match self.table.find(hash, |x| k.eq(x.0.borrow())) {
847-
Some(item) => unsafe {
848-
let &(ref key, ref value) = item.as_ref();
849-
Some((key, value))
850-
},
845+
match self.get_inner(k) {
846+
Some(&(ref key, ref value)) => Some((key, value)),
851847
None => None,
852848
}
853849
}
854850

851+
#[inline]
852+
fn get_inner<Q: ?Sized>(&self, k: &Q) -> Option<&(K, V)>
853+
where
854+
K: Borrow<Q>,
855+
Q: Hash + Eq,
856+
{
857+
let hash = make_hash(&self.hash_builder, k);
858+
self.table.get(hash, |x| k.eq(x.0.borrow()))
859+
}
860+
855861
/// Returns the key-value pair corresponding to the supplied key, with a mutable reference to value.
856862
///
857863
/// The supplied key may be any borrowed form of the map's key type, but
@@ -881,13 +887,9 @@ where
881887
K: Borrow<Q>,
882888
Q: Hash + Eq,
883889
{
884-
let hash = make_hash(&self.hash_builder, k);
885890
// Avoid `Option::map` because it bloats LLVM IR.
886-
match self.table.find(hash, |x| k.eq(x.0.borrow())) {
887-
Some(item) => unsafe {
888-
let &mut (ref key, ref mut value) = item.as_mut();
889-
Some((key, value))
890-
},
891+
match self.get_inner_mut(k) {
892+
Some(&mut (ref key, ref mut value)) => Some((key, value)),
891893
None => None,
892894
}
893895
}
@@ -917,7 +919,7 @@ where
917919
K: Borrow<Q>,
918920
Q: Hash + Eq,
919921
{
920-
self.get(k).is_some()
922+
self.get_inner(k).is_some()
921923
}
922924

923925
/// Returns a mutable reference to the value corresponding to the key.
@@ -947,14 +949,23 @@ where
947949
K: Borrow<Q>,
948950
Q: Hash + Eq,
949951
{
950-
let hash = make_hash(&self.hash_builder, k);
951952
// Avoid `Option::map` because it bloats LLVM IR.
952-
match self.table.find(hash, |x| k.eq(x.0.borrow())) {
953-
Some(item) => Some(unsafe { &mut item.as_mut().1 }),
953+
match self.get_inner_mut(k) {
954+
Some(&mut (_, ref mut v)) => Some(v),
954955
None => None,
955956
}
956957
}
957958

959+
#[inline]
960+
fn get_inner_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut (K, V)>
961+
where
962+
K: Borrow<Q>,
963+
Q: Hash + Eq,
964+
{
965+
let hash = make_hash(&self.hash_builder, k);
966+
self.table.get_mut(hash, |x| k.eq(x.0.borrow()))
967+
}
968+
958969
/// Inserts a key-value pair into the map.
959970
///
960971
/// If the map did not have this key present, [`None`] is returned.
@@ -982,16 +993,14 @@ where
982993
/// ```
983994
#[cfg_attr(feature = "inline-more", inline)]
984995
pub fn insert(&mut self, k: K, v: V) -> Option<V> {
985-
unsafe {
986-
let hash = make_hash(&self.hash_builder, &k);
987-
if let Some(item) = self.table.find(hash, |x| k.eq(&x.0)) {
988-
Some(mem::replace(&mut item.as_mut().1, v))
989-
} else {
990-
let hash_builder = &self.hash_builder;
991-
self.table
992-
.insert(hash, (k, v), |x| make_hash(hash_builder, &x.0));
993-
None
994-
}
996+
let hash = make_hash(&self.hash_builder, &k);
997+
if let Some((_, item)) = self.table.get_mut(hash, |x| k.eq(&x.0)) {
998+
Some(mem::replace(item, v))
999+
} else {
1000+
let hash_builder = &self.hash_builder;
1001+
self.table
1002+
.insert(hash, (k, v), |x| make_hash(hash_builder, &x.0));
1003+
None
9951004
}
9961005
}
9971006

@@ -1054,14 +1063,8 @@ where
10541063
K: Borrow<Q>,
10551064
Q: Hash + Eq,
10561065
{
1057-
unsafe {
1058-
let hash = make_hash(&self.hash_builder, &k);
1059-
if let Some(item) = self.table.find(hash, |x| k.eq(x.0.borrow())) {
1060-
Some(self.table.remove(item))
1061-
} else {
1062-
None
1063-
}
1064-
}
1066+
let hash = make_hash(&self.hash_builder, &k);
1067+
self.table.remove_entry(hash, |x| k.eq(x.0.borrow()))
10651068
}
10661069
}
10671070

@@ -1593,11 +1596,8 @@ impl<'a, K, V, S> RawEntryBuilder<'a, K, V, S> {
15931596
where
15941597
F: FnMut(&K) -> bool,
15951598
{
1596-
match self.map.table.find(hash, |(k, _)| is_match(k)) {
1597-
Some(item) => unsafe {
1598-
let &(ref key, ref value) = item.as_ref();
1599-
Some((key, value))
1600-
},
1599+
match self.map.table.get(hash, |(k, _)| is_match(k)) {
1600+
Some(&(ref key, ref value)) => Some((key, value)),
16011601
None => None,
16021602
}
16031603
}
@@ -1964,11 +1964,10 @@ impl<'a, K, V, S> RawVacantEntryMut<'a, K, V, S> {
19641964
where
19651965
H: Fn(&K) -> u64,
19661966
{
1967-
unsafe {
1968-
let elem = self.table.insert(hash, (key, value), |x| hasher(&x.0));
1969-
let &mut (ref mut k, ref mut v) = elem.as_mut();
1970-
(k, v)
1971-
}
1967+
let &mut (ref mut k, ref mut v) = self
1968+
.table
1969+
.insert_entry(hash, (key, value), |x| hasher(&x.0));
1970+
(k, v)
19721971
}
19731972

19741973
#[cfg_attr(feature = "inline-more", inline)]
@@ -2977,10 +2976,11 @@ impl<'a, K, V, S> VacantEntry<'a, K, V, S> {
29772976
S: BuildHasher,
29782977
{
29792978
let hash_builder = &self.table.hash_builder;
2980-
let bucket = self.table.table.insert(self.hash, (self.key, value), |x| {
2979+
let table = &mut self.table.table;
2980+
let entry = table.insert_entry(self.hash, (self.key, value), |x| {
29812981
make_hash(hash_builder, &x.0)
29822982
});
2983-
unsafe { &mut bucket.as_mut().1 }
2983+
&mut entry.1
29842984
}
29852985

29862986
#[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)