@@ -142,149 +142,84 @@ orderingExplanation = """\
142
142
// partition()
143
143
//===----------------------------------------------------------------------===//
144
144
145
- % # Generate two versions: with explicit predicates and with
146
- % # a Comparable requirement.
147
- % for preds in [ True, False] :
148
-
149
- % if preds:
150
-
151
- extension MutableCollection where Self : RandomAccessCollection
152
-
153
- % else :
154
-
155
- extension MutableCollection
156
- where Self : RandomAccessCollection , ${ IElement} : Comparable
157
-
158
- % end
159
- {
160
-
161
- % if preds:
162
- /// Reorders the elements in the collection and returns a pivot index, using
163
- /// the given predicate as the comparison between elements.
164
- ///
165
- /// This method is typically one step of a sorting algorithm. A collection is
166
- /// partitioned around a pivot index when each of the elements before the
167
- /// pivot is correctly ordered before each of the elements at or after the
168
- /// pivot. The `partition(by:)` method reorders the elements of
169
- /// the collection and returns a pivot index that satisfies this condition,
170
- /// using the given predicate to determine the relative order of any two
171
- /// elements.
172
- ///
173
- ${ orderingExplanation}
174
- /// Here's an example that uses a predicate that orders elements from largest
175
- /// to smallest:
176
- ///
177
- /// var numbers = [50, 30, 60, 50, 80, 10, 40, 30]
178
- /// let pivot = numbers.partition { a, b in a > b }
179
- ///
180
- /// print(pivot)
181
- /// // Prints "2"
182
- /// print(numbers)
183
- /// // Prints "[60, 80, 50, 50, 30, 10, 40, 30]"
184
- ///
185
- /// The return value of the call to `numbers.partition()` is the pivot for
186
- /// the rearranged `numbers` array. `pivot` divides the collection into two
187
- /// subranges, `numbers[0..<pivot]` and `numbers[pivot..<8]`.
188
- ///
189
- /// print(numbers[0..<pivot])
190
- /// // Prints "[60, 80]"
191
- /// print(numbers[pivot..<8])
192
- /// // Prints "[50, 50, 30, 10, 40, 30]"
193
- ///
194
- /// The elements of `numbers` are rearranged so that every element in the
195
- /// subrange before `pivot` is ordered before every element in the subrange
196
- /// after. Because the supplied predicate returns `true` when its first
197
- /// argument is greater than its second argument, larger elements are
198
- /// ordered before smaller elements.
199
- ///
200
- /// - Parameter areInIncreasingOrder: A predicate that returns `true` if its first
201
- /// argument should be ordered before its second argument; otherwise,
202
- /// `false`.
203
- /// - Returns: A pivot index, such that every element before the pivot is
204
- /// ordered before every element at or above the pivot, using
205
- /// `areInIncreasingOrder` to determine the relative order of any two elements.
206
- /// The returned pivot is equal to the collection's end index only if the
207
- /// collection is empty.
208
- ///
209
- /// - SeeAlso: `partition()`
145
+ extension MutableCollection {
210
146
public mutating func partition(
211
- by areInIncreasingOrder : @noescape ( ${ IElement} , $ { IElement } ) -> Bool
212
- ) -> Index
147
+ by belongsInSecondPartition : @noescape ( ${ IElement} ) throws -> Bool
148
+ ) rethrows -> Index {
213
149
214
- % else :
150
+ var pivot = startIndex
151
+ while true {
152
+ if pivot == endIndex {
153
+ return pivot
154
+ }
155
+ if try belongsInSecondPartition ( self [ pivot] ) {
156
+ break
157
+ }
158
+ formIndex ( after: & pivot)
159
+ }
215
160
216
- /// Reorders the elements in the collection and returns a pivot index.
217
- ///
218
- /// This method is typically one step of a sorting algorithm. A collection is
219
- /// partitioned around a pivot index when each of the elements before the
220
- /// pivot are less than each of the elements at or after the pivot. The
221
- /// `partition()` method reorders the elements of the collection and returns
222
- /// a pivot index that satisfies this condition.
223
- ///
224
- /// For example:
225
- ///
226
- /// var numbers = [50, 30, 60, 50, 80, 10, 40, 30]
227
- /// let pivot = numbers.partition()
228
- ///
229
- /// print(pivot)
230
- /// // Prints "4"
231
- /// print(numbers)
232
- /// // Prints "[10, 30, 30, 40, 50, 80, 50, 60]"
233
- ///
234
- /// The return value of the call to `numbers.partition()` is the pivot for
235
- /// the rearranged `numbers` array. `pivot` divides the collection into two
236
- /// subranges, `numbers[0..<pivot]` and `numbers[pivot..<8]`.
237
- ///
238
- /// print(numbers[0..<pivot])
239
- /// // Prints "[10, 30, 30, 40]"
240
- /// print(numbers[pivot..<8])
241
- /// // Prints "[50, 80, 50, 60]"
242
- ///
243
- /// The elements of `numbers` are rearranged so that every element in the
244
- /// subrange before `pivot` is less than every element in the subrange
245
- /// after.
246
- ///
247
- /// - Returns: A pivot index, such that every element before the pivot is
248
- /// less than every element at or above the pivot. The returned pivot is
249
- /// equal to the collection's end index only if the collection is empty.
250
- ///
251
- /// - SeeAlso: `partition(by:)`
252
- public mutating func partition( ) -> Index
161
+ var i = index ( after: pivot)
162
+ while i < endIndex {
163
+ if try ! belongsInSecondPartition( self [ i] ) {
164
+ swap ( & self [ i] , & self [ pivot] )
165
+ formIndex ( after: & pivot)
166
+ }
167
+ formIndex ( after: & i)
168
+ }
169
+ return pivot
170
+ }
171
+ }
253
172
254
- % end
255
- {
256
- let maybeOffset = _withUnsafeMutableBufferPointerIfSupported {
173
+ extension MutableCollection where Self: BidirectionalCollection {
174
+ public mutating func partition(
175
+ by belongsInSecondPartition: @noescape ( ${ IElement} ) throws -> Bool
176
+ ) rethrows -> Index {
177
+ let maybeOffset = try _withUnsafeMutableBufferPointerIfSupported {
257
178
( baseAddress, count) -> Int in
258
179
var bufferPointer =
259
180
UnsafeMutableBufferPointer ( start: baseAddress, count: count)
260
- let unsafeBufferPivot = bufferPointer. partition (
261
- % if preds:
262
- by: areInIncreasingOrder
263
- % end
264
- )
181
+ let unsafeBufferPivot = try bufferPointer. partition (
182
+ by: belongsInSecondPartition)
265
183
return unsafeBufferPivot - bufferPointer. startIndex
266
184
}
267
185
if let offset = maybeOffset {
268
186
return index ( startIndex, offsetBy: numericCast ( offset) )
269
187
}
270
188
271
- % if preds:
272
- typealias EscapingBinaryPredicate =
273
- ( ${ IElement} , ${ IElement} ) - > Bool
274
- var escapableIsOrderedBefore =
275
- unsafeBitCast ( areInIncreasingOrder, to: EscapingBinaryPredicate . self)
276
- return _partition(
277
- & self ,
278
- subRange: startIndex..< endIndex,
279
- by: & escapableIsOrderedBefore)
280
- % else:
281
- return _partition( & self , subRange: startIndex..< endIndex)
282
- % end
189
+ var lo = startIndex
190
+ var hi = endIndex
191
+
192
+ // 'Loop' invariants (at start of Loop, all are true):
193
+ // * lo < hi
194
+ // * predicate(self[i]) == false, for i in startIndex ..< lo
195
+ // * predicate(self[i]) == true, for i in hi ..< endIndex
196
+
197
+ Loop: while true {
198
+ FindLo: repeat {
199
+ while lo < hi {
200
+ if try belongsInSecondPartition ( self [ lo] ) { break FindLo }
201
+ formIndex ( after: & lo)
202
+ }
203
+ break Loop
204
+ } while false
205
+
206
+ FindHi: repeat {
207
+ formIndex ( before: & hi)
208
+ while lo < hi {
209
+ if try ! belongsInSecondPartition( self [ hi] ) { break FindHi }
210
+ formIndex ( before: & hi)
211
+ }
212
+ break Loop
213
+ } while false
214
+
215
+ swap ( & self [ lo] , & self [ hi] )
216
+ formIndex ( after: & lo)
217
+ }
218
+
219
+ return lo
283
220
}
284
221
}
285
222
286
- % end
287
-
288
223
//===----------------------------------------------------------------------===//
289
224
// sorted()
290
225
//===----------------------------------------------------------------------===//
@@ -632,6 +567,12 @@ ${subscriptCommentPost}
632
567
//===--- Unavailable stuff ------------------------------------------------===//
633
568
634
569
extension MutableCollection where Self : Rando mAccessCollection {
570
+ @available ( * , unavailable, message: " call partition(by:) " )
571
+ public mutating func partition(
572
+ isOrderedBefore: @noescape ( ${ IElement} , ${ IElement} ) -> Bool
573
+ ) -> Index {
574
+ Builtin . unreachable ( )
575
+ }
635
576
636
577
@available ( * , unavailable, message: " slice the collection using the range, and call partition(by:) " )
637
578
public mutating func partition(
@@ -645,7 +586,12 @@ extension MutableCollection where Self : RandomAccessCollection {
645
586
extension MutableCollection
646
587
where Self : RandomAccessCollection, ${ IElement} : Comparable {
647
588
648
- @available ( * , unavailable, message: " slice the collection using the range, and call partition() " )
589
+ @available ( * , unavailable, message: " call partition(by:) " )
590
+ public mutating func partition( ) -> Index {
591
+ Builtin . unreachable ( )
592
+ }
593
+
594
+ @available ( * , unavailable, message: " slice the collection using the range, and call partition(by:) " )
649
595
public mutating func partition( _ range: Range < Index > ) -> Index {
650
596
Builtin . unreachable ( )
651
597
}
0 commit comments