Path: blob/main/cranelift/codegen/src/ranges.rs
1693 views
//! The [`Ranges`] type stores a list of contiguous index ranges that1//! span some other list's full length.23use alloc::vec::Vec;4use core::ops::Range;56/// A list of contiguous index ranges.7#[derive(Default)]8pub struct Ranges {9ranges: Vec<u32>,10reverse: bool,11}1213impl Ranges {14/// Constructs a new, empty, list of ranges with at least the15/// specified capacity.16pub fn with_capacity(capacity: usize) -> Self {17let mut new = Ranges::default();18new.reserve(capacity);19new20}2122/// Add a new range which begins at the end of the previous range23/// and ends at the specified offset, exclusive.24pub fn push_end(&mut self, end: usize) {25debug_assert!(!self.reverse);26// To keep this implementation simple we explicitly store the27// starting index, which is always 0, so that all ranges are28// represented by adjacent pairs in the list. But we add it29// lazily so that an empty list doesn't have to allocate.30if self.ranges.is_empty() {31self.ranges.push(0);32}33self.ranges.push(u32::try_from(end).unwrap());34}3536/// Number of ranges in this list.37pub fn len(&self) -> usize {38self.ranges.len().saturating_sub(1)39}4041/// Reserves capacity for at least `additional` more ranges to be42/// added to this list.43pub fn reserve(&mut self, mut additional: usize) {44if additional > 0 && self.ranges.is_empty() {45additional = additional.saturating_add(1);46}47self.ranges.reserve(additional);48}4950/// Get the range at the specified index.51pub fn get(&self, index: usize) -> Range<usize> {52let len = self.len();53assert!(index < len, "index {index} is too big for length {len}");54let index = self.map_index(index);55self.ranges[index] as usize..self.ranges[index + 1] as usize56}5758/// Visit ranges in unspecified order, paired with the index each59/// range occurs at.60pub fn iter(61&self,62) -> impl DoubleEndedIterator<Item = (usize, Range<usize>)> + ExactSizeIterator + '_ {63self.ranges64.windows(2)65.enumerate()66.map(|(index, range)| (self.map_index(index), range[0] as usize..range[1] as usize))67}6869/// Reverse this list of ranges, so that the first range is at the70/// last index and the last range is at the first index.71///72/// ```ignore73/// use cranelift_codegen::ranges::Ranges;74/// let mut ranges = Ranges::default();75/// ranges.push_end(4);76/// ranges.push_end(6);77/// ranges.reverse_index();78/// assert_eq!(ranges.get(0), 4..6);79/// assert_eq!(ranges.get(1), 0..4);80/// ```81pub fn reverse_index(&mut self) {82// We can't easily change the order of the endpoints in83// self.ranges: they need to be in ascending order or our84// compressed representation gets complicated. So instead we85// change our interpretation of indexes using map_index below,86// controlled by a simple flag. As a bonus, reversing the list87// is constant-time!88self.reverse = !self.reverse;89}9091fn map_index(&self, index: usize) -> usize {92if self.reverse {93// These subtractions can't overflow because callers94// enforce that 0 <= index < self.len()95self.len() - 1 - index96} else {97index98}99}100101/// Update these ranges to reflect that the list they refer to has102/// been reversed. Afterwards, the ranges will still be indexed103/// in the same order, but the first range will refer to the104/// same-length range at the end of the target list instead of at105/// the beginning, and subsequent ranges will proceed backwards106/// from there.107///108/// ```ignore109/// use cranelift_codegen::ranges::Ranges;110/// let mut ranges = Ranges::default();111/// ranges.push_end(4);112/// ranges.push_end(6);113/// ranges.reverse_target(6);114/// assert_eq!(ranges.get(0), 2..6);115/// assert_eq!(ranges.get(1), 0..2);116/// ```117pub fn reverse_target(&mut self, target_len: usize) {118let target_len = u32::try_from(target_len).unwrap();119// The last endpoint added should be the same as the current120// length of the target list.121debug_assert_eq!(target_len, *self.ranges.last().unwrap_or(&0));122for end in self.ranges.iter_mut() {123*end = target_len - *end;124}125// Put the endpoints back in ascending order, but that means126// now our indexes are backwards.127self.ranges.reverse();128self.reverse_index();129}130}131132133