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