10
10
//===----------------------------------------------------------------------===//
11
11
12
12
//===----------------------------------------------------------------------===//
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:)
14
67
//-------------------------------------------------------------------------===//
15
68
16
69
extension Sequence {
@@ -41,8 +94,11 @@ extension Sequence {
41
94
sortedBy areInIncreasingOrder: ( Element , Element ) throws -> Bool
42
95
) rethrows -> Bool
43
96
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
46
102
}
47
103
}
48
104
@@ -83,12 +139,12 @@ extension Sequence {
83
139
/// let base = [9, 8, 7, 6, 6, 3, 2, 1, 0]
84
140
/// let test1 = base.overlap(withSorted: [8, 7, 6, 2, 1], sortedBy: >)
85
141
/// 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 )
92
148
///
93
149
/// - Precondition: Both the receiver and `other` must be sorted according to
94
150
/// `areInIncreasingOrder`,
@@ -107,17 +163,15 @@ extension Sequence {
107
163
/// - bailAfterOtherExclusive: Indicate that this function should abort as
108
164
/// soon as one element that is exclusive to `other` is found.
109
165
/// 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.
121
175
///
122
176
/// - Complexity: O(*n*), where `n` is the length of the shorter sequence.
123
177
public func overlap< T: Sequence > (
@@ -126,63 +180,63 @@ extension Sequence {
126
180
bailAfterShared: Bool = false ,
127
181
bailAfterOtherExclusive: Bool = false ,
128
182
sortedBy areInIncreasingOrder: ( Element , Element ) throws -> Bool
129
- ) rethrows -> (
130
- elementsFromSelf: Bool ? ,
131
- sharedElements: Bool ? ,
132
- elementsFromOther: Bool ?
133
- )
183
+ ) rethrows -> OverlapDegree
134
184
where T. Element == Element {
135
185
var firstElement , secondElement : Element ?
136
186
var iterator = makeIterator ( ) , otherIterator = other. makeIterator ( )
137
- var result : ( fromSelf: Bool ? , shared: Bool ? , fromOther: Bool ? )
187
+ var fromSelf , shared , fromOther : Bool ?
138
188
loop:
139
- while result != ( true , true , true ) {
189
+ while ( fromSelf , shared , fromOther ) != ( true , true , true ) {
140
190
firstElement = firstElement ?? iterator. next ( )
141
191
secondElement = secondElement ?? otherIterator. next ( )
142
192
switch ( firstElement, secondElement) {
143
193
case let ( s? , o? ) where try areInIncreasingOrder ( s, o) :
144
194
// Exclusive to self
145
- result . fromSelf = true
195
+ fromSelf = true
146
196
guard !bailAfterSelfExclusive else { break loop }
147
197
148
198
// Move to the next element in self.
149
199
firstElement = nil
150
200
case let ( s? , o? ) where try areInIncreasingOrder ( o, s) :
151
201
// Exclusive to other
152
- result . fromOther = true
202
+ fromOther = true
153
203
guard !bailAfterOtherExclusive else { break loop }
154
204
155
205
// Move to the next element in other.
156
206
secondElement = nil
157
207
case ( _? , _? ) :
158
208
// Shared
159
- result . shared = true
209
+ shared = true
160
210
guard !bailAfterShared else { break loop }
161
211
162
212
// Iterate to the next element for both sequences.
163
213
firstElement = nil
164
214
secondElement = nil
165
215
case ( _? , nil ) :
166
216
// 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
170
220
break loop
171
221
case ( nil , _? ) :
172
222
// 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
176
226
break loop
177
227
case ( nil , nil ) :
178
228
// 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
182
232
break loop
183
233
}
184
234
}
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) !
186
240
}
187
241
}
188
242
@@ -193,12 +247,12 @@ extension Sequence where Element: Comparable {
193
247
/// let base = [0, 1, 2, 3, 6, 6, 7, 8, 9]
194
248
/// let test1 = base.overlap(withSorted: [1, 2, 6, 7, 8])
195
249
/// 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 )
202
256
///
203
257
/// - Precondition: Both the receiver and `other` must be sorted.
204
258
/// At least one of the involved sequences must be finite.
@@ -214,17 +268,15 @@ extension Sequence where Element: Comparable {
214
268
/// - bailAfterOtherExclusive: Indicate that this function should abort as
215
269
/// soon as one element that is exclusive to `other` is found.
216
270
/// 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.
228
280
///
229
281
/// - Complexity: O(*n*), where `n` is the length of the shorter sequence.
230
282
@inlinable
@@ -233,11 +285,7 @@ extension Sequence where Element: Comparable {
233
285
bailAfterSelfExclusive: Bool = false ,
234
286
bailAfterShared: Bool = false ,
235
287
bailAfterOtherExclusive: Bool = false
236
- ) -> (
237
- elementsFromSelf: Bool ? ,
238
- sharedElements: Bool ? ,
239
- elementsFromOther: Bool ?
240
- )
288
+ ) -> OverlapDegree
241
289
where T. Element == Element {
242
290
return overlap (
243
291
withSorted: other,
0 commit comments