#[inline]
pub fn count_leading_zeros_u32(x: u32) -> u32 {
x.leading_zeros()
}
#[inline]
pub fn count_leading_zeros_u64(x: u64) -> u32 {
x.leading_zeros()
}
#[inline]
pub fn count_trailing_zeros_u32(x: u32) -> u32 {
x.trailing_zeros()
}
#[inline]
pub fn count_trailing_zeros_u64(x: u64) -> u32 {
x.trailing_zeros()
}
#[inline]
pub fn count_population_u32(x: u32) -> u32 {
x.count_ones()
}
#[inline]
pub fn count_population_u64(x: u64) -> u32 {
x.count_ones()
}
#[inline]
pub fn is_power_of_2_u32(x: u32) -> bool {
x != 0 && (x & (x.wrapping_sub(1))) == 0
}
#[inline]
pub fn is_power_of_2_u64(x: u64) -> bool {
x != 0 && (x & (x.wrapping_sub(1))) == 0
}
#[inline]
pub fn next_power_of_2_u32(x: u32) -> u32 {
if x == 0 {
return 1;
}
x.checked_next_power_of_two().unwrap_or(0)
}
#[inline]
pub fn next_power_of_2_u64(x: u64) -> u64 {
if x == 0 {
return 1;
}
x.checked_next_power_of_two().unwrap_or(0)
}
#[inline]
pub fn floor_log2_u32(x: u32) -> u32 {
debug_assert!(x > 0, "floor_log2_u32: argument must be > 0");
u32::BITS - 1 - x.leading_zeros()
}
#[inline]
pub fn floor_log2_u64(x: u64) -> u32 {
debug_assert!(x > 0, "floor_log2_u64: argument must be > 0");
u64::BITS - 1 - x.leading_zeros()
}
#[inline]
pub fn ceil_log2_u32(x: u32) -> u32 {
debug_assert!(x > 0, "ceil_log2_u32: argument must be > 0");
if x == 1 {
return 0;
}
floor_log2_u32(x - 1) + 1
}
#[inline]
pub fn ceil_log2_u64(x: u64) -> u32 {
debug_assert!(x > 0, "ceil_log2_u64: argument must be > 0");
if x == 1 {
return 0;
}
floor_log2_u64(x - 1) + 1
}
#[inline]
pub fn align_to<T>(value: T, align: T) -> T
where
T: Copy + Into<u64> + std::convert::TryFrom<u64>,
{
let v: u64 = value.into();
let a: u64 = align.into();
debug_assert!(
a > 0 && (a & (a - 1)) == 0,
"align_to: align must be a power of 2"
);
let result = (v + a - 1) & !(a - 1);
T::try_from(result)
.unwrap_or_else(|_| panic!("align_to: result {} does not fit in target type", result))
}
#[inline]
pub fn align_down<T>(value: T, align: T) -> T
where
T: Copy + Into<u64> + std::convert::TryFrom<u64>,
{
let v: u64 = value.into();
let a: u64 = align.into();
debug_assert!(
a > 0 && (a & (a - 1)) == 0,
"align_down: align must be a power of 2"
);
let result = v & !(a - 1);
T::try_from(result)
.unwrap_or_else(|_| panic!("align_down: result {} does not fit in target type", result))
}
#[inline]
pub fn is_aligned<T>(value: T, align: T) -> bool
where
T: Copy + Into<u64>,
{
let v: u64 = value.into();
let a: u64 = align.into();
debug_assert!(
a > 0 && (a & (a - 1)) == 0,
"is_aligned: align must be a power of 2"
);
(v & (a - 1)) == 0
}
#[inline]
pub fn find_first_set_u32(x: u32) -> i32 {
if x == 0 {
-1
} else {
x.trailing_zeros() as i32
}
}
#[inline]
pub fn find_first_set_u64(x: u64) -> i32 {
if x == 0 {
-1
} else {
x.trailing_zeros() as i32
}
}
#[inline]
pub fn find_last_set_u32(x: u32) -> i32 {
if x == 0 {
-1
} else {
(u32::BITS - 1 - x.leading_zeros()) as i32
}
}
#[inline]
pub fn find_last_set_u64(x: u64) -> i32 {
if x == 0 {
-1
} else {
(u64::BITS - 1 - x.leading_zeros()) as i32
}
}
#[inline]
pub fn reverse_bits_u32(x: u32) -> u32 {
x.reverse_bits()
}
#[inline]
pub fn reverse_bits_u64(x: u64) -> u64 {
x.reverse_bits()
}
#[inline]
pub fn bit_floor_u32(x: u32) -> u32 {
if x == 0 {
return 0;
}
1u32 << floor_log2_u32(x)
}
#[inline]
pub fn bit_floor_u64(x: u64) -> u64 {
if x == 0 {
return 0;
}
1u64 << floor_log2_u64(x)
}
#[inline]
pub fn bit_ceil_u32(x: u32) -> u32 {
if x <= 1 {
return 1;
}
next_power_of_2_u32(x)
}
#[inline]
pub fn bit_ceil_u64(x: u64) -> u64 {
if x <= 1 {
return 1;
}
next_power_of_2_u64(x)
}
#[inline]
pub fn is_shifted_mask_32(value: u32) -> (bool, u32, u32) {
if value == 0 {
return (false, 0, 0);
}
let trailing = value.trailing_zeros();
let shifted = value >> trailing;
if shifted & shifted.wrapping_add(1) == 0 {
let mask_len = shifted.count_ones();
(true, trailing, mask_len)
} else {
(false, 0, 0)
}
}
#[inline]
pub fn is_shifted_mask_64(value: u64) -> (bool, u32, u32) {
if value == 0 {
return (false, 0, 0);
}
let trailing = value.trailing_zeros();
let shifted = value >> trailing;
if shifted & shifted.wrapping_add(1) == 0 {
let mask_len = shifted.count_ones();
(true, trailing, mask_len)
} else {
(false, 0, 0)
}
}
#[inline]
pub fn mask_trailing_ones_u32(n: u32) -> u32 {
if n >= u32::BITS {
u32::MAX
} else {
(1u32 << n).wrapping_sub(1)
}
}
#[inline]
pub fn mask_trailing_ones_u64(n: u32) -> u64 {
if n >= u64::BITS {
u64::MAX
} else {
(1u64 << n).wrapping_sub(1)
}
}
#[inline]
pub fn mask_trailing_zeros_u32(n: u32) -> u32 {
!mask_trailing_ones_u32(n)
}
#[inline]
pub fn mask_trailing_zeros_u64(n: u32) -> u64 {
!mask_trailing_ones_u64(n)
}
#[inline]
pub fn umin<T: Ord>(a: T, b: T) -> T {
std::cmp::min(a, b)
}
#[inline]
pub fn umax<T: Ord>(a: T, b: T) -> T {
std::cmp::max(a, b)
}
#[inline]
pub fn saturating_add_u32(a: u32, b: u32) -> u32 {
a.saturating_add(b)
}
#[inline]
pub fn saturating_sub_u32(a: u32, b: u32) -> u32 {
a.saturating_sub(b)
}
#[inline]
pub fn saturating_add_u64(a: u64, b: u64) -> u64 {
a.saturating_add(b)
}
#[inline]
pub fn saturating_sub_u64(a: u64, b: u64) -> u64 {
a.saturating_sub(b)
}
#[inline]
pub fn divide_nearest_u32(numerator: u32, denominator: u32) -> u32 {
assert!(denominator != 0, "divide_nearest_u32: division by zero");
(numerator + denominator / 2) / denominator
}
#[inline]
pub fn divide_nearest_u64(numerator: u64, denominator: u64) -> u64 {
assert!(denominator != 0, "divide_nearest_u64: division by zero");
(numerator + denominator / 2) / denominator
}
#[inline]
pub fn divide_ceil_u32(numerator: u32, denominator: u32) -> u32 {
assert!(denominator != 0, "divide_ceil_u32: division by zero");
(numerator + denominator - 1) / denominator
}
#[inline]
pub fn divide_ceil_u64(numerator: u64, denominator: u64) -> u64 {
assert!(denominator != 0, "divide_ceil_u64: division by zero");
(numerator + denominator - 1) / denominator
}
#[inline]
pub fn rotl_u32(x: u32, r: u32) -> u32 {
x.rotate_left(r)
}
#[inline]
pub fn rotr_u32(x: u32, r: u32) -> u32 {
x.rotate_right(r)
}
#[inline]
pub fn rotl_u64(x: u64, r: u32) -> u64 {
x.rotate_left(r)
}
#[inline]
pub fn rotr_u64(x: u64, r: u32) -> u64 {
x.rotate_right(r)
}
#[inline]
pub fn byte_swap_16(x: u16) -> u16 {
x.swap_bytes()
}
#[inline]
pub fn byte_swap_32(x: u32) -> u32 {
x.swap_bytes()
}
#[inline]
pub fn byte_swap_64(x: u64) -> u64 {
x.swap_bytes()
}
#[inline]
pub fn mul_hi_u32(a: u32, b: u32) -> u32 {
((a as u64).wrapping_mul(b as u64) >> 32) as u32
}
#[inline]
pub fn mul_lo_u32(a: u32, b: u32) -> u32 {
a.wrapping_mul(b)
}
#[inline]
pub fn mul_hi_u64(a: u64, b: u64) -> u64 {
((a as u128).wrapping_mul(b as u128) >> 64) as u64
}
#[inline]
pub fn mul_lo_u64(a: u64, b: u64) -> u64 {
a.wrapping_mul(b)
}
#[inline]
pub fn add_overflow_u32(a: u32, b: u32) -> (u32, bool) {
a.overflowing_add(b)
}
#[inline]
pub fn add_overflow_u64(a: u64, b: u64) -> (u64, bool) {
a.overflowing_add(b)
}
#[inline]
pub fn sub_overflow_u32(a: u32, b: u32) -> (u32, bool) {
a.overflowing_sub(b)
}
#[inline]
pub fn sub_overflow_u64(a: u64, b: u64) -> (u64, bool) {
a.overflowing_sub(b)
}
#[inline]
pub fn mul_overflow_u32(a: u32, b: u32) -> (u32, bool) {
a.overflowing_mul(b)
}
#[inline]
pub fn mul_overflow_u64(a: u64, b: u64) -> (u64, bool) {
a.overflowing_mul(b)
}
#[inline]
pub fn is_power_of_2_32(v: u32) -> bool {
v != 0 && (v & (v - 1)) == 0
}
#[inline]
pub fn is_power_of_2_64(v: u64) -> bool {
v != 0 && (v & (v - 1)) == 0
}
#[inline]
pub fn next_power_of_2_32(v: u32) -> u32 {
if v == 0 {
return 1;
}
let mut p = 1u32;
while p < v {
p = p.wrapping_mul(2);
}
p
}
#[inline]
pub fn next_power_of_2_64(v: u64) -> u64 {
if v == 0 {
return 1;
}
let mut p = 1u64;
while p < v {
p = p.wrapping_mul(2);
}
p
}
#[inline]
pub fn align_to_u32(v: u32, alignment: u32) -> u32 {
debug_assert!(is_power_of_2_32(alignment));
(v + alignment - 1) & !(alignment - 1)
}
#[inline]
pub fn align_to_u64(v: u64, alignment: u64) -> u64 {
debug_assert!(is_power_of_2_64(alignment));
(v + alignment - 1) & !(alignment - 1)
}
#[inline]
pub fn align_down_u32(v: u32, alignment: u32) -> u32 {
debug_assert!(is_power_of_2_32(alignment));
v & !(alignment - 1)
}
#[inline]
pub fn align_down_u64(v: u64, alignment: u64) -> u64 {
debug_assert!(is_power_of_2_64(alignment));
v & !(alignment - 1)
}
#[inline]
pub fn clz_u32(v: u32) -> u32 {
if v == 0 {
32
} else {
v.leading_zeros()
}
}
#[inline]
pub fn clz_u64(v: u64) -> u32 {
if v == 0 {
64
} else {
v.leading_zeros()
}
}
#[inline]
pub fn ctz_u32(v: u32) -> u32 {
if v == 0 {
32
} else {
v.trailing_zeros()
}
}
#[inline]
pub fn ctz_u64(v: u64) -> u32 {
if v == 0 {
64
} else {
v.trailing_zeros()
}
}
#[inline]
pub fn popcount_u32(v: u32) -> u32 {
v.count_ones()
}
#[inline]
pub fn popcount_u64(v: u64) -> u32 {
v.count_ones()
}
#[inline]
pub fn max_int_n(bits: u32) -> i64 {
if bits == 0 {
return 0;
}
if bits >= 64 {
return i64::MAX;
}
(1i64 << (bits - 1)) - 1
}
#[inline]
pub fn min_int_n(bits: u32) -> i64 {
if bits == 0 {
return 0;
}
if bits >= 64 {
return i64::MIN;
}
-(1i64 << (bits - 1))
}
#[inline]
pub fn is_int_n(v: i64, bits: u32) -> bool {
if bits >= 64 {
return true;
}
let min = min_int_n(bits);
let max = max_int_n(bits);
v >= min && v <= max
}
#[inline]
pub fn is_uint_n(v: u64, bits: u32) -> bool {
if bits >= 64 {
return true;
}
v < (1u64 << bits)
}
#[inline]
pub fn mask_leading_ones_u32(count: u32) -> u32 {
if count == 0 {
return 0;
}
mask_trailing_ones_u32(count).rotate_left(32 - count)
}
#[inline]
pub fn mask_leading_ones_u64(count: u32) -> u64 {
if count == 0 {
return 0;
}
mask_trailing_ones_u64(count).rotate_left(64 - count)
}
#[inline]
pub fn rotl_32(v: u32, count: u32) -> u32 {
v.rotate_left(count % 32)
}
#[inline]
pub fn rotr_32(v: u32, count: u32) -> u32 {
v.rotate_right(count % 32)
}
#[inline]
pub fn rotl_64(v: u64, count: u32) -> u64 {
v.rotate_left(count as u32 % 64)
}
#[inline]
pub fn rotr_64(v: u64, count: u32) -> u64 {
v.rotate_right(count as u32 % 64)
}
#[inline]
pub fn sign_extend(val: u64, from_bits: u32) -> i64 {
let shift = 64 - from_bits;
((val << shift) as i64) >> shift
}
#[inline]
pub fn zero_extend(val: u64, from_bits: u32) -> u64 {
if from_bits >= 64 {
return val;
}
val & ((1u64 << from_bits) - 1)
}
#[inline]
pub fn lo_half(val: u64) -> u32 {
val as u32
}
#[inline]
pub fn hi_half(val: u64) -> u32 {
(val >> 32) as u32
}
#[inline]
pub fn make_u64(hi: u32, lo: u32) -> u64 {
((hi as u64) << 32) | (lo as u64)
}
#[inline]
pub fn extract_bits_u32(val: u32, msb: u32, lsb: u32) -> u32 {
debug_assert!(msb >= lsb);
let width = msb - lsb + 1;
if width >= 32 {
return val >> lsb;
}
(val >> lsb) & ((1u32 << width) - 1)
}
#[inline]
pub fn extract_bits_u64(val: u64, msb: u32, lsb: u32) -> u64 {
debug_assert!(msb >= lsb);
let width = msb - lsb + 1;
if width >= 64 {
return val >> lsb;
}
(val >> lsb) & ((1u64 << width) - 1)
}
#[inline]
pub fn is_mask_32(val: u32) -> bool {
val != 0 && (val & (val + 1)) == 0
}
#[inline]
pub fn is_mask_64(val: u64) -> bool {
val != 0 && (val & (val + 1)) == 0
}
#[inline]
pub fn get_bit_u32(val: u32, pos: u32) -> bool {
debug_assert!(pos < 32);
(val >> pos) & 1 != 0
}
#[inline]
pub fn get_bit_u64(val: u64, pos: u32) -> bool {
debug_assert!(pos < 64);
(val >> pos) & 1 != 0
}
#[inline]
pub fn set_bit_u32(val: u32, pos: u32) -> u32 {
val | (1u32 << pos)
}
#[inline]
pub fn set_bit_u64(val: u64, pos: u32) -> u64 {
val | (1u64 << pos)
}
#[inline]
pub fn clear_bit_u32(val: u32, pos: u32) -> u32 {
val & !(1u32 << pos)
}
#[inline]
pub fn clear_bit_u64(val: u64, pos: u32) -> u64 {
val & !(1u64 << pos)
}
#[inline]
pub fn flip_bit_u32(val: u32, pos: u32) -> u32 {
val ^ (1u32 << pos)
}
#[inline]
pub fn flip_bit_u64(val: u64, pos: u32) -> u64 {
val ^ (1u64 << pos)
}
#[inline]
pub fn abs_diff_u32(a: u32, b: u32) -> u32 {
if a > b {
a - b
} else {
b - a
}
}
#[inline]
pub fn abs_diff_u64(a: u64, b: u64) -> u64 {
if a > b {
a - b
} else {
b - a
}
}
#[inline]
pub fn min_u32(a: u32, b: u32) -> u32 {
if a < b {
a
} else {
b
}
}
#[inline]
pub fn max_u32(a: u32, b: u32) -> u32 {
if a > b {
a
} else {
b
}
}
#[inline]
pub fn min_u64(a: u64, b: u64) -> u64 {
if a < b {
a
} else {
b
}
}
#[inline]
pub fn max_u64(a: u64, b: u64) -> u64 {
if a > b {
a
} else {
b
}
}
#[inline]
pub fn mul_u32_hi(a: u32, b: u32, shift: u32) -> u32 {
let product = (a as u64) * (b as u64);
(product >> shift) as u32
}
#[inline]
pub fn mul_u64_hi(a: u64, b: u64, shift: u32) -> u64 {
let product = (a as u128) * (b as u128);
(product >> shift) as u64
}
#[inline]
pub fn avg_floor_u32(a: u32, b: u32) -> u32 {
(a & b) + ((a ^ b) >> 1)
}
#[inline]
pub fn avg_floor_u64(a: u64, b: u64) -> u64 {
(a & b) + ((a ^ b) >> 1)
}
#[inline]
pub fn ceil_div_u32(a: u32, b: u32) -> u32 {
(a + b - 1) / b
}
#[inline]
pub fn ceil_div_u64(a: u64, b: u64) -> u64 {
(a + b - 1) / b
}
#[inline]
pub fn mod_pow2_u32(a: u32, b: u32) -> u32 {
debug_assert!(is_power_of_2_32(b));
a & (b - 1)
}
#[inline]
pub fn mod_pow2_u64(a: u64, b: u64) -> u64 {
debug_assert!(is_power_of_2_64(b));
a & (b - 1)
}
#[inline]
pub fn byteswap_16(v: u16) -> u16 {
((v & 0xFF) << 8) | ((v >> 8) & 0xFF)
}
#[inline]
pub fn byteswap_32(v: u32) -> u32 {
((v & 0xFF) << 24) | ((v & 0xFF00) << 8) | ((v >> 8) & 0xFF00) | ((v >> 24) & 0xFF)
}
#[inline]
pub fn byteswap_64(v: u64) -> u64 {
((v & 0xFF) << 56)
| ((v & 0xFF00) << 40)
| ((v & 0xFF_0000) << 24)
| ((v & 0xFF_0000_00) << 8)
| ((v >> 8) & 0xFF_0000_00)
| ((v >> 24) & 0xFF_0000)
| ((v >> 40) & 0xFF00)
| ((v >> 56) & 0xFF)
}
#[inline]
pub fn interleave_16(a: u32, b: u32) -> u32 {
let mut result = 0u32;
for i in 0..16 {
result |= ((a >> i) & 1) << (2 * i);
result |= ((b >> i) & 1) << (2 * i + 1);
}
result
}
#[inline]
pub fn bits_all_zero_u32(val: u32, msb: u32, lsb: u32) -> bool {
extract_bits_u32(val, msb, lsb) == 0
}
#[inline]
pub fn bits_all_zero_u64(val: u64, msb: u32, lsb: u32) -> bool {
extract_bits_u64(val, msb, lsb) == 0
}
#[inline]
pub fn gray_encode_u32(val: u32) -> u32 {
val ^ (val >> 1)
}
#[inline]
pub fn gray_decode_u32(mut val: u32) -> u32 {
let mut mask = val >> 1;
while mask != 0 {
val ^= mask;
mask >>= 1;
}
val
}
#[inline]
pub fn abs_i32(v: i32) -> i32 {
v.abs()
}
#[inline]
pub fn abs_i64(v: i64) -> i64 {
v.abs()
}
#[inline]
pub fn clamp_u32(val: u32, min: u32, max: u32) -> u32 {
if val < min {
min
} else if val > max {
max
} else {
val
}
}
#[inline]
pub fn clamp_u64(val: u64, min: u64, max: u64) -> u64 {
if val < min {
min
} else if val > max {
max
} else {
val
}
}
#[inline]
pub fn log2_u32(v: u32) -> u32 {
debug_assert!(is_power_of_2_32(v));
31 - v.leading_zeros()
}
#[inline]
pub fn log2_u64(v: u64) -> u32 {
debug_assert!(is_power_of_2_64(v));
63 - v.leading_zeros()
}
#[inline]
pub fn gcd_u32(mut a: u32, mut b: u32) -> u32 {
while b != 0 {
let t = b;
b = a % b;
a = t;
}
a
}
#[inline]
pub fn gcd_u64(mut a: u64, mut b: u64) -> u64 {
while b != 0 {
let t = b;
b = a % b;
a = t;
}
a
}
#[inline]
pub fn lcm_u32(a: u32, b: u32) -> u32 {
if a == 0 || b == 0 {
return 0;
}
a / gcd_u32(a, b) * b
}
#[inline]
pub fn lcm_u64(a: u64, b: u64) -> u64 {
if a == 0 || b == 0 {
return 0;
}
a / gcd_u64(a, b) * b
}
#[inline]
pub fn in_range_u32(v: u32, lo: u32, hi: u32) -> bool {
v >= lo && v <= hi
}
#[inline]
pub fn in_range_u64(v: u64, lo: u64, hi: u64) -> bool {
v >= lo && v <= hi
}
#[inline]
pub fn round_up_u32(v: u32, mult: u32) -> u32 {
((v + mult - 1) / mult) * mult
}
#[inline]
pub fn round_up_u64(v: u64, mult: u64) -> u64 {
((v + mult - 1) / mult) * mult
}
#[inline]
pub fn round_down_u32(v: u32, mult: u32) -> u32 {
(v / mult) * mult
}
#[inline]
pub fn round_down_u64(v: u64, mult: u64) -> u64 {
(v / mult) * mult
}
#[inline]
pub fn bswap_16(v: u16) -> u16 {
v.swap_bytes()
}
#[inline]
pub fn bswap_32(v: u32) -> u32 {
v.swap_bytes()
}
#[inline]
pub fn bswap_64(v: u64) -> u64 {
v.swap_bytes()
}
#[inline]
pub fn count_trailing_ones_u32(v: u32) -> u32 {
if v == u32::MAX {
32
} else {
(!v).trailing_zeros()
}
}
#[inline]
pub fn count_trailing_ones_u64(v: u64) -> u32 {
if v == u64::MAX {
64
} else {
(!v).trailing_zeros()
}
}
#[inline]
pub fn count_leading_ones_u32(v: u32) -> u32 {
if v == u32::MAX {
32
} else {
(!v).leading_zeros()
}
}
#[inline]
pub fn count_leading_ones_u64(v: u64) -> u32 {
if v == u64::MAX {
64
} else {
(!v).leading_zeros()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_count_leading_zeros() {
assert_eq!(count_leading_zeros_u32(0), 32);
assert_eq!(count_leading_zeros_u32(1), 31);
assert_eq!(count_leading_zeros_u32(0x8000_0000), 0);
assert_eq!(count_leading_zeros_u32(0x0000_FFFF), 16);
assert_eq!(count_leading_zeros_u64(0), 64);
assert_eq!(count_leading_zeros_u64(1), 63);
assert_eq!(count_leading_zeros_u64(0x8000_0000_0000_0000), 0);
assert_eq!(count_leading_zeros_u64(0x0000_0000_FFFF_FFFF), 32);
}
#[test]
fn test_count_trailing_zeros() {
assert_eq!(count_trailing_zeros_u32(0), 32);
assert_eq!(count_trailing_zeros_u32(1), 0);
assert_eq!(count_trailing_zeros_u32(2), 1);
assert_eq!(count_trailing_zeros_u32(0x8000_0000), 31);
assert_eq!(count_trailing_zeros_u32(12), 2);
assert_eq!(count_trailing_zeros_u64(0), 64);
assert_eq!(count_trailing_zeros_u64(1), 0);
assert_eq!(count_trailing_zeros_u64(0x8000_0000_0000_0000), 63);
assert_eq!(count_trailing_zeros_u64(24), 3); }
#[test]
fn test_count_population() {
assert_eq!(count_population_u32(0), 0);
assert_eq!(count_population_u32(1), 1);
assert_eq!(count_population_u32(0xFFFF_FFFF), 32);
assert_eq!(count_population_u32(0x5555_5555), 16);
assert_eq!(count_population_u64(0), 0);
assert_eq!(count_population_u64(1), 1);
assert_eq!(count_population_u64(0xFFFF_FFFF_FFFF_FFFF), 64);
assert_eq!(count_population_u64(0xAAAA_AAAA_AAAA_AAAA), 32);
}
#[test]
fn test_is_power_of_2() {
assert!(!is_power_of_2_u32(0));
assert!(is_power_of_2_u32(1));
assert!(is_power_of_2_u32(2));
assert!(is_power_of_2_u32(4));
assert!(!is_power_of_2_u32(3));
assert!(!is_power_of_2_u32(5));
assert!(is_power_of_2_u32(0x8000_0000));
assert!(!is_power_of_2_u64(0));
assert!(is_power_of_2_u64(1));
assert!(is_power_of_2_u64(0x8000_0000_0000_0000));
assert!(!is_power_of_2_u64(0x8000_0000_0000_0001));
}
#[test]
fn test_next_power_of_2() {
assert_eq!(next_power_of_2_u32(0), 1);
assert_eq!(next_power_of_2_u32(1), 1);
assert_eq!(next_power_of_2_u32(2), 2);
assert_eq!(next_power_of_2_u32(3), 4);
assert_eq!(next_power_of_2_u32(5), 8);
assert_eq!(next_power_of_2_u32(0x8000_0001), 0);
assert_eq!(next_power_of_2_u64(0), 1);
assert_eq!(next_power_of_2_u64(3), 4);
assert_eq!(next_power_of_2_u64(1u64 << 62), 1u64 << 62);
assert_eq!(next_power_of_2_u64((1u64 << 62) + 1), 1u64 << 63);
assert_eq!(next_power_of_2_u64(0x8000_0000_0000_0001), 0); }
#[test]
fn test_floor_log2() {
assert_eq!(floor_log2_u32(1), 0);
assert_eq!(floor_log2_u32(2), 1);
assert_eq!(floor_log2_u32(3), 1);
assert_eq!(floor_log2_u32(4), 2);
assert_eq!(floor_log2_u32(7), 2);
assert_eq!(floor_log2_u32(8), 3);
assert_eq!(floor_log2_u32(0x8000_0000), 31);
assert_eq!(floor_log2_u64(1), 0);
assert_eq!(floor_log2_u64(0x8000_0000_0000_0000), 63);
assert_eq!(floor_log2_u64((1u64 << 63) | (1u64 << 62)), 63);
}
#[test]
fn test_ceil_log2() {
assert_eq!(ceil_log2_u32(1), 0);
assert_eq!(ceil_log2_u32(2), 1);
assert_eq!(ceil_log2_u32(3), 2);
assert_eq!(ceil_log2_u32(4), 2);
assert_eq!(ceil_log2_u32(5), 3);
assert_eq!(ceil_log2_u32(8), 3);
assert_eq!(ceil_log2_u32(9), 4);
assert_eq!(ceil_log2_u64(1), 0);
assert_eq!(ceil_log2_u64(3), 2);
assert_eq!(ceil_log2_u64(1u64 << 63), 63);
assert_eq!(ceil_log2_u64((1u64 << 63) | 1), 64);
}
#[test]
fn test_align_to() {
assert_eq!(align_to(0u64, 4u64), 0);
assert_eq!(align_to(1u64, 4u64), 4);
assert_eq!(align_to(3u64, 4u64), 4);
assert_eq!(align_to(4u64, 4u64), 4);
assert_eq!(align_to(5u64, 4u64), 8);
assert_eq!(align_to(0u32, 8u32), 0);
assert_eq!(align_to(7u32, 8u32), 8);
assert_eq!(align_to(8u32, 8u32), 8);
assert_eq!(align_to(9u32, 8u32), 16);
}
#[test]
fn test_align_down() {
assert_eq!(align_down(0u64, 4u64), 0);
assert_eq!(align_down(1u64, 4u64), 0);
assert_eq!(align_down(3u64, 4u64), 0);
assert_eq!(align_down(4u64, 4u64), 4);
assert_eq!(align_down(5u64, 4u64), 4);
assert_eq!(align_down(7u64, 4u64), 4);
assert_eq!(align_down(8u64, 4u64), 8);
}
#[test]
fn test_is_aligned() {
assert!(is_aligned(0u64, 4u64));
assert!(!is_aligned(1u64, 4u64));
assert!(!is_aligned(2u64, 4u64));
assert!(!is_aligned(3u64, 4u64));
assert!(is_aligned(4u64, 4u64));
assert!(is_aligned(8u64, 4u64));
assert!(is_aligned(16u64, 8u64));
assert!(!is_aligned(17u64, 8u64));
}
#[test]
fn test_find_first_set() {
assert_eq!(find_first_set_u32(0), -1);
assert_eq!(find_first_set_u32(1), 0);
assert_eq!(find_first_set_u32(2), 1);
assert_eq!(find_first_set_u32(4), 2);
assert_eq!(find_first_set_u32(8), 3);
assert_eq!(find_first_set_u32(0x8000_0000), 31);
assert_eq!(find_first_set_u32(0b10100), 2);
assert_eq!(find_first_set_u64(0), -1);
assert_eq!(find_first_set_u64(1), 0);
assert_eq!(find_first_set_u64(0x8000_0000_0000_0000), 63);
assert_eq!(find_first_set_u64(12), 2);
}
#[test]
fn test_find_last_set() {
assert_eq!(find_last_set_u32(0), -1);
assert_eq!(find_last_set_u32(1), 0);
assert_eq!(find_last_set_u32(2), 1);
assert_eq!(find_last_set_u32(0x8000_0000), 31);
assert_eq!(find_last_set_u32(0b10100), 4);
assert_eq!(find_last_set_u32(0xFFFF_FFFF), 31);
assert_eq!(find_last_set_u64(0), -1);
assert_eq!(find_last_set_u64(1), 0);
assert_eq!(find_last_set_u64(0x8000_0000_0000_0000), 63);
assert_eq!(find_last_set_u64(0xFFFF_FFFF_FFFF_FFFF), 63);
}
#[test]
fn test_reverse_bits() {
assert_eq!(reverse_bits_u32(0), 0);
assert_eq!(reverse_bits_u32(0x8000_0000), 1);
assert_eq!(reverse_bits_u32(1), 0x8000_0000);
assert_eq!(reverse_bits_u32(0xFFFF_FFFF), 0xFFFF_FFFF);
assert_eq!(reverse_bits_u32(0xC000_0000), 3);
assert_eq!(reverse_bits_u64(0), 0);
assert_eq!(reverse_bits_u64(1), 0x8000_0000_0000_0000);
assert_eq!(reverse_bits_u64(0x8000_0000_0000_0000), 1);
}
#[test]
fn test_bit_floor() {
assert_eq!(bit_floor_u32(0), 0);
assert_eq!(bit_floor_u32(1), 1);
assert_eq!(bit_floor_u32(2), 2);
assert_eq!(bit_floor_u32(3), 2);
assert_eq!(bit_floor_u32(4), 4);
assert_eq!(bit_floor_u32(5), 4);
assert_eq!(bit_floor_u32(7), 4);
assert_eq!(bit_floor_u32(8), 8);
assert_eq!(bit_floor_u32(0x8000_0000), 0x8000_0000);
assert_eq!(bit_floor_u64(0), 0);
assert_eq!(bit_floor_u64(3), 2);
assert_eq!(bit_floor_u64(0x8000_0000_0000_0000), 0x8000_0000_0000_0000);
}
#[test]
fn test_bit_ceil() {
assert_eq!(bit_ceil_u32(0), 1);
assert_eq!(bit_ceil_u32(1), 1);
assert_eq!(bit_ceil_u32(2), 2);
assert_eq!(bit_ceil_u32(3), 4);
assert_eq!(bit_ceil_u32(4), 4);
assert_eq!(bit_ceil_u32(5), 8);
assert_eq!(bit_ceil_u32(0x8000_0000), 0x8000_0000);
assert_eq!(bit_ceil_u32(0x8000_0001), 0);
assert_eq!(bit_ceil_u64(0), 1);
assert_eq!(bit_ceil_u64(3), 4);
assert_eq!(bit_ceil_u64(0x8000_0000_0000_0000), 0x8000_0000_0000_0000);
}
#[test]
fn test_is_shifted_mask() {
assert_eq!(is_shifted_mask_32(0b1), (true, 0, 1));
assert_eq!(is_shifted_mask_32(0b11), (true, 0, 2));
assert_eq!(is_shifted_mask_32(0b110), (true, 1, 2));
assert_eq!(is_shifted_mask_32(0b11100), (true, 2, 3));
assert_eq!(is_shifted_mask_32(0xFFFF_FFFF), (true, 0, 32));
assert_eq!(is_shifted_mask_32(0b101), (false, 0, 0));
assert_eq!(is_shifted_mask_32(0b10010), (false, 0, 0));
assert_eq!(is_shifted_mask_32(0), (false, 0, 0));
assert_eq!(is_shifted_mask_64(0x00FF_FF00), (true, 8, 16));
assert_eq!(is_shifted_mask_64(0), (false, 0, 0));
assert_eq!(is_shifted_mask_64(0xFFFF_FFFF_FFFF_FFFF), (true, 0, 64));
assert_eq!(is_shifted_mask_64(0xA000_0000_0000_0000), (false, 0, 0));
}
#[test]
fn test_mask_trailing_ones() {
assert_eq!(mask_trailing_ones_u32(0), 0);
assert_eq!(mask_trailing_ones_u32(1), 1);
assert_eq!(mask_trailing_ones_u32(2), 3);
assert_eq!(mask_trailing_ones_u32(3), 7);
assert_eq!(mask_trailing_ones_u32(31), 0x7FFF_FFFF);
assert_eq!(mask_trailing_ones_u32(32), u32::MAX);
assert_eq!(mask_trailing_ones_u32(100), u32::MAX);
assert_eq!(mask_trailing_ones_u64(0), 0);
assert_eq!(mask_trailing_ones_u64(1), 1);
assert_eq!(mask_trailing_ones_u64(2), 3);
assert_eq!(mask_trailing_ones_u64(63), 0x7FFF_FFFF_FFFF_FFFF);
assert_eq!(mask_trailing_ones_u64(64), u64::MAX);
assert_eq!(mask_trailing_ones_u64(100), u64::MAX);
}
#[test]
fn test_mask_trailing_zeros() {
assert_eq!(mask_trailing_zeros_u32(0), u32::MAX);
assert_eq!(mask_trailing_zeros_u32(1), u32::MAX - 1);
assert_eq!(mask_trailing_zeros_u32(2), u32::MAX - 3);
assert_eq!(mask_trailing_zeros_u32(32), 0);
assert_eq!(mask_trailing_zeros_u64(0), u64::MAX);
assert_eq!(mask_trailing_zeros_u64(1), u64::MAX - 1);
assert_eq!(mask_trailing_zeros_u64(64), 0);
}
#[test]
fn test_umin_umax() {
assert_eq!(umin(3u32, 5u32), 3);
assert_eq!(umin(10u32, 7u32), 7);
assert_eq!(umin(0u64, 0u64), 0);
assert_eq!(umax(3u32, 5u32), 5);
assert_eq!(umax(10u32, 7u32), 10);
assert_eq!(umax(0u64, 0u64), 0);
}
#[test]
fn test_saturating_add() {
assert_eq!(saturating_add_u32(10, 20), 30);
assert_eq!(saturating_add_u32(u32::MAX, 1), u32::MAX);
assert_eq!(saturating_add_u32(u32::MAX, u32::MAX), u32::MAX);
assert_eq!(saturating_add_u64(10, 20), 30);
assert_eq!(saturating_add_u64(u64::MAX, 1), u64::MAX);
}
#[test]
fn test_saturating_sub() {
assert_eq!(saturating_sub_u32(20, 10), 10);
assert_eq!(saturating_sub_u32(10, 20), 0);
assert_eq!(saturating_sub_u32(0, 1), 0);
assert_eq!(saturating_sub_u64(20, 10), 10);
assert_eq!(saturating_sub_u64(0, 1), 0);
}
#[test]
fn test_divide_nearest() {
assert_eq!(divide_nearest_u32(10, 3), 3); assert_eq!(divide_nearest_u32(11, 3), 4); assert_eq!(divide_nearest_u32(9, 3), 3);
assert_eq!(divide_nearest_u32(5, 2), 3);
assert_eq!(divide_nearest_u64(10, 3), 3);
assert_eq!(divide_nearest_u64(5, 2), 3);
}
#[test]
fn test_divide_ceil() {
assert_eq!(divide_ceil_u32(10, 3), 4);
assert_eq!(divide_ceil_u32(9, 3), 3);
assert_eq!(divide_ceil_u32(1, 3), 1);
assert_eq!(divide_ceil_u32(0, 3), 0);
assert_eq!(divide_ceil_u64(10, 3), 4);
assert_eq!(divide_ceil_u64(9, 3), 3);
}
#[test]
#[should_panic]
fn test_divide_nearest_by_zero() {
divide_nearest_u32(10, 0);
}
#[test]
#[should_panic]
fn test_divide_ceil_by_zero() {
divide_ceil_u64(10, 0);
}
#[test]
fn test_rotl() {
assert_eq!(rotl_u32(0x0000_0001, 0), 0x0000_0001);
assert_eq!(rotl_u32(0x0000_0001, 1), 0x0000_0002);
assert_eq!(rotl_u32(0x0000_0001, 31), 0x8000_0000);
assert_eq!(rotl_u32(0x8000_0000, 1), 1);
assert_eq!(rotl_u32(0x0000_0001, 32), 0x0000_0001); assert_eq!(rotl_u32(0x0000_0001, 33), 0x0000_0002);
assert_eq!(rotl_u64(1, 63), 0x8000_0000_0000_0000);
assert_eq!(rotl_u64(0x8000_0000_0000_0000, 1), 1);
assert_eq!(rotl_u64(1, 64), 1);
}
#[test]
fn test_rotr() {
assert_eq!(rotr_u32(0x0000_0001, 0), 0x0000_0001);
assert_eq!(rotr_u32(0x0000_0001, 1), 0x8000_0000);
assert_eq!(rotr_u32(0x8000_0000, 1), 0x4000_0000);
assert_eq!(rotr_u32(0x8000_0000, 31), 1);
assert_eq!(rotr_u64(0x8000_0000_0000_0000, 63), 1);
assert_eq!(rotr_u64(1, 1), 0x8000_0000_0000_0000);
}
#[test]
fn test_byte_swap() {
assert_eq!(byte_swap_16(0x1234u16), 0x3412u16);
assert_eq!(byte_swap_16(0x0001u16), 0x0100u16);
assert_eq!(byte_swap_32(0x1234_5678u32), 0x7856_3412u32);
assert_eq!(byte_swap_32(0x0000_00FFu32), 0xFF00_0000u32);
assert_eq!(byte_swap_32(0xFF00_0000u32), 0x0000_00FFu32);
assert_eq!(
byte_swap_64(0x0123_4567_89AB_CDEFu64),
0xEFCD_AB89_6745_2301u64
);
assert_eq!(
byte_swap_64(byte_swap_64(0xDEAD_BEEF_CAFE_BABEu64)),
0xDEAD_BEEF_CAFE_BABEu64
);
}
#[test]
fn test_mul_hi_lo() {
assert_eq!(mul_hi_u32(0x0001_0001, 2), 0);
assert_eq!(mul_lo_u32(0x0001_0001, 2), 0x0002_0002);
assert_eq!(mul_hi_u32(u32::MAX, u32::MAX), u32::MAX - 1); assert_eq!(mul_lo_u32(u32::MAX, u32::MAX), 1);
assert_eq!(mul_hi_u64(0x1_0000_0000u64, 0x1_0000_0000u64), 1);
assert_eq!(mul_lo_u64(0x1_0000_0000u64, 0x1_0000_0000u64), 0);
assert_eq!(mul_hi_u64(u64::MAX, u64::MAX), u64::MAX - 1);
assert_eq!(mul_lo_u64(u64::MAX, u64::MAX), 1);
}
#[test]
fn test_add_overflow() {
assert_eq!(add_overflow_u32(10, 20), (30, false));
assert_eq!(add_overflow_u32(u32::MAX, 1), (0, true));
assert_eq!(add_overflow_u32(u32::MAX, 0), (u32::MAX, false));
assert_eq!(add_overflow_u64(10, 20), (30, false));
assert_eq!(add_overflow_u64(u64::MAX, 1), (0, true));
}
#[test]
fn test_sub_overflow() {
assert_eq!(sub_overflow_u32(20, 10), (10, false));
assert_eq!(sub_overflow_u32(0, 1), (u32::MAX, true));
assert_eq!(sub_overflow_u32(10, 20), (u32::MAX - 9, true));
assert_eq!(sub_overflow_u64(20, 10), (10, false));
assert_eq!(sub_overflow_u64(0, 1), (u64::MAX, true));
}
#[test]
fn test_mul_overflow() {
assert_eq!(mul_overflow_u32(10, 20), (200, false));
assert_eq!(mul_overflow_u32(u32::MAX, 2), (u32::MAX - 1, true));
assert_eq!(mul_overflow_u32(0, u32::MAX), (0, false));
assert_eq!(mul_overflow_u64(10, 20), (200, false));
assert_eq!(mul_overflow_u64(u64::MAX, 2), (u64::MAX - 1, true));
}
#[test]
fn test_floor_log2_edge() {
assert_eq!(floor_log2_u32(1), 0);
assert_eq!(floor_log2_u32(u32::MAX), 31);
}
#[test]
#[should_panic]
fn test_floor_log2_zero_panics() {
floor_log2_u32(0);
}
#[test]
fn test_align_to_power_of_two_requirement() {
assert_eq!(align_to(0u32, 8u32), 0);
assert_eq!(align_to(21879u32, 8u32), 21880);
}
}