• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
5 use std::cmp;
6 use std::ops::RangeInclusive;
7 
8 use serde::Deserialize;
9 use 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)]
18 pub struct AddressRange {
19     pub start: u64,
20     pub end: u64,
21 }
22 
23 impl AddressRange {
24     /// Creates a new `AddressRange` from `start` and `end` (inclusive) addresses.
from_start_and_end(start: u64, end: u64) -> Self25     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`.
from_start_and_size(start: u64, size: u64) -> Option<Self>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.
empty() -> Self43     pub const fn empty() -> Self {
44         AddressRange { start: 1, end: 0 }
45     }
46 
47     /// Returns `true` if this range is empty (contains no addresses).
is_empty(&self) -> bool48     pub fn is_empty(&self) -> bool {
49         self.end < self.start
50     }
51 
52     /// Returns `true` if this range contains `address`.
contains(&self, address: u64) -> bool53     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.
contains_range(&self, other: AddressRange) -> bool60     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.
overlaps(&self, other: AddressRange) -> bool65     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.
intersect(&self, other: AddressRange) -> AddressRange72     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.
non_overlapping_ranges(&self, other: AddressRange) -> (AddressRange, AddressRange)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.
split_at(&self, split_start: u64) -> (AddressRange, AddressRange)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`).
len(&self) -> Option<u64>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 
log(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result155     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 
164 impl std::fmt::Display for AddressRange {
fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result165     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
166         self.log(f)
167     }
168 }
169 
170 impl std::fmt::Debug for AddressRange {
fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result171     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
172         self.log(f)
173     }
174 }
175 
176 impl From<RangeInclusive<u64>> for AddressRange {
from(range: RangeInclusive<u64>) -> AddressRange177     fn from(range: RangeInclusive<u64>) -> AddressRange {
178         AddressRange {
179             start: *range.start(),
180             end: *range.end(),
181         }
182     }
183 }
184 
185 impl From<AddressRange> for RangeInclusive<u64> {
from(address_range: AddressRange) -> 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.
193 impl cmp::Ord for AddressRange {
cmp(&self, other: &Self) -> cmp::Ordering194     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 
211 impl cmp::PartialOrd for AddressRange {
partial_cmp(&self, other: &Self) -> Option<cmp::Ordering>212     fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
213         Some(cmp::Ord::cmp(self, other))
214     }
215 }
216 
217 impl cmp::PartialEq for AddressRange {
eq(&self, other: &Self) -> bool218     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.
224 impl cmp::Eq for AddressRange {}
225 
226 #[cfg(test)]
227 mod tests {
228     use super::*;
229 
230     #[test]
is_empty()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]
contains()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]
contains_range()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 
test_intersect(a: (u64, u64), b: (u64, u64), answer: (u64, u64))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]
intersect()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 
test_intersect_empty(a: (u64, u64), b: (u64, u64))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]
intersect_empty()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]
non_overlapping_ranges()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]
split_at()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]
from_start_and_size_valid()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]
from_start_and_size_invalid()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]
display()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]
cmp()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]
cmp_empty()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 }
598