unthbuf 1.0.0

Unsigned N-bit Buffer: A structure that holds a fixed buffer of `bits`-sized unsigned integer elements.
Documentation
//! Modules containing tests.

#[cfg(test)]
use crate::{*, aligned::*, packed::*};

#[cfg(test)]
const PRIMES: &[usize] = &[2, 5, 13, 29, 61, 113, 251, 509, 1021, 2039, 4093, 8179, 16381, 32749, 65521, 131063, 262139, 524269, 1048573, 2097143, 4194301, 8388593, 16777213, 33554393, 67108859, 134217689, 268435399, 536870909, 1073741789, 2147483629, 4294967291, 8589934583, 17179869143, 34359738337, 68719476731, 137438953447, 274877906899, 549755813881, 1099511627689, 2199023255531, 4398046511093, 8796093022151, 17592186044399, 35184372088777, 70368744177643, 140737488355213, 281474976710597, 562949953421231, 1125899906842597, 2251799813685119, 4503599627370449, 9007199254740881, 18014398509481951, 36028797018963913, 72057594037927931, 144115188075855859, 288230376151711717, 576460752303423433, 1152921504606846883, 2305843009213693921, 4611686018427387847, 9223372036854775783, 18446744073709551557];

#[test]
#[ignore = "simply prints all valid indices"]
fn aligned_location_of() {
    for bits in 1..=64 {
        let buf = UnthBuf::<AlignedLayout>::new(bits.try_into().unwrap(), 4096);
        println!("--- {bits} BITS");
        
        for loc in buf.get_indices() {
            let loc = buf.location_of(loc as usize);
            print!("{loc:?} ")
        }
        println!();
    }
}

#[test]
#[ignore = "simply prints all valid indices"]
fn packed_location_of() {
    for bits in 1..=64 {
        let buf = UnthBuf::<PackedLayout>::new(bits.try_into().unwrap(), 4096);
        println!("--- {bits} BITS");
        
        for loc in buf.get_indices() {
            let loc = buf.location_of(loc as usize);
            print!("{loc:?} ")
        }
        println!();
    }
}

#[test]
fn aligned_setget() {
    
    for prime
    in PRIMES.iter().copied().chain(
        (1..64usize).map(|b| 2usize.pow(b as u32)-1)
    ) {
        let bits: u8 = match prime.checked_next_power_of_two() {
            Some(pot) => pot.trailing_zeros() as u8 + 1,
            None => 64
        };
        
        let mut buf = UnthBuf::<AlignedLayout>::new_from_capacity_and_iter(bits.try_into().unwrap(), 4096, std::iter::repeat(prime));
        if ! buf.can_element_fit(prime) {continue;}
        
        println!("--- {bits} BITS / Value {prime}");
        for idx in buf.get_indices() {
            let in_prime = prime;
            buf.set(idx, in_prime).unwrap();
            let out_prime = buf.get(idx).unwrap();
            let loc = buf.location_of(idx);
            debug_assert!(
                in_prime == out_prime,
                "{in_prime} != {out_prime} {loc:?} = {:b}", buf.data[loc.cell]
            )
        }
    }
    
}


#[test]
fn unaligned_setget() {
    
    for prime
    in PRIMES.iter().copied().chain(
        (1..64usize).map(|b| 2usize.pow(b as u32)-1)
    ) {
        let bits: u8 = match prime.checked_next_power_of_two() {
            Some(pot) => (pot - 1).count_ones() as u8,
            None => 64
        };
        
        if bits == 0 {continue}
        
        let mut buf = UnthBuf::<PackedLayout>::new_from_capacity_and_iter(bits.try_into().unwrap(), 4096, std::iter::repeat(prime));
        if ! buf.can_element_fit(prime) {continue;}
        
        println!("--- {bits} BITS / Value {prime}");
        for idx in buf.get_indices() {
            let in_prime = prime;
            buf.set(idx, in_prime).unwrap();
            let out_prime = buf.get(idx).unwrap();
            let loc = buf.location_of(idx);
            debug_assert!(
                in_prime == out_prime,
                "{in_prime} != {out_prime} {loc:?} = {:b}{:b}",
                buf.data[loc.cell+1], buf.data[loc.cell]
            )
        }
    }
    
}


#[cfg(test)]
const BITSIZE: u8 = 5;

#[cfg(test)]
const RNG_SEED: u64 = 134217728;

#[cfg(test)]
const ITERATIONS: usize = 256usize.pow(3);//134217728; // 100000000;

#[cfg(test)]
type ValType = u8;

#[cfg(test)]
fn test_values(bitsize: u8, rng: &mut rand::prelude::StdRng) -> Vec<ValType> {
    use rand::prelude::*;
    let mut values = vec![0u8; ITERATIONS];
    values.fill_with(|| rng.gen_range(0..2_usize.pow(bitsize as u32)) as ValType);
    values
}

#[cfg(test)]
fn test_indices(rng: &mut rand::prelude::StdRng) -> Vec<usize> {
    use rand::prelude::*;
    let mut indices: Vec<usize> = (0..ITERATIONS).collect();
    //indices.shuffle(rng);
    indices
}

#[test]
#[ignore = "benchmark"]
pub fn bench_io_unaligned() {
    use std::time::Instant;
    use rand::prelude::*;
    
    let mut rng = rand::rngs::StdRng::seed_from_u64(RNG_SEED);
    
    let n = ITERATIONS;
    let bitsize = BITSIZE;
    let values = test_values(bitsize, &mut rng);
    let indices = test_indices(&mut rng);
    
    // init bench
    println!();
    let now = Instant::now();
    let mut packed = UnthBuf::<PackedLayout>::new_from_capacity_and_iter(
        bitsize.try_into().unwrap(),
        values.len(),
        values.iter().copied().map(|v|v as usize)
    );
    let elapsed = now.elapsed();
    println!("Initia. {} unaligned values took {} ms / {} ns per int.", n, elapsed.as_millis(), elapsed.div_f64(n as f64).as_nanos());
    
    // write bench
    let values = test_values(bitsize.try_into().unwrap(), &mut rng);
    let now = Instant::now();
    for i in indices.iter().copied() {
        packed.set(i, values[i] as usize).unwrap();
    }
    let elapsed = now.elapsed();
    println!("Writing {} unaligned values took {} ms / {} ns per int.", n, elapsed.as_millis(), elapsed.div_f64(n as f64).as_nanos());
    
    // read bench
    let mut values = vec![0 as ValType; n];
    let now = Instant::now();
    for i in indices.iter().copied() {
        values[i] = packed.get(i).unwrap() as ValType;
    }
    let elapsed = now.elapsed();
    println!("Reading {} unaligned values took {} ms / {} ns per int.", n, elapsed.as_millis(), elapsed.div_f64(n as f64).as_nanos());
}


#[test]
#[ignore = "benchmark"]
pub fn bench_io_aligned() {
    use std::time::Instant;
    use rand::prelude::*;
    
    let mut rng = rand::rngs::StdRng::seed_from_u64(RNG_SEED);
    
    let n = ITERATIONS;
    let bitsize = BITSIZE;
    let values = test_values(bitsize, &mut rng);
    let indices = test_indices(&mut rng);
    
    // init bench
    println!();
    let now = Instant::now();
    let mut packed = UnthBuf::<AlignedLayout>::new_from_capacity_and_iter(
        bitsize.try_into().unwrap(),
        values.len(),
        values.iter().copied().map(|v|v as usize)
    );
    let elapsed = now.elapsed();
    println!("Initia. {}   aligned values took {} ms / {} ns per int.", n, elapsed.as_millis(), elapsed.div_f64(n as f64).as_nanos());
    
    // write bench
    let values = test_values(bitsize, &mut rng);
    let now = Instant::now();
    for i in indices.iter().copied() {
        packed.set(i, values[i] as usize).unwrap();
    }
    let elapsed = now.elapsed();
    println!("Writing {}   aligned values took {} ms / {} ns per int.", n, elapsed.as_millis(), elapsed.div_f64(n as f64).as_nanos());
    
    // read bench
    let mut values = vec![0 as ValType; n];
    let now = Instant::now();
    for i in indices.iter().copied() {
        values[i] = packed.get(i).unwrap() as ValType;
    }
    let elapsed = now.elapsed();
    println!("Reading {}   aligned values took {} ms / {} ns per int.", n, elapsed.as_millis(), elapsed.div_f64(n as f64).as_nanos());
}




#[test]
#[ignore = "benchmark"]
pub fn bench_io_baseline() {
    use std::time::Instant;
    use rand::prelude::*;
    
    let mut rng = rand::rngs::StdRng::seed_from_u64(RNG_SEED);
    
    let n = ITERATIONS;
    let bitsize = BITSIZE;
    
    let values = test_values(bitsize, &mut rng);
    let indices = test_indices(&mut rng);
    
    // init bench
    println!();
    let now = Instant::now();
    let mut packed = Vec::<ValType>::from_iter(values.iter().copied().map(|v|v as ValType));
    let elapsed = now.elapsed();
    println!("Initia. {}  baseline values took {} ms / {} ns per int.", n, elapsed.as_millis(), elapsed.div_f64(n as f64).as_nanos());
    
    // write bench
    let values = test_values(bitsize, &mut rng);
    let now = Instant::now();
    for i in indices.iter().copied() {
        *packed.get_mut(i).unwrap() = values[i];
    }
    let elapsed = now.elapsed();
    println!("Writing {}  baseline values took {} ms / {} ns per int.", n, elapsed.as_millis(), elapsed.div_f64(n as f64).as_nanos());
    
    // read bench
    let mut values = vec![0 as ValType; n];
    let now = Instant::now();
    for i in indices.iter().copied() {
        values[i] = *packed.get(i).unwrap();
    }
    let elapsed = now.elapsed();
    println!("Reading {}  baseline values took {} ms / {} ns per int.", n, elapsed.as_millis(), elapsed.div_f64(n as f64).as_nanos());
}