corevm_host/
range_set.rs

1use alloc::vec::Vec;
2use codec::{Decode, Encode, Input, MaxEncodedLen};
3
4// TODO @ivan Proper B-Tree-based implementation would be useful for both CoreVM and PolkaVM.
5#[derive(Clone, PartialEq, Eq, Encode, Default)]
6pub struct RangeSet {
7	ranges: Vec<Range>,
8}
9
10impl RangeSet {
11	pub const fn new() -> Self {
12		Self { ranges: Vec::new() }
13	}
14
15	pub fn with_capacity(capacity: usize) -> Self {
16		Self { ranges: Vec::with_capacity(capacity) }
17	}
18
19	pub fn insert(&mut self, mut new_range: Range) {
20		if new_range.is_empty() {
21			return;
22		}
23		if self.ranges.is_empty() {
24			self.ranges.push(new_range);
25			return;
26		}
27		let (at, from) =
28			match self.ranges.binary_search_by(|range| range.start.cmp(&new_range.start)) {
29				Ok(i) => (i, i),
30				Err(i) => (i, i.saturating_sub(1)),
31			};
32		let mut splice_range = at..at;
33		for i in from..self.ranges.len() {
34			let r = &mut self.ranges[i];
35			let contains_start = (r.start..=r.end).contains(&new_range.start);
36			let contains_end = (r.start..=r.end).contains(&new_range.end);
37			if contains_start && contains_end {
38				return;
39			}
40			if contains_start {
41				new_range.start = r.start;
42				splice_range = i..i + 1;
43				continue;
44			}
45			if contains_end {
46				new_range.end = r.end;
47				splice_range.end = i + 1;
48				break;
49			}
50		}
51		self.ranges.splice(splice_range, [new_range]);
52	}
53
54	pub fn remove(&mut self, range: &Range) {
55		if range.is_empty() {
56			return;
57		}
58		let from = match self.ranges.binary_search_by(|r| r.start.cmp(&range.start)) {
59			Ok(i) => i,
60			Err(i) => i.saturating_sub(1),
61		};
62		#[allow(clippy::reversed_empty_ranges)]
63		let mut drain_range = usize::MAX..0;
64		for i in from..self.ranges.len() {
65			let r = &mut self.ranges[i];
66			let contains_start = (r.start..r.end).contains(&range.start);
67			let contains_end = (r.start..=r.end).contains(&range.end);
68			if contains_start && contains_end {
69				let old_end = r.end;
70				r.end = range.start;
71				let new_range = Range::new(range.end, old_end);
72				if r.is_empty() && new_range.is_empty() {
73					drain_range = i..i + 1;
74					break;
75				}
76				if r.is_empty() {
77					self.ranges[i] = new_range;
78					break;
79				}
80				if !new_range.is_empty() {
81					self.ranges.insert(i + 1, new_range);
82				}
83				break;
84			}
85			if range.contains_range(r) {
86				if i < drain_range.start {
87					drain_range.start = i;
88				}
89				if i + 1 > drain_range.end {
90					drain_range.end = i + 1;
91				}
92			} else if contains_start {
93				r.end = range.start;
94				drain_range.start = if r.is_empty() { i } else { i + 1 };
95			}
96			if contains_end {
97				r.start = range.end;
98				drain_range.end = if r.is_empty() { i + 1 } else { i };
99				break;
100			}
101		}
102		if !drain_range.is_empty() {
103			self.ranges.drain(drain_range);
104		}
105	}
106
107	pub fn overlap(&self, range: &Range) -> bool {
108		if range.is_empty() {
109			return false;
110		}
111		for r in &self.ranges {
112			if r.start < range.end && range.start < r.end {
113				return true;
114			}
115		}
116		false
117	}
118
119	pub fn clear(&mut self) {
120		self.ranges.clear();
121	}
122
123	pub fn enclosing_range(&self) -> Option<Range> {
124		if self.ranges.is_empty() {
125			return None;
126		}
127		let start = self.ranges[0].start;
128		let end = self.ranges[self.ranges.len() - 1].end;
129		Some(Range::new(start, end))
130	}
131
132	pub fn count(&self) -> u64 {
133		self.ranges.iter().map(|range| range.end - range.start).sum()
134	}
135
136	pub fn contains_index(&self, index: u64) -> bool {
137		let i = match self.ranges.binary_search_by(|range| range.start.cmp(&index)) {
138			Ok(i) => i,
139			Err(i) => i.saturating_sub(1),
140		};
141		self.ranges.get(i).map(|range| range.contains(index)).unwrap_or(false)
142	}
143
144	pub fn as_slice(&self) -> &[Range] {
145		self.ranges.as_slice()
146	}
147}
148
149impl AsRef<[Range]> for RangeSet {
150	fn as_ref(&self) -> &[Range] {
151		&self.ranges[..]
152	}
153}
154
155impl core::fmt::Debug for RangeSet {
156	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
157		f.debug_list().entries(self.ranges.iter()).finish()
158	}
159}
160
161impl FromIterator<Range> for RangeSet {
162	fn from_iter<I: IntoIterator<Item = Range>>(items: I) -> Self {
163		let iter = items.into_iter();
164		let (min_size, max_size) = iter.size_hint();
165		let mut set = RangeSet::with_capacity(max_size.unwrap_or(min_size));
166		set.extend(iter);
167		set
168	}
169}
170
171impl Extend<Range> for RangeSet {
172	fn extend<I: IntoIterator<Item = Range>>(&mut self, iter: I) {
173		for range in iter.into_iter() {
174			self.insert(range);
175		}
176	}
177}
178
179impl Decode for RangeSet {
180	fn decode<I: Input>(input: &mut I) -> Result<Self, codec::Error> {
181		let ranges = Vec::<Range>::decode(input)?;
182		if !validate_ranges(&ranges) {
183			return Err("RangeSet: out-of-order/overlapping/empty ranges".into());
184		}
185		Ok(Self { ranges })
186	}
187}
188
189fn validate_ranges(ranges: &[Range]) -> bool {
190	if ranges.iter().any(|r| r.is_empty()) {
191		return false;
192	}
193	for window in ranges.windows(2) {
194		let a = &window[0];
195		let b = &window[1];
196		if b.start <= a.start || b.start <= a.end {
197			return false;
198		}
199	}
200	true
201}
202
203#[derive(Clone, PartialEq, Eq, Encode, Decode, MaxEncodedLen)]
204pub struct Range {
205	/// The start of the range (inclusive).
206	#[codec(compact)]
207	pub start: u64,
208	/// The end of the range (exclusive).
209	#[codec(compact)]
210	pub end: u64,
211}
212
213impl Range {
214	pub const fn new(start: u64, end: u64) -> Self {
215		Self { start, end }
216	}
217
218	pub const fn is_empty(&self) -> bool {
219		self.start >= self.end
220	}
221
222	/// Returns `true` if `self` is fully contains `other`.
223	///
224	/// If `other` range is empty, returns `false`.
225	pub fn contains_range(&self, other: &Range) -> bool {
226		!other.is_empty() &&
227			(self.start..self.end).contains(&other.start) &&
228			(self.start..=self.end).contains(&other.end)
229	}
230
231	pub const fn contains(&self, i: u64) -> bool {
232		self.start <= i && i < self.end
233	}
234}
235
236impl core::fmt::Display for Range {
237	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
238		if self.start.saturating_add(1) == self.end {
239			write!(f, "{}", self.start)
240		} else {
241			write!(f, "{}..{}", self.start, self.end)
242		}
243	}
244}
245
246impl core::fmt::Debug for Range {
247	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
248		core::fmt::Display::fmt(self, f)
249	}
250}
251
252#[cfg(test)]
253mod tests {
254	use super::*;
255	use rand::{seq::SliceRandom, Rng};
256
257	#[test]
258	fn insert_works() {
259		let mut ranges = RangeSet::new();
260		assert_eq!(0, ranges.as_ref().len());
261		ranges.insert(Range::new(0, 0));
262		assert_eq!(0, ranges.as_ref().len());
263		ranges.insert(Range::new(0, 1));
264		assert_eq!(1, ranges.as_ref().len());
265		ranges.insert(Range::new(0, 1));
266		assert_eq!(1, ranges.as_ref().len());
267		ranges.insert(Range::new(2, 3));
268		assert_eq!([Range::new(0, 1), Range::new(2, 3)].as_slice(), ranges.as_ref());
269		ranges.insert(Range::new(1, 2));
270		assert_eq!([Range::new(0, 3)].as_slice(), ranges.as_ref());
271		ranges.insert(Range::new(3, 10));
272		assert_eq!([Range::new(0, 10)].as_slice(), ranges.as_ref());
273	}
274
275	#[test]
276	fn remove_works() {
277		let mut ranges = RangeSet::new();
278		assert_eq!(0, ranges.as_ref().len());
279		// Remove exact.
280		ranges.insert(Range::new(0, 1));
281		assert_eq!(1, ranges.as_ref().len());
282		ranges.remove(&Range::new(0, 1));
283		assert_eq!(0, ranges.as_ref().len());
284		// Remove in the middle.
285		ranges.insert(Range::new(0, 4));
286		ranges.remove(&Range::new(1, 3));
287		assert_eq!([Range::new(0, 1), Range::new(3, 4)].as_slice(), ranges.as_ref());
288		// Remove at the start.
289		ranges.clear();
290		ranges.insert(Range::new(0, 4));
291		ranges.remove(&Range::new(0, 1));
292		assert_eq!([Range::new(1, 4)].as_slice(), ranges.as_ref());
293		// Remove at the end.
294		ranges.clear();
295		ranges.insert(Range::new(0, 4));
296		ranges.remove(&Range::new(3, 4));
297		assert_eq!([Range::new(0, 3)].as_slice(), ranges.as_ref());
298		// Remove enclosing range.
299		ranges.clear();
300		ranges.insert(Range::new(1, 4));
301		ranges.remove(&Range::new(0, 5));
302		assert_eq!(([] as [Range; 0]).as_slice(), ranges.as_ref());
303		// Remove overlaping-at-the-start range.
304		ranges.clear();
305		ranges.insert(Range::new(1, 4));
306		ranges.remove(&Range::new(0, 2));
307		assert_eq!([Range::new(2, 4)].as_slice(), ranges.as_ref());
308		// Remove overlaping-at-the-end range.
309		ranges.clear();
310		ranges.insert(Range::new(1, 4));
311		ranges.remove(&Range::new(3, 5));
312		assert_eq!([Range::new(1, 3)].as_slice(), ranges.as_ref());
313	}
314
315	#[test]
316	fn insert_remove_random() {
317		let mut rng = rand::rng();
318		for _ in 0..1000 {
319			let mut ranges = Vec::new();
320			let mut offset = 0;
321			for _ in 0..10 {
322				let start = offset;
323				let end = rng.random_range(start..=start + 20);
324				offset = end;
325				ranges.push(Range::new(start, end));
326			}
327			// Insert all ranges in random order.
328			ranges.shuffle(&mut rng);
329			let mut set = RangeSet::new();
330			for range in ranges.iter() {
331				set.insert(range.clone());
332			}
333			assert_eq!(1, set.as_ref().len());
334			assert_eq!(&[Range::new(0, offset)], set.as_ref());
335			// Remove all ranges in random order.
336			ranges.shuffle(&mut rng);
337			for range in ranges.iter() {
338				set.remove(range);
339			}
340			assert_eq!(0, set.as_ref().len());
341		}
342	}
343
344	#[test]
345	fn remove_reverts_insert() {
346		let mut rng = rand::rng();
347		for _ in 0..1000 {
348			let mut ranges = RangeSet::new();
349			{
350				let mut offset = 0;
351				for _ in 0..10 {
352					let start = rng.random_range(offset..=20);
353					let end = rng.random_range(start..=20);
354					offset = end;
355					ranges.insert(Range::new(start, end));
356				}
357			}
358			let range = {
359				let start = rng.random_range(0..=20);
360				Range::new(start, rng.random_range(start..=20))
361			};
362			if ranges.overlap(&range) {
363				// `remove` reverts `insert` only if there is no overlap
364				continue;
365			}
366			let expected = ranges.clone();
367			ranges.insert(range.clone());
368			let middle = ranges.clone();
369			ranges.remove(&range);
370			assert_eq!(expected, ranges,
371                "ranges = {expected:?}, insert/remove {range:?}, after insert = {middle:?}, after remove = {ranges:?}");
372			assert_eq!(expected.encoded_size(), ranges.encoded_size());
373		}
374	}
375
376	#[test]
377	fn insert_reverts_remove() {
378		let mut rng = rand::rng();
379		for _ in 0..1000 {
380			let mut ranges = RangeSet::new();
381			{
382				let mut offset = 0;
383				for _ in 0..10 {
384					let start = rng.random_range(offset..=20);
385					let end = rng.random_range(start..=20);
386					offset = end;
387					ranges.insert(Range::new(start, end));
388				}
389			}
390			let range = {
391				let start = rng.random_range(0..=20);
392				Range::new(start, rng.random_range(start..=20))
393			};
394			if !ranges.as_ref().iter().any(|r| r.contains_range(&range)) {
395				// `insert` reverts `remove` only if the new range is fully contained in one of the
396				// existing ranges
397				continue;
398			}
399			let expected = ranges.clone();
400			ranges.remove(&range);
401			let middle = ranges.clone();
402			ranges.insert(range.clone());
403			assert_eq!(expected, ranges,
404                "ranges = {expected:?}, remove/insert {range:?}, after remove = {middle:?}, after insert = {ranges:?}");
405		}
406	}
407
408	#[test]
409	fn validate_works() {
410		assert!(!validate_ranges(&[Range::new(0, 0)]));
411		assert!(!validate_ranges(&[Range::new(0, 1), Range::new(0, 2)]));
412		assert!(!validate_ranges(&[Range::new(0, 2), Range::new(1, 3)]));
413		assert!(!validate_ranges(&[Range::new(0, 1), Range::new(1, 2)]));
414		assert!(!validate_ranges(&[Range::new(2, 3), Range::new(0, 1)]));
415		assert!(validate_ranges(&[Range::new(0, 1), Range::new(2, 3)]));
416	}
417}