Discrete integer intervals
DiscreteInterval<T> is the discrete counterpart to
Interval<T>. Where Interval<T> models a continuum of
coordinates, DiscreteInterval<T> (constrained to IBinaryInteger<T> -
int, long, BigInteger, …) models the set of representable integers
between its bounds. That difference changes two behaviours that matter for
integer ranges such as indices, pages, or IDs.
Emptiness reflects representable membership
A continuous open interval over two consecutive integers is non-empty - it holds all the reals between them - but it contains no integer. The discrete type reports that correctly:
Interval<int>.Open(1, 2).IsEmpty; // False - continuous range (1, 2)
DiscreteInterval<int>.Open(1, 2).IsEmpty; // True - no integer strictly between 1 and 2
Every shape is canonicalized to inclusive [First, Last] integer bounds at
construction (an open bound shifts inward by one), so equal integer sets share
one representation and the default value is the empty set:
DiscreteInterval<int>.Open(1, 5) == DiscreteInterval<int>.Closed(2, 4); // True
DiscreteInterval<int>.Closed(1, 10).Count; // 10
Adjacency is by successor
Two integer intervals with no integer between them are adjacent and union to a single run, even though their endpoints are not equal:
var a = DiscreteInterval<int>.Closed(1, 2);
var b = DiscreteInterval<int>.Closed(3, 4);
a.TryUnion(b, out var run); // run = [1, 4], result = true - 2 and 3 are successors
DiscreteInterval<int>.Closed(1, 2)
.TryUnion(DiscreteInterval<int>.Closed(4, 5), out _); // false - 3 is missing
The surface
DiscreteInterval<T> offers First / Last / IsBounded / IsEmpty /
Count (which throws InvalidOperationException for an unbounded interval,
and OverflowException when the member count does not fit in T - a
full-domain interval has one more member than the type can represent),
Contains, Overlaps,
Intersect, TryUnion, Difference, and SymmetricDifference (the last two
returning a DiscreteIntervalPair<T> of up to two runs); the
Closed / Open / ClosedOpen / OpenClosed / Singleton / Empty
factories and the unbounded All / AtLeast / GreaterThan / AtMost /
LessThan family (with type-inferring DiscreteInterval.* helpers); equality;
and ToInterval() / FromInterval(...) conversions to and from the continuous
type. Formatting mirrors Interval<T>: the type implements
IFormattable, ISpanFormattable, and IUtf8SpanFormattable, delegating to
the equivalent continuous interval's canonical closed form.
DiscreteInterval<int>.Closed(0, 10).Difference(DiscreteInterval<int>.Closed(3, 5)); // [0, 2] ∪ [6, 10]
For an arbitrary union of ranges over the continuous domain, see
IntervalSet<T>.
See also
- Interval algebra - the continuous
Interval<T>set surface. DiscreteInterval<T>API reference and theDiscreteIntervalhelpers.