#![allow(dead_code)]
use nar_dev_utils::{manipulate, pipe};
use serde::{Deserialize, Serialize};
use std::fmt::Debug;
pub trait Distribute<T = usize, I = usize> {
fn pick(&self, index: I) -> T;
fn next(&self, index: I) -> I;
fn iter(&self, start_i: I) -> Iter<'_, T, I, Self>
where
Self: Sized,
{
Iter {
distributor: self,
index: start_i,
_mark_t: std::marker::PhantomData,
}
}
fn iter_default(&self) -> Iter<'_, T, I, Self>
where
I: Default,
Self: Sized,
{
self.iter(I::default())
}
fn take_n(&self, start_i: I, n: usize) -> impl Iterator<Item = T>
where
I: Copy,
T: Copy,
Self: Sized,
{
self.iter(start_i).take(n)
}
}
pub struct Iter<'a, T, I, D>
where
D: Distribute<T, I>,
{
distributor: &'a D,
index: I,
_mark_t: std::marker::PhantomData<T>,
}
impl<T, I, D> Iterator for Iter<'_, T, I, D>
where
T: Copy,
I: Copy,
D: Distribute<T, I>,
{
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
let result = Some(self.distributor.pick(self.index));
self.index = self.distributor.next(self.index);
result
}
}
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct Distributor {
range: usize,
order: Box<[usize]>,
next: Box<[usize]>,
}
impl Distributor {
pub fn new(range: usize) -> Self {
let (capacity, order) = Self::range_to_capacity_and_order(range);
let next = Self::capacity_to_next(capacity);
Self { range, order, next }
}
pub fn capacity_to_next(capacity: usize) -> Box<[usize]> {
manipulate!(
(1..capacity).collect::<Vec<_>>()
=> .push(0)
)
.into_boxed_slice()
}
pub fn range_to_capacity_and_order(range: usize) -> (usize, Box<[usize]>) {
let capacity: usize = range * (range + 1) / 2;
let mut order = vec![0; capacity].into_boxed_slice();
let mut index = capacity - 1;
for rank in (1..=range).rev() {
for _ in 0..rank {
index = ((capacity / rank) + index) % capacity;
while order[index] > 0 {
index += 1;
index %= capacity;
}
order[index] = rank;
}
}
for order_i in order.iter_mut() {
*order_i -= 1;
}
(capacity, order)
}
pub fn capacity(&self) -> usize {
self.order.len()
}
}
#[derive(Clone)]
struct RawDebug(String);
impl Debug for RawDebug {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl Debug for Distributor {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Distributor")
.field("range", &self.range)
.field("order", &RawDebug(debug_truncated_arr(&self.order, 50)))
.field(
"next",
&RawDebug(format!(
"[Array `next[i] = i + 1 % {}` with len = {}]",
self.capacity(),
self.next.len()
)),
)
.finish()
}
}
fn debug_truncated_arr<T: Debug>(arr: &[T], max_len: usize) -> String {
if arr.len() <= max_len {
format!("{:?}", arr)
} else {
let mut s = format!("{:?}", &arr[..max_len]);
s.pop(); s.push_str(&format!(", ... (len = {})]", arr.len()));
s
}
}
impl Distribute for Distributor {
fn pick(&self, index: usize) -> usize {
self.order[index]
}
fn next(&self, index: usize) -> usize {
self.next[index]
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
struct DistributorSerde {
range: usize,
}
impl From<&Distributor> for DistributorSerde {
fn from(d: &Distributor) -> Self {
Self { range: d.range }
}
}
impl From<DistributorSerde> for Distributor {
fn from(d: DistributorSerde) -> Self {
Self::new(d.range)
}
}
impl Serialize for Distributor {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
pipe! {
self
=> DistributorSerde::from
=> .serialize(serializer)
}
}
}
impl<'de> Deserialize<'de> for Distributor {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
pipe! {
deserializer
=> DistributorSerde::deserialize => {?}#
=> Distributor::from
=> Ok
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::HashMap;
#[test]
fn test_debug_truncated_arr() {
let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
assert_eq!(
debug_truncated_arr(&arr, 5),
"[1, 2, 3, 4, 5, ... (len = 10)]"
);
}
#[test]
fn test_distributor() {
let range = 10..=20;
for n in range {
_test_distributor(n);
}
}
fn _test_distributor(n: usize) {
let d = Distributor::new(n);
println!("d = {d:?}");
_test_next(&d);
_test_weight(&_weights(d.take_n(0, d.capacity())));
_test_local_weights(&d, d.range);
}
fn _test_next(d: &Distributor) {
let c = d.capacity();
for i in 0..(c - 1) {
assert_eq!(d.next(i), i + 1);
}
assert_eq!(d.next(c - 1), 0);
}
fn _test_local_weights(d: &Distributor, n: usize) {
let c = d.capacity();
let l = c * n;
let results = d.iter_default().take(l).collect::<Vec<_>>();
for i in 0..(l - c) {
let slice = &results[i..(i + c)];
_test_weight(&_weights(slice.iter().copied()));
}
}
fn _test_weight(weights: &HashMap<usize, usize>) {
let mut weights_arr = weights.iter().map(|(k, v)| (*k, *v)).collect::<Vec<_>>();
weights_arr.sort_by(|a, b| a.0.cmp(&b.0));
for (i, (term, w)) in weights_arr.iter().enumerate() {
if i > 0 {
let (previous, w_p) = weights_arr[i - 1];
assert_eq!(
*term < previous,
*w < w_p,
"error with weights = {:?} and (term, w) = ({term}, {w}), (previous, w_p) = ({previous}, {w_p}))",
&weights_arr
);
}
}
}
fn _weights(term_iter: impl Iterator<Item = usize>) -> HashMap<usize, usize> {
let mut weights = HashMap::new();
for t in term_iter {
weights.entry(t).and_modify(|u| *u += 1).or_insert(1);
}
weights
}
#[test]
fn serde() {
const TEST_RANGE: std::ops::Range<usize> = 10..100;
for range in TEST_RANGE {
let d0 = Distributor::new(range);
let s = serde_json::to_string(&d0).unwrap();
let d = serde_json::from_str::<Distributor>(&s).unwrap();
assert_eq!(d0, d);
}
}
}