{% import "macros.rs.tera" as macros %} // 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 }}))] #[cfg_attr(target_arch = "spirv", rust_gpu::vector::v1)] 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 %} assert!(index < {{ dim }}, "index out of bounds"); 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 %} {% if dim < 4 %} assert!(index < {{ dim }}, "index out of bounds"); {%- endif %} 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(&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 %} } } {{ macros::impl_ref_binop(imp="BitAnd", self_t=self_t, rhs_t=self_t, output_t=self_t) }} {{ macros::impl_op_assign(imp="BitAnd", self_t=self_t, rhs_t=self_t) }} 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 %} } } {{ macros::impl_ref_binop(imp="BitOr", self_t=self_t, rhs_t=self_t, output_t=self_t) }} {{ macros::impl_op_assign(imp="BitOr", self_t=self_t, rhs_t=self_t) }} 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 %} } } {{ macros::impl_ref_binop(imp="BitXor", self_t=self_t, rhs_t=self_t, output_t=self_t) }} {{ macros::impl_op_assign(imp="BitXor", self_t=self_t, rhs_t=self_t) }} 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 %} } } {{ macros::impl_ref_unop(imp="Not", self_t=self_t, output_t=self_t) }} {% 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() } }