-
Notifications
You must be signed in to change notification settings - Fork 292
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #568 from clarfonthey/control-module-p1
Further sequester `Group`/`Tag` code
- Loading branch information
Showing
10 changed files
with
171 additions
and
136 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
cfg_if! { | ||
// Use the SSE2 implementation if possible: it allows us to scan 16 buckets | ||
// at once instead of 8. We don't bother with AVX since it would require | ||
// runtime dispatch and wouldn't gain us much anyways: the probability of | ||
// finding a match drops off drastically after the first few buckets. | ||
// | ||
// I attempted an implementation on ARM using NEON instructions, but it | ||
// turns out that most NEON instructions have multi-cycle latency, which in | ||
// the end outweighs any gains over the generic implementation. | ||
if #[cfg(all( | ||
target_feature = "sse2", | ||
any(target_arch = "x86", target_arch = "x86_64"), | ||
not(miri), | ||
))] { | ||
mod sse2; | ||
use sse2 as imp; | ||
} else if #[cfg(all( | ||
target_arch = "aarch64", | ||
target_feature = "neon", | ||
// NEON intrinsics are currently broken on big-endian targets. | ||
// See https://github.com/rust-lang/stdarch/issues/1484. | ||
target_endian = "little", | ||
not(miri), | ||
))] { | ||
mod neon; | ||
use neon as imp; | ||
} else { | ||
mod generic; | ||
use generic as imp; | ||
} | ||
} | ||
pub(crate) use self::imp::Group; | ||
pub(super) use self::imp::{ | ||
BitMaskWord, NonZeroBitMaskWord, BITMASK_ITER_MASK, BITMASK_MASK, BITMASK_STRIDE, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
mod bitmask; | ||
mod group; | ||
mod tag; | ||
|
||
use self::bitmask::BitMask; | ||
pub(crate) use self::{ | ||
bitmask::BitMaskIter, | ||
group::Group, | ||
tag::{Tag, TagSliceExt}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
use core::{fmt, mem}; | ||
|
||
/// Single tag in a control group. | ||
#[derive(Copy, Clone, PartialEq, Eq)] | ||
#[repr(transparent)] | ||
pub(crate) struct Tag(pub(super) u8); | ||
impl Tag { | ||
/// Control tag value for an empty bucket. | ||
pub(crate) const EMPTY: Tag = Tag(0b1111_1111); | ||
|
||
/// Control tag value for a deleted bucket. | ||
pub(crate) const DELETED: Tag = Tag(0b1000_0000); | ||
|
||
/// Checks whether a control tag represents a full bucket (top bit is clear). | ||
#[inline] | ||
pub(crate) const fn is_full(self) -> bool { | ||
self.0 & 0x80 == 0 | ||
} | ||
|
||
/// Checks whether a control tag represents a special value (top bit is set). | ||
#[inline] | ||
pub(crate) const fn is_special(self) -> bool { | ||
self.0 & 0x80 != 0 | ||
} | ||
|
||
/// Checks whether a special control value is EMPTY (just check 1 bit). | ||
#[inline] | ||
pub(crate) const fn special_is_empty(self) -> bool { | ||
debug_assert!(self.is_special()); | ||
self.0 & 0x01 != 0 | ||
} | ||
|
||
/// Creates a control tag representing a full bucket with the given hash. | ||
#[inline] | ||
#[allow(clippy::cast_possible_truncation)] | ||
pub(crate) const fn full(hash: u64) -> Tag { | ||
// Constant for function that grabs the top 7 bits of the hash. | ||
const MIN_HASH_LEN: usize = if mem::size_of::<usize>() < mem::size_of::<u64>() { | ||
mem::size_of::<usize>() | ||
} else { | ||
mem::size_of::<u64>() | ||
}; | ||
|
||
// Grab the top 7 bits of the hash. While the hash is normally a full 64-bit | ||
// value, some hash functions (such as FxHash) produce a usize result | ||
// instead, which means that the top 32 bits are 0 on 32-bit platforms. | ||
// So we use MIN_HASH_LEN constant to handle this. | ||
let top7 = hash >> (MIN_HASH_LEN * 8 - 7); | ||
Tag((top7 & 0x7f) as u8) // truncation | ||
} | ||
} | ||
impl fmt::Debug for Tag { | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
if self.is_special() { | ||
if self.special_is_empty() { | ||
f.pad("EMPTY") | ||
} else { | ||
f.pad("DELETED") | ||
} | ||
} else { | ||
f.debug_tuple("full").field(&(self.0 & 0x7F)).finish() | ||
} | ||
} | ||
} | ||
|
||
/// Extension trait for slices of tags. | ||
pub(crate) trait TagSliceExt { | ||
/// Fills the control with the given tag. | ||
fn fill_tag(&mut self, tag: Tag); | ||
|
||
/// Clears out the control. | ||
#[inline] | ||
fn fill_empty(&mut self) { | ||
self.fill_tag(Tag::EMPTY) | ||
} | ||
} | ||
impl TagSliceExt for [Tag] { | ||
#[inline] | ||
fn fill_tag(&mut self, tag: Tag) { | ||
// SAFETY: We have access to the entire slice, so, we can write to the entire slice. | ||
unsafe { self.as_mut_ptr().write_bytes(tag.0, self.len()) } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.