use crate::simd::SimdValue;
use std::ops::{BitAnd, BitOr, BitXor, Not};
/// Lane-wise generalization of `bool` for SIMD booleans.
///
/// This trait implemented by `bool` as well as SIMD boolean types like `packed_simd::m32x4`.
/// It is designed to abstract the behavior of booleans so it can work with multi-lane boolean
/// values in an AoSoA setting.
pub trait SimdBool:
Copy
+ BitAnd<Self, Output = Self>
+ BitOr<Self, Output = Self>
+ BitXor<Self, Output = Self>
+ Not<Output = Self>
{
/// A bit mask representing the boolean state of each lanes of `self`.
///
/// The `i-th` bit of the result is `1` iff. the `i-th` lane of `self` is `true`.
fn bitmask(self) -> u64;
/// Lane-wise bitwise and of the vector elements.
fn and(self) -> bool;
/// Lane-wise bitwise or of the vector elements.
fn or(self) -> bool;
/// Lane-wise bitwise xor of the vector elements.
fn xor(self) -> bool;
/// Are all vector lanes true?
fn all(self) -> bool;
/// Is any vector lane true?
fn any(self) -> bool;
/// Are all vector lanes false?
fn none(self) -> bool;
/// Merges the value of `if_value()` and `else_value()` depending on the lanes of `self`.
///
/// - For each lane of `self` containing `1`, the result will contain the corresponding lane of `if_value()`.
/// - For each lane of `self` containing `0`, the result will contain the corresponding lane of `else_value()`.
///
/// The implementor of this trait is free to choose on what cases `if_value` and `else_value` are actually
/// called.
fn if_else<Res: SimdValue<SimdBool = Self>>(
self,
if_value: impl FnOnce() -> Res,
else_value: impl FnOnce() -> Res,
) -> Res;
/// Merges the value of `if_value()` and `else_if.1()` and `else_value()` depending on the lanes of `self` and `else_if.0()`.
///
/// - For each lane of `self` containing `1`, the result will contain the corresponding lane of `if_value()`.
/// - For each lane of `self` containing `0` but with a corresponding lane of `else_if.0()` containing `1`, the result will contain the corresponding lane of `else_if.1()`.
/// - For each lane of `self` containing `0` but with a corresponding lane of `else_if.0()` containing `0`, the result will contain the corresponding lane of `else_value()`.
///
/// The implementor of this trait is free to choose on what cases any of those closures are implemented.
fn if_else2<Res: SimdValue<SimdBool = Self>>(
self,
if_value: impl FnOnce() -> Res,
else_if: (impl FnOnce() -> Self, impl FnOnce() -> Res),
else_value: impl FnOnce() -> Res,
) -> Res;
/// Merges the value of `if_value()` and `else_if.1()` and `else_else_if.1()` and `else_value()` depending on the lanes of `self` and `else_if.0()` and `else_else_if.0()`.
///
/// - For each lane of `self` containing `1`, the result will contain the corresponding lane of `if_value()`.
/// - For each lane of `self` containing `0` but with a corresponding lane of `else_if.0()` containing `1`, the result will contain the corresponding lane of `else_if.1()`.
/// - For each lane of `self` containing `0` and `else_if.0()` containing `0` and `else_else_if.0()` containing `1`, the result will contain the corresponding lane of `else_else_if.1()`.
/// - Other lanes will contain the corresponding lane of `else_value()`.
///
/// The implementor of this trait is free to choose on what cases any of those closures are implemented.
fn if_else3<Res: SimdValue<SimdBool = Self>>(
self,
if_value: impl FnOnce() -> Res,
else_if: (impl FnOnce() -> Self, impl FnOnce() -> Res),
else_else_if: (impl FnOnce() -> Self, impl FnOnce() -> Res),
else_value: impl FnOnce() -> Res,
) -> Res;
}
impl SimdBool for bool {
#[inline(always)]
fn bitmask(self) -> u64 {
self as u64
}
#[inline(always)]
fn and(self) -> bool {
self
}
#[inline(always)]
fn or(self) -> bool {
self
}
#[inline(always)]
fn xor(self) -> bool {
self
}
#[inline(always)]
fn all(self) -> bool {
self
}
#[inline(always)]
fn any(self) -> bool {
self
}
#[inline(always)]
fn none(self) -> bool {
!self
}
#[inline(always)]
fn if_else<Res: SimdValue<SimdBool = Self>>(
self,
if_value: impl FnOnce() -> Res,
else_value: impl FnOnce() -> Res,
) -> Res {
if self {
if_value()
} else {
else_value()
}
}
#[inline(always)]
fn if_else2<Res: SimdValue<SimdBool = Self>>(
self,
if_value: impl FnOnce() -> Res,
else_if: (impl FnOnce() -> Self, impl FnOnce() -> Res),
else_value: impl FnOnce() -> Res,
) -> Res {
if self {
if_value()
} else if else_if.0() {
else_if.1()
} else {
else_value()
}
}
#[inline(always)]
fn if_else3<Res: SimdValue<SimdBool = Self>>(
self,
if_value: impl FnOnce() -> Res,
else_if: (impl FnOnce() -> Self, impl FnOnce() -> Res),
else_else_if: (impl FnOnce() -> Self, impl FnOnce() -> Res),
else_value: impl FnOnce() -> Res,
) -> Res {
if self {
if_value()
} else if else_if.0() {
else_if.1()
} else if else_else_if.0() {
else_else_if.1()
} else {
else_value()
}
}
}