npsimd 0.3.0

An ergonomic library for architecture-specific vectorization.
Documentation
//! SIMD mask types.
//!
//! This module provides specific types for representing masks.  A mask is a
//! sequence of boolean values corresponding to vector elements.  They are
//! represented differently in different SIMD generations.
//!
//! With SSE and AVX, masks are usually represented as normal SIMD vectors, with
//! all 1 bits representing an active mask element and all 0 bits representing
//! an inactive mask element (this is the format used by e.g. `PCMPEQB`).  This
//! format is provided by [`Mask8`], [`Mask16`], etc. (though with no soundness
//! guarantee, so that incorrect conversions are sound but logic bugs).

use core::fmt;

use super::*;

#[cfg(feature = "proptest")]
use proptest::{arbitrary::Arbitrary, strategy::{self, Strategy}};

macro_rules! impl_mask_elem {
    { $(
        $(#[$attr:meta])*
        $vis:vis type $name:ident($base:ty);
    )* } => { $(
        $(#[$attr])*
        #[derive(Copy, Clone)]
        #[repr(transparent)]
        $vis struct $name($base);

        impl $name {
            /// Construct a new mask from a boolean.
            pub const fn new(value: bool) -> Self {
                Self(if value { -1 } else { 0 })
            }

            /// The value of this mask.
            pub const fn value(self) -> bool {
                self.0 < 0
            }

            /// An active mask.
            pub const ACTIVE: Self = Self(-1);

            /// An inactive mask.
            pub const INACTIVE: Self = Self(0);
        }

        unsafe impl<const LEN: usize> Element<LEN> for $name
        where $base: Element<LEN> {
            type Primitive = <$base as Element<LEN>>::Primitive;
        }

        impl From<bool> for $name {
            fn from(value: bool) -> Self {
                Self::new(value)
            }
        }

        impl From<$name> for bool {
            fn from(value: $name) -> Self {
                value.value()
            }
        }

        impl From<$base> for $name {
            fn from(value: $base) -> Self {
                Self::new(value < 0)
            }
        }

        impl From<$name> for $base {
            fn from(value: $name) -> Self {
                value.0
            }
        }

        impl PartialEq for $name {
            fn eq(&self, that: &Self) -> bool {
                self.value() == that.value()
            }
        }

        impl Eq for $name {}

        impl fmt::Debug for $name {
            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                f.debug_tuple(stringify!($name))
                    .field(&self.value())
                    .finish()
            }
        }

        #[cfg(feature = "proptest")]
        impl Arbitrary for $name {
            type Parameters = ();
            type Strategy = strategy::MapInto<
                <bool as Arbitrary>::Strategy, $name>;

            fn arbitrary_with((): Self::Parameters) -> Self::Strategy {
                bool::arbitrary_with(()).prop_map_into()
            }
        }
    )* };
}

impl_mask_elem! {
    /// An 8-bit mask element.
    pub type Mask8(i8);

    /// An 16-bit mask element.
    pub type Mask16(i16);

    /// An 32-bit mask element.
    pub type Mask32(i32);

    /// An 64-bit mask element.
    pub type Mask64(i64);
}