1use std::ops::RangeFull;
2use std::{fmt, iter};
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 /// use rustc_abi::{Size, WrappingRange};
154 ///
155 /// let chain = std::iter::chain(10..20, 30..40);
156 /// let range = WrappingRange::smallest_range_containing(chain, Size::from_bytes(2));
157 /// assert_eq!(range.unwrap(), WrappingRange { start: 10, end: 39 });
158 ///
159 /// // Values don't need to be sorted nor unique
160 /// let range = WrappingRange::smallest_range_containing([3, 5, 3, 1, 3], Size::from_bytes(2));
161 /// assert_eq!(range.unwrap(), WrappingRange { start: 1, end: 5 });
162 ///
163 /// // The size matters because it changes where the wrapping can happen:
164 /// let range = WrappingRange::smallest_range_containing([1, 254], Size::from_bytes(1));
165 /// assert_eq!(range.unwrap(), WrappingRange { start: 254, end: 1 });
166 /// let range = WrappingRange::smallest_range_containing([1, 254], Size::from_bytes(4));
167 /// assert_eq!(range.unwrap(), WrappingRange { start: 1, end: 254 });
168 /// ```
169pub fn smallest_range_containing(
170 values: impl IntoIterator<Item = u128>,
171 size: Size,
172 ) -> Option<Self> {
173let mut values: Vec<_> = values.into_iter().collect();
174175let (min, max) = values
176 .iter()
177 .copied()
178 .map(|x| (x, x))
179 .reduce(|a, b| (u128::min(a.0, b.0), u128::max(a.1, b.1)))?;
180181// Just checking the max is enough to ensure that everything is in-range.
182if !(max <= size.unsigned_int_max()) {
{
::core::panicking::panic_fmt(format_args!("Value {0:?} is too big for {1:?}",
max, size));
}
};assert!(max <= size.unsigned_int_max(), "Value {max:?} is too big for {size:?}");
183184// The simple answer is the non-wraparound range `min..=max`.
185let obvious_range = WrappingRange { start: min, end: max };
186187// It's very common that the input was only small non-negative integers and the
188 // obvious range turns out to be the best we can do.
189 // Every possible wraparound range must include at least `(...=min) | (max..)`,
190 // so if what we found already is at least that good, just use it.
191 // WR(min, max).width() ≤ WR(max, min).width()
192 // (max - min) % 2ⁿ ≤ (min - max) % 2ⁿ
193 // max - min ≤ min - max + 2ⁿ
194 // 2×(max - min) ≤ 2ⁿ
195 // max - min ≤ 2ⁿ⁻¹
196let half_range = 1 << (size.bits() - 1);
197if max - min <= half_range {
198return Some(obvious_range);
199 }
200201// But every `[.., end, start, ..]` is also a potential candidate for a wraparound
202 // range `(..=end) | (start..)`, so long as `start` and `end` aren't duplicates.
203values.sort_unstable();
204let wraparound_ranges = values205 .array_windows::<2>()
206 .filter_map(|&[end, start]| (start != end).then_some(WrappingRange { start, end }));
207208// Pick whichever range is smallest. By putting the non-wraparound range first,
209 // it'll be preferred over a wraparound range with the same width.
210iter::chain(iter::once(obvious_range), wraparound_ranges).min_by_key(|r| r.width(size))
211 }
212}
213214impl fmt::Debugfor WrappingRange {
215fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
216if self.start > self.end {
217fmt.write_fmt(format_args!("(..={0}) | ({1}..)", self.end, self.start))write!(fmt, "(..={}) | ({}..)", self.end, self.start)?;
218 } else {
219fmt.write_fmt(format_args!("{0}..={1}", self.start, self.end))write!(fmt, "{}..={}", self.start, self.end)?;
220 }
221Ok(())
222 }
223}