1use fuchsia_sync::{Mutex, MutexGuard};
6use std::ops::Range;
7
8#[derive(Debug, Clone, PartialEq, Eq)]
12pub enum RangeType {
13 Cow(Range<u64>),
14 Overwrite(Range<u64>),
15}
16
17#[derive(Debug)]
26pub struct AllocatedRanges {
27 ranges: Mutex<Vec<Range<u64>>>,
28}
29
30pub struct RangeOverlapIter<'a> {
34 query_range: Range<u64>,
35 index: usize,
36 ranges: MutexGuard<'a, Vec<Range<u64>>>,
37}
38
39impl<'a> Iterator for RangeOverlapIter<'a> {
40 type Item = RangeType;
41
42 fn next(&mut self) -> Option<Self::Item> {
43 if self.query_range.start == self.query_range.end {
44 return None;
45 }
46
47 if self.index == self.ranges.len() || self.query_range.start < self.ranges[self.index].start
48 {
49 let range = self.query_range.start
50 ..std::cmp::min(
51 self.query_range.end,
52 self.ranges.get(self.index).map(|r| r.start).unwrap_or(self.query_range.end),
53 );
54 self.query_range.start = range.end;
55 return Some(RangeType::Cow(range));
56 }
57
58 let range = self.query_range.start
59 ..std::cmp::min(self.query_range.end, self.ranges[self.index].end);
60 self.query_range.start = range.end;
61 self.index += 1;
62
63 return Some(RangeType::Overwrite(range));
64 }
65}
66
67impl AllocatedRanges {
68 pub fn new(ranges_to_apply: &[Range<u64>]) -> Self {
69 let mut ranges = Vec::new();
70 for range_to_apply in ranges_to_apply {
71 Self::apply_range_to(&mut ranges, range_to_apply.clone());
72 }
73 Self { ranges: Mutex::new(ranges) }
74 }
75
76 pub fn clear(&self) {
77 self.ranges.lock().clear();
78 }
79
80 pub fn is_empty(&self) -> bool {
81 self.ranges.lock().is_empty()
82 }
83
84 pub fn overlap<'a>(&'a self, query_range: Range<u64>) -> RangeOverlapIter<'a> {
91 let ranges = self.ranges.lock();
92 let index = match ranges.binary_search_by_key(&query_range.start, |r| r.end) {
93 Ok(pos) => pos + 1,
96 Err(pos) => pos,
97 };
98 RangeOverlapIter { query_range, index, ranges }
99 }
100
101 pub fn apply_range(&self, new_range: Range<u64>) {
105 Self::apply_range_to(self.ranges.lock().as_mut(), new_range)
106 }
107
108 pub fn apply_range_to(ranges: &mut Vec<Range<u64>>, new_range: Range<u64>) {
109 let merge_start = match ranges.binary_search_by_key(&new_range.start, |r| r.end) {
110 Ok(pos) => pos,
113 Err(pos) => pos,
114 };
115 if merge_start == ranges.len() {
116 ranges.push(new_range);
118 return;
119 }
120
121 if ranges[merge_start].start <= new_range.start {
122 ranges[merge_start].end = std::cmp::max(ranges[merge_start].end, new_range.end);
125 } else {
126 ranges.insert(merge_start, new_range);
128 }
129
130 let mut merge_index = merge_start + 1;
131 while merge_index < ranges.len() && ranges[merge_index].start <= ranges[merge_start].end {
132 ranges[merge_start].end =
133 std::cmp::max(ranges[merge_start].end, ranges[merge_index].end);
134 merge_index += 1;
135 }
136 ranges.drain(merge_start + 1..merge_index);
137 }
138
139 pub fn truncate(&self, cutoff: u64) -> bool {
146 let mut ranges = self.ranges.lock();
147 if ranges.is_empty() {
148 return false;
151 }
152 let mut index = match ranges.binary_search_by_key(&cutoff, |r| r.end) {
153 Ok(pos) => pos + 1,
156 Err(pos) => pos,
157 };
158 if index == ranges.len() {
160 return false;
161 }
162 if ranges[index].start < cutoff {
164 ranges[index].end = cutoff;
165 index += 1;
166 }
167
168 ranges.truncate(index);
169 index == 0
172 }
173}
174
175#[cfg(test)]
176mod tests {
177 use super::{AllocatedRanges, RangeType};
178 use std::ops::Range;
179
180 #[fuchsia::test]
181 fn test_allocated_ranges() {
182 struct Case {
183 applied_ranges: Vec<Range<u64>>,
184 expected_ranges: Vec<Range<u64>>,
185 }
186 let cases = [
187 Case { applied_ranges: vec![0..1], expected_ranges: vec![0..1] },
188 Case { applied_ranges: vec![0..1, 2..3], expected_ranges: vec![0..1, 2..3] },
189 Case {
190 applied_ranges: vec![0..1, 2..3, 4..5],
191 expected_ranges: vec![0..1, 2..3, 4..5],
192 },
193 Case {
194 applied_ranges: vec![4..5, 2..3, 0..1],
195 expected_ranges: vec![0..1, 2..3, 4..5],
196 },
197 Case {
198 applied_ranges: vec![0..1, 4..5, 2..3],
199 expected_ranges: vec![0..1, 2..3, 4..5],
200 },
201 Case { applied_ranges: vec![0..10, 20..30], expected_ranges: vec![0..10, 20..30] },
202 Case { applied_ranges: vec![0..5, 0..5], expected_ranges: vec![0..5] },
203 Case { applied_ranges: vec![0..5, 0..1], expected_ranges: vec![0..5] },
204 Case { applied_ranges: vec![0..5, 0..10], expected_ranges: vec![0..10] },
205 Case { applied_ranges: vec![3..4, 2..3], expected_ranges: vec![2..4] },
206 Case { applied_ranges: vec![2..3, 3..4], expected_ranges: vec![2..4] },
207 Case { applied_ranges: vec![2..3, 3..4, 4..5, 1..2], expected_ranges: vec![1..5] },
208 Case { applied_ranges: vec![1..10, 2..4, 8..9, 2..9], expected_ranges: vec![1..10] },
209 Case { applied_ranges: vec![2..3, 3..4, 1..2, 0..10], expected_ranges: vec![0..10] },
210 Case {
211 applied_ranges: vec![1..2, 3..4, 5..6, 7..8],
212 expected_ranges: vec![1..2, 3..4, 5..6, 7..8],
213 },
214 Case {
215 applied_ranges: vec![1..2, 3..4, 5..6, 7..8, 0..10],
216 expected_ranges: vec![0..10],
217 },
218 Case { applied_ranges: vec![4..8, 6..10], expected_ranges: vec![4..10] },
219 Case { applied_ranges: vec![4..8, 2..6], expected_ranges: vec![2..8] },
220 Case {
221 applied_ranges: vec![2..5, 7..11, 13..18, 20..30, 40..45, 10..25],
222 expected_ranges: vec![2..5, 7..30, 40..45],
223 },
224 ];
225
226 for case in cases {
227 let ranges = AllocatedRanges::new(&case.applied_ranges);
228 assert_eq!(*ranges.ranges.lock(), case.expected_ranges);
229 }
230 }
231
232 #[fuchsia::test]
233 fn test_allocated_ranges_overlap() {
234 let ranges = AllocatedRanges::new(&[]);
235 assert_eq!(ranges.overlap(0..1).collect::<Vec<_>>(), vec![RangeType::Cow(0..1)]);
238 assert_eq!(ranges.overlap(10..20).collect::<Vec<_>>(), vec![RangeType::Cow(10..20)]);
239
240 ranges.apply_range(10..20);
241 assert_eq!(ranges.overlap(30..35).collect::<Vec<_>>(), vec![RangeType::Cow(30..35)]);
242 assert_eq!(ranges.overlap(20..30).collect::<Vec<_>>(), vec![RangeType::Cow(20..30)]);
243 assert_eq!(ranges.overlap(0..5).collect::<Vec<_>>(), vec![RangeType::Cow(0..5)]);
244 assert_eq!(ranges.overlap(0..10).collect::<Vec<_>>(), vec![RangeType::Cow(0..10)]);
245
246 assert_eq!(ranges.overlap(12..13).collect::<Vec<_>>(), vec![RangeType::Overwrite(12..13)]);
247 assert_eq!(ranges.overlap(10..20).collect::<Vec<_>>(), vec![RangeType::Overwrite(10..20)]);
248
249 assert_eq!(
250 ranges.overlap(5..15).collect::<Vec<_>>(),
251 vec![RangeType::Cow(5..10), RangeType::Overwrite(10..15)]
252 );
253 assert_eq!(
254 ranges.overlap(5..20).collect::<Vec<_>>(),
255 vec![RangeType::Cow(5..10), RangeType::Overwrite(10..20)]
256 );
257 assert_eq!(
258 ranges.overlap(5..25).collect::<Vec<_>>(),
259 vec![RangeType::Cow(5..10), RangeType::Overwrite(10..20), RangeType::Cow(20..25)]
260 );
261
262 assert_eq!(ranges.overlap(10..15).collect::<Vec<_>>(), vec![RangeType::Overwrite(10..15)]);
263 assert_eq!(ranges.overlap(10..20).collect::<Vec<_>>(), vec![RangeType::Overwrite(10..20)]);
264 assert_eq!(
265 ranges.overlap(10..25).collect::<Vec<_>>(),
266 vec![RangeType::Overwrite(10..20), RangeType::Cow(20..25)]
267 );
268
269 assert_eq!(ranges.overlap(15..20).collect::<Vec<_>>(), vec![RangeType::Overwrite(15..20)]);
270 assert_eq!(
271 ranges.overlap(15..25).collect::<Vec<_>>(),
272 vec![RangeType::Overwrite(15..20), RangeType::Cow(20..25)]
273 );
274
275 assert_eq!(ranges.overlap(20..25).collect::<Vec<_>>(), vec![RangeType::Cow(20..25)]);
276
277 ranges.apply_range(30..40);
278 ranges.apply_range(50..60);
279
280 assert_eq!(
281 ranges.overlap(15..35).collect::<Vec<_>>(),
282 vec![
283 RangeType::Overwrite(15..20),
284 RangeType::Cow(20..30),
285 RangeType::Overwrite(30..35)
286 ]
287 );
288 assert_eq!(
289 ranges.overlap(25..45).collect::<Vec<_>>(),
290 vec![RangeType::Cow(25..30), RangeType::Overwrite(30..40), RangeType::Cow(40..45)]
291 );
292 assert_eq!(
293 ranges.overlap(0..70).collect::<Vec<_>>(),
294 vec![
295 RangeType::Cow(0..10),
296 RangeType::Overwrite(10..20),
297 RangeType::Cow(20..30),
298 RangeType::Overwrite(30..40),
299 RangeType::Cow(40..50),
300 RangeType::Overwrite(50..60),
301 RangeType::Cow(60..70)
302 ]
303 );
304
305 ranges.apply_range(0..100);
306 assert_eq!(ranges.overlap(0..100).collect::<Vec<_>>(), vec![RangeType::Overwrite(0..100)]);
307 }
308
309 #[fuchsia::test]
310 fn test_trim_ranges() {
311 struct Case {
312 applied: Vec<Range<u64>>,
313 cutoff: u64,
314 expected: Vec<Range<u64>>,
315 dropped_all: bool,
316 }
317
318 let cases = [
319 Case { applied: vec![], cutoff: 10, expected: vec![], dropped_all: false },
320 Case { applied: vec![0..20], cutoff: 0, expected: vec![], dropped_all: true },
321 Case { applied: vec![0..20], cutoff: 10, expected: vec![0..10], dropped_all: false },
322 Case { applied: vec![0..20], cutoff: 20, expected: vec![0..20], dropped_all: false },
323 Case { applied: vec![0..20], cutoff: 30, expected: vec![0..20], dropped_all: false },
324 Case { applied: vec![0..20, 30..50], cutoff: 0, expected: vec![], dropped_all: true },
325 Case {
326 applied: vec![0..20, 30..50],
327 cutoff: 10,
328 expected: vec![0..10],
329 dropped_all: false,
330 },
331 Case {
332 applied: vec![0..20, 30..50],
333 cutoff: 30,
334 expected: vec![0..20],
335 dropped_all: false,
336 },
337 Case {
338 applied: vec![0..20, 30..50],
339 cutoff: 40,
340 expected: vec![0..20, 30..40],
341 dropped_all: false,
342 },
343 Case {
344 applied: vec![30..50, 60..80, 90..100],
345 cutoff: 29,
346 expected: vec![],
347 dropped_all: true,
348 },
349 Case {
350 applied: vec![30..50, 60..80, 90..100],
351 cutoff: 30,
352 expected: vec![],
353 dropped_all: true,
354 },
355 Case {
356 applied: vec![30..50, 60..80, 90..100],
357 cutoff: 31,
358 expected: vec![30..31],
359 dropped_all: false,
360 },
361 Case {
362 applied: vec![30..50, 60..80, 90..100],
363 cutoff: 70,
364 expected: vec![30..50, 60..70],
365 dropped_all: false,
366 },
367 Case {
368 applied: vec![30..50, 60..80, 90..100],
369 cutoff: 110,
370 expected: vec![30..50, 60..80, 90..100],
371 dropped_all: false,
372 },
373 ];
374
375 for (i, case) in cases.into_iter().enumerate() {
376 let ranges = AllocatedRanges::new(&case.applied);
377 assert_eq!(ranges.truncate(case.cutoff), case.dropped_all, "failed case # {}", i);
378 assert_eq!(*ranges.ranges.lock(), case.expected, "failed case # {}", i);
379 }
380 }
381}