1010//===----------------------------------------------------------------------===//
1111
1212//===----------------------------------------------------------------------===//
13- // MARK: Sequence.includes(sorted:sortedBy:)
13+ // MARK: OverlapDegree
14+ //-------------------------------------------------------------------------===//
15+
16+ /// The amount of overlap between two sets.
17+ public enum OverlapDegree : UInt , CaseIterable {
18+ /// Both sets are empty (degenerate).
19+ case bothEmpty
20+ /// Have a nonempty first set, empty second (degenerate).
21+ case onlyFirstNonempty
22+ /// Have an empty first set, nonempty second (degenerate).
23+ case onlySecondNonempty
24+ /// Have two nonempty sets with no overlap.
25+ case disjoint
26+ /// The two sets are equivalent and nonempty.
27+ case identical
28+ /// The first set is a strict superset of a nonempty second.
29+ case firstIncludesNonemptySecond
30+ /// The first set is a nonempty strict subset of the second.
31+ case secondIncludesNonemptyFirst
32+ /// The sets overlap but each still have exclusive elements.
33+ case partialOverlap
34+ }
35+
36+ extension OverlapDegree {
37+ /// The bit mask checking if there are elements exclusive to the first set.
38+ @usableFromInline
39+ static var firstOnlyMask : RawValue { 1 << 0 }
40+ /// The bit mask checking if there are elements exclusive to the second set.
41+ @usableFromInline
42+ static var secondOnlyMask : RawValue { 1 << 1 }
43+ /// The bit mask checking if there are elements shared by both sets.
44+ @usableFromInline
45+ static var sharedMask : RawValue { 1 << 2 }
46+ }
47+
48+ extension OverlapDegree {
49+ /// Whether there are any elements in the first set that are not in
50+ /// the second.
51+ @inlinable
52+ public var hasElementsExclusiveToFirst : Bool
53+ { rawValue & Self . firstOnlyMask != 0 }
54+ /// Whether there are any elements in the second set that are not in
55+ /// the first.
56+ @inlinable
57+ public var hasElementsExclusiveToSecond : Bool
58+ { rawValue & Self . secondOnlyMask != 0 }
59+ /// Whether there are any elements that occur in both sets.
60+ @inlinable
61+ public var hasSharedElements : Bool
62+ { rawValue & Self . sharedMask != 0 }
63+ }
64+
65+ //===----------------------------------------------------------------------===//
66+ // MARK: - Sequence.includes(sorted:sortedBy:)
1467//-------------------------------------------------------------------------===//
1568
1669extension Sequence {
@@ -41,8 +94,11 @@ extension Sequence {
4194 sortedBy areInIncreasingOrder: ( Element , Element ) throws -> Bool
4295 ) rethrows -> Bool
4396 where T. Element == Element {
44- return try ! overlap( withSorted: other, bailAfterOtherExclusive: true ,
45- sortedBy: areInIncreasingOrder) . elementsFromOther!
97+ return try ! overlap(
98+ withSorted: other,
99+ bailAfterOtherExclusive: true ,
100+ sortedBy: areInIncreasingOrder
101+ ) . hasElementsExclusiveToSecond
46102 }
47103}
48104
@@ -83,12 +139,12 @@ extension Sequence {
83139 /// let base = [9, 8, 7, 6, 6, 3, 2, 1, 0]
84140 /// let test1 = base.overlap(withSorted: [8, 7, 6, 2, 1], sortedBy: >)
85141 /// let test2 = base.overlap(withSorted: [8, 7, 5, 2, 1], sortedBy: >)
86- /// assert(test1.elementsFromSelf! )
87- /// assert(test1.sharedElements! )
88- /// assert(!test1.elementsFromOther! )
89- /// assert(test2.elementsFromSelf !)
90- /// assert(test2.sharedElements! )
91- /// assert(test2.elementsFromOther! )
142+ /// assert(test1.hasElementsExclusiveToFirst )
143+ /// assert(test1.hasSharedElements )
144+ /// assert(!test1.hasElementsExclusiveToSecond )
145+ /// assert(test2.hasElementsExclusiveToFirst !)
146+ /// assert(test2.hasSharedElements )
147+ /// assert(test2.hasElementsExclusiveToSecond )
92148 ///
93149 /// - Precondition: Both the receiver and `other` must be sorted according to
94150 /// `areInIncreasingOrder`,
@@ -107,17 +163,15 @@ extension Sequence {
107163 /// - bailAfterOtherExclusive: Indicate that this function should abort as
108164 /// soon as one element that is exclusive to `other` is found.
109165 /// If not given, defaults to `false`.
110- /// - Returns: A tuple of three `Bool` members indicating whether there are
111- /// elements exclusive to `self`,
112- /// there are elements shared between the sequences,
113- /// and there are elements exclusive to `other`.
114- /// If a member is `true`,
115- /// then at least one element in that category exists.
116- /// If a member is `false`,
117- /// then there are no elements in that category.
118- /// If a member is `nil`,
119- /// then the function aborted before its category's status could be
120- /// determined.
166+ /// - Returns: A value representing the categories of overlap found.
167+ /// If none of the abort arguments were `true`,
168+ /// or otherwise none of their corresponding categories were found,
169+ /// then all of the category flags from the returned value are accurate.
170+ /// Otherwise,
171+ /// the returned value has exactly one of the flags in the
172+ /// short-circuit subset as `true`,
173+ /// and the flags outside that set may have invalid values.
174+ /// The receiver is considered the first set, and `other` as the second.
121175 ///
122176 /// - Complexity: O(*n*), where `n` is the length of the shorter sequence.
123177 public func overlap< T: Sequence > (
@@ -126,63 +180,63 @@ extension Sequence {
126180 bailAfterShared: Bool = false ,
127181 bailAfterOtherExclusive: Bool = false ,
128182 sortedBy areInIncreasingOrder: ( Element , Element ) throws -> Bool
129- ) rethrows -> (
130- elementsFromSelf: Bool ? ,
131- sharedElements: Bool ? ,
132- elementsFromOther: Bool ?
133- )
183+ ) rethrows -> OverlapDegree
134184 where T. Element == Element {
135185 var firstElement , secondElement : Element ?
136186 var iterator = makeIterator ( ) , otherIterator = other. makeIterator ( )
137- var result : ( fromSelf: Bool ? , shared: Bool ? , fromOther: Bool ? )
187+ var fromSelf , shared , fromOther : Bool ?
138188 loop:
139- while result != ( true , true , true ) {
189+ while ( fromSelf , shared , fromOther ) != ( true , true , true ) {
140190 firstElement = firstElement ?? iterator. next ( )
141191 secondElement = secondElement ?? otherIterator. next ( )
142192 switch ( firstElement, secondElement) {
143193 case let ( s? , o? ) where try areInIncreasingOrder ( s, o) :
144194 // Exclusive to self
145- result . fromSelf = true
195+ fromSelf = true
146196 guard !bailAfterSelfExclusive else { break loop }
147197
148198 // Move to the next element in self.
149199 firstElement = nil
150200 case let ( s? , o? ) where try areInIncreasingOrder ( o, s) :
151201 // Exclusive to other
152- result . fromOther = true
202+ fromOther = true
153203 guard !bailAfterOtherExclusive else { break loop }
154204
155205 // Move to the next element in other.
156206 secondElement = nil
157207 case ( _? , _? ) :
158208 // Shared
159- result . shared = true
209+ shared = true
160210 guard !bailAfterShared else { break loop }
161211
162212 // Iterate to the next element for both sequences.
163213 firstElement = nil
164214 secondElement = nil
165215 case ( _? , nil ) :
166216 // Never bail, just finalize after finding an exclusive to self.
167- result . fromSelf = true
168- result . shared = result . shared ?? false
169- result . fromOther = result . fromOther ?? false
217+ fromSelf = true
218+ shared = shared ?? false
219+ fromOther = fromOther ?? false
170220 break loop
171221 case ( nil , _? ) :
172222 // Never bail, just finalize after finding an exclusive to other.
173- result . fromSelf = result . fromSelf ?? false
174- result . shared = result . shared ?? false
175- result . fromOther = true
223+ fromSelf = fromSelf ?? false
224+ shared = shared ?? false
225+ fromOther = true
176226 break loop
177227 case ( nil , nil ) :
178228 // Finalize everything instead of bailing
179- result . fromSelf = result . fromSelf ?? false
180- result . shared = result . shared ?? false
181- result . fromOther = result . fromOther ?? false
229+ fromSelf = fromSelf ?? false
230+ shared = shared ?? false
231+ fromOther = fromOther ?? false
182232 break loop
183233 }
184234 }
185- return ( result. fromSelf, result. shared, result. fromOther)
235+
236+ let selfBit = fromSelf == true ? OverlapDegree . firstOnlyMask : 0 ,
237+ shareBit = shared == true ? OverlapDegree . sharedMask : 0 ,
238+ otherBit = fromOther == true ? OverlapDegree . secondOnlyMask : 0
239+ return . init( rawValue: selfBit | shareBit | otherBit) !
186240 }
187241}
188242
@@ -193,12 +247,12 @@ extension Sequence where Element: Comparable {
193247 /// let base = [0, 1, 2, 3, 6, 6, 7, 8, 9]
194248 /// let test1 = base.overlap(withSorted: [1, 2, 6, 7, 8])
195249 /// let test2 = base.overlap(withSorted: [1, 2, 5, 7, 8])
196- /// assert(test1.elementsFromSelf! )
197- /// assert(test1.sharedElements! )
198- /// assert(!test1.elementsFromOther! )
199- /// assert(test2.elementsFromSelf! )
200- /// assert(test2.sharedElements! )
201- /// assert(test2.elementsFromOther! )
250+ /// assert(test1.hasElementsExclusiveToFirst )
251+ /// assert(test1.hasSharedElements )
252+ /// assert(!test1.hasElementsExclusiveToSecond )
253+ /// assert(test2.hasElementsExclusiveToFirst )
254+ /// assert(test2.hasSharedElements )
255+ /// assert(test2.hasElementsExclusiveToSecond )
202256 ///
203257 /// - Precondition: Both the receiver and `other` must be sorted.
204258 /// At least one of the involved sequences must be finite.
@@ -214,17 +268,15 @@ extension Sequence where Element: Comparable {
214268 /// - bailAfterOtherExclusive: Indicate that this function should abort as
215269 /// soon as one element that is exclusive to `other` is found.
216270 /// If not given, defaults to `false`.
217- /// - Returns: A tuple of three `Bool` members indicating whether there are
218- /// elements exclusive to `self`,
219- /// elements shared between the sequences,
220- /// and elements exclusive to `other`.
221- /// If a member is `true`,
222- /// then at least one element in that category exists.
223- /// If a member is `false`,
224- /// then there are no elements in that category.
225- /// If a member is `nil`,
226- /// then the function aborted before its category's status could be
227- /// determined.
271+ /// - Returns: A value representing the categories of overlap found.
272+ /// If none of the abort arguments were `true`,
273+ /// or otherwise none of their corresponding categories were found,
274+ /// then all of the category flags from the returned value are accurate.
275+ /// Otherwise,
276+ /// the returned value has exactly one of the flags in the
277+ /// short-circuit subset as `true`,
278+ /// and the flags outside that set may have invalid values.
279+ /// The receiver is considered the first set, and `other` as the second.
228280 ///
229281 /// - Complexity: O(*n*), where `n` is the length of the shorter sequence.
230282 @inlinable
@@ -233,11 +285,7 @@ extension Sequence where Element: Comparable {
233285 bailAfterSelfExclusive: Bool = false ,
234286 bailAfterShared: Bool = false ,
235287 bailAfterOtherExclusive: Bool = false
236- ) -> (
237- elementsFromSelf: Bool ? ,
238- sharedElements: Bool ? ,
239- elementsFromOther: Bool ?
240- )
288+ ) -> OverlapDegree
241289 where T. Element == Element {
242290 return overlap (
243291 withSorted: other,
0 commit comments