use crate::num::basic::integers::PrimitiveInt;
use crate::num::logic::traits::{BitConvertible, NotAssign};
use std::fmt::Debug;
const COUNTER_WIDTH: usize = u64::WIDTH as usize;
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct BitDistributorOutputType {
weight: usize, max_bits: Option<usize>,
}
impl BitDistributorOutputType {
pub fn normal(weight: usize) -> BitDistributorOutputType {
assert_ne!(weight, 0);
BitDistributorOutputType {
weight,
max_bits: None,
}
}
pub const fn tiny() -> BitDistributorOutputType {
BitDistributorOutputType {
weight: 0,
max_bits: None,
}
}
}
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct BitDistributor {
#[cfg(feature = "test_build")]
pub output_types: Vec<BitDistributorOutputType>,
#[cfg(not(feature = "test_build"))]
output_types: Vec<BitDistributorOutputType>,
bit_map: [usize; COUNTER_WIDTH],
counter: [bool; COUNTER_WIDTH],
}
impl BitDistributor {
fn new_without_init(output_types: &[BitDistributorOutputType]) -> BitDistributor {
if output_types
.iter()
.all(|output_type| output_type.weight == 0)
{
panic!("All output_types cannot be tiny");
}
BitDistributor {
output_types: output_types.to_vec(),
bit_map: [0; COUNTER_WIDTH],
counter: [false; COUNTER_WIDTH],
}
}
pub fn new(output_types: &[BitDistributorOutputType]) -> BitDistributor {
let mut distributor = BitDistributor::new_without_init(output_types);
distributor.update_bit_map();
distributor
}
pub fn bit_map_as_slice(&self) -> &[usize] {
self.bit_map.as_ref()
}
fn update_bit_map(&mut self) {
let (mut normal_output_type_indices, mut tiny_output_type_indices): (
Vec<usize>,
Vec<usize>,
) = (0..self.output_types.len()).partition(|&i| self.output_types[i].weight != 0);
let mut normal_output_types_bits_used = vec![0; normal_output_type_indices.len()];
let mut tiny_output_types_bits_used = vec![0; tiny_output_type_indices.len()];
let mut ni = normal_output_type_indices.len() - 1;
let mut ti = tiny_output_type_indices.len().saturating_sub(1);
let mut weight_counter = self.output_types[normal_output_type_indices[ni]].weight;
for i in 0..COUNTER_WIDTH {
let use_normal_output_type = !normal_output_type_indices.is_empty()
&& (tiny_output_type_indices.is_empty() || !usize::is_power_of_two(i + 1));
if use_normal_output_type {
self.bit_map[i] = normal_output_type_indices[ni];
let output_type = self.output_types[normal_output_type_indices[ni]];
normal_output_types_bits_used[ni] += 1;
weight_counter -= 1;
if output_type.max_bits == Some(normal_output_types_bits_used[ni]) {
normal_output_type_indices.remove(ni);
normal_output_types_bits_used.remove(ni);
if normal_output_type_indices.is_empty() {
continue;
}
weight_counter = 0;
}
if weight_counter == 0 {
if ni == 0 {
ni = normal_output_type_indices.len() - 1;
} else {
ni -= 1;
}
weight_counter = self.output_types[normal_output_type_indices[ni]].weight;
}
} else {
if tiny_output_type_indices.is_empty() {
self.bit_map[i] = usize::MAX;
continue;
}
self.bit_map[i] = tiny_output_type_indices[ti];
let output_type = self.output_types[tiny_output_type_indices[ti]];
tiny_output_types_bits_used[ti] += 1;
if output_type.max_bits == Some(tiny_output_types_bits_used[ti]) {
tiny_output_type_indices.remove(ti);
tiny_output_types_bits_used.remove(ti);
if tiny_output_type_indices.is_empty() {
continue;
}
}
if ti == 0 {
ti = tiny_output_type_indices.len() - 1;
} else {
ti -= 1;
}
}
}
}
pub fn set_max_bits(&mut self, output_type_indices: &[usize], max_bits: usize) {
assert_ne!(max_bits, 0);
for &index in output_type_indices {
self.output_types[index].max_bits = Some(max_bits);
}
self.update_bit_map();
}
pub fn increment_counter(&mut self) {
for b in self.counter.iter_mut() {
b.not_assign();
if *b {
break;
}
}
}
pub fn get_output(&self, index: usize) -> usize {
assert!(index < self.output_types.len());
usize::from_bits_asc(
self.bit_map
.iter()
.zip(self.counter.iter())
.filter_map(|(&m, &c)| if m == index { Some(c) } else { None }),
)
}
}