int-interval-set 0.2.0

Integer half-open interval set structures built on top of int-interval.
Documentation
// -----------------------------------------------------------------------------
// This file is generated by `cargo run -p codegen -- --unsigned`.
// Do not edit manually.
// -----------------------------------------------------------------------------

use crate::{
    U128COSetBuilder,
    u128::tests::test_support::{interval_pair, iv},
};

#[test]
fn seal_empty_builder_returns_empty_set() {
    let set = U128COSetBuilder::new().seal();

    assert!(set.is_empty());
    assert_eq!(set.interval_count(), 0);
    assert_eq!(set.as_slice(), &[]);
}

#[test]
fn seal_keeps_disjoint_intervals_sorted() {
    let b = U128COSetBuilder::new();

    b.insert(iv(40, 50));
    b.insert(iv(0, 10));
    b.insert(iv(20, 30));

    let set = b.seal();

    assert_eq!(set.as_slice(), &[iv(0, 10), iv(20, 30), iv(40, 50)]);
}

#[test]
fn seal_merges_adjacent_intervals() {
    let b = U128COSetBuilder::new();

    b.insert(iv(10, 20));
    b.insert(iv(0, 5));
    b.insert(iv(5, 10));
    b.insert(iv(20, 25));

    let set = b.seal();

    assert_eq!(set.as_slice(), &[iv(0, 25)]);
}

#[test]
fn seal_merges_overlapping_intervals() {
    let b = U128COSetBuilder::new();

    b.insert(iv(10, 20));
    b.insert(iv(15, 30));
    b.insert(iv(25, 40));

    let set = b.seal();

    assert_eq!(set.as_slice(), &[iv(10, 40)]);
}

#[test]
fn seal_merges_mixed_adjacent_and_overlapping_intervals() {
    let b = U128COSetBuilder::new();

    b.insert(iv(10, 20));
    b.insert(iv(0, 5));
    b.insert(iv(5, 10));
    b.insert(iv(18, 31));
    b.insert(iv(30, 40));

    let set = b.seal();

    assert_eq!(set.as_slice(), &[iv(0, 40)]);
}

#[test]
fn duplicate_intervals_are_deduplicated_by_set_semantics() {
    let b = U128COSetBuilder::new();

    b.insert(iv(1, 4));
    b.insert(iv(1, 4));
    b.insert(iv(1, 4));

    let set = b.seal();

    assert_eq!(set.as_slice(), &[iv(1, 4)]);
}

#[test]
fn seal_handles_domain_endpoints() {
    let b = U128COSetBuilder::new();

    b.insert(iv(u128::MIN, u128::MIN + 1));
    b.insert(iv(2, 3));
    b.insert(iv(u128::MAX - 1, u128::MAX));

    let set = b.seal();

    assert_eq!(
        set.as_slice(),
        &[iv(u128::MIN, u128::MIN + 1), iv(2, 3), iv(u128::MAX - 1, u128::MAX)]
    );
}

#[test]
fn concurrent_writes_are_collected_before_seal() {
    let b = U128COSetBuilder::new();

    std::thread::scope(|s| {
        let b0 = &b;
        s.spawn(move || {
            b0.insert(iv(0, 4));
            b0.insert(iv(20, 25));
        });

        let b1 = &b;
        s.spawn(move || {
            b1.insert(iv(4, 8));
            b1.insert(iv(25, 30));
        });

        let b2 = &b;
        s.spawn(move || {
            b2.insert(iv(8, 10));
            b2.insert(iv(30, 31));
        });
    });

    let set = b.seal();

    assert_eq!(set.as_slice(), &[iv(0, 10), iv(20, 31)]);
}

use int_interval::U128CO;
use proptest::prelude::*;

fn reference_normalize(mut xs: Vec<(u128, u128)>) -> Vec<U128CO> {
    xs.sort_unstable();

    let mut out: Vec<int_interval::U128CO> = Vec::new();

    for (start, end_excl) in xs {
        let iv = iv(start, end_excl);

        match out.last_mut() {
            Some(last) if last.is_contiguous_with(iv) => {
                *last = last.convex_hull(iv);
            }
            _ => out.push(iv),
        }
    }

    out
}

proptest! {
    #[test]
    fn prop_seal_matches_reference_normalize(
        xs in prop::collection::vec(interval_pair(), 0..64)
    ) {
        let b = U128COSetBuilder::new();

        for &(start, end_excl) in &xs {
            b.insert(iv(start, end_excl));
        }

        let set = b.seal();
        let expected = reference_normalize(xs);

        prop_assert_eq!(set.as_slice(), expected.as_slice());
    }

    #[test]
    fn prop_seal_output_is_canonical(
        xs in prop::collection::vec(interval_pair(), 0..64)
    ) {
        let b = U128COSetBuilder::new();

        for (start, end_excl) in xs {
            b.insert(iv(start, end_excl));
        }

        let set = b.seal();

        prop_assert!(
            set.as_slice()
                .windows(2)
                .all(|w| w[0].end_excl() < w[1].start())
        );
    }
}