1 //! Implements a map from integer indices to data.
2 //! Rather than storing data for every index, internally, this maps entire ranges to the data.
3 //! To this end, the APIs all work on ranges, not on individual integers. Ranges are split as
4 //! necessary (e.g., when [0,5) is first associated with X, and then [1,2) is mutated).
5 //! Users must not depend on whether a range is coalesced or not, even though this is observable
6 //! via the iteration APIs.
10 use rustc_target::abi::Size;
12 #[derive(Clone, Debug)]
14 /// The range covered by this element; never empty.
15 range: ops::Range<u64>,
16 /// The data stored for this element.
19 #[derive(Clone, Debug)]
20 pub struct RangeMap<T> {
25 /// Creates a new `RangeMap` for the given size, and with the given initial value used for
28 pub fn new(size: Size, init: T) -> RangeMap<T> {
29 let size = size.bytes();
30 let mut map = RangeMap { v: Vec::new() };
32 map.v.push(Elem { range: 0..size, data: init });
37 /// Finds the index containing the given offset.
38 fn find_offset(&self, offset: u64) -> usize {
39 // We do a binary search.
40 let mut left = 0usize; // inclusive
41 let mut right = self.v.len(); // exclusive
43 debug_assert!(left < right, "find_offset: offset {} is out-of-bounds", offset);
44 let candidate = left.checked_add(right).unwrap() / 2;
45 let elem = &self.v[candidate];
46 if offset < elem.range.start {
47 // We are too far right (offset is further left).
48 debug_assert!(candidate < right); // we are making progress
50 } else if offset >= elem.range.end {
51 // We are too far left (offset is further right).
52 debug_assert!(candidate >= left); // we are making progress
61 /// Provides read-only iteration over everything in the given range. This does
62 /// *not* split items if they overlap with the edges. Do not use this to mutate
63 /// through interior mutability.
65 /// The iterator also provides the offset of the given element.
66 pub fn iter<'a>(&'a self, offset: Size, len: Size) -> impl Iterator<Item = (Size, &'a T)> + 'a {
67 let offset = offset.bytes();
68 let len = len.bytes();
69 // Compute a slice starting with the elements we care about.
70 let slice: &[Elem<T>] = if len == 0 {
71 // We just need any empty iterator. We don't even want to
72 // yield the element that surrounds this position.
75 let first_idx = self.find_offset(offset);
78 // The first offset that is not included any more.
79 let end = offset + len;
80 slice.iter().take_while(move |elem| elem.range.start < end).map(|elem| (Size::from_bytes(elem.range.start), &elem.data))
83 pub fn iter_mut_all<'a>(&'a mut self) -> impl Iterator<Item = &'a mut T> + 'a {
84 self.v.iter_mut().map(|elem| &mut elem.data)
87 // Splits the element situated at the given `index`, such that the 2nd one starts at offset
88 // `split_offset`. Do nothing if the element already starts there.
89 // Returns whether a split was necessary.
90 fn split_index(&mut self, index: usize, split_offset: u64) -> bool
94 let elem = &mut self.v[index];
95 if split_offset == elem.range.start || split_offset == elem.range.end {
100 elem.range.contains(&split_offset),
101 "the `split_offset` is not in the element to be split"
104 // Now we really have to split. Reduce length of first element.
105 let second_range = split_offset..elem.range.end;
106 elem.range.end = split_offset;
107 // Copy the data, and insert second element.
108 let second = Elem { range: second_range, data: elem.data.clone() };
109 self.v.insert(index + 1, second);
113 /// Provides mutable iteration over everything in the given range. As a side-effect,
114 /// this will split entries in the map that are only partially hit by the given range,
115 /// to make sure that when they are mutated, the effect is constrained to the given range.
116 /// Moreover, this will opportunistically merge neighbouring equal blocks.
118 /// The iterator also provides the offset of the given element.
123 ) -> impl Iterator<Item = (Size, &'a mut T)> + 'a
125 T: Clone + PartialEq,
127 let offset = offset.bytes();
128 let len = len.bytes();
129 // Compute a slice containing exactly the elements we care about
130 let slice: &mut [Elem<T>] = if len == 0 {
131 // We just need any empty iterator. We don't even want to
132 // yield the element that surrounds this position, nor do
136 // Make sure we got a clear beginning
137 let mut first_idx = self.find_offset(offset);
138 if self.split_index(first_idx, offset) {
139 // The newly created 2nd element is ours
143 let first_idx = first_idx;
144 // Find our end. Linear scan, but that's ok because the iteration
145 // is doing the same linear scan anyway -- no increase in complexity.
146 // We combine this scan with a scan for duplicates that we can merge, to reduce
147 // the number of elements.
148 // We stop searching after the first "block" of size 1, to avoid spending excessive
149 // amounts of time on the merging.
150 let mut equal_since_idx = first_idx;
151 // Once we see too many non-mergeable blocks, we stop.
152 // The initial value is chosen via... magic. Benchmarking and magic.
153 let mut successful_merge_count = 3usize;
154 // When the loop is done, this is the first excluded element.
155 let mut end_idx = first_idx;
157 // Compute if `end` is the last element we need to look at.
158 let done = self.v[end_idx].range.end >= offset + len;
159 // We definitely need to include `end`, so move the index.
162 done || end_idx < self.v.len(),
163 "iter_mut: end-offset {} is out-of-bounds",
166 // see if we want to merge everything in `equal_since..end` (exclusive at the end!)
167 if successful_merge_count > 0 {
168 if done || self.v[end_idx].data != self.v[equal_since_idx].data {
169 // Everything in `equal_since..end` was equal. Make them just one element covering
171 let removed_elems = end_idx - equal_since_idx - 1; // number of elements that we would remove
172 if removed_elems > 0 {
173 // Adjust the range of the first element to cover all of them.
174 let equal_until = self.v[end_idx - 1].range.end; // end of range of last of the equal elements
175 self.v[equal_since_idx].range.end = equal_until;
176 // Delete the rest of them.
177 self.v.splice(equal_since_idx + 1..end_idx, std::iter::empty());
178 // Adjust `end_idx` because we made the list shorter.
179 end_idx -= removed_elems;
180 // Adjust the count for the cutoff.
181 successful_merge_count += removed_elems;
183 // Adjust the count for the cutoff.
184 successful_merge_count -= 1;
186 // Go on scanning for the next block starting here.
187 equal_since_idx = end_idx;
190 // Leave loop if this is the last element.
195 // Move to last included instead of first excluded index.
196 let end_idx = end_idx - 1;
197 // We need to split the end as well. Even if this performs a
198 // split, we don't have to adjust our index as we only care about
199 // the first part of the split.
200 self.split_index(end_idx, offset + len);
201 // Now we yield the slice. `end` is inclusive.
202 &mut self.v[first_idx..=end_idx]
204 slice.iter_mut().map(|elem| (Size::from_bytes(elem.range.start), &mut elem.data))
212 /// Query the map at every offset in the range and collect the results.
213 fn to_vec<T: Copy>(map: &RangeMap<T>, offset: u64, len: u64) -> Vec<T> {
214 (offset..offset + len)
216 .map(|i| map.iter(Size::from_bytes(i), Size::from_bytes(1)).next().map(|(_, &t)| t).unwrap())
222 let mut map = RangeMap::<i32>::new(Size::from_bytes(20), -1);
224 for (_, x) in map.iter_mut(Size::from_bytes(10), Size::from_bytes(1)) {
228 assert_eq!(to_vec(&map, 10, 1), vec![42]);
229 assert_eq!(map.v.len(), 3);
231 // Insert with size 0.
232 for (_, x) in map.iter_mut(Size::from_bytes(10), Size::from_bytes(0)) {
235 for (_, x) in map.iter_mut(Size::from_bytes(11), Size::from_bytes(0)) {
238 assert_eq!(to_vec(&map, 10, 2), vec![42, -1]);
239 assert_eq!(map.v.len(), 3);
244 let mut map = RangeMap::<i32>::new(Size::from_bytes(20), -1);
245 for (_, x) in map.iter_mut(Size::from_bytes(11), Size::from_bytes(1)) {
248 for (_, x) in map.iter_mut(Size::from_bytes(15), Size::from_bytes(1)) {
251 assert_eq!(map.v.len(), 5);
252 assert_eq!(to_vec(&map, 10, 10), vec![-1, 42, -1, -1, -1, 43, -1, -1, -1, -1]);
254 for (_, x) in map.iter_mut(Size::from_bytes(10), Size::from_bytes(10)) {
259 assert_eq!(map.v.len(), 6);
260 assert_eq!(to_vec(&map, 10, 10), vec![23, 42, 23, 23, 23, 43, 23, 23, 23, 23]);
261 assert_eq!(to_vec(&map, 13, 5), vec![23, 23, 43, 23, 23]);
263 for (_, x) in map.iter_mut(Size::from_bytes(15), Size::from_bytes(5)) {
266 assert_eq!(map.v.len(), 6);
267 assert_eq!(to_vec(&map, 10, 10), vec![23, 42, 23, 23, 23, 19, 19, 19, 19, 19]);
268 // Should be seeing two blocks with 19.
270 map.iter(Size::from_bytes(15), Size::from_bytes(2)).map(|(_, &t)| t).collect::<Vec<_>>(),
274 // A NOP `iter_mut` should trigger merging.
275 for _ in map.iter_mut(Size::from_bytes(15), Size::from_bytes(5)) {}
276 assert_eq!(map.v.len(), 5);
277 assert_eq!(to_vec(&map, 10, 10), vec![23, 42, 23, 23, 23, 19, 19, 19, 19, 19]);