miri/data_structures/
range_object_map.rs1use std::ops::Range;
6
7use rustc_abi::Size;
8use rustc_const_eval::interpret::AllocRange;
9
10#[derive(Clone, Debug)]
11struct Elem<T> {
12 range: AllocRange,
14 data: T,
16}
17
18type Position = usize;
20
21#[derive(Clone, Debug)]
22pub struct RangeObjectMap<T> {
23 v: Vec<Elem<T>>,
24}
25
26#[derive(Clone, Debug, PartialEq)]
27pub enum AccessType {
28 PerfectlyOverlapping(Position),
30 Empty(Position),
32 ImperfectlyOverlapping(Range<Position>),
34}
35
36impl<T> RangeObjectMap<T> {
37 pub fn new() -> Self {
38 Self { v: Vec::new() }
39 }
40
41 fn find_offset(&self, offset: Size) -> Result<Position, Position> {
45 self.v.binary_search_by(|elem| -> std::cmp::Ordering {
46 if offset < elem.range.start {
47 std::cmp::Ordering::Greater
50 } else if offset >= elem.range.end() {
51 std::cmp::Ordering::Less
53 } else {
54 std::cmp::Ordering::Equal
56 }
57 })
58 }
59
60 pub fn access_type(&self, range: AllocRange) -> AccessType {
63 match self.find_offset(range.start) {
64 Ok(pos) => {
65 let elem = &self.v[pos];
67 if elem.range.start == range.start && elem.range.size == range.size {
69 AccessType::PerfectlyOverlapping(pos)
71 } else {
72 let end_pos = match self.find_offset(range.end() - Size::from_bytes(1)) {
74 Ok(inclusive_pos) => inclusive_pos + 1,
76 Err(exclusive_pos) => exclusive_pos,
77 };
78
79 AccessType::ImperfectlyOverlapping(pos..end_pos)
80 }
81 }
82 Err(pos) => {
83 match self.find_offset(range.end() - Size::from_bytes(1)) {
85 Err(end_pos) =>
87 if pos == end_pos {
88 AccessType::Empty(pos)
90 } else {
91 AccessType::ImperfectlyOverlapping(pos..end_pos)
93 },
94 Ok(end_pos) => AccessType::ImperfectlyOverlapping(pos..end_pos + 1),
96 }
97 }
98 }
99 }
100
101 pub fn insert_at_pos(&mut self, pos: Position, range: AllocRange, data: T) {
106 assert!(range.size > Size::ZERO);
107
108 self.v.insert(pos, Elem { range, data });
109
110 if pos > 0 {
113 assert!(self.v[pos - 1].range.end() <= range.start);
114 }
115 if pos < self.v.len() - 1 {
117 assert!(range.end() <= self.v[pos + 1].range.start);
118 }
119 }
120
121 pub fn remove_pos_range(&mut self, pos_range: Range<Position>) {
122 self.v.drain(pos_range);
123 }
124
125 pub fn remove_from_pos(&mut self, pos: Position) -> T {
126 self.v.remove(pos).data
127 }
128
129 pub fn iter(&self) -> impl Iterator<Item = &T> {
130 self.v.iter().map(|e| &e.data)
131 }
132
133 pub fn range(&self, range: AllocRange) -> impl Iterator<Item = &T> {
134 let begin = self.find_offset(range.start).unwrap_or_else(|i| i);
135 self.v[begin..]
136 .iter()
137 .take_while(move |elem| {
138 debug_assert!(elem.range.end() > range.start);
139 elem.range.start < range.end()
141 })
142 .map(|e| &e.data)
143 }
144
145 pub fn remove_range_if(&mut self, range: AllocRange, pred: impl Fn(&T) -> bool) {
146 let mut idx = self.find_offset(range.start).unwrap_or_else(|i| i);
147 loop {
148 let Some(elem) = self.v.get(idx) else { break };
149 if elem.range.start >= range.end() {
151 break;
152 }
153 if pred(&elem.data) {
155 self.v.remove(idx);
156 } else {
158 idx += 1;
160 }
161 }
162 }
163
164 pub fn get_start(&self, offset: Size) -> Option<&T> {
166 let idx = self.find_offset(offset).ok()?;
167 let elem = &self.v[idx];
168 (elem.range.start == offset).then_some(&elem.data)
169 }
170
171 pub fn get_start_mut(&mut self, offset: Size) -> Option<&mut T> {
173 let idx = self.find_offset(offset).ok()?;
174 let elem = &mut self.v[idx];
175 (elem.range.start == offset).then_some(&mut elem.data)
176 }
177
178 pub fn get_pos(&self, pos: Position) -> Option<&T> {
179 self.v.get(pos).map(|e| &e.data)
180 }
181
182 pub fn get_mut_pos(&mut self, pos: Position) -> Option<&mut T> {
183 self.v.get_mut(pos).map(|e| &mut e.data)
184 }
185
186 pub fn is_empty(&self) -> bool {
187 self.v.is_empty()
188 }
189}
190
191#[cfg(test)]
192mod tests {
193 use rustc_const_eval::interpret::alloc_range;
194
195 use super::*;
196
197 #[test]
198 fn empty_map() {
199 let four = Size::from_bytes(4);
201 let map = RangeObjectMap::<()>::new();
202
203 assert_eq!(map.find_offset(Size::from_bytes(3)), Err(0));
205
206 assert_eq!(map.access_type(alloc_range(Size::ZERO, four)), AccessType::Empty(0));
208 }
209
210 #[test]
211 #[should_panic]
212 fn no_overlapping_inserts() {
213 let four = Size::from_bytes(4);
214
215 let mut map = RangeObjectMap::<&str>::new();
216
217 map.insert_at_pos(0, alloc_range(four, four), "#");
220 map.insert_at_pos(0, alloc_range(Size::from_bytes(1), four), "@");
223 }
224
225 #[test]
226 fn boundaries() {
227 let four = Size::from_bytes(4);
228
229 let mut map = RangeObjectMap::<&str>::new();
230
231 map.insert_at_pos(0, alloc_range(Size::ZERO, four), "#");
234 assert_eq!(map.find_offset(four), Err(1));
237 assert_eq!(map.access_type(alloc_range(four, four)), AccessType::Empty(1));
240
241 let eight = Size::from_bytes(8);
242 map.insert_at_pos(1, alloc_range(eight, four), "@");
245 assert_eq!(map.find_offset(Size::from_bytes(7)), Err(1));
248 assert_eq!(map.access_type(alloc_range(four, four)), AccessType::Empty(1));
251 }
252
253 #[test]
254 fn perfectly_overlapping() {
255 let four = Size::from_bytes(4);
256
257 let mut map = RangeObjectMap::<&str>::new();
258
259 map.insert_at_pos(0, alloc_range(Size::ZERO, four), "#");
262 assert_eq!(map.find_offset(Size::ZERO), Ok(0));
265 assert_eq!(
266 map.access_type(alloc_range(Size::ZERO, four)),
267 AccessType::PerfectlyOverlapping(0)
268 );
269
270 map.insert_at_pos(1, alloc_range(four, four), "@");
273 assert_eq!(map.find_offset(four), Ok(1));
276 assert_eq!(map.access_type(alloc_range(four, four)), AccessType::PerfectlyOverlapping(1));
277 }
278
279 #[test]
280 fn straddling() {
281 let four = Size::from_bytes(4);
282
283 let mut map = RangeObjectMap::<&str>::new();
284
285 map.insert_at_pos(0, alloc_range(four, four), "#");
288 assert_eq!(
291 map.access_type(alloc_range(Size::from_bytes(2), four)),
292 AccessType::ImperfectlyOverlapping(0..1)
293 );
294 assert_eq!(
297 map.access_type(alloc_range(Size::from_bytes(6), four)),
298 AccessType::ImperfectlyOverlapping(0..1)
299 );
300 assert_eq!(
303 map.access_type(alloc_range(Size::from_bytes(2), Size::from_bytes(8))),
304 AccessType::ImperfectlyOverlapping(0..1)
305 );
306
307 map.insert_at_pos(1, alloc_range(Size::from_bytes(10), Size::from_bytes(2)), "@");
310 assert_eq!(
313 map.access_type(alloc_range(Size::from_bytes(6), Size::from_bytes(8))),
314 AccessType::ImperfectlyOverlapping(0..2)
315 );
316 }
317}