From 24affba02e1db9fdfe446e68a74a0ba98acbdd71 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 10 Dec 2021 17:30:39 -0800 Subject: [PATCH] Allow `memcmp` for more array comparisons This way comparing `[NonZeroU8; 8]` is just as fast as comparing `[u8; 8]`. --- library/core/src/array/equality.rs | 54 +++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 5 deletions(-) diff --git a/library/core/src/array/equality.rs b/library/core/src/array/equality.rs index a882d18b1514c..25e056501be96 100644 --- a/library/core/src/array/equality.rs +++ b/library/core/src/array/equality.rs @@ -1,3 +1,6 @@ +use crate::num::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize}; +use crate::num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize}; + #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq<[B; N]> for [A; N] where @@ -124,7 +127,7 @@ impl, Other, const N: usize> SpecArrayEq for T { } } -impl + IsRawEqComparable, U, const N: usize> SpecArrayEq for T { +impl, U, const N: usize> SpecArrayEq for T { fn spec_eq(a: &[T; N], b: &[U; N]) -> bool { // SAFETY: This is why `IsRawEqComparable` is an `unsafe trait`. unsafe { @@ -145,11 +148,52 @@ impl + IsRawEqComparable, U, const N: usize> SpecArrayEq` is byte-wise (this means no floats, among other things) #[rustc_specialization_trait] -unsafe trait IsRawEqComparable {} +unsafe trait IsRawEqComparable: PartialEq {} -macro_rules! is_raw_comparable { - ($($t:ty),+) => {$( +macro_rules! is_raw_eq_comparable { + ($($t:ty),+ $(,)?) => {$( unsafe impl IsRawEqComparable<$t> for $t {} )+}; } -is_raw_comparable!(bool, char, u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize); + +// SAFETY: All the ordinary integer types allow all bit patterns as distinct values +is_raw_eq_comparable!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize); + +// SAFETY: bool and char have *niches*, but no *padding*, so this is sound +is_raw_eq_comparable!(bool, char); + +// SAFETY: Similarly, the non-zero types have a niche, but no undef, +// and they compare like their underlying numeric type. +is_raw_eq_comparable!( + NonZeroU8, + NonZeroU16, + NonZeroU32, + NonZeroU64, + NonZeroU128, + NonZeroUsize, + NonZeroI8, + NonZeroI16, + NonZeroI32, + NonZeroI64, + NonZeroI128, + NonZeroIsize, +); + +// SAFETY: The NonZero types have the "null" optimization guaranteed, and thus +// are also safe to equality-compare bitwise inside an `Option`. +// The way `PartialOrd` is defined for `Option` means that this wouldn't work +// for `<` or `>` on the signed types, but since we only do `==` it's fine. +is_raw_eq_comparable!( + Option, + Option, + Option, + Option, + Option, + Option, + Option, + Option, + Option, + Option, + Option, + Option, +);