Skip to content

Commit 3784c2f

Browse files
committed
Auto merge of #433 - Amanieu:internal_cleanups, r=Amanieu
Clean up some internals
2 parents f552bdb + 9f20bd0 commit 3784c2f

File tree

8 files changed

+56
-108
lines changed

8 files changed

+56
-108
lines changed

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ rayon = "1.0"
3636
fnv = "1.0.7"
3737
serde_test = "1.0"
3838
doc-comment = "0.3.1"
39-
bumpalo = "3.6.0"
39+
bumpalo = { version = "3.13.0", features = ["allocator-api2"] }
4040
rkyv = { version = "0.7.42", features = ["validation"] }
4141

4242
[features]

src/map.rs

+7-44
Original file line numberDiff line numberDiff line change
@@ -260,29 +260,6 @@ where
260260
hash_builder.hash_one(val)
261261
}
262262

263-
#[cfg(not(feature = "nightly"))]
264-
#[cfg_attr(feature = "inline-more", inline)]
265-
pub(crate) fn make_insert_hash<K, S>(hash_builder: &S, val: &K) -> u64
266-
where
267-
K: Hash,
268-
S: BuildHasher,
269-
{
270-
use core::hash::Hasher;
271-
let mut state = hash_builder.build_hasher();
272-
val.hash(&mut state);
273-
state.finish()
274-
}
275-
276-
#[cfg(feature = "nightly")]
277-
#[cfg_attr(feature = "inline-more", inline)]
278-
pub(crate) fn make_insert_hash<K, S>(hash_builder: &S, val: &K) -> u64
279-
where
280-
K: Hash,
281-
S: BuildHasher,
282-
{
283-
hash_builder.hash_one(val)
284-
}
285-
286263
#[cfg(feature = "ahash")]
287264
impl<K, V> HashMap<K, V, DefaultHashBuilder> {
288265
/// Creates an empty `HashMap`.
@@ -368,8 +345,6 @@ impl<K, V, A: Allocator + Clone> HashMap<K, V, DefaultHashBuilder, A> {
368345
/// # Examples
369346
///
370347
/// ```
371-
/// # #[cfg(feature = "nightly")]
372-
/// # fn test() {
373348
/// use hashbrown::HashMap;
374349
/// use bumpalo::Bump;
375350
///
@@ -388,11 +363,6 @@ impl<K, V, A: Allocator + Clone> HashMap<K, V, DefaultHashBuilder, A> {
388363
/// assert_eq!(map.len(), 1);
389364
/// // And it also allocates some capacity
390365
/// assert!(map.capacity() > 1);
391-
/// # }
392-
/// # fn main() {
393-
/// # #[cfg(feature = "nightly")]
394-
/// # test()
395-
/// # }
396366
/// ```
397367
#[cfg_attr(feature = "inline-more", inline)]
398368
pub fn new_in(alloc: A) -> Self {
@@ -419,8 +389,6 @@ impl<K, V, A: Allocator + Clone> HashMap<K, V, DefaultHashBuilder, A> {
419389
/// # Examples
420390
///
421391
/// ```
422-
/// # #[cfg(feature = "nightly")]
423-
/// # fn test() {
424392
/// use hashbrown::HashMap;
425393
/// use bumpalo::Bump;
426394
///
@@ -444,11 +412,6 @@ impl<K, V, A: Allocator + Clone> HashMap<K, V, DefaultHashBuilder, A> {
444412
/// assert_eq!(map.len(), 5);
445413
/// // But its capacity isn't changed
446414
/// assert_eq!(map.capacity(), empty_map_capacity)
447-
/// # }
448-
/// # fn main() {
449-
/// # #[cfg(feature = "nightly")]
450-
/// # test()
451-
/// # }
452415
/// ```
453416
#[cfg_attr(feature = "inline-more", inline)]
454417
pub fn with_capacity_in(capacity: usize, alloc: A) -> Self {
@@ -1262,7 +1225,7 @@ where
12621225
/// ```
12631226
#[cfg_attr(feature = "inline-more", inline)]
12641227
pub fn entry(&mut self, key: K) -> Entry<'_, K, V, S, A> {
1265-
let hash = make_insert_hash::<K, S>(&self.hash_builder, &key);
1228+
let hash = make_hash::<K, S>(&self.hash_builder, &key);
12661229
if let Some(elem) = self.table.find(hash, equivalent_key(&key)) {
12671230
Entry::Occupied(OccupiedEntry {
12681231
hash,
@@ -1782,7 +1745,7 @@ where
17821745
/// ```
17831746
#[cfg_attr(feature = "inline-more", inline)]
17841747
pub fn insert(&mut self, k: K, v: V) -> Option<V> {
1785-
let hash = make_insert_hash::<K, S>(&self.hash_builder, &k);
1748+
let hash = make_hash::<K, S>(&self.hash_builder, &k);
17861749
let hasher = make_hasher::<_, V, S>(&self.hash_builder);
17871750
match self
17881751
.table
@@ -1849,7 +1812,7 @@ where
18491812
/// ```
18501813
#[cfg_attr(feature = "inline-more", inline)]
18511814
pub fn insert_unique_unchecked(&mut self, k: K, v: V) -> (&K, &mut V) {
1852-
let hash = make_insert_hash::<K, S>(&self.hash_builder, &k);
1815+
let hash = make_hash::<K, S>(&self.hash_builder, &k);
18531816
let bucket = self
18541817
.table
18551818
.insert(hash, (k, v), make_hasher::<_, V, S>(&self.hash_builder));
@@ -4003,7 +3966,7 @@ impl<'a, K, V, S, A: Allocator + Clone> RawVacantEntryMut<'a, K, V, S, A> {
40033966
K: Hash,
40043967
S: BuildHasher,
40053968
{
4006-
let hash = make_insert_hash::<K, S>(self.hash_builder, &key);
3969+
let hash = make_hash::<K, S>(self.hash_builder, &key);
40073970
self.insert_hashed_nocheck(hash, key, value)
40083971
}
40093972

@@ -4111,7 +4074,7 @@ impl<'a, K, V, S, A: Allocator + Clone> RawVacantEntryMut<'a, K, V, S, A> {
41114074
K: Hash,
41124075
S: BuildHasher,
41134076
{
4114-
let hash = make_insert_hash::<K, S>(self.hash_builder, &key);
4077+
let hash = make_hash::<K, S>(self.hash_builder, &key);
41154078
let elem = self.table.insert(
41164079
hash,
41174080
(key, value),
@@ -8194,7 +8157,7 @@ mod test_map {
81948157
let mut map: HashMap<_, _> = xs.iter().copied().collect();
81958158

81968159
let compute_hash = |map: &HashMap<i32, i32>, k: i32| -> u64 {
8197-
super::make_insert_hash::<i32, _>(map.hasher(), &k)
8160+
super::make_hash::<i32, _>(map.hasher(), &k)
81988161
};
81998162

82008163
// Existing key (insert)
@@ -8356,7 +8319,7 @@ mod test_map {
83568319
loop {
83578320
// occasionally remove some elements
83588321
if i < n && rng.gen_bool(0.1) {
8359-
let hash_value = super::make_insert_hash(&hash_builder, &i);
8322+
let hash_value = super::make_hash(&hash_builder, &i);
83608323

83618324
unsafe {
83628325
let e = map.table.find(hash_value, |q| q.0.eq(&i));

src/raw/bitmask.rs

+18-19
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
use super::imp::{BitMaskWord, BITMASK_ITER_MASK, BITMASK_MASK, BITMASK_STRIDE};
2-
#[cfg(feature = "nightly")]
3-
use core::intrinsics;
1+
use super::imp::{
2+
BitMaskWord, NonZeroBitMaskWord, BITMASK_ITER_MASK, BITMASK_MASK, BITMASK_STRIDE,
3+
};
44

55
/// A bit mask which contains the result of a `Match` operation on a `Group` and
66
/// allows iterating through them.
@@ -47,26 +47,13 @@ impl BitMask {
4747
/// Returns the first set bit in the `BitMask`, if there is one.
4848
#[inline]
4949
pub(crate) fn lowest_set_bit(self) -> Option<usize> {
50-
if self.0 == 0 {
51-
None
50+
if let Some(nonzero) = NonZeroBitMaskWord::new(self.0) {
51+
Some(Self::nonzero_trailing_zeros(nonzero))
5252
} else {
53-
Some(unsafe { self.lowest_set_bit_nonzero() })
53+
None
5454
}
5555
}
5656

57-
/// Returns the first set bit in the `BitMask`, if there is one. The
58-
/// bitmask must not be empty.
59-
#[inline]
60-
#[cfg(feature = "nightly")]
61-
pub(crate) unsafe fn lowest_set_bit_nonzero(self) -> usize {
62-
intrinsics::cttz_nonzero(self.0) as usize / BITMASK_STRIDE
63-
}
64-
#[inline]
65-
#[cfg(not(feature = "nightly"))]
66-
pub(crate) unsafe fn lowest_set_bit_nonzero(self) -> usize {
67-
self.trailing_zeros()
68-
}
69-
7057
/// Returns the number of trailing zeroes in the `BitMask`.
7158
#[inline]
7259
pub(crate) fn trailing_zeros(self) -> usize {
@@ -82,6 +69,18 @@ impl BitMask {
8269
}
8370
}
8471

72+
/// Same as above but takes a `NonZeroBitMaskWord`.
73+
#[inline]
74+
fn nonzero_trailing_zeros(nonzero: NonZeroBitMaskWord) -> usize {
75+
if cfg!(target_arch = "arm") && BITMASK_STRIDE % 8 == 0 {
76+
// SAFETY: A byte-swapped non-zero value is still non-zero.
77+
let swapped = unsafe { NonZeroBitMaskWord::new_unchecked(nonzero.get().swap_bytes()) };
78+
swapped.leading_zeros() as usize / BITMASK_STRIDE
79+
} else {
80+
nonzero.trailing_zeros() as usize / BITMASK_STRIDE
81+
}
82+
}
83+
8584
/// Returns the number of leading zeroes in the `BitMask`.
8685
#[inline]
8786
pub(crate) fn leading_zeros(self) -> usize {

src/raw/generic.rs

+16-14
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,24 @@ use core::{mem, ptr};
55
// Use the native word size as the group size. Using a 64-bit group size on
66
// a 32-bit architecture will just end up being more expensive because
77
// shifts and multiplies will need to be emulated.
8-
#[cfg(any(
9-
target_pointer_width = "64",
10-
target_arch = "aarch64",
11-
target_arch = "x86_64",
12-
target_arch = "wasm32",
13-
))]
14-
type GroupWord = u64;
15-
#[cfg(all(
16-
any(target_pointer_width = "32", target_pointer_width = "16"),
17-
not(target_arch = "aarch64"),
18-
not(target_arch = "x86_64"),
19-
not(target_arch = "wasm32"),
20-
))]
21-
type GroupWord = u32;
8+
9+
cfg_if! {
10+
if #[cfg(any(
11+
target_pointer_width = "64",
12+
target_arch = "aarch64",
13+
target_arch = "x86_64",
14+
target_arch = "wasm32",
15+
))] {
16+
type GroupWord = u64;
17+
type NonZeroGroupWord = core::num::NonZeroU64;
18+
} else {
19+
type GroupWord = u32;
20+
type NonZeroGroupWord = core::num::NonZeroU32;
21+
}
22+
}
2223

2324
pub(crate) type BitMaskWord = GroupWord;
25+
pub(crate) type NonZeroBitMaskWord = NonZeroGroupWord;
2426
pub(crate) const BITMASK_STRIDE: usize = 8;
2527
// We only care about the highest bit of each byte for the mask.
2628
#[allow(clippy::cast_possible_truncation, clippy::unnecessary_cast)]

src/raw/mod.rs

+8-28
Original file line numberDiff line numberDiff line change
@@ -44,32 +44,12 @@ use self::imp::Group;
4444

4545
// Branch prediction hint. This is currently only available on nightly but it
4646
// consistently improves performance by 10-15%.
47-
#[cfg(feature = "nightly")]
48-
use core::intrinsics::{likely, unlikely};
49-
50-
// On stable we can use #[cold] to get a equivalent effect: this attributes
51-
// suggests that the function is unlikely to be called
5247
#[cfg(not(feature = "nightly"))]
53-
#[inline]
54-
#[cold]
55-
fn cold() {}
56-
57-
#[cfg(not(feature = "nightly"))]
58-
#[inline]
59-
fn likely(b: bool) -> bool {
60-
if !b {
61-
cold();
62-
}
63-
b
64-
}
48+
use core::convert::identity as likely;
6549
#[cfg(not(feature = "nightly"))]
66-
#[inline]
67-
fn unlikely(b: bool) -> bool {
68-
if b {
69-
cold();
70-
}
71-
b
72-
}
50+
use core::convert::identity as unlikely;
51+
#[cfg(feature = "nightly")]
52+
use core::intrinsics::{likely, unlikely};
7353

7454
// Use strict provenance functions if available.
7555
#[cfg(feature = "nightly")]
@@ -1668,14 +1648,14 @@ impl<A: Allocator + Clone> RawTableInner<A> {
16681648
// we will never end up in the given branch, since
16691649
// `(probe_seq.pos + bit) & self.bucket_mask` in `find_insert_slot_in_group` cannot
16701650
// return a full bucket index. For tables smaller than the group width, calling the
1671-
// `lowest_set_bit_nonzero` function (when `nightly` feature enabled) is also
1651+
// `unwrap_unchecked` function is also
16721652
// safe, as the trailing control bytes outside the range of the table are filled
16731653
// with EMPTY bytes, so this second scan either finds an empty slot (due to the
1674-
// load factor) or hits the trailing control bytes (containing EMPTY). See
1675-
// `intrinsics::cttz_nonzero` for more information.
1654+
// load factor) or hits the trailing control bytes (containing EMPTY).
16761655
index = Group::load_aligned(self.ctrl(0))
16771656
.match_empty_or_deleted()
1678-
.lowest_set_bit_nonzero();
1657+
.lowest_set_bit()
1658+
.unwrap_unchecked();
16791659
}
16801660
InsertSlot { index }
16811661
}

src/raw/neon.rs

+2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ use super::bitmask::BitMask;
22
use super::EMPTY;
33
use core::arch::aarch64 as neon;
44
use core::mem;
5+
use core::num::NonZeroU64;
56

67
pub(crate) type BitMaskWord = u64;
8+
pub(crate) type NonZeroBitMaskWord = NonZeroU64;
79
pub(crate) const BITMASK_STRIDE: usize = 8;
810
pub(crate) const BITMASK_MASK: BitMaskWord = !0;
911
pub(crate) const BITMASK_ITER_MASK: BitMaskWord = 0x8080_8080_8080_8080;

src/raw/sse2.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
use super::bitmask::BitMask;
22
use super::EMPTY;
33
use core::mem;
4+
use core::num::NonZeroU16;
45

56
#[cfg(target_arch = "x86")]
67
use core::arch::x86;
78
#[cfg(target_arch = "x86_64")]
89
use core::arch::x86_64 as x86;
910

1011
pub(crate) type BitMaskWord = u16;
12+
pub(crate) type NonZeroBitMaskWord = NonZeroU16;
1113
pub(crate) const BITMASK_STRIDE: usize = 1;
1214
pub(crate) const BITMASK_MASK: BitMaskWord = 0xffff;
1315
pub(crate) const BITMASK_ITER_MASK: BitMaskWord = !0;

src/rustc_entry.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use self::RustcEntry::*;
2-
use crate::map::{make_insert_hash, Drain, HashMap, IntoIter, Iter, IterMut};
2+
use crate::map::{make_hash, Drain, HashMap, IntoIter, Iter, IterMut};
33
use crate::raw::{Allocator, Bucket, Global, RawTable};
44
use core::fmt::{self, Debug};
55
use core::hash::{BuildHasher, Hash};
@@ -32,7 +32,7 @@ where
3232
/// ```
3333
#[cfg_attr(feature = "inline-more", inline)]
3434
pub fn rustc_entry(&mut self, key: K) -> RustcEntry<'_, K, V, A> {
35-
let hash = make_insert_hash(&self.hash_builder, &key);
35+
let hash = make_hash(&self.hash_builder, &key);
3636
if let Some(elem) = self.table.find(hash, |q| q.0.eq(&key)) {
3737
RustcEntry::Occupied(RustcOccupiedEntry {
3838
key: Some(key),

0 commit comments

Comments
 (0)