diff --git a/library/core/src/slice/cmp.rs b/library/core/src/slice/cmp.rs index 10a0088477162..3a62e7f61b2b4 100644 --- a/library/core/src/slice/cmp.rs +++ b/library/core/src/slice/cmp.rs @@ -391,10 +391,16 @@ where } } -impl SliceContains for u8 { +impl SliceContains for T { #[inline] fn slice_contains(&self, x: &[Self]) -> bool { - memchr::memchr(*self, x).is_some() + // SAFETY: `UnsignedBytewiseOrd` guarantees that `Self` has the same + // layout as `u8` and is initialized, so both the value and slice can + // be read as bytes. + let (byte, bytes) = unsafe { + (*(self as *const Self).cast::(), from_raw_parts(x.as_ptr().cast::(), x.len())) + }; + memchr::memchr(byte, bytes).is_some() } } diff --git a/library/coretests/tests/slice.rs b/library/coretests/tests/slice.rs index a4db7304fff90..22b1ba7738af9 100644 --- a/library/coretests/tests/slice.rs +++ b/library/coretests/tests/slice.rs @@ -5,6 +5,39 @@ use core::num::NonZero; use core::ops::{Range, RangeInclusive}; use core::slice; +#[test] +fn test_contains_bytewise_types() { + let mut bools = [false; 64]; + assert!(bools.contains(&false)); + assert!(!bools.contains(&true)); + bools[31] = true; + assert!(bools.contains(&true)); + + let one = NonZero::new(1_u8).unwrap(); + let two = NonZero::new(2_u8).unwrap(); + let three = NonZero::new(3_u8).unwrap(); + let mut nonzeros = [one; 64]; + nonzeros[31] = two; + assert!(nonzeros.contains(&one)); + assert!(nonzeros.contains(&two)); + assert!(!nonzeros.contains(&three)); + + let mut optional_nonzeros = [Some(one); 64]; + optional_nonzeros[31] = None; + assert!(optional_nonzeros.contains(&Some(one))); + assert!(optional_nonzeros.contains(&None)); + assert!(!optional_nonzeros.contains(&Some(two))); + + let a = core::ascii::Char::CapitalA; + let q = core::ascii::Char::CapitalQ; + let z = core::ascii::Char::CapitalZ; + let mut ascii = [a; 64]; + ascii[31] = z; + assert!(ascii.contains(&a)); + assert!(ascii.contains(&z)); + assert!(!ascii.contains(&q)); +} + #[test] fn test_position() { let b = [1, 2, 3, 5, 5]; diff --git a/tests/codegen-llvm/lib-optimizations/slice-contains.rs b/tests/codegen-llvm/lib-optimizations/slice-contains.rs new file mode 100644 index 0000000000000..ecca007875148 --- /dev/null +++ b/tests/codegen-llvm/lib-optimizations/slice-contains.rs @@ -0,0 +1,36 @@ +// Ensure one-byte slice `contains` specializations use the optimized byte search. +//@ compile-flags: -Copt-level=3 -Zinline-mir=false + +#![crate_type = "lib"] +#![feature(ascii_char)] + +use std::ascii::Char as AsciiChar; +use std::num::NonZeroU8; + +// CHECK-LABEL: @contains_bool +#[no_mangle] +pub fn contains_bool(x: bool, data: &[bool]) -> bool { + // CHECK: call core::slice::memchr + data.contains(&x) +} + +// CHECK-LABEL: @contains_nonzero_u8 +#[no_mangle] +pub fn contains_nonzero_u8(x: NonZeroU8, data: &[NonZeroU8]) -> bool { + // CHECK: call core::slice::memchr + data.contains(&x) +} + +// CHECK-LABEL: @contains_option_nonzero_u8 +#[no_mangle] +pub fn contains_option_nonzero_u8(x: Option, data: &[Option]) -> bool { + // CHECK: call core::slice::memchr + data.contains(&x) +} + +// CHECK-LABEL: @contains_ascii_char +#[no_mangle] +pub fn contains_ascii_char(x: AsciiChar, data: &[AsciiChar]) -> bool { + // CHECK: call core::slice::memchr + data.contains(&x) +}