diff --git a/benches/operations.rs b/benches/operations.rs index c328412..27656dd 100644 --- a/benches/operations.rs +++ b/benches/operations.rs @@ -1,7 +1,46 @@ use criterion::{black_box, criterion_group, criterion_main, Criterion}; use tailcall_chunk::Chunk; -const N: usize = 10000; +const N: usize = 100; + +/// A simple immutable vector implementation. +#[derive(Clone)] +struct Vector { + vec: Vec, +} + +impl Vector { + fn push(self, value: A) -> Self { + let mut vec = self.vec.clone(); + vec.push(value); + Self { vec } + } + + fn concat(self, other: Self) -> Self { + let mut vec = self.vec.clone(); + vec.extend(other.vec.iter().cloned()); + Self { vec } + } + + fn prepend(&self, value: A) -> Self { + let mut vec = Vec::with_capacity(self.vec.len() + 1); + vec.push(value); + vec.extend(self.vec.iter().cloned()); + Self { vec } + } + + fn new() -> Self { + Self { vec: Vec::new() } + } +} + +impl FromIterator for Vector { + fn from_iter>(iter: I) -> Self { + Self { + vec: iter.into_iter().collect(), + } + } +} fn bench_operations(c: &mut Criterion) { // Benchmark append operations @@ -18,9 +57,9 @@ fn bench_operations(c: &mut Criterion) { }) .bench_function("vec_append", |b| { b.iter(|| { - let mut vec = Vec::new(); + let mut vec = Vector::new(); for i in 0..10000 { - vec.push(i.to_string()); + vec = vec.push(i.to_string()); } black_box(vec); }) @@ -39,9 +78,9 @@ fn bench_operations(c: &mut Criterion) { }) .bench_function("vec_prepend", |b| { b.iter(|| { - let mut vec = Vec::new(); + let mut vec = Vector::new(); for i in 0..10000 { - vec.insert(0, i.to_string()); + vec = vec.prepend(i.to_string()); } black_box(vec); }) @@ -52,33 +91,23 @@ fn bench_operations(c: &mut Criterion) { .bench_function("chunk_concat", |b| { let chunk1: Chunk<_> = (0..5000).map(|i| i.to_string()).collect(); let chunk2: Chunk<_> = (5000..10000).map(|i| i.to_string()).collect(); - b.iter(|| { - black_box(chunk1.clone().concat(chunk2.clone())); - }) + b.iter(|| black_box(chunk1.clone().concat(chunk2.clone()))) }) .bench_function("vec_concat", |b| { - let vec1: Vec<_> = (0..5000).map(|i| i.to_string()).collect(); - let vec2: Vec<_> = (5000..10000).map(|i| i.to_string()).collect(); - b.iter(|| { - let mut result = vec1.clone(); - result.extend(vec2.iter().cloned()); - black_box(result) - }) + let vec1: Vector<_> = (0..5000).map(|i| i.to_string()).collect(); + let vec2: Vector<_> = (5000..10000).map(|i| i.to_string()).collect(); + b.iter(|| black_box(vec1.clone().concat(vec2.clone()))) }); // Benchmark clone operations c.benchmark_group("clone") .bench_function("chunk_clone", |b| { let chunk: Chunk<_> = (0..10000).collect(); - b.iter(|| { - black_box(chunk.clone()); - }) + b.iter(|| black_box(chunk.clone())) }) .bench_function("vec_clone", |b| { - let vec: Vec<_> = (0..10000).collect(); - b.iter(|| { - black_box(vec.clone()); - }) + let vec: Vector<_> = (0..10000).collect(); + b.iter(|| black_box(vec.clone())) }); // Benchmark from_iter operation @@ -86,7 +115,7 @@ fn bench_operations(c: &mut Criterion) { .bench_function("Chunk", |b| { b.iter(|| Chunk::from_iter((0..N).into_iter())); }) - .bench_function("Vec", |b| b.iter(|| Vec::from_iter((0..N).into_iter()))); + .bench_function("Vec", |b| b.iter(|| Vector::from_iter((0..N).into_iter()))); } criterion_group!(benches, bench_operations);