Skip to main content

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}