use super::*;
pub trait NumericBuiltinCountLeadingZeros {
fn count_leading_zeros(self) -> Self;
}
pub fn count_leading_zeros<T: NumericBuiltinCountLeadingZeros>(e: T) -> T {
<T as NumericBuiltinCountLeadingZeros>::count_leading_zeros(e)
}
mod count_leading_zeros {
use super::*;
impl NumericBuiltinCountLeadingZeros for u32 {
fn count_leading_zeros(self) -> Self {
self.leading_zeros()
}
}
impl NumericBuiltinCountLeadingZeros for i32 {
fn count_leading_zeros(self) -> Self {
self.leading_zeros() as i32
}
}
macro_rules! impl_clz_vec {
($ty:ty, $scalar:ty) => {
impl NumericBuiltinCountLeadingZeros for $ty {
fn count_leading_zeros(self) -> Self {
let mut array = self.to_array();
for elem in array.iter_mut() {
*elem = (*elem).leading_zeros() as $scalar;
}
Self::from_array(array)
}
}
};
}
impl_clz_vec!(Vec2u, u32);
impl_clz_vec!(Vec3u, u32);
impl_clz_vec!(Vec4u, u32);
impl_clz_vec!(Vec2i, i32);
impl_clz_vec!(Vec3i, i32);
impl_clz_vec!(Vec4i, i32);
}
pub trait NumericBuiltinCountOneBits {
fn count_one_bits(self) -> Self;
}
pub fn count_one_bits<T: NumericBuiltinCountOneBits>(e: T) -> T {
<T as NumericBuiltinCountOneBits>::count_one_bits(e)
}
mod count_one_bits {
use super::*;
impl NumericBuiltinCountOneBits for u32 {
fn count_one_bits(self) -> Self {
self.count_ones()
}
}
impl NumericBuiltinCountOneBits for i32 {
fn count_one_bits(self) -> Self {
self.count_ones() as i32
}
}
macro_rules! impl_popcount_vec {
($ty:ty, $scalar:ty) => {
impl NumericBuiltinCountOneBits for $ty {
fn count_one_bits(self) -> Self {
let mut array = self.to_array();
for elem in array.iter_mut() {
*elem = (*elem).count_ones() as $scalar;
}
Self::from_array(array)
}
}
};
}
impl_popcount_vec!(Vec2u, u32);
impl_popcount_vec!(Vec3u, u32);
impl_popcount_vec!(Vec4u, u32);
impl_popcount_vec!(Vec2i, i32);
impl_popcount_vec!(Vec3i, i32);
impl_popcount_vec!(Vec4i, i32);
}
pub trait NumericBuiltinCountTrailingZeros {
fn count_trailing_zeros(self) -> Self;
}
pub fn count_trailing_zeros<T: NumericBuiltinCountTrailingZeros>(e: T) -> T {
<T as NumericBuiltinCountTrailingZeros>::count_trailing_zeros(e)
}
mod count_trailing_zeros {
use super::*;
impl NumericBuiltinCountTrailingZeros for u32 {
fn count_trailing_zeros(self) -> Self {
self.trailing_zeros()
}
}
impl NumericBuiltinCountTrailingZeros for i32 {
fn count_trailing_zeros(self) -> Self {
self.trailing_zeros() as i32
}
}
macro_rules! impl_ctz_vec {
($ty:ty, $scalar:ty) => {
impl NumericBuiltinCountTrailingZeros for $ty {
fn count_trailing_zeros(self) -> Self {
let mut array = self.to_array();
for elem in array.iter_mut() {
*elem = (*elem).trailing_zeros() as $scalar;
}
Self::from_array(array)
}
}
};
}
impl_ctz_vec!(Vec2u, u32);
impl_ctz_vec!(Vec3u, u32);
impl_ctz_vec!(Vec4u, u32);
impl_ctz_vec!(Vec2i, i32);
impl_ctz_vec!(Vec3i, i32);
impl_ctz_vec!(Vec4i, i32);
}
pub trait NumericBuiltinReverseBits {
fn reverse_bits(self) -> Self;
}
pub fn reverse_bits<T: NumericBuiltinReverseBits>(e: T) -> T {
<T as NumericBuiltinReverseBits>::reverse_bits(e)
}
mod reverse_bits {
use super::*;
impl NumericBuiltinReverseBits for u32 {
fn reverse_bits(self) -> Self {
self.reverse_bits()
}
}
impl NumericBuiltinReverseBits for i32 {
fn reverse_bits(self) -> Self {
self.reverse_bits()
}
}
macro_rules! impl_reverse_bits_vec {
($ty:ty) => {
impl NumericBuiltinReverseBits for $ty {
fn reverse_bits(self) -> Self {
let mut array = self.to_array();
for elem in array.iter_mut() {
*elem = (*elem).reverse_bits();
}
Self::from_array(array)
}
}
};
}
impl_reverse_bits_vec!(Vec2u);
impl_reverse_bits_vec!(Vec3u);
impl_reverse_bits_vec!(Vec4u);
impl_reverse_bits_vec!(Vec2i);
impl_reverse_bits_vec!(Vec3i);
impl_reverse_bits_vec!(Vec4i);
}
pub trait NumericBuiltinFirstLeadingBit {
fn first_leading_bit(self) -> Self;
}
pub fn first_leading_bit<T: NumericBuiltinFirstLeadingBit>(e: T) -> T {
<T as NumericBuiltinFirstLeadingBit>::first_leading_bit(e)
}
mod first_leading_bit {
use super::*;
impl NumericBuiltinFirstLeadingBit for u32 {
fn first_leading_bit(self) -> Self {
if self == 0 {
u32::MAX } else {
31 - self.leading_zeros()
}
}
}
impl NumericBuiltinFirstLeadingBit for i32 {
fn first_leading_bit(self) -> Self {
if self == 0 || self == -1 {
-1
} else if self > 0 {
31 - self.leading_zeros() as i32
} else {
31 - self.leading_ones() as i32
}
}
}
macro_rules! impl_first_leading_bit_vec_u {
($ty:ty) => {
impl NumericBuiltinFirstLeadingBit for $ty {
fn first_leading_bit(self) -> Self {
let mut array = self.to_array();
for elem in array.iter_mut() {
*elem = if *elem == 0 {
u32::MAX
} else {
31 - (*elem).leading_zeros()
};
}
Self::from_array(array)
}
}
};
}
impl_first_leading_bit_vec_u!(Vec2u);
impl_first_leading_bit_vec_u!(Vec3u);
impl_first_leading_bit_vec_u!(Vec4u);
macro_rules! impl_first_leading_bit_vec_i {
($ty:ty) => {
impl NumericBuiltinFirstLeadingBit for $ty {
fn first_leading_bit(self) -> Self {
let mut array = self.to_array();
for elem in array.iter_mut() {
*elem = if *elem == 0 || *elem == -1 {
-1
} else if *elem > 0 {
31 - (*elem).leading_zeros() as i32
} else {
31 - (*elem).leading_ones() as i32
};
}
Self::from_array(array)
}
}
};
}
impl_first_leading_bit_vec_i!(Vec2i);
impl_first_leading_bit_vec_i!(Vec3i);
impl_first_leading_bit_vec_i!(Vec4i);
}
pub trait NumericBuiltinFirstTrailingBit {
fn first_trailing_bit(self) -> Self;
}
pub fn first_trailing_bit<T: NumericBuiltinFirstTrailingBit>(e: T) -> T {
<T as NumericBuiltinFirstTrailingBit>::first_trailing_bit(e)
}
mod first_trailing_bit {
use super::*;
impl NumericBuiltinFirstTrailingBit for u32 {
fn first_trailing_bit(self) -> Self {
if self == 0 {
u32::MAX } else {
self.trailing_zeros()
}
}
}
impl NumericBuiltinFirstTrailingBit for i32 {
fn first_trailing_bit(self) -> Self {
if self == 0 {
-1
} else {
self.trailing_zeros() as i32
}
}
}
macro_rules! impl_first_trailing_bit_vec_u {
($ty:ty) => {
impl NumericBuiltinFirstTrailingBit for $ty {
fn first_trailing_bit(self) -> Self {
let mut array = self.to_array();
for elem in array.iter_mut() {
*elem = if *elem == 0 {
u32::MAX
} else {
(*elem).trailing_zeros()
};
}
Self::from_array(array)
}
}
};
}
impl_first_trailing_bit_vec_u!(Vec2u);
impl_first_trailing_bit_vec_u!(Vec3u);
impl_first_trailing_bit_vec_u!(Vec4u);
macro_rules! impl_first_trailing_bit_vec_i {
($ty:ty) => {
impl NumericBuiltinFirstTrailingBit for $ty {
fn first_trailing_bit(self) -> Self {
let mut array = self.to_array();
for elem in array.iter_mut() {
*elem = if *elem == 0 {
-1
} else {
(*elem).trailing_zeros() as i32
};
}
Self::from_array(array)
}
}
};
}
impl_first_trailing_bit_vec_i!(Vec2i);
impl_first_trailing_bit_vec_i!(Vec3i);
impl_first_trailing_bit_vec_i!(Vec4i);
}
pub trait NumericBuiltinExtractBits {
fn extract_bits(self, offset: u32, count: u32) -> Self;
}
pub fn extract_bits<T: NumericBuiltinExtractBits>(e: T, offset: u32, count: u32) -> T {
debug_assert!(
offset + count <= 32,
"extractBits: offset ({}) + count ({}) must not exceed 32",
offset,
count
);
<T as NumericBuiltinExtractBits>::extract_bits(e, offset, count)
}
mod extract_bits {
use super::*;
impl NumericBuiltinExtractBits for u32 {
fn extract_bits(self, offset: u32, count: u32) -> Self {
let w = 32u32;
let o = std::cmp::Ord::min(offset, w);
let c = std::cmp::Ord::min(count, w - o);
if c == 0 {
return 0;
}
let mask = if c >= 32 { u32::MAX } else { (1u32 << c) - 1 };
(self >> o) & mask
}
}
impl NumericBuiltinExtractBits for i32 {
fn extract_bits(self, offset: u32, count: u32) -> Self {
let w = 32u32;
let o = std::cmp::Ord::min(offset, w);
let c = std::cmp::Ord::min(count, w - o);
if c == 0 {
return 0;
}
let mask = if c >= 32 { u32::MAX } else { (1u32 << c) - 1 };
let extracted = ((self as u32) >> o) & mask;
let sign_bit = 1u32 << (c - 1);
if extracted & sign_bit != 0 {
let sign_extend_mask = !mask;
(extracted | sign_extend_mask) as i32
} else {
extracted as i32
}
}
}
macro_rules! impl_extract_bits_vec_u {
($ty:ty) => {
impl NumericBuiltinExtractBits for $ty {
fn extract_bits(self, offset: u32, count: u32) -> Self {
let w = 32u32;
let o = std::cmp::Ord::min(offset, w);
let c = std::cmp::Ord::min(count, w - o);
if c == 0 {
return Self::from_array(self.to_array().map(|_| 0));
}
let mask = if c >= 32 { u32::MAX } else { (1u32 << c) - 1 };
let mut array = self.to_array();
for elem in array.iter_mut() {
*elem = (*elem >> o) & mask;
}
Self::from_array(array)
}
}
};
}
impl_extract_bits_vec_u!(Vec2u);
impl_extract_bits_vec_u!(Vec3u);
impl_extract_bits_vec_u!(Vec4u);
macro_rules! impl_extract_bits_vec_i {
($ty:ty) => {
impl NumericBuiltinExtractBits for $ty {
fn extract_bits(self, offset: u32, count: u32) -> Self {
let w = 32u32;
let o = std::cmp::Ord::min(offset, w);
let c = std::cmp::Ord::min(count, w - o);
if c == 0 {
return Self::from_array(self.to_array().map(|_| 0));
}
let mask = if c >= 32 { u32::MAX } else { (1u32 << c) - 1 };
let sign_bit = 1u32 << (c - 1);
let sign_extend_mask = !mask;
let mut array = self.to_array();
for elem in array.iter_mut() {
let extracted = ((*elem as u32) >> o) & mask;
*elem = if extracted & sign_bit != 0 {
(extracted | sign_extend_mask) as i32
} else {
extracted as i32
};
}
Self::from_array(array)
}
}
};
}
impl_extract_bits_vec_i!(Vec2i);
impl_extract_bits_vec_i!(Vec3i);
impl_extract_bits_vec_i!(Vec4i);
}
pub trait NumericBuiltinInsertBits {
fn insert_bits(self, newbits: Self, offset: u32, count: u32) -> Self;
}
pub fn insert_bits<T: NumericBuiltinInsertBits>(e: T, newbits: T, offset: u32, count: u32) -> T {
debug_assert!(
offset + count <= 32,
"insertBits: offset ({}) + count ({}) must not exceed 32",
offset,
count
);
<T as NumericBuiltinInsertBits>::insert_bits(e, newbits, offset, count)
}
mod insert_bits {
use super::*;
impl NumericBuiltinInsertBits for u32 {
fn insert_bits(self, newbits: Self, offset: u32, count: u32) -> Self {
let w = 32u32;
let o = std::cmp::Ord::min(offset, w);
let c = std::cmp::Ord::min(count, w - o);
if c == 0 {
return self;
}
let low_mask = if c >= 32 { u32::MAX } else { (1u32 << c) - 1 };
let mask = low_mask << o;
(self & !mask) | ((newbits & low_mask) << o)
}
}
impl NumericBuiltinInsertBits for i32 {
fn insert_bits(self, newbits: Self, offset: u32, count: u32) -> Self {
let w = 32u32;
let o = std::cmp::Ord::min(offset, w);
let c = std::cmp::Ord::min(count, w - o);
if c == 0 {
return self;
}
let e = self as u32;
let nb = newbits as u32;
let low_mask = if c >= 32 { u32::MAX } else { (1u32 << c) - 1 };
let mask = low_mask << o;
((e & !mask) | ((nb & low_mask) << o)) as i32
}
}
macro_rules! impl_insert_bits_vec_u {
($ty:ty) => {
impl NumericBuiltinInsertBits for $ty {
fn insert_bits(self, newbits: Self, offset: u32, count: u32) -> Self {
let w = 32u32;
let o = std::cmp::Ord::min(offset, w);
let c = std::cmp::Ord::min(count, w - o);
if c == 0 {
return self;
}
let low_mask = if c >= 32 { u32::MAX } else { (1u32 << c) - 1 };
let mask = low_mask << o;
let mut array = self.to_array();
let newbits_array = newbits.to_array();
for (elem, nb) in array.iter_mut().zip(newbits_array.iter()) {
*elem = (*elem & !mask) | ((*nb & low_mask) << o);
}
Self::from_array(array)
}
}
};
}
impl_insert_bits_vec_u!(Vec2u);
impl_insert_bits_vec_u!(Vec3u);
impl_insert_bits_vec_u!(Vec4u);
macro_rules! impl_insert_bits_vec_i {
($ty:ty) => {
impl NumericBuiltinInsertBits for $ty {
fn insert_bits(self, newbits: Self, offset: u32, count: u32) -> Self {
let w = 32u32;
let o = std::cmp::Ord::min(offset, w);
let c = std::cmp::Ord::min(count, w - o);
if c == 0 {
return self;
}
let low_mask = if c >= 32 { u32::MAX } else { (1u32 << c) - 1 };
let mask = low_mask << o;
let mut array = self.to_array();
let newbits_array = newbits.to_array();
for (elem, nb) in array.iter_mut().zip(newbits_array.iter()) {
let e = *elem as u32;
let n = *nb as u32;
*elem = ((e & !mask) | ((n & low_mask) << o)) as i32;
}
Self::from_array(array)
}
}
};
}
impl_insert_bits_vec_i!(Vec2i);
impl_insert_bits_vec_i!(Vec3i);
impl_insert_bits_vec_i!(Vec4i);
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn sanity_count_leading_zeros() {
assert_eq!(count_leading_zeros(0u32), 32);
assert_eq!(count_leading_zeros(1u32), 31);
assert_eq!(count_leading_zeros(0x80000000u32), 0);
assert_eq!(count_leading_zeros(0x00010000u32), 15);
assert_eq!(count_leading_zeros(0i32), 32);
assert_eq!(count_leading_zeros(1i32), 31);
assert_eq!(count_leading_zeros(-1i32), 0);
let v = vec2u(0, 1);
let result = count_leading_zeros(v);
assert_eq!(result.x(), 32);
assert_eq!(result.y(), 31);
}
#[test]
fn sanity_count_one_bits() {
assert_eq!(count_one_bits(0u32), 0);
assert_eq!(count_one_bits(1u32), 1);
assert_eq!(count_one_bits(0b1111u32), 4);
assert_eq!(count_one_bits(u32::MAX), 32);
assert_eq!(count_one_bits(0i32), 0);
assert_eq!(count_one_bits(1i32), 1);
assert_eq!(count_one_bits(-1i32), 32);
let v = vec2u(0b1010, 0b1111);
let result = count_one_bits(v);
assert_eq!(result.x(), 2);
assert_eq!(result.y(), 4);
}
#[test]
fn sanity_count_trailing_zeros() {
assert_eq!(count_trailing_zeros(0u32), 32);
assert_eq!(count_trailing_zeros(1u32), 0);
assert_eq!(count_trailing_zeros(0b1000u32), 3);
assert_eq!(count_trailing_zeros(0x80000000u32), 31);
assert_eq!(count_trailing_zeros(0i32), 32);
assert_eq!(count_trailing_zeros(1i32), 0);
assert_eq!(count_trailing_zeros(-1i32), 0);
let v = vec2u(0b1000, 0b0100);
let result = count_trailing_zeros(v);
assert_eq!(result.x(), 3);
assert_eq!(result.y(), 2);
}
#[test]
fn sanity_reverse_bits() {
assert_eq!(reverse_bits(0u32), 0);
assert_eq!(reverse_bits(1u32), 0x80000000);
assert_eq!(reverse_bits(0x80000000u32), 1);
assert_eq!(reverse_bits(u32::MAX), u32::MAX);
assert_eq!(reverse_bits(0i32), 0);
assert_eq!(reverse_bits(1i32), i32::MIN); assert_eq!(reverse_bits(-1i32), -1);
let v = vec2u(1, 0x80000000);
let result = reverse_bits(v);
assert_eq!(result.x(), 0x80000000);
assert_eq!(result.y(), 1);
}
#[test]
fn sanity_first_leading_bit() {
assert_eq!(first_leading_bit(0u32), u32::MAX); assert_eq!(first_leading_bit(1u32), 0);
assert_eq!(first_leading_bit(2u32), 1);
assert_eq!(first_leading_bit(0x80000000u32), 31);
assert_eq!(first_leading_bit(0b1010u32), 3);
assert_eq!(first_leading_bit(0i32), -1);
assert_eq!(first_leading_bit(-1i32), -1);
assert_eq!(first_leading_bit(1i32), 0);
assert_eq!(first_leading_bit(0b1010i32), 3);
assert_eq!(first_leading_bit(-2i32), 0);
let v = vec2u(0, 8);
let result = first_leading_bit(v);
assert_eq!(result.x(), u32::MAX);
assert_eq!(result.y(), 3);
}
#[test]
fn sanity_first_trailing_bit() {
assert_eq!(first_trailing_bit(0u32), u32::MAX); assert_eq!(first_trailing_bit(1u32), 0);
assert_eq!(first_trailing_bit(0b1000u32), 3);
assert_eq!(first_trailing_bit(0x80000000u32), 31);
assert_eq!(first_trailing_bit(0i32), -1);
assert_eq!(first_trailing_bit(1i32), 0);
assert_eq!(first_trailing_bit(0b1000i32), 3);
assert_eq!(first_trailing_bit(-1i32), 0);
let v = vec2u(0, 0b1000);
let result = first_trailing_bit(v);
assert_eq!(result.x(), u32::MAX);
assert_eq!(result.y(), 3);
}
#[test]
fn sanity_extract_bits() {
assert_eq!(extract_bits(0b11111111u32, 0, 4), 0b1111);
assert_eq!(extract_bits(0b11111111u32, 4, 4), 0b1111);
assert_eq!(extract_bits(0b11110000u32, 4, 4), 0b1111);
assert_eq!(extract_bits(0xFFFFFFFFu32, 0, 32), 0xFFFFFFFF);
assert_eq!(extract_bits(0x12345678u32, 0, 0), 0);
assert_eq!(extract_bits(0b1111i32, 0, 4), -1);
assert_eq!(extract_bits(0b0111i32, 0, 4), 7);
assert_eq!(extract_bits(0xFFi32, 0, 8), -1);
let v = vec2u(0xFF, 0xF0);
let result = extract_bits(v, 4, 4);
assert_eq!(result.x(), 0xF);
assert_eq!(result.y(), 0xF);
}
#[test]
fn sanity_insert_bits() {
assert_eq!(insert_bits(0u32, 0b1111u32, 0, 4), 0b1111);
assert_eq!(insert_bits(0u32, 0b1111u32, 4, 4), 0b11110000);
assert_eq!(insert_bits(0xFFFFFFFFu32, 0u32, 0, 4), 0xFFFFFFF0);
assert_eq!(insert_bits(0x12345678u32, 0u32, 0, 0), 0x12345678);
assert_eq!(insert_bits(0i32, 0b1111i32, 0, 4), 0b1111);
assert_eq!(insert_bits(0i32, 0b1111i32, 4, 4), 0b11110000);
assert_eq!(insert_bits(-1i32, 0i32, 0, 4), -16);
let v = vec2u(0, 0xFF);
let newbits = vec2u(0xF, 0);
let result = insert_bits(v, newbits, 4, 4);
assert_eq!(result.x(), 0xF0);
assert_eq!(result.y(), 0x0F); }
#[test]
fn sanity_bit_manipulation_vectors() {
let v3u = vec3u(1, 2, 4);
let clz = count_leading_zeros(v3u);
assert_eq!(clz.x(), 31);
assert_eq!(clz.y(), 30);
assert_eq!(clz.z(), 29);
let v4i = vec4i(0, 1, -1, 8);
let ftb = first_trailing_bit(v4i);
assert_eq!(ftb.x(), -1);
assert_eq!(ftb.y(), 0);
assert_eq!(ftb.z(), 0);
assert_eq!(ftb.w(), 3);
}
}