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