pub struct Range { /* private fields */ }Expand description
What an integer value can be.
A few disjoint intervals over the unsigned reading of the bit pattern, and the bits that are
known, at a width. The two halves are kept consistent with each other by Range::narrow, so
a range that came out of any constructor here has intervals no wider than its bits allow and
bits no vaguer than its intervals prove.
Implementations§
Source§impl Range
impl Range
Sourcepub const fn empty(width: u32) -> Self
pub const fn empty(width: u32) -> Self
Nothing at all, which is the range of a value on a path that is never taken.
Sourcepub const fn full(width: u32) -> Self
pub const fn full(width: u32) -> Self
Every value of this width, which is what is known about a value nothing has said anything about.
Sourcepub fn of(ty: Type) -> Self
pub fn of(ty: Type) -> Self
Everything a value of this type can be.
A type that is not a scalar integer gets the widest full range, because saying nothing about a vector or a pointer is always true and this module is about integers.
Sourcepub fn between(lo: u128, hi: u128, width: u32) -> Self
pub fn between(lo: u128, hi: u128, width: u32) -> Self
Every bit pattern from one bound to the other, inclusive, wrapping if the low bound is above the high one.
The wrapping case is what a signed interval becomes here: [-5, 5] in eight bits is
[0xfb, 0x05], which is the two intervals [0, 5] and [0xfb, 0xff], and taking the
bounds in that order is how a caller says so without having to split it itself.
Sourcepub fn signed_between(lo: i128, hi: i128, width: u32) -> Self
pub fn signed_between(lo: i128, hi: i128, width: u32) -> Self
Every value from one signed bound to the other, inclusive.
The bounds are read as signed numbers of that width and the intervals come out over bit
patterns, so [-5, 5] in eight bits becomes [0, 5] and [0xfb, 0xff] on its own. A
signed interval is always one wrapping interval in the unsigned domain, so nothing is lost
on the way through.
Sourcepub fn other_than(value: u128, width: u32) -> Self
pub fn other_than(value: u128, width: u32) -> Self
Every value except this one.
Range::other_than(0, width) is the non-zero range, which section 10.2 calls the single
most useful range fact in a C compiler.
Sourcepub fn from_pairs(pairs: &[(u128, u128)], width: u32) -> Self
pub fn from_pairs(pairs: &[(u128, u128)], width: u32) -> Self
A range from intervals that need not be sorted, disjoint or in bounds.
This is the way in from an operation that produced a handful of intervals and does not
want to think about their order. Anything beyond PAIRS of them after merging collapses
to the hull of the ones that did not fit, which loses precision and never soundness.
Sourcepub fn narrow(self, bits: Bits) -> Self
pub fn narrow(self, bits: Bits) -> Self
The same intervals with these bits also known.
The two refine each other here and nowhere else, which is what section 10.2 asks for. An interval whose ends the bits rule out is pulled in to the nearest value the bits allow, the bits are then recomputed from what survived, and a range whose halves contradict each other comes back empty.
Sourcepub fn list(self, limit: usize) -> Option<Vec<u128>>
pub fn list(self, limit: usize) -> Option<Vec<u128>>
Every value in it, or None when there are more than that many.
For walking a shift count or a switch selector, where the range is usually a handful of values and enumerating them gives an exact answer that reasoning about the bounds would round off. The limit is what stops that turning into a walk over four billion of them.
Sourcepub const fn is_empty(self) -> bool
pub const fn is_empty(self) -> bool
Whether nothing is in it, which means the value is on a path that is never taken.
Sourcepub fn contains(self, value: u128) -> bool
pub fn contains(self, value: u128) -> bool
Whether this value is in it.
A range is its intervals and its bits together, so this asks both. A value inside one of
the intervals whose bits are wrong is not in the range, which is what makes “somewhere in
[0, 1023] and a multiple of eight” mean the hundred and twenty eight values it says
rather than the thousand and twenty four the interval alone would.
Sourcepub fn unsigned_bounds(self) -> Option<(u128, u128)>
pub fn unsigned_bounds(self) -> Option<(u128, u128)>
The least and greatest, read as unsigned, or None when the range is empty.
Sourcepub fn signed_bounds(self) -> Option<(i128, i128)>
pub fn signed_bounds(self) -> Option<(i128, i128)>
The least and greatest, read as signed at this width, or None when the range is empty.
The intervals are over bit patterns, so the signed answer is not the first and last of them. Everything at or above the sign boundary is negative and sorts below everything under it, so the least signed value is the first pattern at or above the boundary when there is one and the first pattern otherwise. That reordering is the whole of what the unsigned domain costs, and it is eleven lines.
Sourcepub fn nonzero(self) -> bool
pub fn nonzero(self) -> bool
Whether nothing in it is zero.
The fact a null check produces and the fact a division needs, which is why it has a name of its own rather than being spelled out at every call.
Sourcepub fn fits_unsigned(self, bits: u32) -> bool
pub fn fits_unsigned(self, bits: u32) -> bool
Whether every value in it fits in that many bits, read as unsigned.
Sourcepub fn fits_signed(self, bits: u32) -> bool
pub fn fits_signed(self, bits: u32) -> bool
Whether every value in it fits in that many bits, read as signed.
Sourcepub fn union(self, other: Self) -> Self
pub fn union(self, other: Self) -> Self
Everything in either of them.
§Panics
Panics if the two are of different widths, since a value is one width and combining the ranges of two that are not is a question with no answer.