ddbug_parser/
range.rs

1use std::mem;
2
3/// An address range.
4#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
5pub struct Range {
6    /// The beginning of the address range (inclusive).
7    pub begin: u64,
8
9    /// The end of the address range (exclusive).
10    pub end: u64,
11}
12
13impl Range {
14    /// A range that covers everything.
15    pub fn all() -> Self {
16        Range { begin: 0, end: !0 }
17    }
18
19    /// The size of the address range.
20    #[inline]
21    pub fn size(&self) -> u64 {
22        self.end - self.begin
23    }
24
25    /// Return true if the range contains the value.
26    #[inline]
27    pub fn contains(&self, addr: u64) -> bool {
28        self.begin <= addr && addr < self.end
29    }
30}
31
32/// A list of address ranges.
33#[derive(Debug, Default, Clone)]
34pub struct RangeList {
35    ranges: Vec<Range>,
36}
37
38impl RangeList {
39    /// The ranges in the list.
40    #[inline]
41    pub fn list(&self) -> &[Range] {
42        &self.ranges
43    }
44
45    /// The total size of the ranges in the list.
46    pub fn size(&self) -> u64 {
47        let mut size = 0;
48        for range in &self.ranges {
49            size += range.size();
50        }
51        size
52    }
53
54    /// Append a range, combining with previous range if possible.
55    pub fn push(&mut self, range: Range) {
56        if range.end <= range.begin {
57            debug!("invalid range: {:?}", range);
58            return;
59        }
60        if let Some(prev) = self.ranges.last_mut() {
61            // Assume up to 15 bytes of padding if range.begin is aligned.
62            // (This may be a wrong assumption, but does it matter and
63            // how do we do better?)
64            // TODO: make alignment configurable
65            let padding = if range.begin == range.begin & !15 {
66                15
67            } else {
68                0
69            };
70            // Merge ranges if new range begins in or after previous range.
71            // We don't care about merging in opposite order (that'll happen
72            // when sorting).
73            if range.begin >= prev.begin && range.begin <= prev.end + padding {
74                if prev.end < range.end {
75                    prev.end = range.end;
76                }
77                return;
78            }
79        }
80        self.ranges.push(range);
81    }
82
83    /// Sort the ranges by beginning address, and combine ranges where possible.
84    pub fn sort(&mut self) {
85        self.ranges.sort_by(|a, b| a.begin.cmp(&b.begin));
86        // Combine ranges by adding to a new list.
87        let mut ranges = Vec::new();
88        mem::swap(&mut ranges, &mut self.ranges);
89        for range in ranges {
90            self.push(range);
91        }
92    }
93
94    /// Remove a list of ranges from the list.
95    ///
96    /// This handles ranges that only partially overlap with existing ranges.
97    pub fn subtract(&self, other: &Self) -> Self {
98        let mut ranges = RangeList::default();
99        let mut other_ranges = other.ranges.iter();
100        let mut other_range = other_ranges.next();
101        for range in &*self.ranges {
102            let mut range = *range;
103            loop {
104                match other_range {
105                    Some(r) => {
106                        // Is r completely before range?
107                        if r.end <= range.begin {
108                            other_range = other_ranges.next();
109                            continue;
110                        }
111                        // Is r completely after range?
112                        if r.begin >= range.end {
113                            ranges.push(range);
114                            break;
115                        }
116                        // Do we need to keep the head of the range?
117                        if r.begin > range.begin {
118                            ranges.push(Range {
119                                begin: range.begin,
120                                end: r.begin,
121                            });
122                        }
123                        // Do we need to keep the tail of the range?
124                        if r.end < range.end {
125                            range.begin = r.end;
126                            other_range = other_ranges.next();
127                            continue;
128                        }
129                        break;
130                    }
131                    None => {
132                        ranges.push(range);
133                        break;
134                    }
135                }
136            }
137        }
138        ranges.sort();
139        ranges
140    }
141}