#![allow(unused_imports)] use super::MaskElement; use crate::simd::intrinsics; use crate::simd::{LaneCount, Simd, SupportedLaneCount, ToBitMask}; use core::marker::PhantomData; /// A mask where each lane is represented by a single bit. #[repr(transparent)] pub struct Mask( as SupportedLaneCount>::BitMask, PhantomData, ) where T: MaskElement, LaneCount: SupportedLaneCount; impl Copy for Mask where T: MaskElement, LaneCount: SupportedLaneCount, { } impl Clone for Mask where T: MaskElement, LaneCount: SupportedLaneCount, { fn clone(&self) -> Self { *self } } impl PartialEq for Mask where T: MaskElement, LaneCount: SupportedLaneCount, { fn eq(&self, other: &Self) -> bool { self.0.as_ref() == other.0.as_ref() } } impl PartialOrd for Mask where T: MaskElement, LaneCount: SupportedLaneCount, { fn partial_cmp(&self, other: &Self) -> Option { self.0.as_ref().partial_cmp(other.0.as_ref()) } } impl Eq for Mask where T: MaskElement, LaneCount: SupportedLaneCount, { } impl Ord for Mask where T: MaskElement, LaneCount: SupportedLaneCount, { fn cmp(&self, other: &Self) -> core::cmp::Ordering { self.0.as_ref().cmp(other.0.as_ref()) } } impl Mask where T: MaskElement, LaneCount: SupportedLaneCount, { #[inline] #[must_use = "method returns a new mask and does not mutate the original value"] pub fn splat(value: bool) -> Self { let mut mask = as SupportedLaneCount>::BitMask::default(); if value { mask.as_mut().fill(u8::MAX) } else { mask.as_mut().fill(u8::MIN) } if LANES % 8 > 0 { *mask.as_mut().last_mut().unwrap() &= u8::MAX >> (8 - LANES % 8); } Self(mask, PhantomData) } #[inline] #[must_use = "method returns a new bool and does not mutate the original value"] pub unsafe fn test_unchecked(&self, lane: usize) -> bool { (self.0.as_ref()[lane / 8] >> (lane % 8)) & 0x1 > 0 } #[inline] pub unsafe fn set_unchecked(&mut self, lane: usize, value: bool) { unsafe { self.0.as_mut()[lane / 8] ^= ((value ^ self.test_unchecked(lane)) as u8) << (lane % 8) } } #[inline] #[must_use = "method returns a new vector and does not mutate the original value"] pub fn to_int(self) -> Simd { unsafe { intrinsics::simd_select_bitmask(self.0, Simd::splat(T::TRUE), Simd::splat(T::FALSE)) } } #[inline] #[must_use = "method returns a new mask and does not mutate the original value"] pub unsafe fn from_int_unchecked(value: Simd) -> Self { unsafe { Self(intrinsics::simd_bitmask(value), PhantomData) } } #[cfg(feature = "generic_const_exprs")] #[inline] #[must_use = "method returns a new array and does not mutate the original value"] pub fn to_bitmask_array(self) -> [u8; N] { assert!(core::mem::size_of::() == N); // Safety: converting an integer to an array of bytes of the same size is safe unsafe { core::mem::transmute_copy(&self.0) } } #[cfg(feature = "generic_const_exprs")] #[inline] #[must_use = "method returns a new mask and does not mutate the original value"] pub fn from_bitmask_array(bitmask: [u8; N]) -> Self { assert!(core::mem::size_of::() == N); // Safety: converting an array of bytes to an integer of the same size is safe Self(unsafe { core::mem::transmute_copy(&bitmask) }, PhantomData) } #[inline] pub fn to_bitmask_integer(self) -> U where super::Mask: ToBitMask, { // Safety: these are the same types unsafe { core::mem::transmute_copy(&self.0) } } #[inline] pub fn from_bitmask_integer(bitmask: U) -> Self where super::Mask: ToBitMask, { // Safety: these are the same types unsafe { Self(core::mem::transmute_copy(&bitmask), PhantomData) } } #[inline] #[must_use = "method returns a new mask and does not mutate the original value"] pub fn convert(self) -> Mask where U: MaskElement, { // Safety: bitmask layout does not depend on the element width unsafe { core::mem::transmute_copy(&self) } } #[inline] #[must_use = "method returns a new bool and does not mutate the original value"] pub fn any(self) -> bool { self != Self::splat(false) } #[inline] #[must_use = "method returns a new bool and does not mutate the original value"] pub fn all(self) -> bool { self == Self::splat(true) } } impl core::ops::BitAnd for Mask where T: MaskElement, LaneCount: SupportedLaneCount, as SupportedLaneCount>::BitMask: AsRef<[u8]> + AsMut<[u8]>, { type Output = Self; #[inline] #[must_use = "method returns a new mask and does not mutate the original value"] fn bitand(mut self, rhs: Self) -> Self { for (l, r) in self.0.as_mut().iter_mut().zip(rhs.0.as_ref().iter()) { *l &= r; } self } } impl core::ops::BitOr for Mask where T: MaskElement, LaneCount: SupportedLaneCount, as SupportedLaneCount>::BitMask: AsRef<[u8]> + AsMut<[u8]>, { type Output = Self; #[inline] #[must_use = "method returns a new mask and does not mutate the original value"] fn bitor(mut self, rhs: Self) -> Self { for (l, r) in self.0.as_mut().iter_mut().zip(rhs.0.as_ref().iter()) { *l |= r; } self } } impl core::ops::BitXor for Mask where T: MaskElement, LaneCount: SupportedLaneCount, { type Output = Self; #[inline] #[must_use = "method returns a new mask and does not mutate the original value"] fn bitxor(mut self, rhs: Self) -> Self::Output { for (l, r) in self.0.as_mut().iter_mut().zip(rhs.0.as_ref().iter()) { *l ^= r; } self } } impl core::ops::Not for Mask where T: MaskElement, LaneCount: SupportedLaneCount, { type Output = Self; #[inline] #[must_use = "method returns a new mask and does not mutate the original value"] fn not(mut self) -> Self::Output { for x in self.0.as_mut() { *x = !*x; } if LANES % 8 > 0 { *self.0.as_mut().last_mut().unwrap() &= u8::MAX >> (8 - LANES % 8); } self } }