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 -- --signed`.
// Do not edit manually.
// -----------------------------------------------------------------------------

use crate::{
    I128COSetBuilder,
    i128::tests::test_support::{interval_pair, iv},
};

#[test]
fn seal_empty_builder_returns_empty_set() {
    let set = I128COSetBuilder::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 = I128COSetBuilder::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 = I128COSetBuilder::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 = I128COSetBuilder::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 = I128COSetBuilder::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 = I128COSetBuilder::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 = I128COSetBuilder::new();

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

    let set = b.seal();

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

#[test]
fn concurrent_writes_are_collected_before_seal() {
    let b = I128COSetBuilder::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)]);
}

#[test]
fn seal_orders_negative_zero_and_positive_intervals() {
    let b = I128COSetBuilder::new();

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

    let set = b.seal();

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

use int_interval::I128CO;
use proptest::prelude::*;

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

    let mut out: Vec<I128CO> = 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 = I128COSetBuilder::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 = I128COSetBuilder::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())
        );
    }
}