Counting Bits

//! This module implements a function to count the number of set bits (1s)
//! in the binary representation of an unsigned integer.
//! It uses Brian Kernighan's algorithm, which efficiently clears the least significant
//! set bit in each iteration until all bits are cleared.
//! The algorithm runs in O(k), where k is the number of set bits.

/// Counts the number of set bits in an unsigned integer.
///
/// # Arguments
///
/// * `n` - An unsigned 32-bit integer whose set bits will be counted.
///
/// # Returns
///
/// * `usize` - The number of set bits (1s) in the binary representation of the input number.
pub fn count_set_bits(mut n: usize) -> usize {
    // Initialize a variable to keep track of the count of set bits
    let mut count = 0;
    while n > 0 {
        // Clear the least significant set bit by
        // performing a bitwise AND operation with (n - 1)
        n &= n - 1;

        // Increment the count for each set bit found
        count += 1;
    }

    count
}

#[cfg(test)]
mod tests {
    use super::*;

    macro_rules! test_count_set_bits {
        ($($name:ident: $test_case:expr,)*) => {
            $(
                #[test]
                fn $name() {
                    let (input, expected) = $test_case;
                    assert_eq!(count_set_bits(input), expected);
                }
            )*
        };
    }
    test_count_set_bits! {
        test_count_set_bits_zero: (0, 0),
        test_count_set_bits_one: (1, 1),
        test_count_set_bits_power_of_two: (16, 1),
        test_count_set_bits_all_set_bits: (usize::MAX, std::mem::size_of::<usize>() * 8),
        test_count_set_bits_alternating_bits: (0b10101010, 4),
        test_count_set_bits_mixed_bits: (0b11011011, 6),
    }
}