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