A modern C++ header-only library implementing Disjoint Interval Sets as a complete Boolean algebra, featuring an elegant STL-aligned API, compile-time interval arithmetic, and mathematical notation parsing.
Working with intervals is fundamental in many domains—from computational geometry to scheduling algorithms. While libraries like Boost.ICL provide interval containers, DIS takes a different approach by treating interval sets as first-class mathematical objects that form a complete Boolean algebra. This leads to:
- Mathematical Elegance: Operations follow Boolean algebra axioms rigorously
- Intuitive API: Express complex set operations naturally with operators
- Zero-Cost Abstractions: Compile-time interval validation with no runtime overhead
- STL Compatibility: Full alignment with C++ Standard Library conventions
- Composability: Features combine seamlessly without surprises
- Production Ready: 97.46% test coverage on core implementation, 94 test cases
Major library redesign focused on STL alignment, API refinement, and testing framework standardization:
- 68 changes implementing full STL container conformance
- 100% backward compatibility through deprecated-but-functional legacy API
- Zero breaking changes to mathematical operators and factory methods
- Testing framework consolidation for improved reliability
- All tests passing with 97.46% core coverage
| Feature | Before | After |
|---|---|---|
| Container Methods | is_empty(), add() |
empty(), insert(), erase() |
| Type Traits | Basic | Full STL typedefs (value_type, iterator, etc.) |
| Comparison | Fixed partial_ordering |
Type-aware ordering (strong for int, partial for double) |
| Range Support | Limited | Full C++20 ranges compatibility |
| Iterator Interface | Forward only | Bidirectional with reverse iterators |
See the full STL alignment report for details.
#include <dis/dis.hpp>
using namespace dis;
// Create intervals with expressive factory methods
auto morning = real_interval::closed(9, 12); // [9, 12]
auto afternoon = real_interval::closed(14, 18); // [14, 18]
// Build sets using fluent interface
auto work_hours = real_set{}
.add(morning)
.add(afternoon);
// Parse from mathematical notation
auto meetings = real_set::from_string("[10,11] ∪ [15,16]");
// Boolean operations with natural syntax
auto free_time = work_hours - meetings; // Set difference
auto conflicts = work_hours & meetings; // Intersection
bool has_conflicts = !conflicts.empty();
// Rich query interface
std::cout << "Free time: " << free_time << '\n';
std::cout << "Total free hours: " << free_time.measure() << '\n';- Features
- Installation
- Usage Examples
- API Reference
- Testing
- Mathematical Foundation
- Performance
- Building and Testing
- Contributing
- License
Full compatibility with C++ Standard Library conventions: empty(), insert(), erase(), clear(), reverse iterators, and proper type traits.
Full support for union, intersection, complement, difference, and symmetric difference with proper algebraic properties.
Parse interval sets from strings using standard mathematical notation: "[0,5) ∪ (10,20] ∪ {25}".
Zero-overhead interval bounds checking at compile-time using template metaprogramming.
Comprehensive set of predicates and queries: gaps, span, density, measure, overlaps, and more.
Support both mathematical operators (|, &, ~) and explicit methods (unite(), intersect(), complement()).
Extensively tested with 90.32% overall coverage and 97.46% coverage on core implementation.
DIS is a header-only library. Simply clone and include:
git clone https://github.com/yourusername/disjoint_interval_set.git// Option 1: Include everything
#include <dis/dis.hpp>
// Option 2: Include only what you need
#include <dis/core/interval.hpp>
#include <dis/core/disjoint_interval_set.hpp>- C++17 or later (uses
std::optional, structured bindings) - C++20 recommended (for ranges and concepts)
- No external dependencies for library usage
- Tested compilers: GCC 9+, Clang 10+, MSVC 2019+
- CMake 3.14+ for build system
- Google Test for running the test suite
- gcovr (optional) for HTML coverage reports:
pip install gcovr
#include <dis/dis.hpp>
using namespace dis;
// Multiple factory methods for clarity
auto closed = real_interval::closed(0, 10); // [0, 10]
auto open = real_interval::open(0, 10); // (0, 10)
auto left_open = real_interval::left_open(0, 10); // (0, 10]
auto right_open = real_interval::right_open(0, 10); // [0, 10)
auto point = real_interval::point(5); // {5}
auto empty = interval<double>{}; // ∅
// Unbounded intervals
auto positive = real_interval::greater_than(0); // (0, ∞)
auto non_negative = real_interval::at_least(0); // [0, ∞)
// Interval operations
auto i1 = real_interval::closed(0, 10);
auto i2 = real_interval::closed(5, 15);
auto intersection = i1 & i2; // [5, 10]
auto hull = i1.hull(i2); // [0, 15]
// Queries
assert(i1.contains(5));
assert(i1.overlaps(i2));
assert(i1.length() == 10);
assert(i1.midpoint() == 5);// Build sets with fluent interface
auto set = real_set{}
.add(0, 10) // Add [0, 10]
.add(20, 30) // Add [20, 30]
.add(25, 35); // Automatically merged to [20, 35]
// STL-compatible insertion
real_set ranges;
ranges.insert(real_interval::closed(0, 5));
ranges.insert(real_interval::closed(10, 15));
// From initializer list
real_set ranges2 = {
real_interval::closed(0, 5),
real_interval::closed(10, 15),
real_interval::closed(12, 20) // Overlaps merged automatically
};
// Set operations with multiple notations
auto a = real_set::from_string("[0,10] ∪ [20,30]");
auto b = real_set::from_string("[5,15] ∪ [25,35]");
auto union_set = a | b; // [0, 15] ∪ [20, 35]
auto intersection = a & b; // [5, 10] ∪ [25, 30]
auto difference = a - b; // [0, 5) ∪ (10, 20) ∪ (30, 35]
auto symmetric = a ^ b; // Symmetric difference
auto complement = ~a; // Complement
// Advanced queries
auto gaps = set.gaps(); // Intervals between components
auto span = set.span(); // Smallest interval containing all
auto density = set.density(); // measure / span.length
auto measure = set.measure(); // Total length covered
// Functional operations
set.for_each([](const auto& interval) {
std::cout << interval << '\n';
});
auto filtered = set.filter([](const auto& i) {
return i.length() > 5;
});// Parse from mathematical notation
auto set = real_set::from_string("[0,5) ∪ (10,20] ∪ {25} ∪ [30,∞)");
// Alternative notation support
auto set2 = real_set::from_string("[0,5) U (10,20] U {25}"); // 'U' for union
auto set3 = real_set::from_string("[0,5), (10,20], {25}"); // Comma separated
// Round-trip formatting
std::string notation = set.to_string();
assert(real_set::from_string(notation) == set);
// Custom formatting
std::cout << set.to_string(format_options::unicode) << '\n'; // Uses ∪, ∩, ∅
std::cout << set.to_string(format_options::ascii) << '\n'; // Uses U, ^, {}#include <dis/static_interval.hpp>
// Define compile-time intervals
template<int Min, int Max>
using valid_range = dis::static_interval<int, Min, Max, false, false>;
// Compile-time validation
using age_range = valid_range<0, 150>;
using percentage_range = valid_range<0, 100>;
static_assert(age_range::contains(25), "25 is a valid age");
static_assert(!age_range::contains(200), "200 is not a valid age");
// Build bounded types with zero runtime overhead
template<int Min, int Max>
class bounded {
using bounds = valid_range<Min, Max>;
int value_;
public:
constexpr bounded(int v) : value_(v) {
if (!bounds::contains(v))
throw std::out_of_range("Value out of bounds");
}
constexpr operator int() const { return value_; }
};
using age = bounded<0, 150>;
using percentage = bounded<0, 100>;real_set set = /* ... */;
// STL algorithms work seamlessly
auto it = std::find_if(set.begin(), set.end(),
[](const auto& i) { return i.length() > 10; });
auto count = std::count_if(set.begin(), set.end(),
[](const auto& i) { return i.contains(50); });
// Reverse iteration
for (auto it = set.rbegin(); it != set.rend(); ++it) {
std::cout << *it << '\n';
}
// C++20 ranges
auto long_intervals = set | std::views::filter(
[](const auto& i) { return i.length() > 100; });
auto lengths = set | std::views::transform(
[](const auto& i) { return i.length(); });Represents a single interval with configurable boundaries.
Key Methods:
empty()- Test if interval is emptycontains(T value)- Test membershipoverlaps(interval other)- Test overlaplength()- Get interval lengthhull(interval other)- Compute convex hullintersect(interval other)- Compute intersection
Factory Methods:
interval::closed(a, b) // [a, b]
interval::open(a, b) // (a, b)
interval::left_open(a, b) // (a, b]
interval::right_open(a, b) // [a, b)
interval::point(x) // {x}
interval::unbounded() // (-∞, ∞)
interval::greater_than(x) // (x, ∞)
interval::at_least(x) // [x, ∞)
interval::less_than(x) // (-∞, x)
interval::at_most(x) // (-∞, x]Maintains a set of non-overlapping intervals with Boolean algebra operations.
STL Container Interface:
empty()- Test if set is emptysize()- Number of disjoint intervalsinsert(interval)- Add interval (merges if needed)erase(iterator)- Remove interval by iteratorerase(interval)- Remove specific intervalclear()- Remove all intervalsswap(other)- Swap contentsbegin(),end()- Forward iteratorsrbegin(),rend()- Reverse iteratorsfront(),back()- Access first/last interval
Set Operations:
unite(other)/operator|- Unionintersect(other)/operator&- Intersectioncomplement()/operator~- Complementdifference(other)/operator-- Set differencesymmetric_difference(other)/operator^- Symmetric difference
Query Operations:
contains(value)- Test value membershipcontains(interval)- Test interval subsetmeasure()- Total length coveredspan()- Smallest containing intervalgaps()- Intervals between componentsdensity()- Measure / span ratio
Type Aliases:
using value_type = typename I::value_type;
using size_type = std::size_t;
using iterator = const_iterator;
using reverse_iterator = std::reverse_iterator<const_iterator>;
// ... and more STL-standard aliasesnamespace dis {
// Common interval types
using real_interval = interval<double>;
using integer_interval = interval<int>;
// Common set types
using real_set = disjoint_interval_set<real_interval>;
using integer_set = disjoint_interval_set<integer_interval>;
}Current test coverage (as of November 2024):
| Component | Coverage | Status |
|---|---|---|
| Core Implementation | 97.46% | Excellent |
disjoint_interval_set.hpp |
97.46% (537/551 lines) | Production-ready |
interval.hpp |
89.53% (479/535 lines) | Well-tested |
| Overall Library | 90.32% | Very good |
parser.hpp |
60.33% | Good |
format.hpp |
24.90% | Basic coverage |
- 94 test cases covering all major functionality
- 500+ assertions ensuring correctness
- ~2,400 lines of test code
Test Categories:
-
Comprehensive Interval Tests (22 test cases)
- Construction, boundaries, containment
- Set operations (intersection, hull)
- Measures (length, midpoint, distance)
- Edge cases (infinity, NaN, extremes)
-
Comprehensive DIS Tests (32 test cases)
- Construction and initialization
- Set operations (union, intersection, etc.)
- Queries (contains, overlaps, gaps)
- Functional operations (filter, map, for_each)
- Performance with 1000+ intervals
-
Elegant API Tests (14 test cases)
- Fluent interface patterns
- Real-world usage scenarios
- Integration tests
-
Parser & Formatter Tests (26 test cases)
- Various interval notations
- Round-trip parsing
- Output formatting styles
First, install Google Test:
# Ubuntu/Debian
sudo apt-get install libgtest-dev cmake
# macOS with Homebrew
brew install googletest
# Or build from source
git clone https://github.com/google/googletest.git
cd googletest
mkdir build && cd build
cmake ..
make
sudo make install# Clone the repository
git clone https://github.com/yourusername/disjoint_interval_set.git
cd disjoint_interval_set
# Build and run tests
mkdir build && cd build
cmake ..
make
ctest --verbose
# Or use the convenience target
make run_tests
# Generate coverage report (requires gcovr: pip install gcovr)
make coverage
# Report opens at: build/coverage/index.htmlSee the full test coverage report for detailed metrics.
The Disjoint Interval Set forms a complete Boolean algebra where:
- Elements: Sets of disjoint intervals
- Join (∨): Union operation (
operator|) - Meet (∧): Intersection operation (
operator&) - Complement (¬): Complement operation (
operator~) - Bottom (⊥): Empty set
- Top (⊤): Universal set
- Associativity:
(A ∪ B) ∪ C = A ∪ (B ∪ C)and(A ∩ B) ∩ C = A ∩ (B ∩ C) - Commutativity:
A ∪ B = B ∪ AandA ∩ B = B ∩ A - Distributivity:
A ∩ (B ∪ C) = (A ∩ B) ∪ (A ∩ C) - Identity:
A ∪ ∅ = AandA ∩ U = A - Complement:
A ∪ ~A = UandA ∩ ~A = ∅ - Idempotence:
A ∪ A = AandA ∩ A = A - Absorption:
A ∪ (A ∩ B) = AandA ∩ (A ∪ B) = A - De Morgan's Laws:
~(A ∪ B) = ~A ∩ ~Band~(A ∩ B) = ~A ∪ ~B
Maintaining disjoint (non-overlapping) intervals provides:
- Canonical Form: Unique representation for each set
- Efficient Operations: O(n + m) for most set operations
- Space Efficiency: No redundant interval storage
- Clear Semantics: Each point belongs to at most one interval
| Operation | Complexity | Notes |
|---|---|---|
insert(interval) |
O(n) | n = number of intervals |
contains(value) |
O(log n) | Binary search |
union (A ∪ B) |
O(n + m) | Linear merge |
intersection (A ∩ B) |
O(n + m) | Linear scan |
complement (~A) |
O(n) | Invert boundaries |
measure() |
O(n) | Sum all lengths |
parse(string) |
O(s) | s = string length |
- Each interval: 2 × sizeof(T) + 2 bits for boundaries
- Set overhead: std::vector overhead + bookkeeping
- No memory allocation for compile-time intervals
- Move Semantics: Full support for efficient transfers
- Small Vector Optimization: For sets with few intervals
- Lazy Evaluation: Operations can be composed without materialization
- Compile-Time Computation: Zero runtime cost for static intervals
| Feature | DIS | Boost.ICL |
|---|---|---|
| Philosophy | Mathematical Boolean algebra | Container-centric |
| API Style | Natural operators (` | , &, ~`) |
| String Parsing | Built-in DSL | Not available |
| Compile-Time | Full support | Limited |
| Dependencies | None | Boost |
| Header-Only | Yes | Yes |
| STL Alignment | Full (v2.0) | Partial |
| Learning Curve | Intuitive | Steeper |
| Feature | DIS | std::set |
|---|---|---|
| Interval Merging | Automatic | Manual |
| Set Operations | O(n + m) | O(n × m) worst case |
| Mathematical Operations | Native | Must implement |
| Memory Usage | Optimized | Higher overhead |
| Type Safety | Interval types | Raw pairs |
# Compile examples
g++ -std=c++17 -I./include examples/elegant_api_demo.cpp -o demo
./demo
# With optimizations
g++ -std=c++20 -O3 -I./include examples/scheduling_demo.cpp -o scheduling
./schedulingBuild the documentation site:
# Install mkdocs if needed
pip install mkdocs mkdocs-material
# Serve locally
mkdocs serve
# Build static site
mkdocs buildVisit the live documentation for comprehensive guides and API reference.
- Computational Geometry: Polygon clipping, CSG operations
- Scheduling Systems: Resource allocation, conflict detection
- Numerical Analysis: Interval arithmetic, error bounds
- Access Control: Time-based permissions, IP range filtering
- Data Visualization: Histogram binning, range queries
- Signal Processing: Frequency band allocation
- Game Development: Collision detection, spatial indexing
- Database Systems: Range partitioning, index optimization
We welcome contributions! Please see our Contributing Guidelines for details.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Write tests for your changes
- Ensure all tests pass with good coverage
- Update documentation as needed
- Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Follow modern C++ best practices
- Use descriptive names
- Document public APIs
- Write comprehensive tests
- Keep commits atomic and well-described
- Write tests for all new features
- Ensure edge cases are covered
- Maintain or improve coverage metrics (aim for 95%+)
- Test compile-time features with
static_assert - Run the full test suite before submitting PRs
- Quick Start Guide
- API Reference
- STL Alignment Report
- Test Coverage Report
- Elegant API Design
- Technical Report
- C++20 concepts for better error messages
- Parallel algorithms for large sets
- Persistent data structures
- Interval tree indexing for very large sets
- Python bindings
- Formal verification of algebraic properties
- Integration with computational geometry libraries
- PMR allocator support (if user demand exists)
- Custom execution policies
- Boost library submission
Note: Multi-dimensional interval support was removed in v1.1.0 to focus the library on 1D interval operations with maximum quality and performance.
This project is licensed under the MIT License - see the LICENSE file for details.
- Inspired by mathematical interval theory and Boolean algebra
- Thanks to the C++ community for feedback and suggestions
- Special thanks to contributors and early adopters
- Boost.ICL for pioneering interval containers in C++
If you use this library in academic work, please cite:
@software{dis2024,
title = {Disjoint Interval Set: A Boolean Algebra for C++},
author = {Your Name},
year = {2024},
url = {https://github.com/yourusername/disjoint_interval_set}
}
Elegant interval arithmetic for modern C++
Documentation •
Issues •
Contributing