Skip to content

Commit d5002fa

Browse files
committed
Auto merge of #279 - Zoxc:find-opt, r=Amanieu
Optimize `find` This optimizes `find` for size and performance. The `cargo llvm-lines` output from the following program is reduced from 15837 to 15771. ```rust fn main() { let mut map1 = hashbrown::HashMap::new(); map1.insert(1u8, ""); map1.reserve(1000); dbg!(map1.get(&1)); let mut map2 = hashbrown::HashMap::new(); map2.insert(1i16, ""); map2.reserve(1000); dbg!(map2.get(&1)); let mut map3 = hashbrown::HashMap::new(); map3.insert(3u16, ""); map3.reserve(1000); dbg!(map3.get(&1)); let mut map4 = hashbrown::HashMap::new(); map4.insert(3u64, ""); map4.reserve(1000); dbg!(map4.get(&1)); dbg!(( map1.iter().next(), map2.iter().next(), map3.iter().next(), map4.iter().next() )); } ``` `rustc_driver` size (with optimizations) is reduced by 0.14%. Impact on compiler performance: ``` clap:check 1.9602s 1.9407s -0.99% helloworld:check 0.0420s 0.0420s +0.06% hyper:check 0.2977s 0.2968s -0.30% regex:check 1.1573s 1.1475s -0.85% syn:check 1.6993s 1.6870s -0.73% syntex_syntax:check 6.8989s 6.8263s -1.05% winapi:check 8.4423s 8.3300s -1.33% Total 20.4977s 20.2702s -1.11% Summary 3.5000s 3.4740s -0.74% ```
2 parents d108056 + 0c528ef commit d5002fa

File tree

1 file changed

+37
-8
lines changed

1 file changed

+37
-8
lines changed

src/raw/mod.rs

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -921,14 +921,14 @@ impl<T, A: Allocator + Clone> RawTable<T, A> {
921921
/// Searches for an element in the table.
922922
#[inline]
923923
pub fn find(&self, hash: u64, mut eq: impl FnMut(&T) -> bool) -> Option<Bucket<T>> {
924-
unsafe {
925-
for bucket in self.iter_hash(hash) {
926-
let elm = bucket.as_ref();
927-
if likely(eq(elm)) {
928-
return Some(bucket);
929-
}
930-
}
931-
None
924+
let result = self.table.find_inner(hash, &mut |index| unsafe {
925+
eq(self.bucket(index).as_ref())
926+
});
927+
928+
// Avoid `Option::map` because it bloats LLVM IR.
929+
match result {
930+
Some(index) => Some(unsafe { self.bucket(index) }),
931+
None => None,
932932
}
933933
}
934934

@@ -1054,6 +1054,7 @@ impl<T, A: Allocator + Clone> RawTable<T, A> {
10541054
/// `RawIterHash`. Because we cannot make the `next` method unsafe on the
10551055
/// `RawIterHash` struct, we have to make the `iter_hash` method unsafe.
10561056
#[cfg_attr(feature = "inline-more", inline)]
1057+
#[cfg(feature = "raw")]
10571058
pub unsafe fn iter_hash(&self, hash: u64) -> RawIterHash<'_, T, A> {
10581059
RawIterHash::new(self, hash)
10591060
}
@@ -1255,6 +1256,32 @@ impl<A: Allocator + Clone> RawTableInner<A> {
12551256
}
12561257
}
12571258

1259+
/// Searches for an element in the table. This uses dynamic dispatch to reduce the amount of
1260+
/// code generated, but it is eliminated by LLVM optimizations.
1261+
#[inline]
1262+
fn find_inner(&self, hash: u64, eq: &mut dyn FnMut(usize) -> bool) -> Option<usize> {
1263+
let h2_hash = h2(hash);
1264+
let mut probe_seq = self.probe_seq(hash);
1265+
1266+
loop {
1267+
let group = unsafe { Group::load(self.ctrl(probe_seq.pos)) };
1268+
1269+
for bit in group.match_byte(h2_hash) {
1270+
let index = (probe_seq.pos + bit) & self.bucket_mask;
1271+
1272+
if likely(eq(index)) {
1273+
return Some(index);
1274+
}
1275+
}
1276+
1277+
if likely(group.match_empty().any_bit_set()) {
1278+
return None;
1279+
}
1280+
1281+
probe_seq.move_next(self.bucket_mask);
1282+
}
1283+
}
1284+
12581285
#[allow(clippy::mut_mut)]
12591286
#[inline]
12601287
unsafe fn prepare_rehash_in_place(&mut self) {
@@ -2187,6 +2214,7 @@ struct RawIterHashInner<'a, A: Allocator + Clone> {
21872214

21882215
impl<'a, T, A: Allocator + Clone> RawIterHash<'a, T, A> {
21892216
#[cfg_attr(feature = "inline-more", inline)]
2217+
#[cfg(feature = "raw")]
21902218
fn new(table: &'a RawTable<T, A>, hash: u64) -> Self {
21912219
RawIterHash {
21922220
inner: RawIterHashInner::new(&table.table, hash),
@@ -2196,6 +2224,7 @@ impl<'a, T, A: Allocator + Clone> RawIterHash<'a, T, A> {
21962224
}
21972225
impl<'a, A: Allocator + Clone> RawIterHashInner<'a, A> {
21982226
#[cfg_attr(feature = "inline-more", inline)]
2227+
#[cfg(feature = "raw")]
21992228
fn new(table: &'a RawTableInner<A>, hash: u64) -> Self {
22002229
unsafe {
22012230
let h2_hash = h2(hash);

0 commit comments

Comments
 (0)