resources/
address_range.rs

1// Copyright 2022 The ChromiumOS Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use std::cmp;
6use std::ops::RangeInclusive;
7
8use serde::Deserialize;
9use serde::Serialize;
10
11/// Represents a range of addresses from `start` to `end`, inclusive.
12///
13/// Why not use the standard `RangeInclusive`? `RangeInclusive` is not `Copy`, because it tries to
14/// be an iterator as well as a range (which also means it is larger than necessary). Additionally,
15/// we would also like to implement some convenience functions for our own type.
16#[derive(Copy, Clone, Deserialize, Serialize)]
17#[serde(deny_unknown_fields)]
18pub struct AddressRange {
19    pub start: u64,
20    pub end: u64,
21}
22
23impl AddressRange {
24    /// Creates a new `AddressRange` from `start` and `end` (inclusive) addresses.
25    pub const fn from_start_and_end(start: u64, end: u64) -> Self {
26        AddressRange { start, end }
27    }
28
29    /// Creates a new `AddressRange` from `start` extending `size` bytes.
30    ///
31    /// Returns `None` if the generated range is not representable as an `AddressRange`.
32    pub const fn from_start_and_size(start: u64, size: u64) -> Option<Self> {
33        if size == 0 {
34            Some(AddressRange::empty())
35        } else if let Some(end) = start.checked_add(size - 1) {
36            Some(AddressRange { start, end })
37        } else {
38            None
39        }
40    }
41
42    /// Returns an empty range.
43    pub const fn empty() -> Self {
44        AddressRange { start: 1, end: 0 }
45    }
46
47    /// Returns `true` if this range is empty (contains no addresses).
48    pub fn is_empty(&self) -> bool {
49        self.end < self.start
50    }
51
52    /// Returns `true` if this range contains `address`.
53    pub fn contains(&self, address: u64) -> bool {
54        address >= self.start && address <= self.end
55    }
56
57    /// Returns `true` if `other` is fully contained within this range.
58    ///
59    /// Empty ranges are considered to be not contained by any range.
60    pub fn contains_range(&self, other: AddressRange) -> bool {
61        !other.is_empty() && other.start >= self.start && other.end <= self.end
62    }
63
64    /// Returns `true` if the two ranges have any addresses in common.
65    pub fn overlaps(&self, other: AddressRange) -> bool {
66        !self.intersect(other).is_empty()
67    }
68
69    /// Find the intersection (overlapping region) of two ranges.
70    ///
71    /// If there is no intersection, the resulting `AddressRange` will be empty.
72    pub fn intersect(&self, other: AddressRange) -> AddressRange {
73        let start = cmp::max(self.start, other.start);
74        let end = cmp::min(self.end, other.end);
75        AddressRange { start, end }
76    }
77
78    /// Returns the ranges of addresses contained in `self` but not in `other`.
79    ///
80    /// If `other` is empty, returns `(*self, Self::empty())`.
81    ///
82    /// The first returned range will contain the addresses in `self` that are less than the start
83    /// of `other`, which will be empty if the starts of the ranges coincide.
84    ///
85    /// The second returned range will contain the addresses in `self` that are greater than the end
86    /// of `other`, which will be empty if the ends of the ranges coincide.
87    pub fn non_overlapping_ranges(&self, other: AddressRange) -> (AddressRange, AddressRange) {
88        if other.is_empty() {
89            return (*self, Self::empty());
90        }
91
92        let before = if self.start >= other.start {
93            Self::empty()
94        } else {
95            let start = cmp::min(self.start, other.start);
96
97            // We know that self.start != other.start, so the maximum of the two cannot be 0, so it
98            // is safe to subtract 1.
99            let end = cmp::max(self.start, other.start) - 1;
100
101            // For non-overlapping ranges, don't allow end to extend past self.end.
102            let end = cmp::min(end, self.end);
103
104            AddressRange { start, end }
105        };
106
107        let after = if self.end <= other.end {
108            Self::empty()
109        } else {
110            // We know that self.end != other.end, so the minimum of the two cannot be `u64::MAX`,
111            // so it is safe to add 1.
112            let start = cmp::min(self.end, other.end) + 1;
113
114            // For non-overlapping ranges, don't allow start to extend before self.start.
115            let start = cmp::max(start, self.start);
116
117            let end = cmp::max(self.end, other.end);
118
119            AddressRange { start, end }
120        };
121
122        (before, after)
123    }
124
125    /// Returns the two subsets of this range split at the `split_start` address.
126    ///
127    /// If `split_start` is not contained in this range, returns the original range and an empty
128    /// range.
129    pub fn split_at(&self, split_start: u64) -> (AddressRange, AddressRange) {
130        // split_start == self.start is handled as a special case so we know that split_start - 1 is
131        // safe below (and so the empty range is always returned second if present).
132        if split_start <= self.start || split_start > self.end {
133            (*self, Self::empty())
134        } else {
135            (
136                AddressRange {
137                    start: self.start,
138                    end: split_start - 1,
139                },
140                AddressRange {
141                    start: split_start,
142                    end: self.end,
143                },
144            )
145        }
146    }
147
148    /// Computes the length of an `AddressRange`.
149    ///
150    /// Returns `None` if the length cannot be represented in `u64` (if the range is
151    /// `0..=u64::MAX`).
152    pub fn len(&self) -> Option<u64> {
153        // Treat any range we consider "empty" (end < start) as having 0 length.
154        if self.is_empty() {
155            Some(0)
156        } else {
157            (self.end - self.start).checked_add(1)
158        }
159    }
160
161    fn log(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
162        if self.is_empty() {
163            f.write_str("empty")
164        } else {
165            f.write_fmt(format_args!("{:#x}..={:#x}", self.start, self.end))
166        }
167    }
168}
169
170impl std::fmt::Display for AddressRange {
171    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
172        self.log(f)
173    }
174}
175
176impl std::fmt::Debug for AddressRange {
177    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
178        self.log(f)
179    }
180}
181
182impl From<RangeInclusive<u64>> for AddressRange {
183    fn from(range: RangeInclusive<u64>) -> AddressRange {
184        AddressRange {
185            start: *range.start(),
186            end: *range.end(),
187        }
188    }
189}
190
191impl From<AddressRange> for RangeInclusive<u64> {
192    fn from(address_range: AddressRange) -> RangeInclusive<u64> {
193        address_range.start..=address_range.end
194    }
195}
196
197/// Custom comparison function that provides a total order over all possible `AddressRange` values
198/// and considers all empty ranges to be equal.
199impl cmp::Ord for AddressRange {
200    fn cmp(&self, other: &Self) -> cmp::Ordering {
201        match (self.is_empty(), other.is_empty()) {
202            // Any empty range is equal to any other empty range.
203            (true, true) => cmp::Ordering::Equal,
204            // An empty range is less than any non-empty range.
205            (true, false) => cmp::Ordering::Less,
206            // Any non-empty range is greater than an empty range.
207            (false, true) => cmp::Ordering::Greater,
208            // Two non-empty ranges are ordered based on `start`, and if those are equal, `end`.
209            (false, false) => self
210                .start
211                .cmp(&other.start)
212                .then_with(|| self.end.cmp(&other.end)),
213        }
214    }
215}
216
217impl cmp::PartialOrd for AddressRange {
218    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
219        Some(cmp::Ord::cmp(self, other))
220    }
221}
222
223impl cmp::PartialEq for AddressRange {
224    fn eq(&self, other: &Self) -> bool {
225        cmp::Ord::cmp(self, other) == cmp::Ordering::Equal
226    }
227}
228
229// The `PartialEq` implementation is reflexive, symmetric, and transitive.
230impl cmp::Eq for AddressRange {}
231
232#[cfg(test)]
233mod tests {
234    use super::*;
235
236    #[test]
237    fn is_empty() {
238        assert!(AddressRange { start: 1, end: 0 }.is_empty());
239        assert!(AddressRange {
240            start: u64::MAX,
241            end: 0
242        }
243        .is_empty());
244        assert!(AddressRange {
245            start: u64::MAX,
246            end: u64::MAX - 1
247        }
248        .is_empty());
249        assert!(AddressRange::empty().is_empty());
250
251        assert!(!AddressRange { start: 0, end: 1 }.is_empty());
252        assert!(!AddressRange { start: 1, end: 1 }.is_empty());
253    }
254
255    #[test]
256    fn contains() {
257        assert!(AddressRange { start: 0, end: 5 }.contains(3));
258        assert!(AddressRange { start: 0, end: 0 }.contains(0));
259        assert!(AddressRange {
260            start: 0,
261            end: u64::MAX
262        }
263        .contains(u64::MAX));
264
265        // Empty ranges do not contain any addresses
266        assert!(!AddressRange { start: 5, end: 0 }.contains(3));
267    }
268
269    #[test]
270    fn contains_range() {
271        assert!(AddressRange { start: 0, end: 5 }.contains_range(AddressRange { start: 0, end: 5 }));
272        assert!(AddressRange { start: 0, end: 5 }.contains_range(AddressRange { start: 1, end: 3 }));
273
274        // Partly overlapping ranges
275        assert!(
276            !AddressRange { start: 0, end: 5 }.contains_range(AddressRange { start: 3, end: 9 })
277        );
278        assert!(
279            !AddressRange { start: 3, end: 9 }.contains_range(AddressRange { start: 0, end: 5 })
280        );
281
282        // Completely discontiguous ranges
283        assert!(
284            !AddressRange { start: 0, end: 5 }.contains_range(AddressRange { start: 6, end: 9 })
285        );
286        assert!(
287            !AddressRange { start: 6, end: 9 }.contains_range(AddressRange { start: 0, end: 5 })
288        );
289
290        // Empty ranges do not contain anything
291        assert!(
292            !AddressRange { start: 5, end: 0 }.contains_range(AddressRange { start: 0, end: 5 })
293        );
294        assert!(
295            !AddressRange { start: 5, end: 0 }.contains_range(AddressRange { start: 5, end: 0 })
296        );
297        assert!(
298            !AddressRange { start: 5, end: 0 }.contains_range(AddressRange { start: 1, end: 3 })
299        );
300
301        // An empty range is not contained by anything
302        assert!(
303            !AddressRange { start: 0, end: 5 }.contains_range(AddressRange { start: 3, end: 1 })
304        );
305    }
306
307    fn test_intersect(a: (u64, u64), b: (u64, u64), answer: (u64, u64)) {
308        let a = AddressRange {
309            start: a.0,
310            end: a.1,
311        };
312        let b = AddressRange {
313            start: b.0,
314            end: b.1,
315        };
316        let answer = AddressRange {
317            start: answer.0,
318            end: answer.1,
319        };
320
321        // intersect() should be commutative, so try it both ways
322        assert_eq!(a.intersect(b), answer);
323        assert_eq!(b.intersect(a), answer);
324    }
325
326    #[test]
327    fn intersect() {
328        test_intersect((0, 5), (0, 5), (0, 5));
329        test_intersect((0, 5), (0, 3), (0, 3));
330        test_intersect((0, 5), (3, 5), (3, 5));
331        test_intersect((0, 5), (5, 5), (5, 5));
332        test_intersect((0, 5), (4, 9), (4, 5));
333        test_intersect((0, u64::MAX), (3, 5), (3, 5));
334        test_intersect((10, 20), (5, 15), (10, 15));
335    }
336
337    fn test_intersect_empty(a: (u64, u64), b: (u64, u64)) {
338        let a = AddressRange {
339            start: a.0,
340            end: a.1,
341        };
342        let b = AddressRange {
343            start: b.0,
344            end: b.1,
345        };
346        assert!(a.intersect(b).is_empty());
347        assert!(b.intersect(a).is_empty());
348    }
349
350    #[test]
351    fn intersect_empty() {
352        test_intersect_empty((0, 5), (10, 20));
353        test_intersect_empty((5, 0), (3, 4));
354        test_intersect_empty((10, 20), (20, 10));
355        test_intersect_empty((10, 20), (30, 40));
356    }
357
358    #[test]
359    fn non_overlapping_ranges() {
360        // Two identical ranges have no non-overlapping ranges.
361        assert_eq!(
362            AddressRange { start: 0, end: 100 }
363                .non_overlapping_ranges(AddressRange { start: 0, end: 100 }),
364            (AddressRange::empty(), AddressRange::empty())
365        );
366
367        // Non-overlapping regions on both sides.
368        assert_eq!(
369            AddressRange { start: 0, end: 100 }
370                .non_overlapping_ranges(AddressRange { start: 10, end: 20 }),
371            (
372                AddressRange { start: 0, end: 9 },
373                AddressRange {
374                    start: 21,
375                    end: 100
376                }
377            )
378        );
379
380        // Non-overlapping region on the left but not on the right.
381        assert_eq!(
382            AddressRange { start: 0, end: 100 }.non_overlapping_ranges(AddressRange {
383                start: 10,
384                end: 100
385            }),
386            (AddressRange { start: 0, end: 9 }, AddressRange::empty())
387        );
388
389        // Non-overlapping region on the right but not on the left.
390        assert_eq!(
391            AddressRange { start: 0, end: 100 }
392                .non_overlapping_ranges(AddressRange { start: 0, end: 50 }),
393            (
394                AddressRange::empty(),
395                AddressRange {
396                    start: 51,
397                    end: 100
398                }
399            )
400        );
401
402        // Other range not contained within this range and greater than this range.
403        assert_eq!(
404            AddressRange { start: 0, end: 100 }.non_overlapping_ranges(AddressRange {
405                start: 200,
406                end: 300
407            }),
408            (AddressRange { start: 0, end: 100 }, AddressRange::empty())
409        );
410
411        // Other range not contained within this range and less than this range.
412        assert_eq!(
413            AddressRange {
414                start: 200,
415                end: 300
416            }
417            .non_overlapping_ranges(AddressRange { start: 0, end: 100 }),
418            (
419                AddressRange::empty(),
420                AddressRange {
421                    start: 200,
422                    end: 300
423                }
424            )
425        );
426
427        // Partially overlapping region with non-overlapping region on the left.
428        assert_eq!(
429            AddressRange { start: 10, end: 20 }
430                .non_overlapping_ranges(AddressRange { start: 15, end: 35 }),
431            (AddressRange { start: 10, end: 14 }, AddressRange::empty())
432        );
433
434        // Partially overlapping region with non-overlapping region on the right.
435        assert_eq!(
436            AddressRange { start: 10, end: 20 }
437                .non_overlapping_ranges(AddressRange { start: 5, end: 15 }),
438            (AddressRange::empty(), AddressRange { start: 16, end: 20 })
439        );
440
441        // Subtracting an empty range returns the original range and an empty range.
442        assert_eq!(
443            AddressRange { start: 0, end: 9 }.non_overlapping_ranges(AddressRange::empty()),
444            (AddressRange { start: 0, end: 9 }, AddressRange::empty())
445        );
446        assert_eq!(
447            AddressRange { start: 0, end: 9 }
448                .non_overlapping_ranges(AddressRange { start: 7, end: 3 }),
449            (AddressRange { start: 0, end: 9 }, AddressRange::empty())
450        );
451    }
452
453    #[test]
454    fn split_at() {
455        assert_eq!(
456            AddressRange { start: 10, end: 20 }.split_at(15),
457            (
458                AddressRange { start: 10, end: 14 },
459                AddressRange { start: 15, end: 20 }
460            )
461        );
462        assert_eq!(
463            AddressRange { start: 10, end: 20 }.split_at(20),
464            (
465                AddressRange { start: 10, end: 19 },
466                AddressRange { start: 20, end: 20 }
467            )
468        );
469        assert_eq!(
470            AddressRange { start: 10, end: 20 }.split_at(10),
471            (AddressRange { start: 10, end: 20 }, AddressRange::empty())
472        );
473        assert_eq!(
474            AddressRange { start: 10, end: 20 }.split_at(21),
475            (AddressRange { start: 10, end: 20 }, AddressRange::empty())
476        );
477        assert_eq!(
478            AddressRange { start: 10, end: 20 }.split_at(9),
479            (AddressRange { start: 10, end: 20 }, AddressRange::empty())
480        );
481    }
482
483    #[test]
484    fn from_start_and_size_valid() {
485        assert_eq!(
486            AddressRange::from_start_and_size(0x100, 0x20),
487            Some(AddressRange {
488                start: 0x100,
489                end: 0x11f
490            })
491        );
492
493        // Max-sized range based at 0
494        assert_eq!(
495            AddressRange::from_start_and_size(0, u64::MAX),
496            Some(AddressRange {
497                start: 0,
498                end: u64::MAX - 1
499            })
500        );
501
502        // Max-sized range based at 1
503        assert_eq!(
504            AddressRange::from_start_and_size(1, u64::MAX),
505            Some(AddressRange {
506                start: 1,
507                end: u64::MAX
508            })
509        );
510
511        // One-byte range based at u64::MAX
512        assert_eq!(
513            AddressRange::from_start_and_size(u64::MAX, 1),
514            Some(AddressRange {
515                start: u64::MAX,
516                end: u64::MAX
517            })
518        );
519
520        // Empty range (size = 0) with arbitrary start
521        assert!(AddressRange::from_start_and_size(u64::MAX, 0)
522            .unwrap()
523            .is_empty());
524    }
525
526    #[test]
527    fn from_start_and_size_invalid() {
528        // 2 + u64::MAX - 1 overflows
529        assert_eq!(AddressRange::from_start_and_size(2, u64::MAX), None);
530
531        // 0x100 + u64::MAX - 1 overflows
532        assert_eq!(AddressRange::from_start_and_size(0x100, u64::MAX), None);
533
534        // 0x100 + (u64::MAX - 0xfe) - 1 overflows
535        assert_eq!(
536            AddressRange::from_start_and_size(0x100, u64::MAX - 0xfe),
537            None
538        );
539    }
540
541    #[test]
542    fn display() {
543        assert_eq!(
544            format!(
545                "{}",
546                AddressRange {
547                    start: 0x1234,
548                    end: 0x5678
549                }
550            ),
551            "0x1234..=0x5678"
552        );
553        assert_eq!(format!("{}", AddressRange::empty()), "empty");
554    }
555
556    #[test]
557    fn cmp() {
558        assert!(
559            AddressRange {
560                start: 0x1000,
561                end: 0x2000
562            } < AddressRange {
563                start: 0x3000,
564                end: 0x4000
565            }
566        );
567        assert!(
568            AddressRange {
569                start: 0x1000,
570                end: 0x2000
571            } == AddressRange {
572                start: 0x1000,
573                end: 0x2000
574            }
575        );
576        assert!(
577            AddressRange {
578                start: 0x3000,
579                end: 0x4000
580            } > AddressRange {
581                start: 0x1000,
582                end: 0x2000
583            }
584        );
585        assert!(
586            AddressRange {
587                start: 0x1000,
588                end: 0x2000
589            } < AddressRange {
590                start: 0x1000,
591                end: 0x3000
592            }
593        );
594    }
595
596    #[test]
597    fn cmp_empty() {
598        // Empty ranges are less than any non-empty range and equal to any other empty range.
599        assert!(
600            AddressRange {
601                start: 0x1000,
602                end: 0x2000
603            } > AddressRange::empty()
604        );
605        assert!(
606            AddressRange::empty()
607                < AddressRange {
608                    start: 0x1000,
609                    end: 0x2000
610                }
611        );
612        assert!(AddressRange { start: 5, end: 3 } == AddressRange { start: 10, end: 1 });
613    }
614}