`FACTOR_POW_DIVISOR == (FACTOR as usize).pow(factor_to_divisor:: () as u32)` but as a constant.
(
input: &mut &[u8],
length: usize,
out: &mut Vec<u8>,
)
| 251 | |
| 252 | /// `FACTOR_POW_DIVISOR == (FACTOR as usize).pow(factor_to_divisor::<FACTOR>() as u32)` but as a constant. |
| 253 | fn unpack_arithmetic_less_than< |
| 254 | const N: usize, |
| 255 | const HISTOGRAM: usize, |
| 256 | const FACTOR: usize, |
| 257 | const FACTOR_POW_DIVISOR: usize, |
| 258 | >( |
| 259 | input: &mut &[u8], |
| 260 | length: usize, |
| 261 | out: &mut Vec<u8>, |
| 262 | ) -> Result<[usize; HISTOGRAM]> { |
| 263 | assert!(HISTOGRAM == N || HISTOGRAM == 0); |
| 264 | assert!(FACTOR >= 2 && FACTOR >= N); |
| 265 | let divisor = factor_to_divisor::<FACTOR>(); |
| 266 | assert_eq!(FACTOR.pow(divisor as u32), FACTOR_POW_DIVISOR); |
| 267 | |
| 268 | let original_input = *input; |
| 269 | unpack_arithmetic::<FACTOR>(input, length, out)?; |
| 270 | if HISTOGRAM == 0 { |
| 271 | check_less_than::<N, HISTOGRAM, FACTOR>(out) |
| 272 | } else { |
| 273 | let floor = length / divisor; |
| 274 | let ceil = crate::nightly::div_ceil_usize(length, divisor); |
| 275 | let whole = &original_input[..floor]; |
| 276 | |
| 277 | // Can only `partial_with_garbage % FACTOR` partial_length times as the rest are undefined garbage. |
| 278 | let partial_length = length - floor * divisor; |
| 279 | let partial_with_garbage = original_input[floor..ceil].first().copied(); |
| 280 | |
| 281 | // POPCNT is much faster than histogram. |
| 282 | let histogram = if FACTOR == 2 { |
| 283 | assert_eq!(N, 2); |
| 284 | assert_eq!(divisor, 8); |
| 285 | let mut one_count = 0; |
| 286 | let mut whole = whole; |
| 287 | while let Ok(chunk) = consume_byte_arrays(&mut whole, 1) { |
| 288 | one_count += u64::from_ne_bytes(chunk[0]).count_ones() as usize; |
| 289 | } |
| 290 | for &byte in whole { |
| 291 | one_count += byte.count_ones() as usize; |
| 292 | } |
| 293 | if let Some(partial_with_garbage) = partial_with_garbage { |
| 294 | // Set undefined garbage bits to zero. |
| 295 | let partial = partial_with_garbage << (divisor - partial_length); |
| 296 | one_count += partial.count_ones() as usize; |
| 297 | } |
| 298 | Ok(std::array::from_fn(|i| match i { |
| 299 | 0 => length - one_count, |
| 300 | 1 => one_count, |
| 301 | _ => unreachable!(), |
| 302 | })) |
| 303 | } else { |
| 304 | check_histogram(if whole.len() < 100 { |
| 305 | // Simple path: histogram of unpacked bytes. |
| 306 | let mut histogram = [0; FACTOR]; |
| 307 | for &v in out.iter() { |
| 308 | // Safety: unpack_arithmetic::<FACTOR> returns bytes < FACTOR. |
| 309 | unsafe { *histogram.get_unchecked_mut(v as usize) += 1 }; |
| 310 | } |
nothing calls this directly
no test coverage detected