1use std::fmt;
2use std::ops::RangeFull;
34use crate::Size;
5#[cfg(feature = "nightly")]
6use crate::StableHash;
78/// Inclusive wrap-around range of valid values, that is, if
9/// start > end, it represents `start..=MAX`, followed by `0..=end`.
10///
11/// That is, for an i8 primitive, a range of `254..=2` means following
12/// sequence:
13///
14/// 254 (-2), 255 (-1), 0, 1, 2
15///
16/// This is intended specifically to mirror LLVM’s `!range` metadata semantics.
17#[derive(#[automatically_derived]
impl ::core::clone::Clone for WrappingRange {
#[inline]
fn clone(&self) -> WrappingRange {
let _: ::core::clone::AssertParamIsClone<u128>;
*self
}
}Clone, #[automatically_derived]
impl ::core::marker::Copy for WrappingRange { }Copy, #[automatically_derived]
impl ::core::cmp::PartialEq for WrappingRange {
#[inline]
fn eq(&self, other: &WrappingRange) -> bool {
self.start == other.start && self.end == other.end
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for WrappingRange {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<u128>;
}
}Eq, #[automatically_derived]
impl ::core::hash::Hash for WrappingRange {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
::core::hash::Hash::hash(&self.start, state);
::core::hash::Hash::hash(&self.end, state)
}
}Hash)]
18#[cfg_attr(feature = "nightly", derive(const _: () =
{
impl ::rustc_data_structures::stable_hash::StableHash for
WrappingRange {
#[inline]
fn stable_hash<__Hcx: ::rustc_data_structures::stable_hash::StableHashCtxt>(&self,
__hcx: &mut __Hcx,
__hasher:
&mut ::rustc_data_structures::stable_hash::StableHasher) {
match *self {
WrappingRange { start: ref __binding_0, end: ref __binding_1
} => {
{ __binding_0.stable_hash(__hcx, __hasher); }
{ __binding_1.stable_hash(__hcx, __hasher); }
}
}
}
}
};StableHash))]
19pub struct WrappingRange {
20pub start: u128,
21pub end: u128,
22}
2324impl WrappingRange {
25pub(crate) fn debug_as(&self, size: Size, is_signed: bool) -> impl fmt::Debug {
26let range = *self;
27 fmt::from_fn(move |f| {
28if range == WrappingRange::full(size) {
29// This is intentionally not using `is_full_for` so that we ensure
30 // different values always debug-print differently.
31 // We don't need the full details when it's the canonical full range,
32 // but if one is looking at the debug output it might be that seeing
33 // `u8 is (..=0) | (1..)` instead of `u8 is ..` is the information
34 // you needed because the problem is that despite being *a* full
35 // range it's not *the* canonical one you expected it was.
36f.write_str("..")
37 } else if is_signed {
38let start = size.sign_extend(range.start);
39let end = size.sign_extend(range.end);
40if start > end {
41f.write_fmt(format_args!("(..={0}) | ({1}..)", end, start))write!(f, "(..={}) | ({}..)", end, start)42 } else {
43f.write_fmt(format_args!("{0}..={1}", start, end))write!(f, "{}..={}", start, end)44 }
45 } else {
46f.write_fmt(format_args!("{0:?}", range))write!(f, "{:?}", range)47 }
48 })
49 }
5051pub fn full(size: Size) -> Self {
52Self { start: 0, end: size.unsigned_int_max() }
53 }
5455/// Returns `true` if `v` is contained in the range.
56#[inline(always)]
57pub fn contains(&self, v: u128) -> bool {
58if self.start <= self.end {
59self.start <= v && v <= self.end
60 } else {
61self.start <= v || v <= self.end
62 }
63 }
6465/// Returns `true` if all the values in `other` are contained in this range,
66 /// when the values are considered as having width `size`.
67#[inline(always)]
68pub fn contains_range(&self, other: Self, size: Size) -> bool {
69if self.is_full_for(size) {
70true
71} else {
72let trunc = |x| size.truncate(x);
7374let delta = self.start;
75let max = trunc(self.end.wrapping_sub(delta));
7677let other_start = trunc(other.start.wrapping_sub(delta));
78let other_end = trunc(other.end.wrapping_sub(delta));
7980// Having shifted both input ranges by `delta`, now we only need to check
81 // whether `0..=max` contains `other_start..=other_end`, which can only
82 // happen if the other doesn't wrap since `self` isn't everything.
83(other_start <= other_end) && (other_end <= max)
84 }
85 }
8687/// Returns `self` with replaced `start`
88#[inline(always)]
89pub(crate) fn with_start(mut self, start: u128) -> Self {
90self.start = start;
91self92 }
9394/// Returns `self` with replaced `end`
95#[inline(always)]
96pub(crate) fn with_end(mut self, end: u128) -> Self {
97self.end = end;
98self99 }
100101/// The wrapping distance from `self.start` to `self.end`.
102fn width(&self, size: Size) -> u128 {
103size.truncate(u128::wrapping_sub(self.end, self.start))
104 }
105106/// Returns `true` if `size` completely fills the range.
107 ///
108 /// Note that this is *not* the same as `self == WrappingRange::full(size)`.
109 /// Niche calculations can produce full ranges which are not the canonical one;
110 /// for example `Option<NonZero<u16>>` gets `valid_range: (..=0) | (1..)`.
111#[inline]
112pub fn is_full_for(&self, size: Size) -> bool {
113let max_value = size.unsigned_int_max();
114if true {
if !(self.start <= max_value && self.end <= max_value) {
::core::panicking::panic("assertion failed: self.start <= max_value && self.end <= max_value")
};
};debug_assert!(self.start <= max_value && self.end <= max_value);
115self.start == (self.end.wrapping_add(1) & max_value)
116 }
117118/// Checks whether this range is considered non-wrapping when the values are
119 /// interpreted as *unsigned* numbers of width `size`.
120 ///
121 /// Returns `Ok(true)` if there's no wrap-around, `Ok(false)` if there is,
122 /// and `Err(..)` if the range is full so it depends how you think about it.
123#[inline]
124pub fn no_unsigned_wraparound(&self, size: Size) -> Result<bool, RangeFull> {
125if self.is_full_for(size) { Err(..) } else { Ok(self.start <= self.end) }
126 }
127128/// Checks whether this range is considered non-wrapping when the values are
129 /// interpreted as *signed* numbers of width `size`.
130 ///
131 /// This is heavily dependent on the `size`, as `100..=200` does wrap when
132 /// interpreted as `i8`, but doesn't when interpreted as `i16`.
133 ///
134 /// Returns `Ok(true)` if there's no wrap-around, `Ok(false)` if there is,
135 /// and `Err(..)` if the range is full so it depends how you think about it.
136#[inline]
137pub fn no_signed_wraparound(&self, size: Size) -> Result<bool, RangeFull> {
138if self.is_full_for(size) {
139Err(..)
140 } else {
141let start: i128 = size.sign_extend(self.start);
142let end: i128 = size.sign_extend(self.end);
143Ok(start <= end)
144 }
145 }
146147/// Returns a `WrappingRange` that contains all of the values from the iterator,
148 /// when they're treated as values `size` wide.
149 ///
150 /// # Examples
151 ///
152 ///
153 /// ```
154 /// use rustc_abi::{Size, WrappingRange};
155 ///
156 /// let range = WrappingRange::smallest_range_containing([2, 6, 12, 4], Size::from_bytes(2));
157 /// assert_eq!(range.unwrap(), WrappingRange { start: 2, end: 12 });
158 ///
159 /// let range = WrappingRange::smallest_range_containing(0..=127, Size::from_bytes(1));
160 /// assert_eq!(range.unwrap(), WrappingRange { start: 0, end: 127 });
161 /// let range = WrappingRange::smallest_range_containing([129, 128, 127], Size::from_bytes(1));
162 /// assert_eq!(range.unwrap(), WrappingRange { start: 127, end: 129 });
163 ///
164 /// // The size matters because it changes where the wrapping can happen:
165 /// let range = WrappingRange::smallest_range_containing([1, 254], Size::from_bytes(1));
166 /// assert_eq!(range.unwrap(), WrappingRange { start: 254, end: 1 });
167 /// let range = WrappingRange::smallest_range_containing([1, 254], Size::from_bytes(4));
168 /// assert_eq!(range.unwrap(), WrappingRange { start: 1, end: 254 });
169 ///
170 /// // Both `100..=228` and `..=228 | 100..` are the same size, but we pick the one without zero.
171 /// let range = WrappingRange::smallest_range_containing([100, 228], Size::from_bytes(1));
172 /// assert_eq!(range.unwrap(), WrappingRange { start: 100, end: 228 });
173 /// // These 4 values are evenly spaced so all 4 candidate ranges have length 193:
174 /// // `(..=32) | (96..)`, `(..=96) | (160..)`, `(..=160) | (224..)`, and `32..=224`.
175 /// // We pick the last one as the only one that doesn't contain zero.
176 /// let range = WrappingRange::smallest_range_containing([0xA0, 0xE0, 0x20, 0x60], Size::from_bytes(1));
177 /// assert_eq!(range.unwrap(), WrappingRange { start: 0x20, end: 0xE0 });
178 /// ```
179pub fn smallest_range_containing(
180 values: impl IntoIterator<Item = u128>,
181 size: Size,
182 ) -> Option<Self> {
183let mut values: Vec<_> = values.into_iter().collect();
184let umax = size.unsigned_int_max();
185for value in &values {
186if true {
if !(*value <= umax) {
{
::core::panicking::panic_fmt(format_args!("Value {0:?} is too big for {1:?}",
value, size));
}
};
};debug_assert!(*value <= umax, "Value {value:?} is too big for {size:?}");
187 }
188values.sort_unstable();
189190// Having sorted all the values, every element is a possible start point for the
191 // range of values, up to the previous element (wrapping around the end of the vec).
192 // Look at all those candidates and pick the one that's as narrow as possible.
193let pairs = std::iter::zip(values.iter().copied(), values.iter().copied().cycle().skip(1));
194let ranges = pairs.map(|(end, start)| WrappingRange { start, end });
195let smallest_range = ranges.min_by_key(|r| (r.width(size), r.start));
196smallest_range197 }
198}
199200impl fmt::Debugfor WrappingRange {
201fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
202if self.start > self.end {
203fmt.write_fmt(format_args!("(..={0}) | ({1}..)", self.end, self.start))write!(fmt, "(..={}) | ({}..)", self.end, self.start)?;
204 } else {
205fmt.write_fmt(format_args!("{0}..={1}", self.start, self.end))write!(fmt, "{}..={}", self.start, self.end)?;
206 }
207Ok(())
208 }
209}