Skip to content

Commit 99695a3

Browse files
Expand IntervalSet APIs
This extends the functionality available on IntervalSet to provide more flexible access needed for the InitMask abstraction (and, likely, more generally useful as code wishes to migrate between the various Idx-based set abstractions available in rustc_index).
1 parent edda7e9 commit 99695a3

File tree

3 files changed

+272
-1
lines changed

3 files changed

+272
-1
lines changed

compiler/rustc_data_structures/src/stable_hasher.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::sip128::SipHasher128;
22
use rustc_index::bit_set;
3+
use rustc_index::interval;
34
use rustc_index::vec;
45
use smallvec::SmallVec;
56
use std::hash::{BuildHasher, Hash, Hasher};
@@ -510,6 +511,12 @@ impl<I: vec::Idx, CTX> HashStable<CTX> for bit_set::BitSet<I> {
510511
}
511512
}
512513

514+
impl<I: vec::Idx, CTX> HashStable<CTX> for interval::IntervalSet<I> {
515+
fn hash_stable(&self, _ctx: &mut CTX, hasher: &mut StableHasher) {
516+
::std::hash::Hash::hash(self, hasher);
517+
}
518+
}
519+
513520
impl<R: vec::Idx, C: vec::Idx, CTX> HashStable<CTX> for bit_set::BitMatrix<R, C> {
514521
fn hash_stable(&self, _ctx: &mut CTX, hasher: &mut StableHasher) {
515522
::std::hash::Hash::hash(self, hasher);

compiler/rustc_index/src/interval.rs

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@ use std::ops::RangeBounds;
55

66
use crate::vec::Idx;
77
use crate::vec::IndexVec;
8+
use rustc_macros::{Decodable, Encodable};
89
use smallvec::SmallVec;
910

1011
#[cfg(test)]
1112
mod tests;
1213

1314
/// Stores a set of intervals on the indices.
14-
#[derive(Debug, Clone)]
15+
#[derive(Debug, Clone, PartialEq, Eq, Hash, Encodable, Decodable)]
1516
pub struct IntervalSet<I> {
1617
// Start, end
1718
map: SmallVec<[(u32, u32); 4]>,
@@ -43,6 +44,17 @@ impl<I: Idx> IntervalSet<I> {
4344
IntervalSet { map: SmallVec::new(), domain, _data: PhantomData }
4445
}
4546

47+
/// Ensure that the set's domain is at least `min_domain_size`.
48+
pub fn ensure(&mut self, min_domain_size: usize) {
49+
if self.domain < min_domain_size {
50+
self.domain = min_domain_size;
51+
}
52+
}
53+
54+
pub fn domain_size(&self) -> usize {
55+
self.domain
56+
}
57+
4658
pub fn clear(&mut self) {
4759
self.map.clear();
4860
}
@@ -67,6 +79,10 @@ impl<I: Idx> IntervalSet<I> {
6779
self.insert_range(point..=point)
6880
}
6981

82+
pub fn remove(&mut self, point: I) {
83+
self.remove_range(point..=point);
84+
}
85+
7086
/// Returns true if we increased the number of elements present.
7187
pub fn insert_range(&mut self, range: impl RangeBounds<I> + Clone) -> bool {
7288
let start = inclusive_start(range.clone());
@@ -134,6 +150,31 @@ impl<I: Idx> IntervalSet<I> {
134150
}
135151
}
136152

153+
pub fn remove_range(&mut self, range: impl RangeBounds<I> + Clone) {
154+
let start = inclusive_start(range.clone());
155+
let Some(end) = inclusive_end(self.domain, range.clone()) else {
156+
// empty range
157+
return;
158+
};
159+
if start > end {
160+
return;
161+
}
162+
// We insert the range, so that any previous gaps are merged into just one large
163+
// range, which we can then split in the next step (either inserting a
164+
// smaller range after or not).
165+
self.insert_range(range);
166+
// Find the range we just inserted.
167+
let idx = self.map.partition_point(|r| r.0 <= end).checked_sub(1).unwrap();
168+
let (prev_start, prev_end) = self.map.remove(idx);
169+
// The range we're looking at contains the range we're removing completely.
170+
assert!(prev_start <= start && end <= prev_end);
171+
self.insert_range(I::new(prev_start as usize)..I::new(start as usize));
172+
self.insert_range((
173+
Bound::Excluded(I::new(end as usize)),
174+
Bound::Included(I::new(prev_end as usize)),
175+
));
176+
}
177+
137178
pub fn contains(&self, needle: I) -> bool {
138179
let needle = needle.index() as u32;
139180
let Some(last) = self.map.partition_point(|r| r.0 <= needle).checked_sub(1) else {
@@ -157,6 +198,44 @@ impl<I: Idx> IntervalSet<I> {
157198
self.map.is_empty()
158199
}
159200

201+
/// Returns the minimum (first) element present in the set from `range`.
202+
pub fn first_set_in(&self, range: impl RangeBounds<I> + Clone) -> Option<I> {
203+
let start = inclusive_start(range.clone());
204+
let Some(end) = inclusive_end(self.domain, range) else {
205+
// empty range
206+
return None;
207+
};
208+
if start > end {
209+
return None;
210+
}
211+
let range = self.map.get(self.map.partition_point(|r| r.1 < start))?;
212+
if range.0 > end { None } else { Some(I::new(std::cmp::max(range.0, start) as usize)) }
213+
}
214+
215+
/// Returns the minimum (first) element **not** present in the set from `range`.
216+
pub fn first_gap_in(&self, range: impl RangeBounds<I> + Clone) -> Option<I> {
217+
let start = inclusive_start(range.clone());
218+
let Some(end) = inclusive_end(self.domain, range) else {
219+
// empty range
220+
return None;
221+
};
222+
if start > end {
223+
return None;
224+
}
225+
let Some(range) = self.map.get(self.map.partition_point(|r| r.1 < start)) else {
226+
return Some(I::new(start as usize));
227+
};
228+
if start < range.0 {
229+
return Some(I::new(start as usize));
230+
} else if range.1 as usize + 1 < self.domain {
231+
if range.1 + 1 <= end {
232+
return Some(I::new(range.1 as usize + 1));
233+
}
234+
}
235+
236+
None
237+
}
238+
160239
/// Returns the maximum (last) element present in the set from `range`.
161240
pub fn last_set_in(&self, range: impl RangeBounds<I> + Clone) -> Option<I> {
162241
let start = inclusive_start(range.clone());

compiler/rustc_index/src/interval/tests.rs

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,61 @@ fn insert_range() {
118118
}
119119
}
120120

121+
#[test]
122+
fn remove_range() {
123+
fn check<A, B>(insert: A, remove: B)
124+
where
125+
A: RangeBounds<usize> + Clone + IntoIterator<Item = usize> + std::fmt::Debug,
126+
B: RangeBounds<usize> + Clone + IntoIterator<Item = usize> + std::fmt::Debug,
127+
{
128+
let mut set = IntervalSet::new(300);
129+
set.insert_range(insert.clone());
130+
set.remove_range(remove.clone());
131+
for i in set.iter() {
132+
assert!(insert.contains(&i) && !remove.contains(&i));
133+
}
134+
for i in insert.clone() {
135+
if i >= 300 {
136+
break;
137+
}
138+
if remove.contains(&i) {
139+
assert!(!set.contains(i));
140+
} else {
141+
assert!(set.contains(i));
142+
}
143+
}
144+
set.insert_range(insert.clone());
145+
for i in set.iter() {
146+
assert!(insert.contains(&i));
147+
}
148+
for i in insert.clone() {
149+
if i >= 300 {
150+
break;
151+
}
152+
assert!(set.contains(i));
153+
}
154+
}
155+
for a in 0..10 {
156+
for b in a..10 {
157+
for i in 0..10 {
158+
for j in i..10 {
159+
check(a..b, i..j);
160+
check(a..=b, i..j);
161+
check(a.., i..j);
162+
163+
check(a..b, i..=j);
164+
check(a..=b, i..=j);
165+
check(a.., i..=j);
166+
167+
check(a..b, i..);
168+
check(a..=b, i..);
169+
check(a.., i..);
170+
}
171+
}
172+
}
173+
}
174+
}
175+
121176
#[test]
122177
fn insert_range_dual() {
123178
let mut set = IntervalSet::<u32>::new(300);
@@ -193,6 +248,136 @@ fn last_set_in() {
193248
cmp(&set, i..);
194249
cmp(&set, i..j);
195250
cmp(&set, i..=j);
251+
set.insert(k / 2);
252+
cmp(&set, ..j);
253+
cmp(&set, i..);
254+
cmp(&set, i..j);
255+
cmp(&set, i..=j);
256+
}
257+
}
258+
}
259+
}
260+
261+
#[test]
262+
fn first_set_in() {
263+
fn easy(set: &IntervalSet<usize>, needle: impl RangeBounds<usize>) -> Option<usize> {
264+
for e in set.iter() {
265+
if needle.contains(&e) {
266+
return Some(e);
267+
}
268+
}
269+
None
270+
}
271+
272+
#[track_caller]
273+
fn cmp(set: &IntervalSet<usize>, needle: impl RangeBounds<usize> + Clone + std::fmt::Debug) {
274+
assert_eq!(
275+
set.first_set_in(needle.clone()),
276+
easy(set, needle.clone()),
277+
"{:?} in {:?}",
278+
needle,
279+
set
280+
);
281+
}
282+
let mut set = IntervalSet::new(300);
283+
cmp(&set, 50..=50);
284+
set.insert(64);
285+
cmp(&set, 64..=64);
286+
set.insert(64 - 1);
287+
cmp(&set, 0..=64 - 1);
288+
cmp(&set, 0..=5);
289+
cmp(&set, 10..100);
290+
set.insert(100);
291+
cmp(&set, 100..110);
292+
cmp(&set, 99..100);
293+
cmp(&set, 99..=100);
294+
295+
for i in 0..=30 {
296+
for j in i..=30 {
297+
for k in 0..30 {
298+
let mut set = IntervalSet::new(100);
299+
cmp(&set, ..j);
300+
cmp(&set, i..);
301+
cmp(&set, i..j);
302+
cmp(&set, i..=j);
303+
set.insert(k);
304+
cmp(&set, ..j);
305+
cmp(&set, i..);
306+
cmp(&set, i..j);
307+
cmp(&set, i..=j);
308+
set.insert(k / 2);
309+
cmp(&set, ..j);
310+
cmp(&set, i..);
311+
cmp(&set, i..j);
312+
cmp(&set, i..=j);
313+
set.insert_range(k / 2..k);
314+
cmp(&set, ..j);
315+
cmp(&set, i..);
316+
cmp(&set, i..j);
317+
cmp(&set, i..=j);
318+
}
319+
}
320+
}
321+
}
322+
323+
#[test]
324+
fn first_gap_in() {
325+
fn easy(set: &IntervalSet<usize>, needle: impl RangeBounds<usize>) -> Option<usize> {
326+
for point in 0..set.domain_size() {
327+
if needle.contains(&point) && !set.contains(point) {
328+
return Some(point);
329+
}
330+
}
331+
None
332+
}
333+
334+
#[track_caller]
335+
fn cmp(set: &IntervalSet<usize>, needle: impl RangeBounds<usize> + Clone + std::fmt::Debug) {
336+
eprintln!("comparing");
337+
assert_eq!(
338+
set.first_gap_in(needle.clone()),
339+
easy(set, needle.clone()),
340+
"{:?} in {:?}",
341+
needle,
342+
set
343+
);
344+
}
345+
let mut set = IntervalSet::new(300);
346+
cmp(&set, 50..=50);
347+
set.insert(64);
348+
cmp(&set, 64..=64);
349+
set.insert(64 - 1);
350+
cmp(&set, 0..=64 - 1);
351+
cmp(&set, 0..=5);
352+
cmp(&set, 10..100);
353+
set.insert(100);
354+
cmp(&set, 100..110);
355+
cmp(&set, 99..100);
356+
cmp(&set, 99..=100);
357+
358+
for i in 0..=30 {
359+
for j in i..=30 {
360+
for k in 0..30 {
361+
let mut set = IntervalSet::new(100);
362+
cmp(&set, ..j);
363+
cmp(&set, i..);
364+
cmp(&set, i..j);
365+
cmp(&set, i..=j);
366+
set.insert(k);
367+
cmp(&set, ..j);
368+
cmp(&set, i..);
369+
cmp(&set, i..j);
370+
cmp(&set, i..=j);
371+
set.insert(k / 2);
372+
cmp(&set, ..j);
373+
cmp(&set, i..);
374+
cmp(&set, i..j);
375+
cmp(&set, i..=j);
376+
set.insert_range(k / 2..k);
377+
cmp(&set, ..j);
378+
cmp(&set, i..);
379+
cmp(&set, i..j);
380+
cmp(&set, i..=j);
196381
}
197382
}
198383
}

0 commit comments

Comments
 (0)