intervalmap 0.1.1

An interval set/map library inspired by Boost.Icl
Documentation
use std::hint::black_box;

use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
use intervalmap::{IntervalMap, IntervalSet};

fn benchmark_interval_set_sequential_insert(c: &mut Criterion) {
    let mut group = c.benchmark_group("IntervalSet/sequential_insert");

    for size in [100, 1000, 10000, 100000].iter() {
        group.bench_with_input(BenchmarkId::from_parameter(size), size, |b, &size| {
            b.iter(|| {
                let mut set = IntervalSet::new();
                for i in 0..size {
                    let start = i * 10;
                    set.insert(start..start + 5);
                }
                black_box(set)
            });
        });
    }

    group.finish();
}

fn benchmark_interval_set_overlapping_insert(c: &mut Criterion) {
    let mut group = c.benchmark_group("IntervalSet/overlapping_insert");

    for size in [100, 1000, 10000].iter() {
        group.bench_with_input(BenchmarkId::from_parameter(size), size, |b, &size| {
            b.iter(|| {
                let mut set = IntervalSet::new();
                for i in 0..size {
                    // Each interval overlaps with the previous
                    let start = i * 5;
                    set.insert(start..start + 10);
                }
                black_box(set)
            });
        });
    }

    group.finish();
}

fn benchmark_interval_set_point_query(c: &mut Criterion) {
    let mut group = c.benchmark_group("IntervalSet/point_query");

    for size in [100, 1000, 10000, 100000].iter() {
        // Pre-populate the set
        let mut set = IntervalSet::new();
        for i in 0..*size {
            let start = i * 10;
            set.insert(start..start + 5);
        }

        group.bench_with_input(BenchmarkId::from_parameter(size), size, |b, &size| {
            b.iter(|| {
                let mut found = 0u32;
                for i in 0..1000 {
                    let point = (i * 7) % (size * 10);
                    if set.contains(point) {
                        found += 1;
                    }
                }
                black_box(found)
            });
        });
    }

    group.finish();
}

fn benchmark_interval_set_remove(c: &mut Criterion) {
    let mut group = c.benchmark_group("IntervalSet/remove");

    for size in [100, 1000, 10000].iter() {
        group.bench_with_input(BenchmarkId::from_parameter(size), size, |b, &size| {
            b.iter_batched(
                || {
                    // Setup: create a fully populated set
                    let mut set = IntervalSet::new();
                    set.insert(0..size * 10);
                    set
                },
                |mut set| {
                    // Remove intervals creating holes
                    for i in 0..size / 10 {
                        let start = i * 100 + 25;
                        set.remove(start..start + 50);
                    }
                    black_box(set)
                },
                criterion::BatchSize::SmallInput,
            );
        });
    }

    group.finish();
}

fn benchmark_interval_set_iteration(c: &mut Criterion) {
    let mut group = c.benchmark_group("IntervalSet/iteration");

    for size in [100, 1000, 10000, 100000].iter() {
        let mut set = IntervalSet::new();
        for i in 0..*size {
            let start = i * 10;
            set.insert(start..start + 5);
        }

        group.bench_with_input(BenchmarkId::from_parameter(size), size, |b, _| {
            b.iter(|| {
                let sum: u32 = set.iter().map(|r| r.start).sum();
                black_box(sum)
            });
        });
    }

    group.finish();
}

fn benchmark_interval_map_insert_with_split(c: &mut Criterion) {
    let mut group = c.benchmark_group("IntervalMap/insert_with_split");

    for size in [100, 1000, 10000].iter() {
        group.bench_with_input(BenchmarkId::from_parameter(size), size, |b, &size| {
            b.iter(|| {
                let mut map = IntervalMap::new();
                // Start with a large interval
                map.insert(0..size * 100, 0);
                // Insert overlapping intervals that cause splits
                for i in 0..size {
                    let start = i * 10;
                    map.insert(start..start + 5, i);
                }
                black_box(map)
            });
        });
    }

    group.finish();
}

fn benchmark_interval_map_point_query(c: &mut Criterion) {
    let mut group = c.benchmark_group("IntervalMap/point_query");

    for size in [100, 1000, 10000, 100000].iter() {
        let mut map: IntervalMap<u32, i32> = IntervalMap::new();
        for i in 0..*size {
            let start = i * 10;
            map.insert(start..start + 5, i as i32);
        }

        group.bench_with_input(BenchmarkId::from_parameter(size), size, |b, &size| {
            b.iter(|| {
                let mut sum = 0i64;
                for i in 0..1000 {
                    let point = (i * 7) % (size * 10);
                    if let Some(&val) = map.get(point) {
                        sum += val as i64;
                    }
                }
                black_box(sum)
            });
        });
    }

    group.finish();
}

fn benchmark_interval_map_merge_same_value(c: &mut Criterion) {
    let mut group = c.benchmark_group("IntervalMap/merge_same_value");

    for size in [100, 1000, 10000].iter() {
        group.bench_with_input(BenchmarkId::from_parameter(size), size, |b, &size| {
            b.iter(|| {
                let mut map = IntervalMap::new();
                // Insert adjacent intervals with same value - should merge
                for i in 0..size {
                    let start = i * 10;
                    map.insert(start..start + 10, "same");
                }
                black_box(map)
            });
        });
    }

    group.finish();
}

criterion_group!(
    benches,
    benchmark_interval_set_sequential_insert,
    benchmark_interval_set_overlapping_insert,
    benchmark_interval_set_point_query,
    benchmark_interval_set_remove,
    benchmark_interval_set_iteration,
    benchmark_interval_map_insert_with_split,
    benchmark_interval_map_point_query,
    benchmark_interval_map_merge_same_value,
);

criterion_main!(benches);