// Generated from {{template_path}} template. Edit the template, not the generated file.
{% if scalar_t == "bool" %}
{% set self_t = "BVec" ~ dim %}
{% set align = 1 %}
{% set is_bool = true %}
{% else %}
{% set self_t = "BVec" ~ dim ~ "A" %}
{% if dim == 4 %}
{% set vec_t = "Vec4" %}
{% elif dim == 3 %}
{% set vec_t = "Vec3A" %}
{% endif %}
{% set align = 16 %}
{% set is_u32 = true %}
{% if is_sse2 %}
{% set simd_t = "__m128" %}
{% elif is_wasm32 %}
{% set simd_t = "v128" %}
{% elif is_neon %}
{% set simd_t = "uint32x4_t" %}
{% elif is_coresimd %}
{% set simd_t = "mask32x4" %}
{% endif %}
{% endif %}
{% set components = ["x", "y", "z", "w"] | slice(end = dim) %}
use core::fmt;
use core::ops::*;
{% if is_sse2 %}
#[cfg(target_arch = "x86")]
use core::arch::x86::*;
#[cfg(target_arch = "x86_64")]
use core::arch::x86_64::*;
{% elif is_wasm32 %}
use core::arch::wasm32::*;
{% elif is_neon %}
use core::arch::aarch64::*;
{% elif is_coresimd %}
use core::simd::*;
{% endif %}
{% if is_sse2 or is_neon or is_coresimd %}
#[repr(C)]
union UnionCast {
a: [u32; 4],
v: {{ self_t }}
}
{% endif %}
/// Creates a {{ dim }}-dimensional `bool` vector mask.
#[inline(always)]
#[must_use]
pub const fn {{ self_t | lower }}(
{% for c in components %}
{{ c }}: bool,
{% endfor %}
) -> {{ self_t }} {
{{ self_t }}::new({{ components | join(sep=",") }})
}
{% if is_scalar and is_bool %}
/// A {{ dim }}-dimensional `bool` vector mask.
{%- elif is_scalar and is_u32 %}
/// A {{ dim }}-dimensional `u32` vector mask.
{%- else %}
/// A {{ dim }}-dimensional SIMD vector mask.
///
/// This type is {{ align }} byte aligned.
{%- endif %}
{%- if is_scalar or is_bool %}
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
{%- else %}
#[derive(Clone, Copy)]
{%- endif %}
{%- if is_scalar %}
#[repr(C, align({{ align }}))]
pub struct {{ self_t }}
{
{% for c in components %}
pub {{ c }}: {{ scalar_t }},
{%- endfor %}
}
{%- else %}
#[repr(transparent)]
pub struct {{ self_t }}(pub(crate) {{ simd_t }});
{% endif %}
const MASK: [u32; 2] = [0, 0xff_ff_ff_ff];
impl {{ self_t }} {
/// All false.
pub const FALSE: Self = Self::splat(false);
/// All true.
pub const TRUE: Self = Self::splat(true);
/// Creates a new vector mask.
#[inline(always)]
#[must_use]
pub const fn new(
{% for c in components %}
{{ c }}: bool,
{% endfor %}
) -> Self {
{% if is_scalar and is_bool %}
Self {
{% for c in components %}
{{ c }},
{%- endfor %}
}
{% elif is_scalar and is_u32 %}
Self {
{% for c in components %}
{{ c }}: MASK[{{ c }} as usize],
{%- endfor %}
}
{% elif is_sse2 or is_neon or is_coresimd %}
unsafe {
UnionCast { a: [
MASK[x as usize],
MASK[y as usize],
MASK[z as usize],
{% if dim == 3 %}
0,
{% elif dim == 4 %}
MASK[w as usize],
{% endif %}
] }.v
}
{% elif is_wasm32 %}
Self(u32x4(
MASK[x as usize],
MASK[y as usize],
MASK[z as usize],
{% if dim == 3 %}
0,
{% elif dim == 4 %}
MASK[w as usize],
{% endif %}
))
{% endif %}
}
/// Creates a vector mask with all elements set to `v`.
#[inline]
#[must_use]
pub const fn splat(v: bool) -> Self {
Self::new(
{% for c in components %}
v,
{%- endfor %}
)
}
/// Creates a new vector mask from a bool array.
#[inline]
#[must_use]
pub const fn from_array(a: [bool; {{ dim }}]) -> Self {
Self::new(
{% for c in components %}
a[{{ loop.index0 }}],
{%- endfor %}
)
}
/// Returns a bitmask with the lowest {{ dim }} bits set from the elements of `self`.
///
/// A true element results in a `1` bit and a false element in a `0` bit. Element `x` goes
/// into the first lowest bit, element `y` into the second, etc.
#[inline]
#[must_use]
pub fn bitmask(self) -> u32 {
{% if is_scalar and is_bool %}
{% for c in components %}
{% if loop.first %}
(self.{{ c }} as u32) |
{% else %}
((self.{{ c }} as u32) << {{ loop.index0 }}) {% if not loop.last %} | {% endif %}
{% endif %}
{% endfor %}
{% elif is_scalar and is_u32 %}
{% for c in components %}
{% if loop.first %}
(self.{{ c }} & 0x1) |
{% else %}
((self.{{ c }} & 0x1) << {{ loop.index0 }}) {% if not loop.last %} | {% endif %}
{% endif %}
{% endfor %}
{% elif is_sse2 %}
{% if dim == 3 %}
unsafe { (_mm_movemask_ps(self.0) as u32) & 0x7 }
{% elif dim == 4 %}
unsafe { _mm_movemask_ps(self.0) as u32 }
{% endif %}
{% elif is_wasm32 %}
{% if dim == 3 %}
(u32x4_bitmask(self.0) & 0x7) as u32
{% elif dim == 4 %}
u32x4_bitmask(self.0) as u32
{% endif %}
{% elif is_neon %}
{% if dim == 3 %}
let movemask = unsafe {
{% elif dim == 4 %}
unsafe {
{% endif %}
let mma = vandq_u32(self.0, vld1q_u32([1, 2, 4, 8].as_ptr())); // [0 1 2 3]
let mmb = vextq_u32(mma, mma, 2); // [2 3 0 1]
let mmc = vorrq_u32(mma, mmb); // [0+2 1+3 0+2 1+3]
let mmd = vextq_u32(mmc, mmc, 3); // [1+3 0+2 1+3 0+2]
let mme = vorrq_u32(mmc, mmd); // [0+1+2+3 ...]
vgetq_lane_u32(mme, 0)
{% if dim == 3 %}
};
movemask & 0x7
{% elif dim == 4 %}
}
{% endif %}
{% elif is_coresimd %}
{% if dim == 3 %}
(self.0.to_bitmask() & 0x7) as u32
{% elif dim == 4 %}
self.0.to_bitmask() as u32
{% endif %}
{% else %}
unimplemented!()
{% endif %}
}
/// Returns true if any of the elements are true, false otherwise.
#[inline]
#[must_use]
pub fn any(self) -> bool {
{% if is_scalar and is_bool %}
{% for c in components %}
self.{{ c }} {% if not loop.last %} || {% endif %}
{%- endfor %}
{% elif is_scalar and is_u32 %}
((
{% for c in components %}
self.{{ c }} {% if not loop.last %} | {% endif %}
{%- endfor %}
) & 0x1) != 0
{% else %}
self.bitmask() != 0
{% endif %}
}
/// Returns true if all the elements are true, false otherwise.
#[inline]
#[must_use]
pub fn all(self) -> bool {
{% if is_scalar and is_bool %}
{% for c in components %}
self.{{ c }} {% if not loop.last %} && {% endif %}
{%- endfor %}
{% elif is_scalar and is_u32 %}
((
{% for c in components %}
self.{{ c }} {% if not loop.last %} & {% endif %}
{%- endfor %}
) & 0x1) != 0
{% else %}
{% if dim == 3 %}
self.bitmask() == 0x7
{% elif dim == 4 %}
self.bitmask() == 0xf
{% endif %}
{% endif %}
}
/// Tests the value at `index`.
///
/// Panics if `index` is greater than {{ dim - 1 }}.
#[inline]
#[must_use]
pub fn test(&self, index: usize) -> bool {
{% if is_coresimd %}
self.0.test(index)
{% else %}
match index {
{% for c in components %}
{%- if is_scalar and is_bool %}
{{ loop.index0 }} => self.{{ c }},
{%- elif is_scalar and is_u32 %}
{{ loop.index0 }} => (self.{{ c }} & 0x1) != 0,
{%- else %}
{{ loop.index0 }} => (self.bitmask() & (1 << {{ loop.index0 }})) != 0,
{%- endif %}
{%- endfor %}
_ => panic!("index out of bounds")
}
{% endif %}
}
/// Sets the element at `index`.
///
/// Panics if `index` is greater than {{ dim - 1 }}.
#[inline]
pub fn set(&mut self, index: usize, value: bool) {
{% if is_scalar %}
match index {
{% for c in components %}
{%- if is_bool %}
{{ loop.index0 }} => self.{{ c }} = value,
{%- elif is_u32 %}
{{ loop.index0 }} => self.{{ c }} = MASK[value as usize],
{%- endif %}
{%- endfor %}
_ => panic!("index out of bounds")
}
{% elif is_coresimd %}
self.0.set(index, value)
{% elif is_neon %}
self.0 = match index {
{% for c in components %}
{{ loop.index0 }} => unsafe {
vsetq_lane_u32(MASK[value as usize], self.0, {{ loop.index0 }})
},
{%- endfor %}
_ => panic!("index out of bounds")
}
{% else %}
use crate::{{ vec_t }};
let mut v = {{ vec_t }}(self.0);
v[index] = f32::from_bits(MASK[value as usize]);
self.0 = v.0;
{% endif %}
}
#[inline]
#[must_use]
fn into_bool_array(self) -> [bool; {{ dim }}] {
{% if is_scalar and is_bool %}
[
{% for c in components %}
self.{{ c }},
{%- endfor %}
]
{% elif is_scalar and is_u32 %}
[
{% for c in components %}
(self.{{ c }} & 0x1) != 0,
{%- endfor %}
]
{% else %}
{% set bits = [1, 2, 4, 8] | slice(end = dim) %}
let bitmask = self.bitmask();
[
{% for b in bits %}
(bitmask & {{ b }}) != 0,
{%- endfor %}
]
{% endif %}
}
#[inline]
#[must_use]
fn into_u32_array(self) -> [u32; {{ dim }}] {
{% if is_scalar and is_bool %}
[
{% for c in components %}
MASK[self.{{ c }} as usize],
{%- endfor %}
]
{% elif is_scalar and is_u32 %}
[
{% for c in components %}
self.{{ c }},
{%- endfor %}
]
{% else %}
let bitmask = self.bitmask();
[
{% for c in components %}
{% if loop.first %}
MASK[(bitmask & 1) as usize],
{% else %}
MASK[((bitmask >> {{ loop.index0 }}) & 1) as usize],
{% endif %}
{%- endfor %}
]
{% endif %}
}
}
impl Default for {{ self_t }} {
#[inline]
fn default() -> Self {
Self::FALSE
}
}
{% if not is_scalar and not is_bool %}
impl PartialEq for {{ self_t }} {
#[inline]
fn eq(&self, rhs: &Self) -> bool {
self.bitmask().eq(&rhs.bitmask())
}
}
impl Eq for {{ self_t }} {}
impl core::hash::Hash for {{ self_t }} {
#[inline]
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.bitmask().hash(state);
}
}
{%- endif %}
impl BitAnd for {{ self_t }} {
type Output = Self;
#[inline]
fn bitand(self, rhs: Self) -> Self {
{% if is_scalar %}
Self {
{% for c in components %}
{{ c }}: self.{{ c }} & rhs.{{ c }},
{%- endfor %}
}
{% elif is_sse2 %}
Self(unsafe { _mm_and_ps(self.0, rhs.0) })
{% elif is_wasm32 %}
Self(v128_and(self.0, rhs.0))
{% elif is_neon %}
Self(unsafe { vandq_u32(self.0, rhs.0) })
{% elif is_coresimd %}
Self(self.0 & rhs.0)
{% else %}
unimplemented!()
{% endif %}
}
}
impl BitAndAssign for {{ self_t }} {
#[inline]
fn bitand_assign(&mut self, rhs: Self) {
*self = self.bitand(rhs);
}
}
impl BitOr for {{ self_t }} {
type Output = Self;
#[inline]
fn bitor(self, rhs: Self) -> Self {
{% if is_scalar %}
Self {
{% for c in components %}
{{ c }}: self.{{ c }} | rhs.{{ c }},
{%- endfor %}
}
{% elif is_sse2 %}
Self(unsafe { _mm_or_ps(self.0, rhs.0) })
{% elif is_wasm32 %}
Self(v128_or(self.0, rhs.0))
{% elif is_neon %}
Self(unsafe { vorrq_u32(self.0, rhs.0) })
{% elif is_coresimd %}
Self(self.0 | rhs.0)
{% else %}
unimplemented!()
{% endif %}
}
}
impl BitOrAssign for {{ self_t }} {
#[inline]
fn bitor_assign(&mut self, rhs: Self) {
*self = self.bitor(rhs);
}
}
impl BitXor for {{ self_t }} {
type Output = Self;
#[inline]
fn bitxor(self, rhs: Self) -> Self {
{% if is_scalar %}
Self {
{% for c in components %}
{{ c }}: self.{{ c }} ^ rhs.{{ c }},
{%- endfor %}
}
{% elif is_sse2 %}
Self(unsafe { _mm_xor_ps(self.0, rhs.0) })
{% elif is_wasm32 %}
Self(v128_xor(self.0, rhs.0))
{% elif is_neon %}
Self(unsafe { veorq_u32(self.0, rhs.0) })
{% elif is_coresimd %}
Self(self.0 ^ rhs.0)
{% else %}
unimplemented!()
{% endif %}
}
}
impl BitXorAssign for {{ self_t }} {
#[inline]
fn bitxor_assign(&mut self, rhs: Self) {
*self = self.bitxor(rhs);
}
}
impl Not for {{ self_t }} {
type Output = Self;
#[inline]
fn not(self) -> Self {
{% if is_scalar %}
Self {
{% for c in components %}
{{ c }}: !self.{{ c }},
{%- endfor %}
}
{% elif is_sse2 %}
Self(unsafe {
_mm_andnot_ps(self.0, _mm_set_ps1(f32::from_bits(0xff_ff_ff_ff)))
})
{% elif is_wasm32 %}
Self(v128_not(self.0))
{% elif is_neon %}
Self(unsafe { vmvnq_u32(self.0) })
{% elif is_coresimd %}
Self(!self.0)
{% else %}
unimplemented!()
{% endif %}
}
}
{% if not is_scalar %}
impl From<{{ self_t }}> for {{ simd_t }} {
#[inline]
fn from(t: {{ self_t }}) -> Self {
t.0
}
}
{% endif %}
impl fmt::Debug for {{ self_t }} {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let arr = self.into_u32_array();
{%- if dim == 2 %}
write!(f, "{}({:#x}, {:#x})", stringify!({{ self_t }}), arr[0], arr[1])
{% elif dim == 3 %}
write!(f, "{}({:#x}, {:#x}, {:#x})", stringify!({{ self_t }}), arr[0], arr[1], arr[2])
{% elif dim == 4 %}
write!(f, "{}({:#x}, {:#x}, {:#x}, {:#x})", stringify!({{ self_t }}), arr[0], arr[1], arr[2], arr[3])
{% endif %}
}
}
impl fmt::Display for {{ self_t }} {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let arr = self.into_bool_array();
{%- if dim == 2 %}
write!(f, "[{}, {}]", arr[0], arr[1])
{% elif dim == 3 %}
write!(f, "[{}, {}, {}]", arr[0], arr[1], arr[2])
{% elif dim == 4 %}
write!(f, "[{}, {}, {}, {}]", arr[0], arr[1], arr[2], arr[3])
{% endif %}
}
}
impl From<[bool; {{ dim }}]> for {{ self_t }} {
#[inline]
fn from(a: [bool; {{ dim }}]) -> Self {
Self::from_array(a)
}
}
impl From<{{ self_t }}> for [bool; {{ dim }}] {
#[inline]
fn from(mask: {{ self_t }}) -> Self {
mask.into_bool_array()
}
}
impl From<{{ self_t }}> for [u32; {{ dim }}] {
#[inline]
fn from(mask: {{ self_t }}) -> Self {
mask.into_u32_array()
}
}