use bitvec::{boxed::BitBox, order::BitOrder, slice::BitSlice, store::BitStore};
use num::{PrimInt, traits::ConstOne};
#[track_caller]
pub fn count_unique_sorted<I, T>(iter: I) -> usize
where
I: IntoIterator<Item = T>,
T: PrimInt,
{
let mut iter = iter.into_iter().peekable();
let mut count = 0;
let mut max = T::zero();
while let Some(curr) = iter.next() {
debug_assert!(curr >= max, "values must be sorted");
max = curr;
count += 1;
while iter.peek() == Some(&curr) {
iter.next();
}
}
count
}
pub fn count_runs_sorted<I, T>(iter: I) -> usize
where
I: IntoIterator<Item = T>,
T: PrimInt + ConstOne,
{
let mut iter = iter.into_iter().peekable();
let mut count = 0;
let mut last = None;
while let Some(mut curr) = iter.next() {
debug_assert!(
Some(curr) > last.replace(curr),
"values must be sorted and unique"
);
count += 1;
curr = curr.saturating_add(T::ONE);
while iter.peek() == Some(&curr) {
curr = curr.saturating_add(T::ONE);
iter.next();
}
}
count
}
pub fn count_bitmap_runs<T, O>(bitmap: &BitSlice<T, O>) -> usize
where
T: BitStore,
O: BitOrder,
{
let shifted = &bitmap[1..];
let transitions = !BitBox::from_bitslice(bitmap) & shifted;
transitions.count_ones() + (bitmap[0] as usize)
}
#[cfg(test)]
mod tests {
use bitvec::{order::Msb0, view::BitView};
use itertools::enumerate;
use super::*;
#[test]
fn test_count_unique_sorted() {
assert_eq!(count_unique_sorted(Vec::<u32>::new()), 0);
assert_eq!(count_unique_sorted(vec![1]), 1);
assert_eq!(count_unique_sorted(vec![1, 1, 1]), 1);
assert_eq!(count_unique_sorted(vec![1, 2, 3]), 3);
assert_eq!(count_unique_sorted(vec![1, 1, 2, 2, 3, 3]), 3);
assert_eq!(count_unique_sorted(vec![1, 2, 2, 2, 3, 4, 4]), 4);
}
#[test]
#[should_panic]
fn test_count_unique_sorted_panic() {
count_unique_sorted(vec![1, 2, 1]);
}
#[test]
fn test_count_runs_sorted() {
let cases = [
(vec![], 0),
(vec![1], 1),
(vec![1, 2], 1),
(vec![1, 2, 4], 2),
(vec![1, 2, 5, 7], 3),
(vec![2, 3, 4, 5], 1),
];
for (input, expected) in cases {
assert_eq!(count_runs_sorted(input.clone()), expected, "{input:?}");
}
}
#[test]
#[should_panic]
fn test_count_runs_sorted_panic() {
count_runs_sorted([1, 2, 1]);
}
#[test]
fn test_count_bitmap_runs() {
let cases = [
(vec![0b00000000_00000000], 0),
(vec![0b00000000_00000001], 1),
(vec![0b00000000_00000010], 1),
(vec![0b00000000_00000011], 1),
(vec![0b10000000_00000000], 1),
(vec![0b10000000_00000000], 1),
(vec![0b01000000_00000000], 1),
(vec![0b00000001_00000001], 2),
(vec![0b10000000_10000000], 2),
(vec![0b10000001_10000000], 2),
(vec![0b00000001_10000000], 1),
(vec![0b00000001_10000001], 2),
(vec![0b11111111_11111111], 1),
(vec![0b11110000_11111111], 2),
(vec![0b11110111_11111111], 2),
(vec![0b10101010_10101010], 8),
(vec![0b01010101_01010101], 8),
(vec![0b11011011_01101101], 6),
(vec![0b11101110_11101110], 4),
([0b10101010_10101010].repeat(128), 128 * 8),
([0b01010101_01010101].repeat(128), 128 * 8),
([0b10000000_00000001].repeat(128), 128 + 1),
([0b10000000_10000001].repeat(128), 128 + 1 + 128),
([0b11111111_11111111].repeat(128), 1),
([0b00000000_00000000].repeat(128), 0),
];
for (i, (bits, expected)) in enumerate(cases) {
let bitmap: &BitSlice<u16, Msb0> = bits.view_bits::<Msb0>();
println!("testing case {i}: {bitmap:b}");
assert_eq!(
count_bitmap_runs(bitmap),
expected,
"case {i} failed: {bitmap:b}"
);
}
}
}