orx-split-vec 3.23.0

An efficient dynamic capacity vector with pinned element guarantees.
Documentation
use criterion::{
    BenchmarkGroup, BenchmarkId, Criterion, criterion_group, criterion_main, measurement::WallTime,
};
use orx_split_vec::*;
use std::hint::black_box;

fn get_value<const N: usize>(i: usize) -> [u64; N] {
    let modulo = i % 3;
    if modulo == 0 {
        [i as u64; N]
    } else if modulo == 1 {
        [(i + 1) as u64; N]
    } else {
        [(i + 2) as u64; N]
    }
}
fn add<const N: usize>(a: [u64; N], b: &[u64; N]) -> [u64; N] {
    let mut sum = [0u64; N];
    for i in 0..N {
        sum[i] = a[i] + b[i];
    }
    sum
}

fn std_vec_with_capacity<T, F: Fn(usize) -> T>(n: usize, value: F) -> Vec<T> {
    let mut vec = Vec::with_capacity(n);
    for i in 0..n {
        vec.push(value(i))
    }
    vec
}
fn split_vec_linear<T, F: Fn(usize) -> T>(
    n: usize,
    value: F,
    constant_fragment_capacity_power: usize,
) -> SplitVec<T, Linear> {
    let mut vec = SplitVec::with_linear_growth(constant_fragment_capacity_power);
    for i in 0..n {
        vec.push(value(i))
    }
    vec
}
fn split_vec_doubling<T, F: Fn(usize) -> T>(n: usize, value: F) -> SplitVec<T, Doubling> {
    let mut vec = SplitVec::with_doubling_growth();
    for i in 0..n {
        vec.push(value(i))
    }
    vec
}

fn calc_std_vec<T: Default, F: Fn(T, &T) -> T>(add: F, vec: &[T]) -> T {
    let mut sum = T::default();
    for x in vec {
        sum = add(sum, x);
    }
    sum
}
fn calc_split_vec<T: Default, F: Fn(T, &T) -> T, G: Growth>(add: F, vec: &SplitVec<T, G>) -> T {
    let mut sum = T::default();
    for x in vec.iter() {
        sum = add(sum, x);
    }
    sum
}
fn calc_split_vec_iter_mut<T: Default, F: Fn(T, &T) -> T, G: Growth>(
    add: F,
    vec: &mut SplitVec<T, G>,
) -> T {
    let mut sum = T::default();
    for x in vec.iter_mut() {
        sum = add(sum, x);
    }
    sum
}

fn test_for_type<T: Default>(
    group: &mut BenchmarkGroup<'_, WallTime>,
    num_u64s: usize,
    treatments: &[usize],
    value: fn(usize) -> T,
    add: fn(T, &T) -> T,
) {
    for n in treatments {
        let treatment = format!("n={},elem-type=[u64;{}]", n, num_u64s);

        group.bench_with_input(BenchmarkId::new("std_vec", &treatment), n, |b, _| {
            let vec = std_vec_with_capacity(black_box(*n), value);
            b.iter(|| calc_std_vec(add, &vec))
        });

        group.bench_with_input(
            BenchmarkId::new("split_vec_linear - 2^10", &treatment),
            n,
            |b, _| {
                let vec = split_vec_linear(black_box(*n), value, 10);
                b.iter(|| calc_split_vec(add, &vec))
            },
        );

        group.bench_with_input(
            BenchmarkId::new("split_vec_doubling", &treatment),
            n,
            |b, _| {
                let vec = split_vec_doubling(black_box(*n), value);
                b.iter(|| calc_split_vec(add, &vec))
            },
        );

        group.bench_with_input(
            BenchmarkId::new("split_vec_recursive", &treatment),
            n,
            |b, _| {
                let vec: SplitVec<_, Recursive> = split_vec_doubling(black_box(*n), value).into();
                b.iter(|| calc_split_vec(add, &vec))
            },
        );

        group.bench_with_input(
            BenchmarkId::new("split_vec_linear - 2^10 - iter_mut", &treatment),
            n,
            |b, _| {
                let mut vec = split_vec_linear(black_box(*n), value, 10);
                b.iter(|| calc_split_vec_iter_mut(add, &mut vec))
            },
        );

        group.bench_with_input(
            BenchmarkId::new("split_vec_doubling - iter_mut", &treatment),
            n,
            |b, _| {
                let mut vec = split_vec_doubling(black_box(*n), value);
                b.iter(|| calc_split_vec_iter_mut(add, &mut vec))
            },
        );

        group.bench_with_input(
            BenchmarkId::new("split_vec_recursive - iter_mut", &treatment),
            n,
            |b, _| {
                let mut vec: SplitVec<_, Recursive> =
                    split_vec_doubling(black_box(*n), value).into();
                b.iter(|| calc_split_vec_iter_mut(add, &mut vec))
            },
        );
    }
}

fn bench(c: &mut Criterion) {
    let treatments = vec![1_024, 16_384, 262_144, 4_194_304];

    let mut group = c.benchmark_group("serial_access");

    const N: usize = 16;
    test_for_type::<[u64; N]>(&mut group, N, &treatments, get_value, add);

    group.finish();
}

criterion_group!(benches, bench);
criterion_main!(benches);