-
Notifications
You must be signed in to change notification settings - Fork 445
/
Copy pathFirstDelta.swift
240 lines (228 loc) · 11 KB
/
FirstDelta.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift Algorithms open source project
//
// Copyright (c) 2020 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
//
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// firstDelta(against: by:)
//===----------------------------------------------------------------------===//
extension Sequence {
/// Returns the first non-matching element pair found when comparing this
/// sequence to the given sequence element-wise, using the given predicate as
/// the equivalence test.
///
/// The predicate must be a *equivalence relation* over the elements. That
/// is, for any elements `a`, `b`, and `c`, the following conditions must
/// hold:
///
/// - `areEquivalent(a, a)` is always `true`. (Reflexivity)
/// - `areEquivalent(a, b)` implies `areEquivalent(b, a)`. (Symmetry)
/// - If `areEquivalent(a, b)` and `areEquivalent(b, c)` are both `true`, then
/// `areEquivalent(a, c)` is also `true`. (Transitivity)
///
/// If one sequence is a proper prefix of the other, its corresponding member
/// in the emitted result will be `nil`. If the two sequences are equivalent,
/// both members of the emitted result will be `nil`.
///
/// - Parameters:
/// - possibleMirror: A sequence to compare to this sequence.
/// - areEquivalent: A predicate that returns `true` if its two arguments
/// are equivalent; otherwise, `false`.
/// - Returns: A two-element tuple containing, upon finding the earliest
/// diverging elements between this sequence and `possibleMirror`, those
/// differing elements. If at least one of the sequences ends before a
/// difference is found, the corresponding member of the returned tuple is
/// `nil`.
///
/// - Complexity: O(*m*), where *m* is the lesser of the length of this
/// sequence and the length of `possibleMirror`.
public func firstDelta<PossibleMirror: Sequence>(
against possibleMirror: PossibleMirror,
by areEquivalent: (Element, PossibleMirror.Element) throws -> Bool
) rethrows -> (Element?, PossibleMirror.Element?) {
var iterator1 = makeIterator(), iterator2 = possibleMirror.makeIterator()
while true {
switch (iterator1.next(), iterator2.next()) {
case let (element1?, element2?) where try areEquivalent(element1, element2):
continue
case let (next1, next2):
return (next1, next2)
}
}
}
}
//===----------------------------------------------------------------------===//
// firstDelta(against:)
//===----------------------------------------------------------------------===//
extension Sequence where Element: Equatable {
/// Returns the first non-equal element pair found when comparing this
/// sequence to the given sequence element-wise.
///
/// If one sequence is a proper prefix of the other, its corresponding member
/// in the emitted result will be `nil`. If the two sequences are equal, both
/// members of the emitted result will be `nil`.
///
/// - Parameters:
/// - possibleMirror: A sequence to compare to this sequence.
/// - Returns: A two-element tuple containing, upon finding the earliest
/// diverging elements between this sequence and `possibleMirror`, those
/// differing elements. If at least one of the sequences ends before a
/// difference is found, the corresponding member of the returned tuple is
/// `nil`.
///
/// - Complexity: O(*m*), where *m* is the lesser of the length of this
/// sequence and the length of `possibleMirror`.
@inlinable
public func firstDelta<PossibleMirror: Sequence>(
against possibleMirror: PossibleMirror
) -> (Element?, Element?) where PossibleMirror.Element == Element {
return firstDelta(against: possibleMirror, by: ==)
}
}
//===----------------------------------------------------------------------===//
// diverges(from: by:)
//===----------------------------------------------------------------------===//
extension Collection {
/// Finds the longest common prefix between this collection and the given
/// collection, using the given predicate as the equivalence test, returning
/// the past-the-end indexes of the respective subsequences.
///
/// The predicate must be a *equivalence relation* over the elements. That
/// is, for any elements `a`, `b`, and `c`, the following conditions must
/// hold:
///
/// - `areEquivalent(a, a)` is always `true`. (Reflexivity)
/// - `areEquivalent(a, b)` implies `areEquivalent(b, a)`. (Symmetry)
/// - If `areEquivalent(a, b)` and `areEquivalent(b, c)` are both `true`, then
/// `areEquivalent(a, c)` is also `true`. (Transitivity)
///
/// If one collection is a proper prefix of the other, its corresponding
/// member in the emitted result will be its source's `endIndex`. If the two
/// collections are equivalent, both members of the emitted result will be
/// their sources' respective `endIndex`.
///
/// - Parameters:
/// - possibleMirror: A collection to compare to this collection.
/// - areEquivalent: A predicate that returns `true` if its two arguments
/// are equivalent; otherwise, `false`.
/// - Returns: A two-element tuple `(x, y)` where *x* and *y* are the largest
/// indices such that
/// `self[..<x].elementsEqual(possibleMirror[..<y], by: areEquivalent)` is
/// `true`. Either one or both members may be its source's `endIndex`.
///
/// - Complexity: O(*m*), where *m* is the lesser of the length of this
/// collection and the length of `possibleMirror`.
@inlinable
public func diverges<PossibleMirror: Collection>(
from possibleMirror: PossibleMirror,
by areEquivalent: (Element, PossibleMirror.Element) throws -> Bool
) rethrows -> (Index, PossibleMirror.Index) {
let (index1, index2) = try indices.firstDelta(against: possibleMirror.indices) {
try areEquivalent(self[$0], possibleMirror[$1])
}
return (index1 ?? endIndex, index2 ?? possibleMirror.endIndex)
}
}
//===----------------------------------------------------------------------===//
// diverges(from:)
//===----------------------------------------------------------------------===//
extension Collection where Element: Equatable {
/// Finds the longest common prefix between this collection and the given
/// collection, returning the past-the-end indexes of the respective
/// subsequences.
///
/// If one collection is a proper prefix of the other, its corresponding
/// member in the emitted result will be its source's `endIndex`. If the two
/// collections are equal, both members of the emitted result will be their
/// sources' respective `endIndex`.
///
/// - Parameters:
/// - possibleMirror: A collection to compare to this collection.
/// - Returns: A two-element tuple `(x, y)` where *x* and *y* are the largest
/// indices such that `self[..<x].elementsEqual(possibleMirror[..<y])` is
/// `true`. Either one or both members may be its source's `endIndex`.
///
/// - Complexity: O(*m*), where *m* is the lesser of the length of this
/// collection and the length of `possibleMirror`.
@inlinable
public func diverges<PossibleMirror: Collection>(
from possibleMirror: PossibleMirror
) -> (Index, PossibleMirror.Index) where PossibleMirror.Element == Element {
return diverges(from: possibleMirror, by: ==)
}
}
//===----------------------------------------------------------------------===//
// converges(with: by:)
//===----------------------------------------------------------------------===//
extension BidirectionalCollection {
/// Finds the longest common suffix between this collection and the given
/// collection, using the given predicate as the equivalence test, returning
/// the starting indexes of the respective subsequences.
///
/// The predicate must be a *equivalence relation* over the elements. That
/// is, for any elements `a`, `b`, and `c`, the following conditions must
/// hold:
///
/// - `areEquivalent(a, a)` is always `true`. (Reflexivity)
/// - `areEquivalent(a, b)` implies `areEquivalent(b, a)`. (Symmetry)
/// - If `areEquivalent(a, b)` and `areEquivalent(b, c)` are both `true`, then
/// `areEquivalent(a, c)` is also `true`. (Transitivity)
///
/// If one collection is a proper suffix of the other, its corresponding
/// member in the emitted result will be its source's `startIndex`. If the
/// two collections are equivalent, both members of the emitted result will be
/// their sources' respective `startIndex`.
///
/// - Parameters:
/// - possibleMirror: A collection to compare to this collection.
/// - areEquivalent: A predicate that returns `true` if its two arguments
/// are equivalent; otherwise, `false`.
/// - Returns: A two-element tuple `(x, y)` where *x* and *y* are the
/// smallest indices such that
/// `self[x...].elementsEqual(possibleMirror[y...], by: areEquivalent)` is
/// `true`. Either one or both members may be its source's `startIndex`.
///
/// - Complexity: O(*m*), where *m* is the lesser of the length of this
/// collection and the length of `possibleMirror`.
@inlinable
public func converges<PossibleMirror: BidirectionalCollection>(
with possibleMirror: PossibleMirror,
by areEquivalent: (Element, PossibleMirror.Element) throws -> Bool
) rethrows -> (Index, PossibleMirror.Index) {
let (reversed1, reversed2) = try reversed().diverges(from: possibleMirror.reversed(), by: areEquivalent)
return (reversed1.base, reversed2.base)
}
}
//===----------------------------------------------------------------------===//
// converges(with:)
//===----------------------------------------------------------------------===//
extension BidirectionalCollection where Element: Equatable {
/// Finds the longest common suffix between this collection and the given
/// collection, returning the starting indexes of the respective subsequences.
///
/// If one collection is a proper suffix of the other, its corresponding
/// member in the emitted result will be its source's `startIndex`. If the
/// two collections are equal, both members of the emitted result will be
/// their sources' respective `startIndex`.
///
/// - Parameters:
/// - possibleMirror: A collection to compare to this collection.
/// - Returns: A two-element tuple `(x, y)` where *x* and *y* are the
/// smallest indices such that
/// `self[x...].elementsEqual(possibleMirror[y...])` is `true`. Either one
/// or both members may be its source's `startIndex`.
///
/// - Complexity: O(*m*), where *m* is the lesser of the length of this
/// collection and the length of `possibleMirror`.
@inlinable
public func converges<PossibleMirror: BidirectionalCollection>(
with possibleMirror: PossibleMirror
) -> (Index, PossibleMirror.Index) where PossibleMirror.Element == Element {
return converges(with: possibleMirror, by: ==)
}
}