rangemap/std_ext.rs
1use core::ops::{Add, Range, RangeInclusive, Sub};
2
3pub trait RangeExt<T> {
4 fn overlaps(&self, other: &Self) -> bool;
5 fn touches(&self, other: &Self) -> bool;
6}
7
8impl<T> RangeExt<T> for Range<T>
9where
10 T: Ord,
11{
12 fn overlaps(&self, other: &Self) -> bool {
13 use core::cmp::{max, min};
14 // Strictly less than, because ends are excluded.
15 max(&self.start, &other.start) < min(&self.end, &other.end)
16 }
17
18 fn touches(&self, other: &Self) -> bool {
19 use core::cmp::{max, min};
20 // Less-than-or-equal-to because if one end is excluded, the other is included.
21 // I.e. the two could be joined into a single range, because they're overlapping
22 // or immediately adjacent.
23 max(&self.start, &other.start) <= min(&self.end, &other.end)
24 }
25}
26
27pub trait RangeInclusiveExt<T> {
28 fn overlaps(&self, other: &Self) -> bool;
29 fn touches<StepFnsT>(&self, other: &Self) -> bool
30 where
31 StepFnsT: StepFns<T>;
32}
33
34impl<T> RangeInclusiveExt<T> for RangeInclusive<T>
35where
36 T: Ord + Clone,
37{
38 fn overlaps(&self, other: &Self) -> bool {
39 use core::cmp::{max, min};
40 // Less than or equal, because ends are included.
41 max(self.start(), other.start()) <= min(self.end(), other.end())
42 }
43
44 fn touches<StepFnsT>(&self, other: &Self) -> bool
45 where
46 StepFnsT: StepFns<T>,
47 {
48 use core::cmp::{max, min};
49
50 // Touching for end-inclusive ranges is equivalent to touching of
51 // slightly longer end-inclusive ranges.
52 //
53 // We need to do a small dance to avoid arithmetic overflow
54 // at the extremes of the key space. And to do this without
55 // needing to bound our key type on something like `num::Bounded`
56 // (https://docs.rs/num/0.3.0/num/trait.Bounded.html),
57 // we'll just extend the end of the _earlier_ range iff
58 // its end is already earlier than the latter range's start.
59 let max_start = max(self.start(), other.start());
60 let min_range_end = min(self.end(), other.end());
61 let min_range_end_extended = if min_range_end < max_start {
62 StepFnsT::add_one(min_range_end)
63 } else {
64 min_range_end.clone()
65 };
66 *max_start <= min_range_end_extended
67 }
68}
69
70/// Minimal version of unstable [`Step`](core::iter::Step) trait
71/// from the Rust standard library.
72///
73/// This is needed for [`RangeInclusiveMap`](crate::RangeInclusiveMap)
74/// because ranges stored as its keys interact with each other
75/// when the start of one is _adjacent_ the end of another.
76/// I.e. we need a concept of successor values rather than just
77/// equality, and that is what `Step` will
78/// eventually provide once it is stabilized.
79///
80/// **NOTE:** This will likely be deprecated and then eventually
81/// removed once the standard library's `Step`
82/// trait is stabilised, as most crates will then likely implement `Step`
83/// for their types where appropriate.
84///
85/// See [this issue](https://github.com/rust-lang/rust/issues/42168)
86/// for details about that stabilization process.
87pub trait StepLite {
88 /// Returns the _successor_ of `self`.
89 ///
90 /// If this would overflow the range of values supported by `Self`,
91 /// this function is allowed to panic, wrap, or saturate.
92 /// The suggested behavior is to panic when debug assertions are enabled,
93 /// and to wrap or saturate otherwise.
94 fn add_one(&self) -> Self;
95
96 /// Returns the _predecessor_ of `self`.
97 ///
98 /// If this would overflow the range of values supported by `Self`,
99 /// this function is allowed to panic, wrap, or saturate.
100 /// The suggested behavior is to panic when debug assertions are enabled,
101 /// and to wrap or saturate otherwise.
102 fn sub_one(&self) -> Self;
103}
104
105// Implement for all common integer types.
106macro_rules! impl_step_lite {
107 ($($t:ty)*) => ($(
108 impl StepLite for $t {
109 #[inline]
110 fn add_one(&self) -> Self {
111 Add::add(*self, 1)
112 }
113
114 #[inline]
115 fn sub_one(&self) -> Self {
116 Sub::sub(*self, 1)
117 }
118 }
119 )*)
120}
121
122impl_step_lite!(usize u8 u16 u32 u64 u128 i8 i16 i32 i64 i128);
123
124// The successor of a float is the next representable float,
125// i.e. one ULP (unit in the last place) away.
126//
127// We can't use the standard library's `next_up` and `next_down` for this
128// because they were only stabilised in Rust 1.86, well beyond our MSRV,
129// so we reimplement them here. These mirror the standard library's versions
130// exactly, including their treatment of zeroes (`-0.0` and `0.0` share the
131// same neighbours, which agrees with how `NotNan` orders them) and their
132// saturation at the infinities. `StepLite` explicitly allows saturating
133// at the ends of the range.
134//
135// We don't need the standard library's NaN check, because `NotNan` has
136// already ruled that out for us.
137//
138// TODO: Delete all of this the next time we raise our MSRV past 1.86,
139// and call `next_up`/`next_down` directly instead.
140#[cfg(feature = "ordered-float5")]
141macro_rules! impl_step_lite_not_nan {
142 ($($t:ty => $bits:ty),* $(,)?) => ($(
143 impl StepLite for ordered_float::NotNan<$t> {
144 #[inline]
145 fn add_one(&self) -> Self {
146 const SIGN_MASK: $bits = 1 << (<$bits>::BITS - 1);
147 // Smallest positive subnormal.
148 const TINY_BITS: $bits = 1;
149
150 let bits = self.into_inner().to_bits();
151 let next_bits = if bits == <$t>::INFINITY.to_bits() {
152 bits
153 } else {
154 let abs = bits & !SIGN_MASK;
155 if abs == 0 {
156 TINY_BITS
157 } else if bits == abs {
158 bits + 1
159 } else {
160 bits - 1
161 }
162 };
163
164 // The successor of a non-NaN float is never NaN.
165 ordered_float::NotNan::new(<$t>::from_bits(next_bits))
166 .expect("successor of a non-NaN float is never NaN")
167 }
168
169 #[inline]
170 fn sub_one(&self) -> Self {
171 const SIGN_MASK: $bits = 1 << (<$bits>::BITS - 1);
172 // Smallest negative subnormal.
173 const NEG_TINY_BITS: $bits = (1 << (<$bits>::BITS - 1)) | 1;
174
175 let bits = self.into_inner().to_bits();
176 let next_bits = if bits == <$t>::NEG_INFINITY.to_bits() {
177 bits
178 } else {
179 let abs = bits & !SIGN_MASK;
180 if abs == 0 {
181 NEG_TINY_BITS
182 } else if bits == abs {
183 bits - 1
184 } else {
185 bits + 1
186 }
187 };
188
189 // The predecessor of a non-NaN float is never NaN.
190 ordered_float::NotNan::new(<$t>::from_bits(next_bits))
191 .expect("predecessor of a non-NaN float is never NaN")
192 }
193 }
194 )*)
195}
196
197#[cfg(feature = "ordered-float5")]
198impl_step_lite_not_nan!(f32 => u32, f64 => u64);
199
200// TODO: When on nightly, a blanket implementation for
201// all types that implement `core::iter::Step` instead
202// of the auto-impl above.
203
204/// Successor and predecessor functions defined for `T`,
205/// but as free functions rather than methods on `T` itself.
206///
207/// This is useful as a workaround for Rust's "orphan rules",
208/// which prevent you from implementing [`StepLite`](crate::StepLite) for `T` if `T`
209/// is a foreign type.
210///
211/// **NOTE:** This will likely be deprecated and then eventually
212/// removed once the standard library's [`Step`](core::iter::Step)
213/// trait is stabilised, as most crates will then likely implement `Step`
214/// for their types where appropriate.
215///
216/// See [this issue](https://github.com/rust-lang/rust/issues/42168)
217/// for details about that stabilization process.
218///
219/// There is also a blanket implementation of `StepFns` for all
220/// types implementing `StepLite`. Consumers of this crate should
221/// prefer to implement `StepLite` for their own types, and only
222/// fall back to `StepFns` when dealing with foreign types.
223pub trait StepFns<T> {
224 /// Returns the _successor_ of value `start`.
225 ///
226 /// If this would overflow the range of values supported by `Self`,
227 /// this function is allowed to panic, wrap, or saturate.
228 /// The suggested behavior is to panic when debug assertions are enabled,
229 /// and to wrap or saturate otherwise.
230 fn add_one(start: &T) -> T;
231
232 /// Returns the _predecessor_ of value `start`.
233 ///
234 /// If this would overflow the range of values supported by `Self`,
235 /// this function is allowed to panic, wrap, or saturate.
236 /// The suggested behavior is to panic when debug assertions are enabled,
237 /// and to wrap or saturate otherwise.
238 fn sub_one(start: &T) -> T;
239}
240
241impl<T> StepFns<T> for T
242where
243 T: StepLite,
244{
245 fn add_one(start: &T) -> T {
246 start.add_one()
247 }
248
249 fn sub_one(start: &T) -> T {
250 start.sub_one()
251 }
252}
253
254#[cfg(all(test, feature = "ordered-float5"))]
255mod tests {
256 use super::*;
257 use alloc as std;
258 use alloc::format;
259 use ordered_float::NotNan;
260 use proptest::prelude::*;
261 use test_strategy::proptest;
262
263 fn not_nan(x: f64) -> NotNan<f64> {
264 NotNan::new(x).unwrap()
265 }
266
267 fn not_nan_32(x: f32) -> NotNan<f32> {
268 NotNan::new(x).unwrap()
269 }
270
271 // We can't check any of these against the standard library's `next_up`
272 // and `next_down`, because those are newer than our MSRV, so spell out
273 // what "one ULP away" means in terms of the underlying bit patterns
274 // instead.
275
276 #[test]
277 fn steps_to_the_next_representable_float() {
278 assert_eq!(
279 not_nan(1.0).add_one(),
280 not_nan(f64::from_bits(1.0f64.to_bits() + 1))
281 );
282 assert_eq!(
283 not_nan(1.0).sub_one(),
284 not_nan(f64::from_bits(1.0f64.to_bits() - 1))
285 );
286
287 // Negative values run the other way through the bit patterns.
288 assert_eq!(
289 not_nan(-1.0).add_one(),
290 not_nan(f64::from_bits((-1.0f64).to_bits() - 1))
291 );
292 assert_eq!(
293 not_nan(-1.0).sub_one(),
294 not_nan(f64::from_bits((-1.0f64).to_bits() + 1))
295 );
296 }
297
298 #[test]
299 fn steps_from_zero_to_the_smallest_subnormals() {
300 let tiny = f64::from_bits(1);
301 assert_eq!(not_nan(0.0).add_one(), not_nan(tiny));
302 assert_eq!(not_nan(0.0).sub_one(), not_nan(-tiny));
303
304 // `NotNan` considers `-0.0` and `0.0` equal, so they have to step
305 // to the same neighbours as each other.
306 assert_eq!(not_nan(-0.0).add_one(), not_nan(tiny));
307 assert_eq!(not_nan(-0.0).sub_one(), not_nan(-tiny));
308 }
309
310 #[test]
311 fn steps_saturate_at_the_infinities() {
312 assert_eq!(not_nan(f64::MAX).add_one(), not_nan(f64::INFINITY));
313 assert_eq!(not_nan(f64::INFINITY).add_one(), not_nan(f64::INFINITY));
314 assert_eq!(not_nan(f64::MIN).sub_one(), not_nan(f64::NEG_INFINITY));
315 assert_eq!(
316 not_nan(f64::NEG_INFINITY).sub_one(),
317 not_nan(f64::NEG_INFINITY)
318 );
319
320 // The infinities still step back inwards, though.
321 assert_eq!(not_nan(f64::INFINITY).sub_one(), not_nan(f64::MAX));
322 assert_eq!(not_nan(f64::NEG_INFINITY).add_one(), not_nan(f64::MIN));
323 }
324
325 #[test]
326 fn f32_steps_the_same_way_as_f64() {
327 assert_eq!(
328 not_nan_32(1.0).add_one(),
329 not_nan_32(f32::from_bits(1.0f32.to_bits() + 1))
330 );
331 assert_eq!(not_nan_32(0.0).add_one(), not_nan_32(f32::from_bits(1)));
332 assert_eq!(not_nan_32(-0.0).add_one(), not_nan_32(f32::from_bits(1)));
333 assert_eq!(not_nan_32(f32::MAX).add_one(), not_nan_32(f32::INFINITY));
334 assert_eq!(
335 not_nan_32(f32::INFINITY).add_one(),
336 not_nan_32(f32::INFINITY)
337 );
338 }
339
340 #[proptest]
341 fn steps_are_reversible(x: NotNan<f64>) {
342 // Not at the infinities, where stepping outwards saturates.
343 prop_assume!(x.into_inner().is_finite());
344 assert_eq!(x.add_one().sub_one(), x);
345 assert_eq!(x.sub_one().add_one(), x);
346 }
347
348 #[proptest]
349 fn steps_move_in_the_right_direction(x: NotNan<f64>) {
350 prop_assume!(x.into_inner().is_finite());
351 assert!(x.add_one() > x);
352 assert!(x.sub_one() < x);
353 }
354}