1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
//! Traits for abstracting over Boolean types.
//!
//! These traits are mainly useful for allowing SIMD values, where bit masks are
//! typically used instead of `bool`.
use core::ops::{BitAnd, BitOr, BitXor, Not};
#[cfg(feature = "wide")]
mod wide;
/// Associates a Boolean type to the implementing type.
///
/// This is primarily used in traits and functions that can accept SIMD values
/// and return a Boolean result. SIMD values use masks to select different values for
/// each lane and `HasBoolMask::Mask` can be used to know which type that mask
/// has.
pub trait HasBoolMask {
/// The mask type to use for selecting `Self` values.
type Mask: BoolMask;
}
impl<T> HasBoolMask for &'_ T
where
T: HasBoolMask,
{
type Mask = T::Mask;
}
impl<T> HasBoolMask for &'_ mut T
where
T: HasBoolMask,
{
type Mask = T::Mask;
}
impl<T> HasBoolMask for [T]
where
T: HasBoolMask,
{
type Mask = T::Mask;
}
impl<T, const N: usize> HasBoolMask for [T; N]
where
T: HasBoolMask,
{
type Mask = T::Mask;
}
macro_rules! impl_has_bool_mask {
($($ty:ident),+) => {
$(
impl HasBoolMask for $ty {
type Mask = bool;
}
)+
};
}
impl_has_bool_mask!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, f32, f64);
/// Basic methods for boolean masks.
pub trait BoolMask {
/// Create a new mask where each lane is set to `value`.
#[must_use]
fn from_bool(value: bool) -> Self;
/// Checks if all lanes in the mask are `true`.
#[must_use]
fn is_true(&self) -> bool;
/// Checks if all lanes in the mask are `false`.
#[must_use]
fn is_false(&self) -> bool;
}
impl BoolMask for bool {
#[inline]
fn from_bool(value: bool) -> Self {
value
}
#[inline]
fn is_true(&self) -> bool {
*self
}
#[inline]
fn is_false(&self) -> bool {
!*self
}
}
/// Makes a mask bale to select between two values.
pub trait Select<T>
where
T: HasBoolMask<Mask = Self>,
{
/// Select lanes from `a` when corresponding lanes in `self` are `true`, and
/// select from `b` when `false`.
#[must_use]
fn select(self, a: T, b: T) -> T;
}
impl<T> Select<T> for bool
where
T: HasBoolMask<Mask = Self>,
{
#[inline(always)]
fn select(self, a: T, b: T) -> T {
if self {
a
} else {
b
}
}
}
/// Like [`Select`], but can avoid evaluating the input.
pub trait LazySelect<T>: Select<T>
where
T: HasBoolMask<Mask = Self>,
{
/// Select lanes from the output of `a` when corresponding lanes in `self`
/// are `true`, and select from the output of `b` when `false`. May avoid
/// evaluating either option if it's not selected.
#[must_use]
fn lazy_select<A, B>(self, a: A, b: B) -> T
where
A: FnOnce() -> T,
B: FnOnce() -> T;
}
impl<T> LazySelect<T> for bool
where
T: HasBoolMask<Mask = Self>,
{
#[inline(always)]
fn lazy_select<A, B>(self, a: A, b: B) -> T
where
A: FnOnce() -> T,
B: FnOnce() -> T,
{
if self {
a()
} else {
b()
}
}
}
/// A helper trait that collects bit traits under one name.
pub trait BitOps:
Sized
+ BitAnd<Output = Self>
+ BitOr<Output = Self>
+ BitXor<Output = Self>
+ Not<Output = Self>
+ for<'a> BitAnd<&'a Self, Output = Self>
+ for<'a> BitOr<&'a Self, Output = Self>
+ for<'a> BitXor<&'a Self, Output = Self>
{
}
impl<T> BitOps for T where
T: Sized
+ BitAnd<Output = Self>
+ BitOr<Output = Self>
+ BitXor<Output = Self>
+ Not<Output = Self>
+ for<'a> BitAnd<&'a Self, Output = Self>
+ for<'a> BitOr<&'a Self, Output = Self>
+ for<'a> BitXor<&'a Self, Output = Self>
{
}