Skip to content

Commit b5734f8

Browse files
committed
maybe no macro?
1 parent 607d85c commit b5734f8

File tree

1 file changed

+163
-150
lines changed

1 file changed

+163
-150
lines changed

src/xxhash3_64.rs

+163-150
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,29 @@ impl<S> RawHasher<S> {
543543
}
544544
}
545545

546+
fn dispatch_f<R>(f: impl FnOnce(&dyn Vector) -> R) -> R {
547+
#[cfg(all(target_arch = "aarch64", feature = "std"))]
548+
{
549+
if std::arch::is_aarch64_feature_detected!("neon") {
550+
// Safety: We just ensured we have the NEON feature
551+
return unsafe { f(&neon::Impl) };
552+
}
553+
}
554+
555+
// #[cfg(all(target_arch = "x86_64", feature = "std"))]
556+
// {
557+
// if is_x86_feature_detected!("avx2") {
558+
// // Safety: We just ensured we have the AVX2 feature
559+
// return unsafe { do_avx2($($arg_name),*) };
560+
// } else if is_x86_feature_detected!("sse2") {
561+
// // Safety: We just ensured we have the SSE2 feature
562+
// return unsafe { do_sse2($($arg_name),*) };
563+
// }
564+
// }
565+
566+
f(&scalar::Impl)
567+
}
568+
546569
macro_rules! dispatch {
547570
(
548571
fn $fn_name:ident<$($gen:ident),*>($($arg_name:ident : $arg_ty:ty),*) $(-> $ret_ty:ty)?
@@ -634,178 +657,158 @@ where
634657
S: FixedBuffer,
635658
{
636659
#[inline]
637-
fn write(&mut self, input: &[u8]) {
638-
let this = self;
639-
dispatch! {
640-
fn write_impl<S>(this: &mut RawHasher<S>, input: &[u8])
641-
[S: FixedBuffer]
642-
}
643-
}
644-
645-
#[inline]
646-
fn finish(&self) -> u64 {
647-
let this = self;
648-
dispatch! {
649-
fn finish_impl<S>(this: &RawHasher<S>) -> u64
650-
[S: FixedBuffer]
651-
}
652-
}
653-
}
660+
fn write(&mut self, mut input: &[u8]) {
661+
dispatch_f(|vector| {
662+
if input.is_empty() {
663+
return;
664+
}
654665

655-
#[inline(always)]
656-
fn write_impl<S>(vector: impl Vector, this: &mut RawHasher<S>, mut input: &[u8])
657-
where
658-
S: FixedBuffer,
659-
{
660-
if input.is_empty() {
661-
return;
662-
}
666+
let RawHasher {
667+
secret_buffer,
668+
buffer_usage,
669+
stripe_accumulator,
670+
total_bytes,
671+
..
672+
} = self;
663673

664-
let RawHasher {
665-
secret_buffer,
666-
buffer_usage,
667-
stripe_accumulator,
668-
total_bytes,
669-
..
670-
} = this;
674+
let n_stripes = secret_buffer.n_stripes();
675+
let (_, secret, buffer) = secret_buffer.parts_mut();
671676

672-
let n_stripes = secret_buffer.n_stripes();
673-
let (_, secret, buffer) = secret_buffer.parts_mut();
677+
*total_bytes += input.len();
674678

675-
*total_bytes += input.len();
679+
// Safety: This is an invariant of the buffer.
680+
unsafe {
681+
debug_assert!(*buffer_usage <= buffer.len());
682+
assert_unchecked(*buffer_usage <= buffer.len())
683+
};
676684

677-
// Safety: This is an invariant of the buffer.
678-
unsafe {
679-
debug_assert!(*buffer_usage <= buffer.len());
680-
assert_unchecked(*buffer_usage <= buffer.len())
681-
};
685+
// We have some previous data saved; try to fill it up and process it first
686+
if !buffer.is_empty() {
687+
let remaining = &mut buffer[*buffer_usage..];
688+
let n_to_copy = usize::min(remaining.len(), input.len());
682689

683-
// We have some previous data saved; try to fill it up and process it first
684-
if !buffer.is_empty() {
685-
let remaining = &mut buffer[*buffer_usage..];
686-
let n_to_copy = usize::min(remaining.len(), input.len());
690+
let (remaining_head, remaining_tail) = remaining.split_at_mut(n_to_copy);
691+
let (input_head, input_tail) = input.split_at(n_to_copy);
687692

688-
let (remaining_head, remaining_tail) = remaining.split_at_mut(n_to_copy);
689-
let (input_head, input_tail) = input.split_at(n_to_copy);
693+
remaining_head.copy_from_slice(input_head);
694+
*buffer_usage += n_to_copy;
690695

691-
remaining_head.copy_from_slice(input_head);
692-
*buffer_usage += n_to_copy;
696+
input = input_tail;
693697

694-
input = input_tail;
698+
// We did not fill up the buffer
699+
if !remaining_tail.is_empty() {
700+
return;
701+
}
695702

696-
// We did not fill up the buffer
697-
if !remaining_tail.is_empty() {
698-
return;
699-
}
703+
// We don't know this isn't the last of the data
704+
if input.is_empty() {
705+
return;
706+
}
700707

701-
// We don't know this isn't the last of the data
702-
if input.is_empty() {
703-
return;
704-
}
708+
let (stripes, _) = buffer.bp_as_chunks();
709+
for stripe in stripes {
710+
stripe_accumulator.process_stripe(vector, stripe, n_stripes, secret);
711+
}
712+
*buffer_usage = 0;
713+
}
705714

706-
let (stripes, _) = buffer.bp_as_chunks();
707-
for stripe in stripes {
708-
stripe_accumulator.process_stripe(vector, stripe, n_stripes, secret);
709-
}
710-
*buffer_usage = 0;
711-
}
712-
713-
debug_assert!(*buffer_usage == 0);
714-
715-
// Process as much of the input data in-place as possible,
716-
// while leaving at least one full stripe for the
717-
// finalization.
718-
if let Some(len) = input.len().checked_sub(STRIPE_BYTES) {
719-
let full_block_point = (len / STRIPE_BYTES) * STRIPE_BYTES;
720-
// Safety: We know that `full_block_point` must be less than
721-
// `input.len()` as we subtracted and then integer-divided
722-
// (which rounds down) and then multiplied back. That's not
723-
// evident to the compiler and `split_at` results in a
724-
// potential panic.
725-
//
726-
// https://github.com/llvm/llvm-project/issues/104827
727-
let (stripes, remainder) = unsafe { input.split_at_unchecked(full_block_point) };
728-
let (stripes, _) = stripes.bp_as_chunks();
729-
730-
for stripe in stripes {
731-
stripe_accumulator.process_stripe(vector, stripe, n_stripes, secret)
732-
}
733-
input = remainder;
734-
}
715+
debug_assert!(*buffer_usage == 0);
716+
717+
// Process as much of the input data in-place as possible,
718+
// while leaving at least one full stripe for the
719+
// finalization.
720+
if let Some(len) = input.len().checked_sub(STRIPE_BYTES) {
721+
let full_block_point = (len / STRIPE_BYTES) * STRIPE_BYTES;
722+
// Safety: We know that `full_block_point` must be less than
723+
// `input.len()` as we subtracted and then integer-divided
724+
// (which rounds down) and then multiplied back. That's not
725+
// evident to the compiler and `split_at` results in a
726+
// potential panic.
727+
//
728+
// https://github.com/llvm/llvm-project/issues/104827
729+
let (stripes, remainder) = unsafe { input.split_at_unchecked(full_block_point) };
730+
let (stripes, _) = stripes.bp_as_chunks();
731+
732+
for stripe in stripes {
733+
stripe_accumulator.process_stripe(&vector, stripe, n_stripes, secret)
734+
}
735+
input = remainder;
736+
}
735737

736-
// Any remaining data has to be less than the buffer, and the
737-
// buffer is empty so just fill up the buffer.
738-
debug_assert!(*buffer_usage == 0);
739-
debug_assert!(!input.is_empty());
738+
// Any remaining data has to be less than the buffer, and the
739+
// buffer is empty so just fill up the buffer.
740+
debug_assert!(*buffer_usage == 0);
741+
debug_assert!(!input.is_empty());
742+
743+
// Safety: We have parsed all the full blocks of input except one
744+
// and potentially a full block minus one byte. That amount of
745+
// data must be less than the buffer.
746+
let buffer_head = unsafe {
747+
debug_assert!(input.len() < 2 * STRIPE_BYTES);
748+
debug_assert!(2 * STRIPE_BYTES < buffer.len());
749+
buffer.get_unchecked_mut(..input.len())
750+
};
740751

741-
// Safety: We have parsed all the full blocks of input except one
742-
// and potentially a full block minus one byte. That amount of
743-
// data must be less than the buffer.
744-
let buffer_head = unsafe {
745-
debug_assert!(input.len() < 2 * STRIPE_BYTES);
746-
debug_assert!(2 * STRIPE_BYTES < buffer.len());
747-
buffer.get_unchecked_mut(..input.len())
748-
};
752+
buffer_head.copy_from_slice(input);
753+
*buffer_usage = input.len();
754+
});
755+
}
749756

750-
buffer_head.copy_from_slice(input);
751-
*buffer_usage = input.len();
752-
}
757+
#[inline]
758+
fn finish(&self) -> u64 {
759+
dispatch_f(|vector| {
760+
let RawHasher {
761+
ref secret_buffer,
762+
buffer_usage,
763+
mut stripe_accumulator,
764+
total_bytes,
765+
} = *self;
766+
767+
let n_stripes = secret_buffer.n_stripes();
768+
let (seed, secret, buffer) = secret_buffer.parts();
769+
770+
// Safety: This is an invariant of the buffer.
771+
unsafe {
772+
debug_assert!(buffer_usage <= buffer.len());
773+
assert_unchecked(buffer_usage <= buffer.len())
774+
};
753775

754-
#[inline(always)]
755-
fn finish_impl<S>(vector: impl Vector, this: &RawHasher<S>) -> u64
756-
where
757-
S: FixedBuffer,
758-
{
759-
let RawHasher {
760-
ref secret_buffer,
761-
buffer_usage,
762-
mut stripe_accumulator,
763-
total_bytes,
764-
} = *this;
765-
766-
let n_stripes = secret_buffer.n_stripes();
767-
let (seed, secret, buffer) = secret_buffer.parts();
768-
769-
// Safety: This is an invariant of the buffer.
770-
unsafe {
771-
debug_assert!(buffer_usage <= buffer.len());
772-
assert_unchecked(buffer_usage <= buffer.len())
773-
};
776+
if total_bytes > CUTOFF {
777+
let input = &buffer[..buffer_usage];
774778

775-
if total_bytes > CUTOFF {
776-
let input = &buffer[..buffer_usage];
779+
// Ingest final stripes
780+
let (stripes, remainder) = stripes_with_tail(input);
781+
for stripe in stripes {
782+
stripe_accumulator.process_stripe(&vector, stripe, n_stripes, secret);
783+
}
777784

778-
// Ingest final stripes
779-
let (stripes, remainder) = stripes_with_tail(input);
780-
for stripe in stripes {
781-
stripe_accumulator.process_stripe(vector, stripe, n_stripes, secret);
782-
}
785+
let mut temp = [0; 64];
783786

784-
let mut temp = [0; 64];
787+
let last_stripe = match input.last_chunk() {
788+
Some(chunk) => chunk,
789+
None => {
790+
let n_to_reuse = 64 - input.len();
791+
let to_reuse = buffer.len() - n_to_reuse;
785792

786-
let last_stripe = match input.last_chunk() {
787-
Some(chunk) => chunk,
788-
None => {
789-
let n_to_reuse = 64 - input.len();
790-
let to_reuse = buffer.len() - n_to_reuse;
793+
let (temp_head, temp_tail) = temp.split_at_mut(n_to_reuse);
794+
temp_head.copy_from_slice(&buffer[to_reuse..]);
795+
temp_tail.copy_from_slice(input);
791796

792-
let (temp_head, temp_tail) = temp.split_at_mut(n_to_reuse);
793-
temp_head.copy_from_slice(&buffer[to_reuse..]);
794-
temp_tail.copy_from_slice(input);
797+
&temp
798+
}
799+
};
795800

796-
&temp
801+
Algorithm(vector).finalize(
802+
stripe_accumulator.accumulator,
803+
remainder,
804+
last_stripe,
805+
secret,
806+
total_bytes,
807+
)
808+
} else {
809+
impl_oneshot(DEFAULT_SECRET, seed, &buffer[..total_bytes])
797810
}
798-
};
799-
800-
Algorithm(vector).finalize(
801-
stripe_accumulator.accumulator,
802-
remainder,
803-
last_stripe,
804-
secret,
805-
total_bytes,
806-
)
807-
} else {
808-
impl_oneshot(DEFAULT_SECRET, seed, &buffer[..total_bytes])
811+
})
809812
}
810813
}
811814

@@ -1171,12 +1174,22 @@ fn stripes_with_tail(block: &[u8]) -> (&[[u8; 64]], &[u8]) {
11711174
}
11721175
}
11731176

1174-
trait Vector: Copy {
1177+
trait Vector {
11751178
fn round_scramble(&self, acc: &mut [u64; 8], secret_end: &[u8; 64]);
11761179

11771180
fn accumulate(&self, acc: &mut [u64; 8], stripe: &[u8; 64], secret: &[u8; 64]);
11781181
}
11791182

1183+
impl<V: Vector + ?Sized> Vector for &V {
1184+
fn round_scramble(&self, acc: &mut [u64; 8], secret_end: &[u8; 64]) {
1185+
V::round_scramble(self, acc, secret_end);
1186+
}
1187+
1188+
fn accumulate(&self, acc: &mut [u64; 8], stripe: &[u8; 64], secret: &[u8; 64]) {
1189+
V::accumulate(self, acc, stripe, secret);
1190+
}
1191+
}
1192+
11801193
#[inline]
11811194
fn avalanche(mut x: u64) -> u64 {
11821195
x ^= x >> 37;

0 commit comments

Comments
 (0)