#![allow(clippy::cast_possible_truncation)]
#![allow(clippy::cast_sign_loss)]
#[inline(always)]
#[must_use]
pub const fn count_ones(value: u64) -> u32 {
value.count_ones()
}
#[inline(always)]
#[must_use]
pub const fn count_zeros(value: u64) -> u32 {
value.count_zeros()
}
#[inline(always)]
#[must_use]
pub const fn is_power_of_two(n: usize) -> bool {
n != 0 && (n & (n - 1)) == 0
}
#[inline]
#[must_use]
pub const fn next_power_of_two(n: usize) -> usize {
if n == 0 {
return 1;
}
if n & (n - 1) == 0 {
return n;
}
1 << (usize::BITS - (n - 1).leading_zeros())
}
#[inline]
#[must_use]
pub const fn prev_power_of_two(n: usize) -> usize {
if n == 0 {
return 0;
}
if n & (n - 1) == 0 {
return n;
}
1 << (usize::BITS - 1 - n.leading_zeros())
}
#[inline]
#[must_use]
pub const fn round_up_to_multiple(n: usize, multiple: usize) -> usize {
assert!(multiple > 0, "multiple must be greater than 0");
if n == 0 {
return 0;
}
n.div_ceil(multiple) * multiple
}
#[inline]
#[must_use]
pub const fn bits_to_words(n_bits: usize) -> usize {
n_bits.div_ceil(64)
}
#[inline]
#[must_use]
pub const fn bits_to_bytes(n_bits: usize) -> usize {
n_bits.div_ceil(8)
}
#[inline(always)]
#[must_use]
pub const fn word_index(bit_index: usize) -> usize {
bit_index >> 6 }
#[inline(always)]
#[must_use]
pub const fn bit_offset(bit_index: usize) -> usize {
bit_index & 63 }
#[inline(always)]
#[must_use]
pub const fn bit_mask(offset: usize) -> u64 {
1u64 << (offset & 63)
}
#[inline]
#[must_use]
pub fn count_ones_slice(words: &[u64]) -> usize {
words.iter().map(|&w| w.count_ones() as usize).sum()
}
#[inline]
#[must_use]
pub fn hamming_distance(a: &[u64], b: &[u64]) -> usize {
assert_eq!(a.len(), b.len(), "Slices must have same length");
a.iter()
.zip(b.iter())
.map(|(&x, &y)| (x ^ y).count_ones() as usize)
.sum()
}
#[must_use]
pub fn all_zeros_in_range(words: &[u64], start_bit: usize, end_bit: usize) -> bool {
if start_bit >= end_bit {
return true;
}
let start_word = word_index(start_bit);
let end_word = word_index(end_bit.saturating_sub(1));
if start_word >= words.len() {
return true;
}
for w in &words[start_word..=end_word.min(words.len().saturating_sub(1))] {
if *w != 0 {
return false;
}
}
true
}
#[inline(always)]
#[must_use]
pub const fn leading_zeros(value: u64) -> u32 {
value.leading_zeros()
}
#[inline(always)]
#[must_use]
pub const fn trailing_zeros(value: u64) -> u32 {
value.trailing_zeros()
}
#[inline]
#[must_use]
pub const fn reverse_bits(value: u64) -> u64 {
value.reverse_bits()
}
#[inline(always)]
#[must_use]
pub const fn rotate_left(value: u64, n: u32) -> u64 {
value.rotate_left(n)
}
#[inline(always)]
#[must_use]
pub const fn rotate_right(value: u64, n: u32) -> u64 {
value.rotate_right(n)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_count_ones() {
assert_eq!(count_ones(0), 0);
assert_eq!(count_ones(0b1), 1);
assert_eq!(count_ones(0b1010), 2);
assert_eq!(count_ones(0b1111), 4);
assert_eq!(count_ones(u64::MAX), 64);
}
#[test]
fn test_count_zeros() {
assert_eq!(count_zeros(0), 64);
assert_eq!(count_zeros(0b1), 63);
assert_eq!(count_zeros(0b1010), 62);
assert_eq!(count_zeros(u64::MAX), 0);
}
#[test]
fn test_is_power_of_two() {
assert!(!is_power_of_two(0));
assert!(is_power_of_two(1));
assert!(is_power_of_two(2));
assert!(!is_power_of_two(3));
assert!(is_power_of_two(4));
assert!(!is_power_of_two(5));
assert!(is_power_of_two(8));
assert!(is_power_of_two(1024));
assert!(!is_power_of_two(1023));
}
#[test]
fn test_next_power_of_two() {
assert_eq!(next_power_of_two(0), 1);
assert_eq!(next_power_of_two(1), 1);
assert_eq!(next_power_of_two(2), 2);
assert_eq!(next_power_of_two(3), 4);
assert_eq!(next_power_of_two(4), 4);
assert_eq!(next_power_of_two(5), 8);
assert_eq!(next_power_of_two(100), 128);
assert_eq!(next_power_of_two(1000), 1024);
assert_eq!(next_power_of_two(1024), 1024);
}
#[test]
fn test_prev_power_of_two() {
assert_eq!(prev_power_of_two(0), 0);
assert_eq!(prev_power_of_two(1), 1);
assert_eq!(prev_power_of_two(2), 2);
assert_eq!(prev_power_of_two(3), 2);
assert_eq!(prev_power_of_two(4), 4);
assert_eq!(prev_power_of_two(5), 4);
assert_eq!(prev_power_of_two(100), 64);
assert_eq!(prev_power_of_two(1000), 512);
assert_eq!(prev_power_of_two(1024), 1024);
}
#[test]
fn test_round_up_to_multiple() {
assert_eq!(round_up_to_multiple(0, 8), 0);
assert_eq!(round_up_to_multiple(1, 8), 8);
assert_eq!(round_up_to_multiple(8, 8), 8);
assert_eq!(round_up_to_multiple(9, 8), 16);
assert_eq!(round_up_to_multiple(10, 8), 16);
assert_eq!(round_up_to_multiple(100, 64), 128);
}
#[test]
#[should_panic(expected = "multiple must be greater than 0")]
fn test_round_up_to_multiple_zero() {
let _ = round_up_to_multiple(10, 0);
}
#[test]
fn test_bits_to_words() {
assert_eq!(bits_to_words(0), 0);
assert_eq!(bits_to_words(1), 1);
assert_eq!(bits_to_words(64), 1);
assert_eq!(bits_to_words(65), 2);
assert_eq!(bits_to_words(128), 2);
assert_eq!(bits_to_words(129), 3);
}
#[test]
fn test_bits_to_bytes() {
assert_eq!(bits_to_bytes(0), 0);
assert_eq!(bits_to_bytes(1), 1);
assert_eq!(bits_to_bytes(8), 1);
assert_eq!(bits_to_bytes(9), 2);
assert_eq!(bits_to_bytes(16), 2);
}
#[test]
fn test_word_index() {
assert_eq!(word_index(0), 0);
assert_eq!(word_index(63), 0);
assert_eq!(word_index(64), 1);
assert_eq!(word_index(127), 1);
assert_eq!(word_index(128), 2);
}
#[test]
fn test_bit_offset() {
assert_eq!(bit_offset(0), 0);
assert_eq!(bit_offset(1), 1);
assert_eq!(bit_offset(63), 63);
assert_eq!(bit_offset(64), 0);
assert_eq!(bit_offset(65), 1);
}
#[test]
fn test_bit_mask() {
assert_eq!(bit_mask(0), 1);
assert_eq!(bit_mask(1), 2);
assert_eq!(bit_mask(2), 4);
assert_eq!(bit_mask(63), 1u64 << 63);
}
#[test]
fn test_count_ones_slice() {
assert_eq!(count_ones_slice(&[]), 0);
assert_eq!(count_ones_slice(&[0]), 0);
assert_eq!(count_ones_slice(&[0b1010]), 2);
assert_eq!(count_ones_slice(&[0b1010, 0b1111]), 6);
assert_eq!(count_ones_slice(&[u64::MAX, u64::MAX]), 128);
}
#[test]
fn test_hamming_distance() {
assert_eq!(hamming_distance(&[], &[]), 0);
assert_eq!(hamming_distance(&[0], &[0]), 0);
assert_eq!(hamming_distance(&[0b1010], &[0b1010]), 0);
assert_eq!(hamming_distance(&[0b1010], &[0b0101]), 4);
assert_eq!(hamming_distance(&[0b1111], &[0b0000]), 4);
}
#[test]
#[should_panic(expected = "Slices must have same length")]
fn test_hamming_distance_different_lengths() {
let _ = hamming_distance(&[0], &[0, 0]);
}
#[test]
fn test_all_zeros_in_range() {
let zeros = vec![0u64; 4];
assert!(all_zeros_in_range(&zeros, 0, 256));
let mixed = vec![0, 0, 1, 0];
assert!(all_zeros_in_range(&mixed, 0, 128));
assert!(!all_zeros_in_range(&mixed, 0, 192));
assert!(all_zeros_in_range(&[], 0, 64));
assert!(all_zeros_in_range(&[0], 100, 50)); }
#[test]
fn test_leading_zeros() {
assert_eq!(leading_zeros(0), 64);
assert_eq!(leading_zeros(1), 63);
assert_eq!(leading_zeros(0b1000), 60);
assert_eq!(leading_zeros(u64::MAX), 0);
}
#[test]
fn test_trailing_zeros() {
assert_eq!(trailing_zeros(0), 64);
assert_eq!(trailing_zeros(1), 0);
assert_eq!(trailing_zeros(0b1000), 3);
assert_eq!(trailing_zeros(0b1100), 2);
}
#[test]
fn test_reverse_bits() {
assert_eq!(reverse_bits(0), 0);
assert_eq!(reverse_bits(1), 1u64 << 63);
assert_eq!(reverse_bits(u64::MAX), u64::MAX);
}
#[test]
fn test_rotate_left() {
assert_eq!(rotate_left(0b1, 1), 0b10);
assert_eq!(rotate_left(0b1, 63), 1u64 << 63);
assert_eq!(rotate_left(0b1, 64), 0b1); }
#[test]
fn test_rotate_right() {
assert_eq!(rotate_right(0b10, 1), 0b1);
assert_eq!(rotate_right(1u64 << 63, 63), 0b1);
assert_eq!(rotate_right(0b1, 64), 0b1); }
}