use core::mem;
use crate::basenum::BaseInt;
use crate::traits::{GenIType, GenInt, GenNum, GenUType};
use crate::vec::vec::{IVec2, IVec3, IVec4, UVec2, UVec3, UVec4};
pub trait IntIntRel<I: BaseInt, T: GenIType>: GenInt<I> {
fn map_int<F: Fn(I) -> i32>(&self, f: F) -> T;
}
macro_rules! impl_IntIntRel_for_int {
($($t: ident),+) => {
$(
impl IntIntRel<i32, $t> for $t {
#[inline(always)]
fn map_int<F: Fn(i32) -> i32>(&self, f: F) -> $t {
self.map(f)
}
}
)+
}
}
impl_IntIntRel_for_int! { i32, IVec2, IVec3, IVec4 }
impl IntIntRel<u32, i32> for u32 {
#[inline(always)]
fn map_int<F: Fn(u32) -> i32>(&self, f: F) -> i32 {
f(*self)
}
}
macro_rules! impl_IntIntRel_for_uint {
($({ $ut: ident, $it: ident, $($field: ident),+ }),+) => {
$(
impl IntIntRel<u32, $it> for $ut {
#[inline(always)]
fn map_int<F: Fn(u32) -> i32>(&self, f: F) -> $it {
$it { $($field: f(self.$field)),+ }
}
}
)+
}
}
impl_IntIntRel_for_uint! {
{ UVec2, IVec2, x, y },
{ UVec3, IVec3, x, y, z },
{ UVec4, IVec4, x, y, z, w }
}
#[inline]
#[allow(non_snake_case)]
pub fn uaddCarry<T: GenUType>(x: T, y: T) -> (T, T) {
x.map2(y, |i, j| -> (u32, u32) {
match i.checked_add(j) {
Some(s) => (s, 0),
None => (i - (0xFFFFFFFF - j + 1), 1),
}
})
}
#[inline]
#[allow(non_snake_case)]
pub fn usubBorrow<T: GenUType>(x: T, y: T) -> (T, T) {
x.map2(y, |i, j| -> (u32, u32) {
if i >= j {
(i - j, 0)
} else {
(0xFFFFFFFF - j + i, 1)
}
})
}
#[allow(non_snake_case)]
pub fn umulExtended<T: GenUType>(x: T, y: T) -> (T, T) {
x.map2(y, |i, j| -> (u32, u32) {
let ei = i as u64;
let ej = j as u64;
let p = ei * ej;
((p >> 32) as u32, p as u32)
})
}
#[allow(non_snake_case)]
pub fn imulExtended<T: GenIType>(x: T, y: T) -> (T, T) {
x.map2(y, |i, j| -> (i32, i32) {
let ei = i as i64;
let ej = j as i64;
let p = ei * ej;
((p >> 32) as i32, p as i32)
})
}
#[allow(non_snake_case)]
pub fn bitfieldExtract<I: BaseInt, T: GenInt<I>>(value: T, offset: usize, bits: usize) -> T {
let ling = T::zero();
if value.is_zero() || bits == 0 || offset + bits > 32 {
ling
} else {
let mask = I::from((1_u32 << bits) - 1).unwrap();
value.map(|i| -> I { (i >> offset) & mask })
}
}
#[allow(non_snake_case)]
pub fn bitfieldInsert<I: BaseInt, T: GenInt<I>>(
base: T,
insert: T,
offset: usize,
bits: usize,
) -> T {
if bits == 0 {
base
} else {
let mask = I::from(((1_u32 << bits) - 1) << offset).unwrap();
base.zip(insert, |i, j| -> I { (i & !mask) | (j & mask) })
}
}
#[allow(non_snake_case)]
pub fn bitfieldReverse<I: BaseInt, T: GenInt<I>>(value: T) -> T {
#[inline(always)]
fn reverse_step(x: u32, mask: u32, shift: usize) -> u32 {
((x & mask) << shift) | ((x & !mask) >> shift)
}
value.map(|i| -> I {
let u: &u32 = unsafe { mem::transmute(&i) };
let mut x = *u;
x = reverse_step(x, 0x55555555, 1);
x = reverse_step(x, 0x33333333, 2);
x = reverse_step(x, 0x0F0F0F0F, 4);
x = reverse_step(x, 0x00FF00FF, 8);
x = reverse_step(x, 0x0000FFFF, 16);
let r: &I = unsafe { mem::transmute(&x) };
*r
})
}
#[allow(non_snake_case)]
pub fn bitCount<I: BaseInt, T: GenInt<I>>(value: T) -> T {
value.map(|i| -> I {
let c = I::from(i.count_ones()).unwrap();
c
})
}
#[allow(non_snake_case)]
pub fn findLSB<B: BaseInt, I: GenIType, T: IntIntRel<B, I>>(value: T) -> I {
value.map_int(|i| -> i32 {
if i.is_zero() {
-1
} else {
i.trailing_zeros() as i32
}
})
}
#[allow(non_snake_case)]
pub fn findMSB<B: BaseInt, I: GenIType, T: IntIntRel<B, I>>(value: T) -> I {
value.map_int(|i| -> i32 {
let ling = B::zero();
if i.is_zero() {
-1
} else if i < ling {
31 - ((!i).leading_zeros() as i32)
} else {
31 - (i.leading_zeros() as i32)
}
})
}