Skip to content

Commit

Permalink
Auto merge of #116422 - the8472:chunked-generic-slice-eq, r=<try>
Browse files Browse the repository at this point in the history
Chunked generic slice eq

looks nice in a microbenchmark, let's see if perf agrees

```
OLD:
    slice::slice_cmp_generic 54.00ns/iter +/- 1.00ns
NEW:
    slice::slice_cmp_generic 20.00ns/iter +/- 2.00ns
```
  • Loading branch information
bors committed Oct 5, 2023
2 parents 5c3a0e9 + ef4600d commit 10dcf57
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 1 deletion.
14 changes: 14 additions & 0 deletions library/core/benches/slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
});
}
35 changes: 34 additions & 1 deletion library/core/src/slice/cmp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,45 @@ impl<A, B> SlicePartialEq<B> for [A]
where
A: PartialEq<B>,
{
#[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::<A>() == 0 && mem::size_of::<B>() == 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::<A>() == mem::zeroed::<B>() };
}

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
}
}

Expand Down

0 comments on commit 10dcf57

Please sign in to comment.