Ranges are finite numerical intervals, e.g. “all integers i
such that (m <= i)
and (i < n)
”. The high end bound is sometimes exclusive, (i < n)
, and sometimes inclusive, (i <= n)
.
In Wuffs syntax, similar to Rust syntax, the exclusive range is m .. n
and the inclusive range is m ..= n
. The conventional mathematical syntax is [m, n)
or [m, n[
for exclusive and [m, n]
for inclusive, but Wuffs is a programming language, and programming language tools prefer brackets to always be balanced.
In Wuffs' C form, the exclusive range is wuffs_base__range_ie_T
and the inclusive range is wuffs_base__range_ii_T
. The ie
means inclusive on the low end, exclusive on the high end. The T
is a numerical type like u32
or u64
.
Both of the ii
and ie
flavors are useful in practice: ii
or m ..= n
is more convenient when computing interval arithmetic, ie
or m .. n
is more convenient when working with slices. The ei
and ee
flavors also exist in theory, but aren't widely used. In Wuffs, the low end is always inclusive.
The ie
(half-open) flavor is recommended by Dijkstra's “Why numbering should start at zero” and see also a further discussion of half-open intervals.
For example, with ie
, the number of elements in “uint32_t
values in the half-open interval m .. n
” is equal to max(0, n - m)
. Furthermore, that number of elements (in one dimension, a length, in two dimensions, a width or height) is itself representable as a uint32_t
without overflow, again for uint32_t
values m
and n
. In the contrasting ii
flavor, the size of the closed interval 0 ..= ((1<<32) - 1)
is 1<<32
, which cannot be represented as a uint32_t
.
In Wuffs' C form, because of this potential overflow, the ie
flavor has length / width / height methods, but the ii
flavor does not.
The ii
(closed) flavor is useful when refining e.g. “the set of all uint32_t
values” to a contiguous subset: “uint32_t
values in the closed interval m ..= n
”, for uint32_t
values m
and n
. An unrefined type (in other words, the set of all uint32_t
values) is not representable in the ie
flavor because if n
equals ((1<<32) - 1)
then (n + 1)
will overflow.
It is valid for m >= n
(for the ie
case) or for m > n
(for the ii
case), in which case the range is empty. There are multiple valid representations of an empty range: (m=1, n=0)
and (m=99, n=77)
are equivalent.
Rects are just the 2-dimensional form of (1-dimensional) ranges. For example, wuffs_base__rect_ii_u32
is a rectangle on the integer grid, containing all points (x, y)
such that (min_incl_x <= x)
and (x <= max_incl_x)
, and likewise for y
.
Once again, it is valid for min > max
, and there are multiple valid representations of an empty rectangle.
When rects are used in graphics, the X and Y axes increase right and down.