Coverage Report

Created: 2026-10-28 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/regex/regex-syntax/src/hir/interval.rs
Line
Count
Source
1
use core::{char, cmp, fmt::Debug, slice};
2
3
use alloc::vec::Vec;
4
5
use crate::unicode;
6
7
// This module contains an *internal* implementation of interval sets.
8
//
9
// The primary invariant that interval sets guards is canonical ordering. That
10
// is, every interval set contains an ordered sequence of intervals where
11
// no two intervals are overlapping or adjacent. While this invariant is
12
// occasionally broken within the implementation, it should be impossible for
13
// callers to observe it.
14
//
15
// Since case folding (as implemented below) breaks that invariant, we roll
16
// that into this API even though it is a little out of place in an otherwise
17
// generic interval set. (Hence the reason why the `unicode` module is imported
18
// here.)
19
//
20
// Some of the implementation complexity here is a result of me wanting to
21
// preserve the sequential representation without using additional memory.
22
// In many cases, we do use linear extra memory, but it is at most 2x and it
23
// is amortized. If we relaxed the memory requirements, this implementation
24
// could become much simpler. The extra memory is honestly probably OK, but
25
// character classes (especially of the Unicode variety) can become quite
26
// large, and it would be nice to keep regex compilation snappy even in debug
27
// builds. (In the past, I have been careless with this area of code and it has
28
// caused slow regex compilations in debug mode, so this isn't entirely
29
// unwarranted.)
30
//
31
// Tests on this are relegated to the public API of HIR in src/hir.rs.
32
33
#[derive(Clone, Debug)]
34
pub struct IntervalSet<I> {
35
    /// A sorted set of non-overlapping ranges.
36
    ranges: Vec<I>,
37
    /// While not required at all for correctness, we keep track of whether an
38
    /// interval set has been case folded or not. This helps us avoid doing
39
    /// redundant work if, for example, a set has already been cased folded.
40
    /// And note that whether a set is folded or not is preserved through
41
    /// all of the pairwise set operations. That is, if both interval sets
42
    /// have been case folded, then any of difference, union, intersection or
43
    /// symmetric difference all produce a case folded set.
44
    ///
45
    /// Note that when this is true, it *must* be the case that the set is case
46
    /// folded. But when it's false, the set *may* be case folded. In other
47
    /// words, we only set this to true when we know it to be case, but we're
48
    /// okay with it being false if it would otherwise be costly to determine
49
    /// whether it should be true. This means code cannot assume that a false
50
    /// value necessarily indicates that the set is not case folded.
51
    ///
52
    /// Bottom line: this is a performance optimization.
53
    folded: bool,
54
}
55
56
impl<I: Interval> Eq for IntervalSet<I> {}
57
58
// We implement PartialEq manually so that we don't consider the set's internal
59
// 'folded' property to be part of its identity. The 'folded' property is
60
// strictly an optimization.
61
impl<I: Interval> PartialEq for IntervalSet<I> {
62
25.2k
    fn eq(&self, other: &IntervalSet<I>) -> bool {
63
25.2k
        self.ranges.eq(&other.ranges)
64
25.2k
    }
<regex_syntax::hir::interval::IntervalSet<regex_syntax::hir::ClassBytesRange> as core::cmp::PartialEq>::eq
Line
Count
Source
62
5.80k
    fn eq(&self, other: &IntervalSet<I>) -> bool {
63
5.80k
        self.ranges.eq(&other.ranges)
64
5.80k
    }
<regex_syntax::hir::interval::IntervalSet<regex_syntax::hir::ClassUnicodeRange> as core::cmp::PartialEq>::eq
Line
Count
Source
62
19.4k
    fn eq(&self, other: &IntervalSet<I>) -> bool {
63
19.4k
        self.ranges.eq(&other.ranges)
64
19.4k
    }
65
}
66
67
impl<I: Interval> IntervalSet<I> {
68
    /// Create a new set from a sequence of intervals. Each interval is
69
    /// specified as a pair of bounds, where both bounds are inclusive.
70
    ///
71
    /// The given ranges do not need to be in any specific order, and ranges
72
    /// may overlap.
73
1.74M
    pub fn new<T: IntoIterator<Item = I>>(intervals: T) -> IntervalSet<I> {
74
1.74M
        let ranges: Vec<I> = intervals.into_iter().collect();
75
        // An empty set is case folded.
76
1.74M
        let folded = ranges.is_empty();
77
1.74M
        let mut set = IntervalSet { ranges, folded };
78
1.74M
        set.canonicalize();
79
1.74M
        set
80
1.74M
    }
<regex_syntax::hir::interval::IntervalSet<regex_syntax::hir::ClassBytesRange>>::new::<[regex_syntax::hir::ClassBytesRange; 1]>
Line
Count
Source
73
6.54k
    pub fn new<T: IntoIterator<Item = I>>(intervals: T) -> IntervalSet<I> {
74
6.54k
        let ranges: Vec<I> = intervals.into_iter().collect();
75
        // An empty set is case folded.
76
6.54k
        let folded = ranges.is_empty();
77
6.54k
        let mut set = IntervalSet { ranges, folded };
78
6.54k
        set.canonicalize();
79
6.54k
        set
80
6.54k
    }
Unexecuted instantiation: <regex_syntax::hir::interval::IntervalSet<regex_syntax::hir::ClassBytesRange>>::new::<[regex_syntax::hir::ClassBytesRange; 2]>
<regex_syntax::hir::interval::IntervalSet<regex_syntax::hir::ClassBytesRange>>::new::<[regex_syntax::hir::ClassBytesRange; 3]>
Line
Count
Source
73
492
    pub fn new<T: IntoIterator<Item = I>>(intervals: T) -> IntervalSet<I> {
74
492
        let ranges: Vec<I> = intervals.into_iter().collect();
75
        // An empty set is case folded.
76
492
        let folded = ranges.is_empty();
77
492
        let mut set = IntervalSet { ranges, folded };
78
492
        set.canonicalize();
79
492
        set
80
492
    }
<regex_syntax::hir::interval::IntervalSet<regex_syntax::hir::ClassBytesRange>>::new::<alloc::vec::Vec<regex_syntax::hir::ClassBytesRange>>
Line
Count
Source
73
407k
    pub fn new<T: IntoIterator<Item = I>>(intervals: T) -> IntervalSet<I> {
74
407k
        let ranges: Vec<I> = intervals.into_iter().collect();
75
        // An empty set is case folded.
76
407k
        let folded = ranges.is_empty();
77
407k
        let mut set = IntervalSet { ranges, folded };
78
407k
        set.canonicalize();
79
407k
        set
80
407k
    }
<regex_syntax::hir::interval::IntervalSet<regex_syntax::hir::ClassBytesRange>>::new::<core::iter::adapters::map::Map<core::iter::adapters::copied::Copied<core::slice::iter::Iter<(u8, u8)>>, <regex_syntax::hir::translate::TranslatorI>::hir_ascii_byte_class::{closure#0}>>
Line
Count
Source
73
24.1k
    pub fn new<T: IntoIterator<Item = I>>(intervals: T) -> IntervalSet<I> {
74
24.1k
        let ranges: Vec<I> = intervals.into_iter().collect();
75
        // An empty set is case folded.
76
24.1k
        let folded = ranges.is_empty();
77
24.1k
        let mut set = IntervalSet { ranges, folded };
78
24.1k
        set.canonicalize();
79
24.1k
        set
80
24.1k
    }
<regex_syntax::hir::interval::IntervalSet<regex_syntax::hir::ClassBytesRange>>::new::<core::iter::adapters::map::Map<core::slice::iter::Iter<regex_syntax::hir::ClassUnicodeRange>, <regex_syntax::hir::ClassUnicode>::to_byte_class::{closure#0}>>
Line
Count
Source
73
3.48k
    pub fn new<T: IntoIterator<Item = I>>(intervals: T) -> IntervalSet<I> {
74
3.48k
        let ranges: Vec<I> = intervals.into_iter().collect();
75
        // An empty set is case folded.
76
3.48k
        let folded = ranges.is_empty();
77
3.48k
        let mut set = IntervalSet { ranges, folded };
78
3.48k
        set.canonicalize();
79
3.48k
        set
80
3.48k
    }
<regex_syntax::hir::interval::IntervalSet<regex_syntax::hir::ClassBytesRange>>::new::<core::iter::adapters::map::Map<alloc::vec::into_iter::IntoIter<u8>, <regex_syntax::hir::Hir>::alternation::{closure#1}>>
Line
Count
Source
73
8
    pub fn new<T: IntoIterator<Item = I>>(intervals: T) -> IntervalSet<I> {
74
8
        let ranges: Vec<I> = intervals.into_iter().collect();
75
        // An empty set is case folded.
76
8
        let folded = ranges.is_empty();
77
8
        let mut set = IntervalSet { ranges, folded };
78
8
        set.canonicalize();
79
8
        set
80
8
    }
<regex_syntax::hir::interval::IntervalSet<regex_syntax::hir::ClassUnicodeRange>>::new::<[regex_syntax::hir::ClassUnicodeRange; 1]>
Line
Count
Source
73
41.5k
    pub fn new<T: IntoIterator<Item = I>>(intervals: T) -> IntervalSet<I> {
74
41.5k
        let ranges: Vec<I> = intervals.into_iter().collect();
75
        // An empty set is case folded.
76
41.5k
        let folded = ranges.is_empty();
77
41.5k
        let mut set = IntervalSet { ranges, folded };
78
41.5k
        set.canonicalize();
79
41.5k
        set
80
41.5k
    }
Unexecuted instantiation: <regex_syntax::hir::interval::IntervalSet<regex_syntax::hir::ClassUnicodeRange>>::new::<[regex_syntax::hir::ClassUnicodeRange; 2]>
<regex_syntax::hir::interval::IntervalSet<regex_syntax::hir::ClassUnicodeRange>>::new::<[regex_syntax::hir::ClassUnicodeRange; 3]>
Line
Count
Source
73
3.06k
    pub fn new<T: IntoIterator<Item = I>>(intervals: T) -> IntervalSet<I> {
74
3.06k
        let ranges: Vec<I> = intervals.into_iter().collect();
75
        // An empty set is case folded.
76
3.06k
        let folded = ranges.is_empty();
77
3.06k
        let mut set = IntervalSet { ranges, folded };
78
3.06k
        set.canonicalize();
79
3.06k
        set
80
3.06k
    }
<regex_syntax::hir::interval::IntervalSet<regex_syntax::hir::ClassUnicodeRange>>::new::<alloc::vec::Vec<regex_syntax::hir::ClassUnicodeRange>>
Line
Count
Source
73
1.04M
    pub fn new<T: IntoIterator<Item = I>>(intervals: T) -> IntervalSet<I> {
74
1.04M
        let ranges: Vec<I> = intervals.into_iter().collect();
75
        // An empty set is case folded.
76
1.04M
        let folded = ranges.is_empty();
77
1.04M
        let mut set = IntervalSet { ranges, folded };
78
1.04M
        set.canonicalize();
79
1.04M
        set
80
1.04M
    }
<regex_syntax::hir::interval::IntervalSet<regex_syntax::hir::ClassUnicodeRange>>::new::<core::iter::adapters::map::Map<core::iter::adapters::map::Map<core::iter::adapters::copied::Copied<core::slice::iter::Iter<(u8, u8)>>, regex_syntax::hir::translate::ascii_class_as_chars::{closure#0}>, <regex_syntax::hir::translate::TranslatorI>::hir_ascii_unicode_class::{closure#0}>>
Line
Count
Source
73
58.7k
    pub fn new<T: IntoIterator<Item = I>>(intervals: T) -> IntervalSet<I> {
74
58.7k
        let ranges: Vec<I> = intervals.into_iter().collect();
75
        // An empty set is case folded.
76
58.7k
        let folded = ranges.is_empty();
77
58.7k
        let mut set = IntervalSet { ranges, folded };
78
58.7k
        set.canonicalize();
79
58.7k
        set
80
58.7k
    }
<regex_syntax::hir::interval::IntervalSet<regex_syntax::hir::ClassUnicodeRange>>::new::<core::iter::adapters::map::Map<core::slice::iter::Iter<regex_syntax::hir::ClassBytesRange>, <regex_syntax::hir::ClassBytes>::to_unicode_class::{closure#0}>>
Line
Count
Source
73
7.32k
    pub fn new<T: IntoIterator<Item = I>>(intervals: T) -> IntervalSet<I> {
74
7.32k
        let ranges: Vec<I> = intervals.into_iter().collect();
75
        // An empty set is case folded.
76
7.32k
        let folded = ranges.is_empty();
77
7.32k
        let mut set = IntervalSet { ranges, folded };
78
7.32k
        set.canonicalize();
79
7.32k
        set
80
7.32k
    }
<regex_syntax::hir::interval::IntervalSet<regex_syntax::hir::ClassUnicodeRange>>::new::<core::iter::adapters::map::Map<alloc::vec::into_iter::IntoIter<char>, <regex_syntax::hir::Hir>::alternation::{closure#0}>>
Line
Count
Source
73
1.94k
    pub fn new<T: IntoIterator<Item = I>>(intervals: T) -> IntervalSet<I> {
74
1.94k
        let ranges: Vec<I> = intervals.into_iter().collect();
75
        // An empty set is case folded.
76
1.94k
        let folded = ranges.is_empty();
77
1.94k
        let mut set = IntervalSet { ranges, folded };
78
1.94k
        set.canonicalize();
79
1.94k
        set
80
1.94k
    }
<regex_syntax::hir::interval::IntervalSet<regex_syntax::hir::ClassBytesRange>>::new::<[regex_syntax::hir::ClassBytesRange; 1]>
Line
Count
Source
73
143k
    pub fn new<T: IntoIterator<Item = I>>(intervals: T) -> IntervalSet<I> {
74
143k
        let ranges: Vec<I> = intervals.into_iter().collect();
75
        // An empty set is case folded.
76
143k
        let folded = ranges.is_empty();
77
143k
        let mut set = IntervalSet { ranges, folded };
78
143k
        set.canonicalize();
79
143k
        set
80
143k
    }
Unexecuted instantiation: <regex_syntax::hir::interval::IntervalSet<regex_syntax::hir::ClassBytesRange>>::new::<[regex_syntax::hir::ClassBytesRange; 2]>
Unexecuted instantiation: <regex_syntax::hir::interval::IntervalSet<regex_syntax::hir::ClassBytesRange>>::new::<[regex_syntax::hir::ClassBytesRange; 3]>
Unexecuted instantiation: <regex_syntax::hir::interval::IntervalSet<regex_syntax::hir::ClassUnicodeRange>>::new::<[regex_syntax::hir::ClassUnicodeRange; 1]>
Unexecuted instantiation: <regex_syntax::hir::interval::IntervalSet<regex_syntax::hir::ClassUnicodeRange>>::new::<[regex_syntax::hir::ClassUnicodeRange; 2]>
Unexecuted instantiation: <regex_syntax::hir::interval::IntervalSet<regex_syntax::hir::ClassUnicodeRange>>::new::<[regex_syntax::hir::ClassUnicodeRange; 3]>
81
82
    /// Add a new interval to this set.
83
1.06M
    pub fn push(&mut self, mut interval: I) {
84
1.06M
        let Err(i) = self.ranges.binary_search(&interval) else {
85
            // Exact match, `interval` is already in the set.
86
226k
            return;
87
        };
88
89
        // The search finds us the first index where the previous interval
90
        // start is less than or equal to the new interval start. Since the
91
        // existing intervals are non-overlapping we only need to try to union
92
        // this single preceding interval
93
838k
        let mut start = i;
94
838k
        if let Some(before_i) = i.checked_sub(1) {
95
588k
            let before = &self.ranges[before_i];
96
588k
            if let Some(union) = before.union(&interval) {
97
125k
                interval = union;
98
125k
                start = before_i;
99
463k
            }
100
250k
        }
101
        // `interval` may overlap any number of intervals following the
102
        // insertion point so will union each of them until we reach the
103
        // first non-overlapping interval
104
838k
        let mut end = i;
105
838k
        for after_i in i..self.ranges.len() {
106
616k
            let after = &self.ranges[after_i];
107
616k
            let Some(union) = interval.union(after) else {
108
480k
                break;
109
            };
110
136k
            interval = union;
111
136k
            end = after_i + 1;
112
        }
113
838k
        self.ranges.splice(start..end, core::iter::once(interval));
114
115
        // We don't know whether the new interval added here is considered
116
        // case folded, so we conservatively assume that the entire set is
117
        // no longer case folded if it was previously.
118
838k
        self.folded = false;
119
1.06M
    }
<regex_syntax::hir::interval::IntervalSet<regex_syntax::hir::ClassBytesRange>>::push
Line
Count
Source
83
576k
    pub fn push(&mut self, mut interval: I) {
84
576k
        let Err(i) = self.ranges.binary_search(&interval) else {
85
            // Exact match, `interval` is already in the set.
86
141k
            return;
87
        };
88
89
        // The search finds us the first index where the previous interval
90
        // start is less than or equal to the new interval start. Since the
91
        // existing intervals are non-overlapping we only need to try to union
92
        // this single preceding interval
93
435k
        let mut start = i;
94
435k
        if let Some(before_i) = i.checked_sub(1) {
95
297k
            let before = &self.ranges[before_i];
96
297k
            if let Some(union) = before.union(&interval) {
97
49.6k
                interval = union;
98
49.6k
                start = before_i;
99
247k
            }
100
138k
        }
101
        // `interval` may overlap any number of intervals following the
102
        // insertion point so will union each of them until we reach the
103
        // first non-overlapping interval
104
435k
        let mut end = i;
105
435k
        for after_i in i..self.ranges.len() {
106
366k
            let after = &self.ranges[after_i];
107
366k
            let Some(union) = interval.union(after) else {
108
288k
                break;
109
            };
110
77.4k
            interval = union;
111
77.4k
            end = after_i + 1;
112
        }
113
435k
        self.ranges.splice(start..end, core::iter::once(interval));
114
115
        // We don't know whether the new interval added here is considered
116
        // case folded, so we conservatively assume that the entire set is
117
        // no longer case folded if it was previously.
118
435k
        self.folded = false;
119
576k
    }
<regex_syntax::hir::interval::IntervalSet<regex_syntax::hir::ClassUnicodeRange>>::push
Line
Count
Source
83
488k
    pub fn push(&mut self, mut interval: I) {
84
488k
        let Err(i) = self.ranges.binary_search(&interval) else {
85
            // Exact match, `interval` is already in the set.
86
85.0k
            return;
87
        };
88
89
        // The search finds us the first index where the previous interval
90
        // start is less than or equal to the new interval start. Since the
91
        // existing intervals are non-overlapping we only need to try to union
92
        // this single preceding interval
93
403k
        let mut start = i;
94
403k
        if let Some(before_i) = i.checked_sub(1) {
95
291k
            let before = &self.ranges[before_i];
96
291k
            if let Some(union) = before.union(&interval) {
97
75.8k
                interval = union;
98
75.8k
                start = before_i;
99
215k
            }
100
111k
        }
101
        // `interval` may overlap any number of intervals following the
102
        // insertion point so will union each of them until we reach the
103
        // first non-overlapping interval
104
403k
        let mut end = i;
105
403k
        for after_i in i..self.ranges.len() {
106
249k
            let after = &self.ranges[after_i];
107
249k
            let Some(union) = interval.union(after) else {
108
191k
                break;
109
            };
110
58.7k
            interval = union;
111
58.7k
            end = after_i + 1;
112
        }
113
403k
        self.ranges.splice(start..end, core::iter::once(interval));
114
115
        // We don't know whether the new interval added here is considered
116
        // case folded, so we conservatively assume that the entire set is
117
        // no longer case folded if it was previously.
118
403k
        self.folded = false;
119
488k
    }
120
121
    /// Return an iterator over all intervals in this set.
122
    ///
123
    /// The iterator yields intervals in ascending order.
124
10.4M
    pub fn iter(&self) -> IntervalSetIter<'_, I> {
125
10.4M
        IntervalSetIter(self.ranges.iter())
126
10.4M
    }
<regex_syntax::hir::interval::IntervalSet<regex_syntax::hir::ClassBytesRange>>::iter
Line
Count
Source
124
4.22M
    pub fn iter(&self) -> IntervalSetIter<'_, I> {
125
4.22M
        IntervalSetIter(self.ranges.iter())
126
4.22M
    }
<regex_syntax::hir::interval::IntervalSet<regex_syntax::hir::ClassUnicodeRange>>::iter
Line
Count
Source
124
6.24M
    pub fn iter(&self) -> IntervalSetIter<'_, I> {
125
6.24M
        IntervalSetIter(self.ranges.iter())
126
6.24M
    }
127
128
    /// Return an immutable slice of intervals in this set.
129
    ///
130
    /// The sequence returned is in canonical ordering.
131
17.9M
    pub fn intervals(&self) -> &[I] {
132
17.9M
        &self.ranges
133
17.9M
    }
<regex_syntax::hir::interval::IntervalSet<regex_syntax::hir::ClassBytesRange>>::intervals
Line
Count
Source
131
5.91M
    pub fn intervals(&self) -> &[I] {
132
5.91M
        &self.ranges
133
5.91M
    }
<regex_syntax::hir::interval::IntervalSet<regex_syntax::hir::ClassUnicodeRange>>::intervals
Line
Count
Source
131
11.9M
    pub fn intervals(&self) -> &[I] {
132
11.9M
        &self.ranges
133
11.9M
    }
134
135
    /// Expand this interval set such that it contains all case folded
136
    /// characters. For example, if this class consists of the range `a-z`,
137
    /// then applying case folding will result in the class containing both the
138
    /// ranges `a-z` and `A-Z`.
139
    ///
140
    /// This returns an error if the necessary case mapping data is not
141
    /// available.
142
749k
    pub fn case_fold_simple(&mut self) -> Result<(), unicode::CaseFoldError> {
143
749k
        if self.folded {
144
97.6k
            return Ok(());
145
652k
        }
146
652k
        let len = self.ranges.len();
147
5.10M
        for i in 0..len {
148
5.10M
            let range = self.ranges[i];
149
5.10M
            if let Err(err) = range.case_fold_simple(&mut self.ranges) {
150
0
                self.canonicalize();
151
0
                return Err(err);
152
5.10M
            }
153
        }
154
652k
        self.canonicalize();
155
652k
        self.folded = true;
156
652k
        Ok(())
157
749k
    }
<regex_syntax::hir::interval::IntervalSet<regex_syntax::hir::ClassBytesRange>>::case_fold_simple
Line
Count
Source
142
230k
    pub fn case_fold_simple(&mut self) -> Result<(), unicode::CaseFoldError> {
143
230k
        if self.folded {
144
63.3k
            return Ok(());
145
167k
        }
146
167k
        let len = self.ranges.len();
147
914k
        for i in 0..len {
148
914k
            let range = self.ranges[i];
149
914k
            if let Err(err) = range.case_fold_simple(&mut self.ranges) {
150
0
                self.canonicalize();
151
0
                return Err(err);
152
914k
            }
153
        }
154
167k
        self.canonicalize();
155
167k
        self.folded = true;
156
167k
        Ok(())
157
230k
    }
<regex_syntax::hir::interval::IntervalSet<regex_syntax::hir::ClassUnicodeRange>>::case_fold_simple
Line
Count
Source
142
519k
    pub fn case_fold_simple(&mut self) -> Result<(), unicode::CaseFoldError> {
143
519k
        if self.folded {
144
34.2k
            return Ok(());
145
485k
        }
146
485k
        let len = self.ranges.len();
147
4.19M
        for i in 0..len {
148
4.19M
            let range = self.ranges[i];
149
4.19M
            if let Err(err) = range.case_fold_simple(&mut self.ranges) {
150
0
                self.canonicalize();
151
0
                return Err(err);
152
4.19M
            }
153
        }
154
485k
        self.canonicalize();
155
485k
        self.folded = true;
156
485k
        Ok(())
157
519k
    }
158
159
    /// Union this set with the given set, in place.
160
612k
    pub fn union(&mut self, other: &IntervalSet<I>) {
161
612k
        if other.ranges.is_empty() || self.ranges == other.ranges {
162
126k
            return;
163
486k
        }
164
        // This could almost certainly be done more efficiently.
165
486k
        self.ranges.extend(&other.ranges);
166
486k
        self.canonicalize();
167
486k
        self.folded = self.folded && other.folded;
168
612k
    }
<regex_syntax::hir::interval::IntervalSet<regex_syntax::hir::ClassBytesRange>>::union
Line
Count
Source
160
191k
    pub fn union(&mut self, other: &IntervalSet<I>) {
161
191k
        if other.ranges.is_empty() || self.ranges == other.ranges {
162
46.6k
            return;
163
145k
        }
164
        // This could almost certainly be done more efficiently.
165
145k
        self.ranges.extend(&other.ranges);
166
145k
        self.canonicalize();
167
145k
        self.folded = self.folded && other.folded;
168
191k
    }
<regex_syntax::hir::interval::IntervalSet<regex_syntax::hir::ClassUnicodeRange>>::union
Line
Count
Source
160
420k
    pub fn union(&mut self, other: &IntervalSet<I>) {
161
420k
        if other.ranges.is_empty() || self.ranges == other.ranges {
162
79.8k
            return;
163
341k
        }
164
        // This could almost certainly be done more efficiently.
165
341k
        self.ranges.extend(&other.ranges);
166
341k
        self.canonicalize();
167
341k
        self.folded = self.folded && other.folded;
168
420k
    }
169
170
    /// Intersect this set with the given set, in place.
171
138k
    pub fn intersect(&mut self, other: &IntervalSet<I>) {
172
138k
        if self.ranges.is_empty() {
173
40.2k
            return;
174
98.4k
        }
175
98.4k
        if other.ranges.is_empty() {
176
13.6k
            self.ranges.clear();
177
            // An empty set is case folded.
178
13.6k
            self.folded = true;
179
13.6k
            return;
180
84.7k
        }
181
182
        // There should be a way to do this in-place with constant memory,
183
        // but I couldn't figure out a simple way to do it. So just append
184
        // the intersection to the end of this range, and then drain it before
185
        // we're done.
186
84.7k
        let drain_end = self.ranges.len();
187
188
84.7k
        let mut ita = 0..drain_end;
189
84.7k
        let mut itb = 0..other.ranges.len();
190
84.7k
        let mut a = ita.next().unwrap();
191
84.7k
        let mut b = itb.next().unwrap();
192
        loop {
193
5.37M
            if let Some(ab) = self.ranges[a].intersect(&other.ranges[b]) {
194
2.51M
                self.ranges.push(ab);
195
2.85M
            }
196
5.37M
            let (it, aorb) =
197
5.37M
                if self.ranges[a].upper() < other.ranges[b].upper() {
198
2.72M
                    (&mut ita, &mut a)
199
                } else {
200
2.65M
                    (&mut itb, &mut b)
201
                };
202
5.37M
            match it.next() {
203
5.29M
                Some(v) => *aorb = v,
204
84.7k
                None => break,
205
            }
206
        }
207
84.7k
        self.ranges.drain(..drain_end);
208
84.7k
        self.folded = self.folded && other.folded;
209
138k
    }
<regex_syntax::hir::interval::IntervalSet<regex_syntax::hir::ClassBytesRange>>::intersect
Line
Count
Source
171
52.0k
    pub fn intersect(&mut self, other: &IntervalSet<I>) {
172
52.0k
        if self.ranges.is_empty() {
173
18.3k
            return;
174
33.7k
        }
175
33.7k
        if other.ranges.is_empty() {
176
7.87k
            self.ranges.clear();
177
            // An empty set is case folded.
178
7.87k
            self.folded = true;
179
7.87k
            return;
180
25.8k
        }
181
182
        // There should be a way to do this in-place with constant memory,
183
        // but I couldn't figure out a simple way to do it. So just append
184
        // the intersection to the end of this range, and then drain it before
185
        // we're done.
186
25.8k
        let drain_end = self.ranges.len();
187
188
25.8k
        let mut ita = 0..drain_end;
189
25.8k
        let mut itb = 0..other.ranges.len();
190
25.8k
        let mut a = ita.next().unwrap();
191
25.8k
        let mut b = itb.next().unwrap();
192
        loop {
193
290k
            if let Some(ab) = self.ranges[a].intersect(&other.ranges[b]) {
194
112k
                self.ranges.push(ab);
195
178k
            }
196
290k
            let (it, aorb) =
197
290k
                if self.ranges[a].upper() < other.ranges[b].upper() {
198
175k
                    (&mut ita, &mut a)
199
                } else {
200
115k
                    (&mut itb, &mut b)
201
                };
202
290k
            match it.next() {
203
264k
                Some(v) => *aorb = v,
204
25.8k
                None => break,
205
            }
206
        }
207
25.8k
        self.ranges.drain(..drain_end);
208
25.8k
        self.folded = self.folded && other.folded;
209
52.0k
    }
<regex_syntax::hir::interval::IntervalSet<regex_syntax::hir::ClassUnicodeRange>>::intersect
Line
Count
Source
171
86.7k
    pub fn intersect(&mut self, other: &IntervalSet<I>) {
172
86.7k
        if self.ranges.is_empty() {
173
21.9k
            return;
174
64.7k
        }
175
64.7k
        if other.ranges.is_empty() {
176
5.79k
            self.ranges.clear();
177
            // An empty set is case folded.
178
5.79k
            self.folded = true;
179
5.79k
            return;
180
58.9k
        }
181
182
        // There should be a way to do this in-place with constant memory,
183
        // but I couldn't figure out a simple way to do it. So just append
184
        // the intersection to the end of this range, and then drain it before
185
        // we're done.
186
58.9k
        let drain_end = self.ranges.len();
187
188
58.9k
        let mut ita = 0..drain_end;
189
58.9k
        let mut itb = 0..other.ranges.len();
190
58.9k
        let mut a = ita.next().unwrap();
191
58.9k
        let mut b = itb.next().unwrap();
192
        loop {
193
5.08M
            if let Some(ab) = self.ranges[a].intersect(&other.ranges[b]) {
194
2.40M
                self.ranges.push(ab);
195
2.68M
            }
196
5.08M
            let (it, aorb) =
197
5.08M
                if self.ranges[a].upper() < other.ranges[b].upper() {
198
2.54M
                    (&mut ita, &mut a)
199
                } else {
200
2.53M
                    (&mut itb, &mut b)
201
                };
202
5.08M
            match it.next() {
203
5.02M
                Some(v) => *aorb = v,
204
58.9k
                None => break,
205
            }
206
        }
207
58.9k
        self.ranges.drain(..drain_end);
208
58.9k
        self.folded = self.folded && other.folded;
209
86.7k
    }
210
211
    /// Subtract the given set from this set, in place.
212
110k
    pub fn difference(&mut self, other: &IntervalSet<I>) {
213
110k
        if self.ranges.is_empty() || other.ranges.is_empty() {
214
63.0k
            return;
215
47.5k
        }
216
217
        // This algorithm is (to me) surprisingly complex. A search of the
218
        // interwebs indicate that this is a potentially interesting problem.
219
        // Folks seem to suggest interval or segment trees, but I'd like to
220
        // avoid the overhead (both runtime and conceptual) of that.
221
        //
222
        // The following is basically my Shitty First Draft. Therefore, in
223
        // order to grok it, you probably need to read each line carefully.
224
        // Simplifications are most welcome!
225
        //
226
        // Remember, we can assume the canonical format invariant here, which
227
        // says that all ranges are sorted, not overlapping and not adjacent in
228
        // each class.
229
47.5k
        let drain_end = self.ranges.len();
230
47.5k
        let (mut a, mut b) = (0, 0);
231
3.31M
        'LOOP: while a < drain_end && b < other.ranges.len() {
232
            // Basically, the easy cases are when neither range overlaps with
233
            // each other. If the `b` range is less than our current `a`
234
            // range, then we can skip it and move on.
235
3.26M
            if other.ranges[b].upper() < self.ranges[a].lower() {
236
1.20M
                b += 1;
237
1.20M
                continue;
238
2.06M
            }
239
            // ... similarly for the `a` range. If it's less than the smallest
240
            // `b` range, then we can add it as-is.
241
2.06M
            if self.ranges[a].upper() < other.ranges[b].lower() {
242
1.04M
                let range = self.ranges[a];
243
1.04M
                self.ranges.push(range);
244
1.04M
                a += 1;
245
1.04M
                continue;
246
1.01M
            }
247
            // Otherwise, we have overlapping ranges.
248
1.01M
            assert!(!self.ranges[a].is_intersection_empty(&other.ranges[b]));
249
250
            // This part is tricky and was non-obvious to me without looking
251
            // at explicit examples (see the tests). The trickiness stems from
252
            // two things: 1) subtracting a range from another range could
253
            // yield two ranges and 2) after subtracting a range, it's possible
254
            // that future ranges can have an impact. The loop below advances
255
            // the `b` ranges until they can't possible impact the current
256
            // range.
257
            //
258
            // For example, if our `a` range is `a-t` and our next three `b`
259
            // ranges are `a-c`, `g-i`, `r-t` and `x-z`, then we need to apply
260
            // subtraction three times before moving on to the next `a` range.
261
1.01M
            let mut range = self.ranges[a];
262
2.45M
            while b < other.ranges.len()
263
2.43M
                && !range.is_intersection_empty(&other.ranges[b])
264
            {
265
2.30M
                let old_range = range;
266
2.30M
                range = match range.difference(&other.ranges[b]) {
267
                    (None, None) => {
268
                        // We lost the entire range, so move on to the next
269
                        // without adding this one.
270
863k
                        a += 1;
271
863k
                        continue 'LOOP;
272
                    }
273
143k
                    (Some(range1), None) | (None, Some(range1)) => range1,
274
1.29M
                    (Some(range1), Some(range2)) => {
275
1.29M
                        self.ranges.push(range1);
276
1.29M
                        range2
277
                    }
278
                };
279
                // It's possible that the `b` range has more to contribute
280
                // here. In particular, if it is greater than the original
281
                // range, then it might impact the next `a` range *and* it
282
                // has impacted the current `a` range as much as possible,
283
                // so we can quit. We don't bump `b` so that the next `a`
284
                // range can apply it.
285
1.44M
                if other.ranges[b].upper() > old_range.upper() {
286
3.90k
                    break;
287
1.43M
                }
288
                // Otherwise, the next `b` range might apply to the current
289
                // `a` range.
290
1.43M
                b += 1;
291
            }
292
155k
            self.ranges.push(range);
293
155k
            a += 1;
294
        }
295
1.06M
        while a < drain_end {
296
1.01M
            let range = self.ranges[a];
297
1.01M
            self.ranges.push(range);
298
1.01M
            a += 1;
299
1.01M
        }
300
47.5k
        self.ranges.drain(..drain_end);
301
47.5k
        self.folded = self.folded && other.folded;
302
110k
    }
<regex_syntax::hir::interval::IntervalSet<regex_syntax::hir::ClassBytesRange>>::difference
Line
Count
Source
212
57.7k
    pub fn difference(&mut self, other: &IntervalSet<I>) {
213
57.7k
        if self.ranges.is_empty() || other.ranges.is_empty() {
214
30.4k
            return;
215
27.2k
        }
216
217
        // This algorithm is (to me) surprisingly complex. A search of the
218
        // interwebs indicate that this is a potentially interesting problem.
219
        // Folks seem to suggest interval or segment trees, but I'd like to
220
        // avoid the overhead (both runtime and conceptual) of that.
221
        //
222
        // The following is basically my Shitty First Draft. Therefore, in
223
        // order to grok it, you probably need to read each line carefully.
224
        // Simplifications are most welcome!
225
        //
226
        // Remember, we can assume the canonical format invariant here, which
227
        // says that all ranges are sorted, not overlapping and not adjacent in
228
        // each class.
229
27.2k
        let drain_end = self.ranges.len();
230
27.2k
        let (mut a, mut b) = (0, 0);
231
223k
        'LOOP: while a < drain_end && b < other.ranges.len() {
232
            // Basically, the easy cases are when neither range overlaps with
233
            // each other. If the `b` range is less than our current `a`
234
            // range, then we can skip it and move on.
235
195k
            if other.ranges[b].upper() < self.ranges[a].lower() {
236
34.9k
                b += 1;
237
34.9k
                continue;
238
160k
            }
239
            // ... similarly for the `a` range. If it's less than the smallest
240
            // `b` range, then we can add it as-is.
241
160k
            if self.ranges[a].upper() < other.ranges[b].lower() {
242
94.8k
                let range = self.ranges[a];
243
94.8k
                self.ranges.push(range);
244
94.8k
                a += 1;
245
94.8k
                continue;
246
65.9k
            }
247
            // Otherwise, we have overlapping ranges.
248
65.9k
            assert!(!self.ranges[a].is_intersection_empty(&other.ranges[b]));
249
250
            // This part is tricky and was non-obvious to me without looking
251
            // at explicit examples (see the tests). The trickiness stems from
252
            // two things: 1) subtracting a range from another range could
253
            // yield two ranges and 2) after subtracting a range, it's possible
254
            // that future ranges can have an impact. The loop below advances
255
            // the `b` ranges until they can't possible impact the current
256
            // range.
257
            //
258
            // For example, if our `a` range is `a-t` and our next three `b`
259
            // ranges are `a-c`, `g-i`, `r-t` and `x-z`, then we need to apply
260
            // subtraction three times before moving on to the next `a` range.
261
65.9k
            let mut range = self.ranges[a];
262
168k
            while b < other.ranges.len()
263
152k
                && !range.is_intersection_empty(&other.ranges[b])
264
            {
265
131k
                let old_range = range;
266
131k
                range = match range.difference(&other.ranges[b]) {
267
                    (None, None) => {
268
                        // We lost the entire range, so move on to the next
269
                        // without adding this one.
270
28.1k
                        a += 1;
271
28.1k
                        continue 'LOOP;
272
                    }
273
25.7k
                    (Some(range1), None) | (None, Some(range1)) => range1,
274
77.4k
                    (Some(range1), Some(range2)) => {
275
77.4k
                        self.ranges.push(range1);
276
77.4k
                        range2
277
                    }
278
                };
279
                // It's possible that the `b` range has more to contribute
280
                // here. In particular, if it is greater than the original
281
                // range, then it might impact the next `a` range *and* it
282
                // has impacted the current `a` range as much as possible,
283
                // so we can quit. We don't bump `b` so that the next `a`
284
                // range can apply it.
285
103k
                if other.ranges[b].upper() > old_range.upper() {
286
622
                    break;
287
102k
                }
288
                // Otherwise, the next `b` range might apply to the current
289
                // `a` range.
290
102k
                b += 1;
291
            }
292
37.8k
            self.ranges.push(range);
293
37.8k
            a += 1;
294
        }
295
62.3k
        while a < drain_end {
296
35.0k
            let range = self.ranges[a];
297
35.0k
            self.ranges.push(range);
298
35.0k
            a += 1;
299
35.0k
        }
300
27.2k
        self.ranges.drain(..drain_end);
301
27.2k
        self.folded = self.folded && other.folded;
302
57.7k
    }
<regex_syntax::hir::interval::IntervalSet<regex_syntax::hir::ClassUnicodeRange>>::difference
Line
Count
Source
212
52.8k
    pub fn difference(&mut self, other: &IntervalSet<I>) {
213
52.8k
        if self.ranges.is_empty() || other.ranges.is_empty() {
214
32.6k
            return;
215
20.2k
        }
216
217
        // This algorithm is (to me) surprisingly complex. A search of the
218
        // interwebs indicate that this is a potentially interesting problem.
219
        // Folks seem to suggest interval or segment trees, but I'd like to
220
        // avoid the overhead (both runtime and conceptual) of that.
221
        //
222
        // The following is basically my Shitty First Draft. Therefore, in
223
        // order to grok it, you probably need to read each line carefully.
224
        // Simplifications are most welcome!
225
        //
226
        // Remember, we can assume the canonical format invariant here, which
227
        // says that all ranges are sorted, not overlapping and not adjacent in
228
        // each class.
229
20.2k
        let drain_end = self.ranges.len();
230
20.2k
        let (mut a, mut b) = (0, 0);
231
3.08M
        'LOOP: while a < drain_end && b < other.ranges.len() {
232
            // Basically, the easy cases are when neither range overlaps with
233
            // each other. If the `b` range is less than our current `a`
234
            // range, then we can skip it and move on.
235
3.06M
            if other.ranges[b].upper() < self.ranges[a].lower() {
236
1.16M
                b += 1;
237
1.16M
                continue;
238
1.90M
            }
239
            // ... similarly for the `a` range. If it's less than the smallest
240
            // `b` range, then we can add it as-is.
241
1.90M
            if self.ranges[a].upper() < other.ranges[b].lower() {
242
948k
                let range = self.ranges[a];
243
948k
                self.ranges.push(range);
244
948k
                a += 1;
245
948k
                continue;
246
952k
            }
247
            // Otherwise, we have overlapping ranges.
248
952k
            assert!(!self.ranges[a].is_intersection_empty(&other.ranges[b]));
249
250
            // This part is tricky and was non-obvious to me without looking
251
            // at explicit examples (see the tests). The trickiness stems from
252
            // two things: 1) subtracting a range from another range could
253
            // yield two ranges and 2) after subtracting a range, it's possible
254
            // that future ranges can have an impact. The loop below advances
255
            // the `b` ranges until they can't possible impact the current
256
            // range.
257
            //
258
            // For example, if our `a` range is `a-t` and our next three `b`
259
            // ranges are `a-c`, `g-i`, `r-t` and `x-z`, then we need to apply
260
            // subtraction three times before moving on to the next `a` range.
261
952k
            let mut range = self.ranges[a];
262
2.28M
            while b < other.ranges.len()
263
2.28M
                && !range.is_intersection_empty(&other.ranges[b])
264
            {
265
2.17M
                let old_range = range;
266
2.17M
                range = match range.difference(&other.ranges[b]) {
267
                    (None, None) => {
268
                        // We lost the entire range, so move on to the next
269
                        // without adding this one.
270
835k
                        a += 1;
271
835k
                        continue 'LOOP;
272
                    }
273
117k
                    (Some(range1), None) | (None, Some(range1)) => range1,
274
1.22M
                    (Some(range1), Some(range2)) => {
275
1.22M
                        self.ranges.push(range1);
276
1.22M
                        range2
277
                    }
278
                };
279
                // It's possible that the `b` range has more to contribute
280
                // here. In particular, if it is greater than the original
281
                // range, then it might impact the next `a` range *and* it
282
                // has impacted the current `a` range as much as possible,
283
                // so we can quit. We don't bump `b` so that the next `a`
284
                // range can apply it.
285
1.33M
                if other.ranges[b].upper() > old_range.upper() {
286
3.28k
                    break;
287
1.33M
                }
288
                // Otherwise, the next `b` range might apply to the current
289
                // `a` range.
290
1.33M
                b += 1;
291
            }
292
117k
            self.ranges.push(range);
293
117k
            a += 1;
294
        }
295
998k
        while a < drain_end {
296
978k
            let range = self.ranges[a];
297
978k
            self.ranges.push(range);
298
978k
            a += 1;
299
978k
        }
300
20.2k
        self.ranges.drain(..drain_end);
301
20.2k
        self.folded = self.folded && other.folded;
302
52.8k
    }
303
304
    /// Compute the symmetric difference of the two sets, in place.
305
    ///
306
    /// This computes the symmetric difference of two interval sets. This
307
    /// removes all elements in this set that are also in the given set,
308
    /// but also adds all elements from the given set that aren't in this
309
    /// set. That is, the set will contain all elements in either set,
310
    /// but will not contain any elements that are in both sets.
311
68.1k
    pub fn symmetric_difference(&mut self, other: &IntervalSet<I>) {
312
        // TODO(burntsushi): Fix this so that it amortizes allocation.
313
68.1k
        let mut intersection = self.clone();
314
68.1k
        intersection.intersect(other);
315
68.1k
        self.union(other);
316
68.1k
        self.difference(&intersection);
317
68.1k
    }
<regex_syntax::hir::interval::IntervalSet<regex_syntax::hir::ClassBytesRange>>::symmetric_difference
Line
Count
Source
311
39.0k
    pub fn symmetric_difference(&mut self, other: &IntervalSet<I>) {
312
        // TODO(burntsushi): Fix this so that it amortizes allocation.
313
39.0k
        let mut intersection = self.clone();
314
39.0k
        intersection.intersect(other);
315
39.0k
        self.union(other);
316
39.0k
        self.difference(&intersection);
317
39.0k
    }
<regex_syntax::hir::interval::IntervalSet<regex_syntax::hir::ClassUnicodeRange>>::symmetric_difference
Line
Count
Source
311
29.1k
    pub fn symmetric_difference(&mut self, other: &IntervalSet<I>) {
312
        // TODO(burntsushi): Fix this so that it amortizes allocation.
313
29.1k
        let mut intersection = self.clone();
314
29.1k
        intersection.intersect(other);
315
29.1k
        self.union(other);
316
29.1k
        self.difference(&intersection);
317
29.1k
    }
318
319
    /// Negate this interval set.
320
    ///
321
    /// For all `x` where `x` is any element, if `x` was in this set, then it
322
    /// will not be in this set after negation.
323
236k
    pub fn negate(&mut self) {
324
236k
        if self.ranges.is_empty() {
325
5.74k
            let (min, max) = (I::Bound::min_value(), I::Bound::max_value());
326
5.74k
            self.ranges.push(I::create(min, max));
327
            // The set containing everything must case folded.
328
5.74k
            self.folded = true;
329
5.74k
            return;
330
230k
        }
331
332
        // There should be a way to do this in-place with constant memory,
333
        // but I couldn't figure out a simple way to do it. So just append
334
        // the negation to the end of this range, and then drain it before
335
        // we're done.
336
230k
        let drain_end = self.ranges.len();
337
338
        // We do checked arithmetic below because of the canonical ordering
339
        // invariant.
340
230k
        if self.ranges[0].lower() > I::Bound::min_value() {
341
192k
            let upper = self.ranges[0].lower().decrement();
342
192k
            self.ranges.push(I::create(I::Bound::min_value(), upper));
343
192k
        }
344
15.9M
        for i in 1..drain_end {
345
15.9M
            let lower = self.ranges[i - 1].upper().increment();
346
15.9M
            let upper = self.ranges[i].lower().decrement();
347
15.9M
            self.ranges.push(I::create(lower, upper));
348
15.9M
        }
349
230k
        if self.ranges[drain_end - 1].upper() < I::Bound::max_value() {
350
195k
            let lower = self.ranges[drain_end - 1].upper().increment();
351
195k
            self.ranges.push(I::create(lower, I::Bound::max_value()));
352
195k
        }
353
230k
        self.ranges.drain(..drain_end);
354
        // We don't need to update whether this set is folded or not, because
355
        // it is conservatively preserved through negation. Namely, if a set
356
        // is not folded, then it is possible that its negation is folded, for
357
        // example, [^☃]. But we're fine with assuming that the set is not
358
        // folded in that case. (`folded` permits false negatives but not false
359
        // positives.)
360
        //
361
        // But what about when a set is folded, is its negation also
362
        // necessarily folded? Yes. Because if a set is folded, then for every
363
        // character in the set, it necessarily included its equivalence class
364
        // of case folded characters. Negating it in turn means that all
365
        // equivalence classes in the set are negated, and any equivalence
366
        // class that was previously not in the set is now entirely in the set.
367
236k
    }
<regex_syntax::hir::interval::IntervalSet<regex_syntax::hir::ClassBytesRange>>::negate
Line
Count
Source
323
26.4k
    pub fn negate(&mut self) {
324
26.4k
        if self.ranges.is_empty() {
325
1.00k
            let (min, max) = (I::Bound::min_value(), I::Bound::max_value());
326
1.00k
            self.ranges.push(I::create(min, max));
327
            // The set containing everything must case folded.
328
1.00k
            self.folded = true;
329
1.00k
            return;
330
25.4k
        }
331
332
        // There should be a way to do this in-place with constant memory,
333
        // but I couldn't figure out a simple way to do it. So just append
334
        // the negation to the end of this range, and then drain it before
335
        // we're done.
336
25.4k
        let drain_end = self.ranges.len();
337
338
        // We do checked arithmetic below because of the canonical ordering
339
        // invariant.
340
25.4k
        if self.ranges[0].lower() > I::Bound::min_value() {
341
22.2k
            let upper = self.ranges[0].lower().decrement();
342
22.2k
            self.ranges.push(I::create(I::Bound::min_value(), upper));
343
22.2k
        }
344
38.7k
        for i in 1..drain_end {
345
38.7k
            let lower = self.ranges[i - 1].upper().increment();
346
38.7k
            let upper = self.ranges[i].lower().decrement();
347
38.7k
            self.ranges.push(I::create(lower, upper));
348
38.7k
        }
349
25.4k
        if self.ranges[drain_end - 1].upper() < I::Bound::max_value() {
350
22.6k
            let lower = self.ranges[drain_end - 1].upper().increment();
351
22.6k
            self.ranges.push(I::create(lower, I::Bound::max_value()));
352
22.6k
        }
353
25.4k
        self.ranges.drain(..drain_end);
354
        // We don't need to update whether this set is folded or not, because
355
        // it is conservatively preserved through negation. Namely, if a set
356
        // is not folded, then it is possible that its negation is folded, for
357
        // example, [^☃]. But we're fine with assuming that the set is not
358
        // folded in that case. (`folded` permits false negatives but not false
359
        // positives.)
360
        //
361
        // But what about when a set is folded, is its negation also
362
        // necessarily folded? Yes. Because if a set is folded, then for every
363
        // character in the set, it necessarily included its equivalence class
364
        // of case folded characters. Negating it in turn means that all
365
        // equivalence classes in the set are negated, and any equivalence
366
        // class that was previously not in the set is now entirely in the set.
367
26.4k
    }
<regex_syntax::hir::interval::IntervalSet<regex_syntax::hir::ClassUnicodeRange>>::negate
Line
Count
Source
323
210k
    pub fn negate(&mut self) {
324
210k
        if self.ranges.is_empty() {
325
4.74k
            let (min, max) = (I::Bound::min_value(), I::Bound::max_value());
326
4.74k
            self.ranges.push(I::create(min, max));
327
            // The set containing everything must case folded.
328
4.74k
            self.folded = true;
329
4.74k
            return;
330
205k
        }
331
332
        // There should be a way to do this in-place with constant memory,
333
        // but I couldn't figure out a simple way to do it. So just append
334
        // the negation to the end of this range, and then drain it before
335
        // we're done.
336
205k
        let drain_end = self.ranges.len();
337
338
        // We do checked arithmetic below because of the canonical ordering
339
        // invariant.
340
205k
        if self.ranges[0].lower() > I::Bound::min_value() {
341
170k
            let upper = self.ranges[0].lower().decrement();
342
170k
            self.ranges.push(I::create(I::Bound::min_value(), upper));
343
170k
        }
344
15.9M
        for i in 1..drain_end {
345
15.9M
            let lower = self.ranges[i - 1].upper().increment();
346
15.9M
            let upper = self.ranges[i].lower().decrement();
347
15.9M
            self.ranges.push(I::create(lower, upper));
348
15.9M
        }
349
205k
        if self.ranges[drain_end - 1].upper() < I::Bound::max_value() {
350
172k
            let lower = self.ranges[drain_end - 1].upper().increment();
351
172k
            self.ranges.push(I::create(lower, I::Bound::max_value()));
352
172k
        }
353
205k
        self.ranges.drain(..drain_end);
354
        // We don't need to update whether this set is folded or not, because
355
        // it is conservatively preserved through negation. Namely, if a set
356
        // is not folded, then it is possible that its negation is folded, for
357
        // example, [^☃]. But we're fine with assuming that the set is not
358
        // folded in that case. (`folded` permits false negatives but not false
359
        // positives.)
360
        //
361
        // But what about when a set is folded, is its negation also
362
        // necessarily folded? Yes. Because if a set is folded, then for every
363
        // character in the set, it necessarily included its equivalence class
364
        // of case folded characters. Negating it in turn means that all
365
        // equivalence classes in the set are negated, and any equivalence
366
        // class that was previously not in the set is now entirely in the set.
367
210k
    }
368
369
    /// Converts this set into a canonical ordering.
370
2.88M
    fn canonicalize(&mut self) {
371
2.88M
        if self.is_canonical() {
372
2.02M
            return;
373
863k
        }
374
863k
        self.ranges.sort();
375
863k
        assert!(!self.ranges.is_empty());
376
377
        // Is there a way to do this in-place with constant memory? I couldn't
378
        // figure out a way to do it. So just append the canonicalization to
379
        // the end of this range, and then drain it before we're done.
380
863k
        let drain_end = self.ranges.len();
381
113M
        for oldi in 0..drain_end {
382
            // If we've added at least one new range, then check if we can
383
            // merge this range in the previously added range.
384
113M
            if self.ranges.len() > drain_end {
385
113M
                let (last, rest) = self.ranges.split_last_mut().unwrap();
386
113M
                if let Some(union) = last.union(&rest[oldi]) {
387
32.7M
                    *last = union;
388
32.7M
                    continue;
389
80.2M
                }
390
863k
            }
391
81.1M
            let range = self.ranges[oldi];
392
81.1M
            self.ranges.push(range);
393
        }
394
863k
        self.ranges.drain(..drain_end);
395
2.88M
    }
<regex_syntax::hir::interval::IntervalSet<regex_syntax::hir::ClassBytesRange>>::canonicalize
Line
Count
Source
370
754k
    fn canonicalize(&mut self) {
371
754k
        if self.is_canonical() {
372
551k
            return;
373
203k
        }
374
203k
        self.ranges.sort();
375
203k
        assert!(!self.ranges.is_empty());
376
377
        // Is there a way to do this in-place with constant memory? I couldn't
378
        // figure out a way to do it. So just append the canonicalization to
379
        // the end of this range, and then drain it before we're done.
380
203k
        let drain_end = self.ranges.len();
381
2.69M
        for oldi in 0..drain_end {
382
            // If we've added at least one new range, then check if we can
383
            // merge this range in the previously added range.
384
2.69M
            if self.ranges.len() > drain_end {
385
2.49M
                let (last, rest) = self.ranges.split_last_mut().unwrap();
386
2.49M
                if let Some(union) = last.union(&rest[oldi]) {
387
725k
                    *last = union;
388
725k
                    continue;
389
1.76M
                }
390
203k
            }
391
1.96M
            let range = self.ranges[oldi];
392
1.96M
            self.ranges.push(range);
393
        }
394
203k
        self.ranges.drain(..drain_end);
395
754k
    }
<regex_syntax::hir::interval::IntervalSet<regex_syntax::hir::ClassUnicodeRange>>::canonicalize
Line
Count
Source
370
1.98M
    fn canonicalize(&mut self) {
371
1.98M
        if self.is_canonical() {
372
1.32M
            return;
373
659k
        }
374
659k
        self.ranges.sort();
375
659k
        assert!(!self.ranges.is_empty());
376
377
        // Is there a way to do this in-place with constant memory? I couldn't
378
        // figure out a way to do it. So just append the canonicalization to
379
        // the end of this range, and then drain it before we're done.
380
659k
        let drain_end = self.ranges.len();
381
111M
        for oldi in 0..drain_end {
382
            // If we've added at least one new range, then check if we can
383
            // merge this range in the previously added range.
384
111M
            if self.ranges.len() > drain_end {
385
110M
                let (last, rest) = self.ranges.split_last_mut().unwrap();
386
110M
                if let Some(union) = last.union(&rest[oldi]) {
387
32.0M
                    *last = union;
388
32.0M
                    continue;
389
78.5M
                }
390
659k
            }
391
79.1M
            let range = self.ranges[oldi];
392
79.1M
            self.ranges.push(range);
393
        }
394
659k
        self.ranges.drain(..drain_end);
395
1.98M
    }
<regex_syntax::hir::interval::IntervalSet<regex_syntax::hir::ClassBytesRange>>::canonicalize
Line
Count
Source
370
143k
    fn canonicalize(&mut self) {
371
143k
        if self.is_canonical() {
372
143k
            return;
373
0
        }
374
0
        self.ranges.sort();
375
0
        assert!(!self.ranges.is_empty());
376
377
        // Is there a way to do this in-place with constant memory? I couldn't
378
        // figure out a way to do it. So just append the canonicalization to
379
        // the end of this range, and then drain it before we're done.
380
0
        let drain_end = self.ranges.len();
381
0
        for oldi in 0..drain_end {
382
            // If we've added at least one new range, then check if we can
383
            // merge this range in the previously added range.
384
0
            if self.ranges.len() > drain_end {
385
0
                let (last, rest) = self.ranges.split_last_mut().unwrap();
386
0
                if let Some(union) = last.union(&rest[oldi]) {
387
0
                    *last = union;
388
0
                    continue;
389
0
                }
390
0
            }
391
0
            let range = self.ranges[oldi];
392
0
            self.ranges.push(range);
393
        }
394
0
        self.ranges.drain(..drain_end);
395
143k
    }
Unexecuted instantiation: <regex_syntax::hir::interval::IntervalSet<regex_syntax::hir::ClassUnicodeRange>>::canonicalize
396
397
    /// Returns true if and only if this class is in a canonical ordering.
398
2.88M
    fn is_canonical(&self) -> bool {
399
119M
        for pair in self.ranges.windows(2) {
400
119M
            if pair[0] >= pair[1] {
401
823k
                return false;
402
118M
            }
403
118M
            if pair[0].is_contiguous(&pair[1]) {
404
39.4k
                return false;
405
118M
            }
406
        }
407
2.02M
        true
408
2.88M
    }
<regex_syntax::hir::interval::IntervalSet<regex_syntax::hir::ClassBytesRange>>::is_canonical
Line
Count
Source
398
754k
    fn is_canonical(&self) -> bool {
399
2.05M
        for pair in self.ranges.windows(2) {
400
2.05M
            if pair[0] >= pair[1] {
401
184k
                return false;
402
1.87M
            }
403
1.87M
            if pair[0].is_contiguous(&pair[1]) {
404
18.4k
                return false;
405
1.85M
            }
406
        }
407
551k
        true
408
754k
    }
<regex_syntax::hir::interval::IntervalSet<regex_syntax::hir::ClassUnicodeRange>>::is_canonical
Line
Count
Source
398
1.98M
    fn is_canonical(&self) -> bool {
399
117M
        for pair in self.ranges.windows(2) {
400
117M
            if pair[0] >= pair[1] {
401
638k
                return false;
402
117M
            }
403
117M
            if pair[0].is_contiguous(&pair[1]) {
404
21.0k
                return false;
405
117M
            }
406
        }
407
1.32M
        true
408
1.98M
    }
<regex_syntax::hir::interval::IntervalSet<regex_syntax::hir::ClassBytesRange>>::is_canonical
Line
Count
Source
398
143k
    fn is_canonical(&self) -> bool {
399
143k
        for pair in self.ranges.windows(2) {
400
0
            if pair[0] >= pair[1] {
401
0
                return false;
402
0
            }
403
0
            if pair[0].is_contiguous(&pair[1]) {
404
0
                return false;
405
0
            }
406
        }
407
143k
        true
408
143k
    }
Unexecuted instantiation: <regex_syntax::hir::interval::IntervalSet<regex_syntax::hir::ClassUnicodeRange>>::is_canonical
409
}
410
411
/// An iterator over intervals.
412
#[derive(Debug)]
413
pub struct IntervalSetIter<'a, I>(slice::Iter<'a, I>);
414
415
impl<'a, I> Iterator for IntervalSetIter<'a, I> {
416
    type Item = &'a I;
417
418
65.1M
    fn next(&mut self) -> Option<&'a I> {
419
65.1M
        self.0.next()
420
65.1M
    }
<regex_syntax::hir::interval::IntervalSetIter<regex_syntax::hir::ClassBytesRange> as core::iter::traits::iterator::Iterator>::next
Line
Count
Source
418
10.6M
    fn next(&mut self) -> Option<&'a I> {
419
10.6M
        self.0.next()
420
10.6M
    }
<regex_syntax::hir::interval::IntervalSetIter<regex_syntax::hir::ClassUnicodeRange> as core::iter::traits::iterator::Iterator>::next
Line
Count
Source
418
54.4M
    fn next(&mut self) -> Option<&'a I> {
419
54.4M
        self.0.next()
420
54.4M
    }
421
}
422
423
pub trait Interval:
424
    Clone + Copy + Debug + Default + Eq + PartialEq + PartialOrd + Ord
425
{
426
    type Bound: Bound;
427
428
    fn lower(&self) -> Self::Bound;
429
    fn upper(&self) -> Self::Bound;
430
    fn set_lower(&mut self, bound: Self::Bound);
431
    fn set_upper(&mut self, bound: Self::Bound);
432
    fn case_fold_simple(
433
        &self,
434
        intervals: &mut Vec<Self>,
435
    ) -> Result<(), unicode::CaseFoldError>;
436
437
    /// Create a new interval.
438
104M
    fn create(lower: Self::Bound, upper: Self::Bound) -> Self {
439
104M
        let mut int = Self::default();
440
104M
        if lower <= upper {
441
104M
            int.set_lower(lower);
442
104M
            int.set_upper(upper);
443
104M
        } else {
444
89
            int.set_lower(upper);
445
89
            int.set_upper(lower);
446
89
        }
447
104M
        int
448
104M
    }
<regex_syntax::hir::ClassBytesRange as regex_syntax::hir::interval::Interval>::create
Line
Count
Source
438
4.60M
    fn create(lower: Self::Bound, upper: Self::Bound) -> Self {
439
4.60M
        let mut int = Self::default();
440
4.60M
        if lower <= upper {
441
4.60M
            int.set_lower(lower);
442
4.60M
            int.set_upper(upper);
443
4.60M
        } else {
444
0
            int.set_lower(upper);
445
0
            int.set_upper(lower);
446
0
        }
447
4.60M
        int
448
4.60M
    }
<regex_syntax::hir::ClassUnicodeRange as regex_syntax::hir::interval::Interval>::create
Line
Count
Source
438
100M
    fn create(lower: Self::Bound, upper: Self::Bound) -> Self {
439
100M
        let mut int = Self::default();
440
100M
        if lower <= upper {
441
100M
            int.set_lower(lower);
442
100M
            int.set_upper(upper);
443
100M
        } else {
444
89
            int.set_lower(upper);
445
89
            int.set_upper(lower);
446
89
        }
447
100M
        int
448
100M
    }
Unexecuted instantiation: <regex_syntax::hir::ClassBytesRange as regex_syntax::hir::interval::Interval>::create
Unexecuted instantiation: <regex_syntax::hir::ClassUnicodeRange as regex_syntax::hir::interval::Interval>::create
449
450
    /// Union the given overlapping range into this range.
451
    ///
452
    /// If the two ranges aren't contiguous, then this returns `None`.
453
114M
    fn union(&self, other: &Self) -> Option<Self> {
454
114M
        if !self.is_contiguous(other) {
455
81.2M
            return None;
456
32.9M
        }
457
32.9M
        let lower = cmp::min(self.lower(), other.lower());
458
32.9M
        let upper = cmp::max(self.upper(), other.upper());
459
32.9M
        Some(Self::create(lower, upper))
460
114M
    }
<regex_syntax::hir::ClassBytesRange as regex_syntax::hir::interval::Interval>::union
Line
Count
Source
453
3.15M
    fn union(&self, other: &Self) -> Option<Self> {
454
3.15M
        if !self.is_contiguous(other) {
455
2.30M
            return None;
456
852k
        }
457
852k
        let lower = cmp::min(self.lower(), other.lower());
458
852k
        let upper = cmp::max(self.upper(), other.upper());
459
852k
        Some(Self::create(lower, upper))
460
3.15M
    }
<regex_syntax::hir::ClassUnicodeRange as regex_syntax::hir::interval::Interval>::union
Line
Count
Source
453
111M
    fn union(&self, other: &Self) -> Option<Self> {
454
111M
        if !self.is_contiguous(other) {
455
78.9M
            return None;
456
32.1M
        }
457
32.1M
        let lower = cmp::min(self.lower(), other.lower());
458
32.1M
        let upper = cmp::max(self.upper(), other.upper());
459
32.1M
        Some(Self::create(lower, upper))
460
111M
    }
Unexecuted instantiation: <regex_syntax::hir::ClassBytesRange as regex_syntax::hir::interval::Interval>::union
Unexecuted instantiation: <regex_syntax::hir::ClassUnicodeRange as regex_syntax::hir::interval::Interval>::union
461
462
    /// Intersect this range with the given range and return the result.
463
    ///
464
    /// If the intersection is empty, then this returns `None`.
465
5.37M
    fn intersect(&self, other: &Self) -> Option<Self> {
466
5.37M
        let lower = cmp::max(self.lower(), other.lower());
467
5.37M
        let upper = cmp::min(self.upper(), other.upper());
468
5.37M
        if lower <= upper {
469
2.51M
            Some(Self::create(lower, upper))
470
        } else {
471
2.85M
            None
472
        }
473
5.37M
    }
<regex_syntax::hir::ClassBytesRange as regex_syntax::hir::interval::Interval>::intersect
Line
Count
Source
465
290k
    fn intersect(&self, other: &Self) -> Option<Self> {
466
290k
        let lower = cmp::max(self.lower(), other.lower());
467
290k
        let upper = cmp::min(self.upper(), other.upper());
468
290k
        if lower <= upper {
469
112k
            Some(Self::create(lower, upper))
470
        } else {
471
178k
            None
472
        }
473
290k
    }
<regex_syntax::hir::ClassUnicodeRange as regex_syntax::hir::interval::Interval>::intersect
Line
Count
Source
465
5.08M
    fn intersect(&self, other: &Self) -> Option<Self> {
466
5.08M
        let lower = cmp::max(self.lower(), other.lower());
467
5.08M
        let upper = cmp::min(self.upper(), other.upper());
468
5.08M
        if lower <= upper {
469
2.40M
            Some(Self::create(lower, upper))
470
        } else {
471
2.68M
            None
472
        }
473
5.08M
    }
474
475
    /// Subtract the given range from this range and return the resulting
476
    /// ranges.
477
    ///
478
    /// If subtraction would result in an empty range, then no ranges are
479
    /// returned.
480
2.30M
    fn difference(&self, other: &Self) -> (Option<Self>, Option<Self>) {
481
2.30M
        if self.is_subset(other) {
482
863k
            return (None, None);
483
1.44M
        }
484
1.44M
        if self.is_intersection_empty(other) {
485
0
            return (Some(self.clone()), None);
486
1.44M
        }
487
1.44M
        let add_lower = other.lower() > self.lower();
488
1.44M
        let add_upper = other.upper() < self.upper();
489
        // We know this because !self.is_subset(other) and the ranges have
490
        // a non-empty intersection.
491
1.44M
        assert!(add_lower || add_upper);
492
1.44M
        let mut ret = (None, None);
493
1.44M
        if add_lower {
494
1.37M
            let upper = other.lower().decrement();
495
1.37M
            ret.0 = Some(Self::create(self.lower(), upper));
496
1.37M
        }
497
1.44M
        if add_upper {
498
1.37M
            let lower = other.upper().increment();
499
1.37M
            let range = Self::create(lower, self.upper());
500
1.37M
            if ret.0.is_none() {
501
72.3k
                ret.0 = Some(range);
502
1.29M
            } else {
503
1.29M
                ret.1 = Some(range);
504
1.29M
            }
505
71.1k
        }
506
1.44M
        ret
507
2.30M
    }
<regex_syntax::hir::ClassBytesRange as regex_syntax::hir::interval::Interval>::difference
Line
Count
Source
480
131k
    fn difference(&self, other: &Self) -> (Option<Self>, Option<Self>) {
481
131k
        if self.is_subset(other) {
482
28.1k
            return (None, None);
483
103k
        }
484
103k
        if self.is_intersection_empty(other) {
485
0
            return (Some(self.clone()), None);
486
103k
        }
487
103k
        let add_lower = other.lower() > self.lower();
488
103k
        let add_upper = other.upper() < self.upper();
489
        // We know this because !self.is_subset(other) and the ranges have
490
        // a non-empty intersection.
491
103k
        assert!(add_lower || add_upper);
492
103k
        let mut ret = (None, None);
493
103k
        if add_lower {
494
89.7k
            let upper = other.lower().decrement();
495
89.7k
            ret.0 = Some(Self::create(self.lower(), upper));
496
89.7k
        }
497
103k
        if add_upper {
498
90.9k
            let lower = other.upper().increment();
499
90.9k
            let range = Self::create(lower, self.upper());
500
90.9k
            if ret.0.is_none() {
501
13.4k
                ret.0 = Some(range);
502
77.4k
            } else {
503
77.4k
                ret.1 = Some(range);
504
77.4k
            }
505
12.2k
        }
506
103k
        ret
507
131k
    }
<regex_syntax::hir::ClassUnicodeRange as regex_syntax::hir::interval::Interval>::difference
Line
Count
Source
480
2.17M
    fn difference(&self, other: &Self) -> (Option<Self>, Option<Self>) {
481
2.17M
        if self.is_subset(other) {
482
835k
            return (None, None);
483
1.33M
        }
484
1.33M
        if self.is_intersection_empty(other) {
485
0
            return (Some(self.clone()), None);
486
1.33M
        }
487
1.33M
        let add_lower = other.lower() > self.lower();
488
1.33M
        let add_upper = other.upper() < self.upper();
489
        // We know this because !self.is_subset(other) and the ranges have
490
        // a non-empty intersection.
491
1.33M
        assert!(add_lower || add_upper);
492
1.33M
        let mut ret = (None, None);
493
1.33M
        if add_lower {
494
1.28M
            let upper = other.lower().decrement();
495
1.28M
            ret.0 = Some(Self::create(self.lower(), upper));
496
1.28M
        }
497
1.33M
        if add_upper {
498
1.28M
            let lower = other.upper().increment();
499
1.28M
            let range = Self::create(lower, self.upper());
500
1.28M
            if ret.0.is_none() {
501
58.8k
                ret.0 = Some(range);
502
1.22M
            } else {
503
1.22M
                ret.1 = Some(range);
504
1.22M
            }
505
58.9k
        }
506
1.33M
        ret
507
2.17M
    }
508
509
    /// Returns true if and only if the two ranges are contiguous. Two ranges
510
    /// are contiguous if and only if the ranges are either overlapping or
511
    /// adjacent.
512
233M
    fn is_contiguous(&self, other: &Self) -> bool {
513
233M
        let lower1 = self.lower().as_u32();
514
233M
        let upper1 = self.upper().as_u32();
515
233M
        let lower2 = other.lower().as_u32();
516
233M
        let upper2 = other.upper().as_u32();
517
233M
        cmp::max(lower1, lower2) <= cmp::min(upper1, upper2).saturating_add(1)
518
233M
    }
<regex_syntax::hir::ClassBytesRange as regex_syntax::hir::interval::Interval>::is_contiguous
Line
Count
Source
512
5.02M
    fn is_contiguous(&self, other: &Self) -> bool {
513
5.02M
        let lower1 = self.lower().as_u32();
514
5.02M
        let upper1 = self.upper().as_u32();
515
5.02M
        let lower2 = other.lower().as_u32();
516
5.02M
        let upper2 = other.upper().as_u32();
517
5.02M
        cmp::max(lower1, lower2) <= cmp::min(upper1, upper2).saturating_add(1)
518
5.02M
    }
<regex_syntax::hir::ClassUnicodeRange as regex_syntax::hir::interval::Interval>::is_contiguous
Line
Count
Source
512
228M
    fn is_contiguous(&self, other: &Self) -> bool {
513
228M
        let lower1 = self.lower().as_u32();
514
228M
        let upper1 = self.upper().as_u32();
515
228M
        let lower2 = other.lower().as_u32();
516
228M
        let upper2 = other.upper().as_u32();
517
228M
        cmp::max(lower1, lower2) <= cmp::min(upper1, upper2).saturating_add(1)
518
228M
    }
Unexecuted instantiation: <regex_syntax::hir::ClassBytesRange as regex_syntax::hir::interval::Interval>::is_contiguous
Unexecuted instantiation: <regex_syntax::hir::ClassUnicodeRange as regex_syntax::hir::interval::Interval>::is_contiguous
519
520
    /// Returns true if and only if the intersection of this range and the
521
    /// other range is empty.
522
6.72M
    fn is_intersection_empty(&self, other: &Self) -> bool {
523
6.72M
        let (lower1, upper1) = (self.lower(), self.upper());
524
6.72M
        let (lower2, upper2) = (other.lower(), other.upper());
525
6.72M
        cmp::max(lower1, lower2) > cmp::min(upper1, upper2)
526
6.72M
    }
<regex_syntax::hir::ClassBytesRange as regex_syntax::hir::interval::Interval>::is_intersection_empty
Line
Count
Source
522
2.15M
    fn is_intersection_empty(&self, other: &Self) -> bool {
523
2.15M
        let (lower1, upper1) = (self.lower(), self.upper());
524
2.15M
        let (lower2, upper2) = (other.lower(), other.upper());
525
2.15M
        cmp::max(lower1, lower2) > cmp::min(upper1, upper2)
526
2.15M
    }
<regex_syntax::hir::ClassUnicodeRange as regex_syntax::hir::interval::Interval>::is_intersection_empty
Line
Count
Source
522
4.57M
    fn is_intersection_empty(&self, other: &Self) -> bool {
523
4.57M
        let (lower1, upper1) = (self.lower(), self.upper());
524
4.57M
        let (lower2, upper2) = (other.lower(), other.upper());
525
4.57M
        cmp::max(lower1, lower2) > cmp::min(upper1, upper2)
526
4.57M
    }
527
528
    /// Returns true if and only if this range is a subset of the other range.
529
2.30M
    fn is_subset(&self, other: &Self) -> bool {
530
2.30M
        let (lower1, upper1) = (self.lower(), self.upper());
531
2.30M
        let (lower2, upper2) = (other.lower(), other.upper());
532
2.30M
        (lower2 <= lower1 && lower1 <= upper2)
533
935k
            && (lower2 <= upper1 && upper1 <= upper2)
534
2.30M
    }
<regex_syntax::hir::ClassBytesRange as regex_syntax::hir::interval::Interval>::is_subset
Line
Count
Source
529
131k
    fn is_subset(&self, other: &Self) -> bool {
530
131k
        let (lower1, upper1) = (self.lower(), self.upper());
531
131k
        let (lower2, upper2) = (other.lower(), other.upper());
532
131k
        (lower2 <= lower1 && lower1 <= upper2)
533
41.5k
            && (lower2 <= upper1 && upper1 <= upper2)
534
131k
    }
<regex_syntax::hir::ClassUnicodeRange as regex_syntax::hir::interval::Interval>::is_subset
Line
Count
Source
529
2.17M
    fn is_subset(&self, other: &Self) -> bool {
530
2.17M
        let (lower1, upper1) = (self.lower(), self.upper());
531
2.17M
        let (lower2, upper2) = (other.lower(), other.upper());
532
2.17M
        (lower2 <= lower1 && lower1 <= upper2)
533
894k
            && (lower2 <= upper1 && upper1 <= upper2)
534
2.17M
    }
535
}
536
537
pub trait Bound:
538
    Copy + Clone + Debug + Eq + PartialEq + PartialOrd + Ord
539
{
540
    fn min_value() -> Self;
541
    fn max_value() -> Self;
542
    fn as_u32(self) -> u32;
543
    fn increment(self) -> Self;
544
    fn decrement(self) -> Self;
545
}
546
547
impl Bound for u8 {
548
48.7k
    fn min_value() -> Self {
549
48.7k
        u8::MIN
550
48.7k
    }
551
49.1k
    fn max_value() -> Self {
552
49.1k
        u8::MAX
553
49.1k
    }
554
20.1M
    fn as_u32(self) -> u32 {
555
20.1M
        u32::from(self)
556
20.1M
    }
557
152k
    fn increment(self) -> Self {
558
152k
        self.checked_add(1).unwrap()
559
152k
    }
560
150k
    fn decrement(self) -> Self {
561
150k
        self.checked_sub(1).unwrap()
562
150k
    }
563
}
564
565
impl Bound for char {
566
380k
    fn min_value() -> Self {
567
380k
        '\x00'
568
380k
    }
569
382k
    fn max_value() -> Self {
570
382k
        '\u{10FFFF}'
571
382k
    }
572
912M
    fn as_u32(self) -> u32 {
573
912M
        u32::from(self)
574
912M
    }
575
576
17.3M
    fn increment(self) -> Self {
577
17.3M
        match self {
578
1.80k
            '\u{D7FF}' => '\u{E000}',
579
17.3M
            c => char::from_u32(u32::from(c).checked_add(1).unwrap()).unwrap(),
580
        }
581
17.3M
    }
582
583
17.3M
    fn decrement(self) -> Self {
584
17.3M
        match self {
585
9.54k
            '\u{E000}' => '\u{D7FF}',
586
17.3M
            c => char::from_u32(u32::from(c).checked_sub(1).unwrap()).unwrap(),
587
        }
588
17.3M
    }
589
}
590
591
// Tests for interval sets are written in src/hir.rs against the public API.