about summary refs log tree commit diff
path: root/compiler/rustc_data_structures/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2025-03-02 22:41:17 +0000
committerbors <bors@rust-lang.org>2025-03-02 22:41:17 +0000
commitdaf59857d6d2b87af4b846316bf1561a6083ed51 (patch)
tree2cec3fcae349e0f2267de0acb169cff616038c46 /compiler/rustc_data_structures/src
parentf4a216d28ee635afce685b4206e713579f66e130 (diff)
parenta36d8acd835c96de1b1184d97648a16648591607 (diff)
downloadrust-daf59857d6d2b87af4b846316bf1561a6083ed51.tar.gz
rust-daf59857d6d2b87af4b846316bf1561a6083ed51.zip
Auto merge of #137704 - nnethercote:opt-empty-prov-range-checks, r=oli-obk
Optimize empty provenance range checks.

Currently it gets the pointers in the range and checks if the result is empty, but it can be done faster if you combine those two steps.

r? `@oli-obk`
Diffstat (limited to 'compiler/rustc_data_structures/src')
-rw-r--r--compiler/rustc_data_structures/src/sorted_map.rs33
1 files changed, 33 insertions, 0 deletions
diff --git a/compiler/rustc_data_structures/src/sorted_map.rs b/compiler/rustc_data_structures/src/sorted_map.rs
index 066ea03b4ac..a01a420dfbd 100644
--- a/compiler/rustc_data_structures/src/sorted_map.rs
+++ b/compiler/rustc_data_structures/src/sorted_map.rs
@@ -1,4 +1,5 @@
 use std::borrow::Borrow;
+use std::cmp::Ordering;
 use std::fmt::Debug;
 use std::mem;
 use std::ops::{Bound, Index, IndexMut, RangeBounds};
@@ -156,6 +157,38 @@ impl<K: Ord, V> SortedMap<K, V> {
         &self.data[start..end]
     }
 
+    /// `sm.range_is_empty(r)` == `sm.range(r).is_empty()`, but is faster.
+    #[inline]
+    pub fn range_is_empty<R>(&self, range: R) -> bool
+    where
+        R: RangeBounds<K>,
+    {
+        // `range` must (via `range_slice_indices`) search for the start and
+        // end separately. But here we can do a single binary search for the
+        // entire range. If a single `x` matching `range` is found then the
+        // range is *not* empty.
+        self.data
+            .binary_search_by(|(x, _)| {
+                // Is `x` below `range`?
+                match range.start_bound() {
+                    Bound::Included(start) if x < start => return Ordering::Less,
+                    Bound::Excluded(start) if x <= start => return Ordering::Less,
+                    _ => {}
+                };
+
+                // Is `x` above `range`?
+                match range.end_bound() {
+                    Bound::Included(end) if x > end => return Ordering::Greater,
+                    Bound::Excluded(end) if x >= end => return Ordering::Greater,
+                    _ => {}
+                };
+
+                // `x` must be within `range`.
+                Ordering::Equal
+            })
+            .is_err()
+    }
+
     #[inline]
     pub fn remove_range<R>(&mut self, range: R)
     where