1*2c409535SJamey Sharp //! The [`Ranges`] type stores a list of contiguous index ranges that
2*2c409535SJamey Sharp //! span some other list's full length.
3*2c409535SJamey Sharp 
4*2c409535SJamey Sharp use alloc::vec::Vec;
5*2c409535SJamey Sharp use core::ops::Range;
6*2c409535SJamey Sharp 
7*2c409535SJamey Sharp /// A list of contiguous index ranges.
8*2c409535SJamey Sharp #[derive(Default)]
9*2c409535SJamey Sharp pub struct Ranges {
10*2c409535SJamey Sharp     ranges: Vec<u32>,
11*2c409535SJamey Sharp     reverse: bool,
12*2c409535SJamey Sharp }
13*2c409535SJamey Sharp 
14*2c409535SJamey Sharp impl Ranges {
15*2c409535SJamey Sharp     /// Constructs a new, empty, list of ranges with at least the
16*2c409535SJamey Sharp     /// specified capacity.
with_capacity(capacity: usize) -> Self17*2c409535SJamey Sharp     pub fn with_capacity(capacity: usize) -> Self {
18*2c409535SJamey Sharp         let mut new = Ranges::default();
19*2c409535SJamey Sharp         new.reserve(capacity);
20*2c409535SJamey Sharp         new
21*2c409535SJamey Sharp     }
22*2c409535SJamey Sharp 
23*2c409535SJamey Sharp     /// Add a new range which begins at the end of the previous range
24*2c409535SJamey Sharp     /// and ends at the specified offset, exclusive.
push_end(&mut self, end: usize)25*2c409535SJamey Sharp     pub fn push_end(&mut self, end: usize) {
26*2c409535SJamey Sharp         debug_assert!(!self.reverse);
27*2c409535SJamey Sharp         // To keep this implementation simple we explicitly store the
28*2c409535SJamey Sharp         // starting index, which is always 0, so that all ranges are
29*2c409535SJamey Sharp         // represented by adjacent pairs in the list. But we add it
30*2c409535SJamey Sharp         // lazily so that an empty list doesn't have to allocate.
31*2c409535SJamey Sharp         if self.ranges.is_empty() {
32*2c409535SJamey Sharp             self.ranges.push(0);
33*2c409535SJamey Sharp         }
34*2c409535SJamey Sharp         self.ranges.push(u32::try_from(end).unwrap());
35*2c409535SJamey Sharp     }
36*2c409535SJamey Sharp 
37*2c409535SJamey Sharp     /// Number of ranges in this list.
len(&self) -> usize38*2c409535SJamey Sharp     pub fn len(&self) -> usize {
39*2c409535SJamey Sharp         self.ranges.len().saturating_sub(1)
40*2c409535SJamey Sharp     }
41*2c409535SJamey Sharp 
42*2c409535SJamey Sharp     /// Reserves capacity for at least `additional` more ranges to be
43*2c409535SJamey Sharp     /// added to this list.
reserve(&mut self, mut additional: usize)44*2c409535SJamey Sharp     pub fn reserve(&mut self, mut additional: usize) {
45*2c409535SJamey Sharp         if additional > 0 && self.ranges.is_empty() {
46*2c409535SJamey Sharp             additional = additional.saturating_add(1);
47*2c409535SJamey Sharp         }
48*2c409535SJamey Sharp         self.ranges.reserve(additional);
49*2c409535SJamey Sharp     }
50*2c409535SJamey Sharp 
51*2c409535SJamey Sharp     /// Get the range at the specified index.
get(&self, index: usize) -> Range<usize>52*2c409535SJamey Sharp     pub fn get(&self, index: usize) -> Range<usize> {
53*2c409535SJamey Sharp         let len = self.len();
54*2c409535SJamey Sharp         assert!(index < len, "index {index} is too big for length {len}");
55*2c409535SJamey Sharp         let index = self.map_index(index);
56*2c409535SJamey Sharp         self.ranges[index] as usize..self.ranges[index + 1] as usize
57*2c409535SJamey Sharp     }
58*2c409535SJamey Sharp 
59*2c409535SJamey Sharp     /// Visit ranges in unspecified order, paired with the index each
60*2c409535SJamey Sharp     /// range occurs at.
iter( &self, ) -> impl DoubleEndedIterator<Item = (usize, Range<usize>)> + ExactSizeIterator + '_61*2c409535SJamey Sharp     pub fn iter(
62*2c409535SJamey Sharp         &self,
63*2c409535SJamey Sharp     ) -> impl DoubleEndedIterator<Item = (usize, Range<usize>)> + ExactSizeIterator + '_ {
64*2c409535SJamey Sharp         self.ranges
65*2c409535SJamey Sharp             .windows(2)
66*2c409535SJamey Sharp             .enumerate()
67*2c409535SJamey Sharp             .map(|(index, range)| (self.map_index(index), range[0] as usize..range[1] as usize))
68*2c409535SJamey Sharp     }
69*2c409535SJamey Sharp 
70*2c409535SJamey Sharp     /// Reverse this list of ranges, so that the first range is at the
71*2c409535SJamey Sharp     /// last index and the last range is at the first index.
72*2c409535SJamey Sharp     ///
73*2c409535SJamey Sharp     /// ```ignore
74*2c409535SJamey Sharp     /// use cranelift_codegen::ranges::Ranges;
75*2c409535SJamey Sharp     /// let mut ranges = Ranges::default();
76*2c409535SJamey Sharp     /// ranges.push_end(4);
77*2c409535SJamey Sharp     /// ranges.push_end(6);
78*2c409535SJamey Sharp     /// ranges.reverse_index();
79*2c409535SJamey Sharp     /// assert_eq!(ranges.get(0), 4..6);
80*2c409535SJamey Sharp     /// assert_eq!(ranges.get(1), 0..4);
81*2c409535SJamey Sharp     /// ```
reverse_index(&mut self)82*2c409535SJamey Sharp     pub fn reverse_index(&mut self) {
83*2c409535SJamey Sharp         // We can't easily change the order of the endpoints in
84*2c409535SJamey Sharp         // self.ranges: they need to be in ascending order or our
85*2c409535SJamey Sharp         // compressed representation gets complicated. So instead we
86*2c409535SJamey Sharp         // change our interpretation of indexes using map_index below,
87*2c409535SJamey Sharp         // controlled by a simple flag. As a bonus, reversing the list
88*2c409535SJamey Sharp         // is constant-time!
89*2c409535SJamey Sharp         self.reverse = !self.reverse;
90*2c409535SJamey Sharp     }
91*2c409535SJamey Sharp 
map_index(&self, index: usize) -> usize92*2c409535SJamey Sharp     fn map_index(&self, index: usize) -> usize {
93*2c409535SJamey Sharp         if self.reverse {
94*2c409535SJamey Sharp             // These subtractions can't overflow because callers
95*2c409535SJamey Sharp             // enforce that 0 <= index < self.len()
96*2c409535SJamey Sharp             self.len() - 1 - index
97*2c409535SJamey Sharp         } else {
98*2c409535SJamey Sharp             index
99*2c409535SJamey Sharp         }
100*2c409535SJamey Sharp     }
101*2c409535SJamey Sharp 
102*2c409535SJamey Sharp     /// Update these ranges to reflect that the list they refer to has
103*2c409535SJamey Sharp     /// been reversed. Afterwards, the ranges will still be indexed
104*2c409535SJamey Sharp     /// in the same order, but the first range will refer to the
105*2c409535SJamey Sharp     /// same-length range at the end of the target list instead of at
106*2c409535SJamey Sharp     /// the beginning, and subsequent ranges will proceed backwards
107*2c409535SJamey Sharp     /// from there.
108*2c409535SJamey Sharp     ///
109*2c409535SJamey Sharp     /// ```ignore
110*2c409535SJamey Sharp     /// use cranelift_codegen::ranges::Ranges;
111*2c409535SJamey Sharp     /// let mut ranges = Ranges::default();
112*2c409535SJamey Sharp     /// ranges.push_end(4);
113*2c409535SJamey Sharp     /// ranges.push_end(6);
114*2c409535SJamey Sharp     /// ranges.reverse_target(6);
115*2c409535SJamey Sharp     /// assert_eq!(ranges.get(0), 2..6);
116*2c409535SJamey Sharp     /// assert_eq!(ranges.get(1), 0..2);
117*2c409535SJamey Sharp     /// ```
reverse_target(&mut self, target_len: usize)118*2c409535SJamey Sharp     pub fn reverse_target(&mut self, target_len: usize) {
119*2c409535SJamey Sharp         let target_len = u32::try_from(target_len).unwrap();
120*2c409535SJamey Sharp         // The last endpoint added should be the same as the current
121*2c409535SJamey Sharp         // length of the target list.
122*2c409535SJamey Sharp         debug_assert_eq!(target_len, *self.ranges.last().unwrap_or(&0));
123*2c409535SJamey Sharp         for end in self.ranges.iter_mut() {
124*2c409535SJamey Sharp             *end = target_len - *end;
125*2c409535SJamey Sharp         }
126*2c409535SJamey Sharp         // Put the endpoints back in ascending order, but that means
127*2c409535SJamey Sharp         // now our indexes are backwards.
128*2c409535SJamey Sharp         self.ranges.reverse();
129*2c409535SJamey Sharp         self.reverse_index();
130*2c409535SJamey Sharp     }
131*2c409535SJamey Sharp }
132