about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSparrowLii <liyuan179@huawei.com>2022-06-08 15:23:11 +0800
committerSparrowLii <liyuan179@huawei.com>2022-06-08 15:23:11 +0800
commit8db6d4bae2ec0551ee091fe345525532d9a03eb3 (patch)
treedd72e2bb2d8ed15fbfaa7f41ff00e82b25f015d9
parent50b00252aeb77b10db04d65dc9e12ce758def4b5 (diff)
downloadrust-8db6d4bae2ec0551ee091fe345525532d9a03eb3.tar.gz
rust-8db6d4bae2ec0551ee091fe345525532d9a03eb3.zip
optimize `superset` method of `IntervalSet`
-rw-r--r--compiler/rustc_index/src/interval.rs25
1 files changed, 21 insertions, 4 deletions
diff --git a/compiler/rustc_index/src/interval.rs b/compiler/rustc_index/src/interval.rs
index 347c8856022..e2617c5b781 100644
--- a/compiler/rustc_index/src/interval.rs
+++ b/compiler/rustc_index/src/interval.rs
@@ -1,7 +1,7 @@
 use std::iter::Step;
 use std::marker::PhantomData;
-use std::ops::Bound;
 use std::ops::RangeBounds;
+use std::ops::{Bound, Range};
 
 use crate::vec::Idx;
 use crate::vec::IndexVec;
@@ -145,9 +145,26 @@ impl<I: Idx> IntervalSet<I> {
     where
         I: Step,
     {
-        // FIXME: Performance here is probably not great. We will be doing a lot
-        // of pointless tree traversals.
-        other.iter().all(|elem| self.contains(elem))
+        let mut sup_iter = self.iter_intervals();
+        let mut current = None;
+        let contains = |sup: Range<I>, sub: Range<I>, current: &mut Option<Range<I>>| {
+            if sup.end < sub.start {
+                // if `sup.end == sub.start`, the next sup doesn't contain `sub.start`
+                None // continue to the next sup
+            } else if sup.end >= sub.end && sup.start <= sub.start {
+                *current = Some(sup); // save the current sup
+                Some(true)
+            } else {
+                Some(false)
+            }
+        };
+        other.iter_intervals().all(|sub| {
+            current
+                .take()
+                .and_then(|sup| contains(sup, sub.clone(), &mut current))
+                .or_else(|| sup_iter.find_map(|sup| contains(sup, sub.clone(), &mut current)))
+                .unwrap_or(false)
+        })
     }
 
     pub fn is_empty(&self) -> bool {