diff --git a/library/core/benches/slice.rs b/library/core/benches/slice.rs index 3bfb35e684ea1..1ec51653d92ef 100644 --- a/library/core/benches/slice.rs +++ b/library/core/benches/slice.rs @@ -171,3 +171,17 @@ fn fold_to_last(b: &mut Bencher) { let slice: &[i32] = &[0; 1024]; b.iter(|| black_box(slice).iter().fold(None, |_, r| Some(NonNull::from(r)))); } + +#[bench] +fn slice_cmp_generic(b: &mut Bencher) { + #[derive(PartialEq, Clone, Copy)] + struct Foo(u32, u32); + + let left = [Foo(128, 128); 128]; + let right = [Foo(128, 128); 128]; + + b.iter(|| { + let (left, right) = (black_box(&left), black_box(&right)); + left.as_slice() == right.as_slice() + }); +} diff --git a/library/core/src/slice/cmp.rs b/library/core/src/slice/cmp.rs index 075347b80d031..8082b48552c73 100644 --- a/library/core/src/slice/cmp.rs +++ b/library/core/src/slice/cmp.rs @@ -55,12 +55,45 @@ impl SlicePartialEq for [A] where A: PartialEq, { + #[inline] default fn equal(&self, other: &[B]) -> bool { if self.len() != other.len() { return false; } - self.iter().zip(other.iter()).all(|(x, y)| x == y) + // ZSTs have no identity and slices don't guarantee which addresses-to-ZSTs they produce + // so we only need to compare them once to determine the behavior of the PartialEq impl + if const { mem::size_of::() == 0 && mem::size_of::() == 0 } { + // zero-length slices are always equal + if self.len() == 0 { + return true; + } + // SAFETY: A and B are ZSTs so it's ok to conjure them out of thin air + return unsafe { mem::zeroed::() == mem::zeroed::() }; + } + + const UNROLL: usize = 4; + let mut i = 0; + let mut is_eq = true; + while i + UNROLL < self.len() && is_eq { + // SAFETY: slices are of the same length and loop conditions ensure indexes are in bounds + unsafe { + is_eq = is_eq & (self.get_unchecked(i) == other.get_unchecked(i)); + is_eq = is_eq & (self.get_unchecked(i + 1) == other.get_unchecked(i + 1)); + is_eq = is_eq & (self.get_unchecked(i + 2) == other.get_unchecked(i + 2)); + is_eq = is_eq & (self.get_unchecked(i + 3) == other.get_unchecked(i + 3)); + i = i.unchecked_add(UNROLL); + } + } + while i < self.len() && is_eq { + // SAFETY: slices are of the same length and loop conditions ensure indexes are in bounds + unsafe { + is_eq = is_eq & (self.get_unchecked(i) == other.get_unchecked(i)); + i = i.unchecked_add(1); + } + } + + is_eq } }