Skip to content

Commit 0836707

Browse files
[stdlib] Deprecate MutableCollection._withUnsafeMutableBufferPointerIfSupported (#36003)
* [stdlib] Deprecate MutableCollection._withUnsafeMutableBufferPointerIfSupported In Swift 5.0, [SE-0237] introduced the public `MutableCollection.withContiguousMutableStorageIfAvailable` method. It’s time we migrated off the old, underscored variant and deprecated it. The default `MutableCollection.sort` and `.partition(by:)` implementations are currently calling this hidden method rather than the documented interface, preventing custom Collection implementations from achieving good performance, even if they have contiguous storage. [SE-0237]: https://github.com/apple/swift-evolution/blob/master/proposals/0237-contiguous-collection.md * [test] Update tests for stdlib behavior changes * Update stdlib/private/StdlibCollectionUnittest/CheckMutableCollectionType.swift Co-authored-by: Nate Cook <[email protected]> * Update stdlib/private/StdlibCollectionUnittest/CheckMutableCollectionType.swift Co-authored-by: Nate Cook <[email protected]> * Apply suggestions from code review Co-authored-by: Nate Cook <[email protected]> * [test] LoggingMutableCollection: Fix logging targets * [stdlib] Fix warning by restoring original workaround Co-authored-by: Nate Cook <[email protected]>
1 parent 2b8c701 commit 0836707

File tree

9 files changed

+46
-23
lines changed

9 files changed

+46
-23
lines changed

stdlib/private/StdlibCollectionUnittest/CheckMutableCollectionType.swift

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,7 @@ func checkSortedPredicateThrow(
512512
}
513513
}
514514

515-
self.test("\(testNamePrefix).sorted/DispatchesThrough_withUnsafeMutableBufferPointerIfSupported/WhereElementIsComparable") {
515+
self.test("\(testNamePrefix).sorted/DispatchesThroughDirectStorageAccessors/WhereElementIsComparable") {
516516
let sequence = [ 5, 4, 3, 2, 1 ]
517517
let elements: [MinimalComparableValue] =
518518
zip(sequence, 0..<sequence.count).map {
@@ -525,13 +525,16 @@ self.test("\(testNamePrefix).sorted/DispatchesThrough_withUnsafeMutableBufferPoi
525525
let result = lc.sorted()
526526
let extractedResult = result.map(extractValueFromComparable)
527527

528+
let actualWUMBPIF = lc.log._withUnsafeMutableBufferPointerIfSupported[type(of: lc)]
529+
let actualWCMSIA = lc.log.withContiguousMutableStorageIfAvailable[type(of: lc)]
530+
531+
let actualWUMBPIFNonNil = lc.log._withUnsafeMutableBufferPointerIfSupportedNonNilReturns[type(of: lc)]
532+
let actualWCMSIANonNil = lc.log.withContiguousMutableStorageIfAvailableNonNilReturns[type(of: lc)]
533+
528534
// This sort operation is not in-place.
529535
// The collection is copied into an array before sorting.
530-
expectEqual(
531-
0, lc.log._withUnsafeMutableBufferPointerIfSupported[type(of: lc)])
532-
expectEqual(
533-
0,
534-
lc.log._withUnsafeMutableBufferPointerIfSupportedNonNilReturns[type(of: lc)])
536+
expectEqual(0, actualWUMBPIF + actualWCMSIA)
537+
expectEqual(0, actualWUMBPIFNonNil + actualWCMSIANonNil)
535538

536539
expectEqualSequence([ 1, 2, 3, 4, 5 ], extractedResult.map { $0.value })
537540
}
@@ -631,7 +634,7 @@ self.test("\(testNamePrefix).sorted/ThrowingPredicateWithLargeNumberElements") {
631634
}
632635

633636

634-
self.test("\(testNamePrefix).sorted/DispatchesThrough_withUnsafeMutableBufferPointerIfSupported/Predicate") {
637+
self.test("\(testNamePrefix).sorted/DispatchesThroughDirectStorageAccessors/Predicate") {
635638
let sequence = [ 5, 4, 3, 2, 1 ]
636639
let elements: [OpaqueValue<Int>] =
637640
zip(sequence, 0..<sequence.count).map {
@@ -644,13 +647,16 @@ self.test("\(testNamePrefix).sorted/DispatchesThrough_withUnsafeMutableBufferPoi
644647
let result = lc.sorted { extractValue($0).value < extractValue($1).value }
645648
let extractedResult = result.map(extractValue)
646649

650+
let actualWUMBPIF = lc.log._withUnsafeMutableBufferPointerIfSupported[type(of: lc)]
651+
let actualWCMSIA = lc.log.withContiguousMutableStorageIfAvailable[type(of: lc)]
652+
653+
let actualWUMBPIFNonNil = lc.log._withUnsafeMutableBufferPointerIfSupportedNonNilReturns[type(of: lc)]
654+
let actualWCMSIAIFNonNil = lc.log.withContiguousMutableStorageIfAvailableNonNilReturns[type(of: lc)]
655+
647656
// This sort operation is not in-place.
648657
// The collection is copied into an array before sorting.
649-
expectEqual(
650-
0, lc.log._withUnsafeMutableBufferPointerIfSupported[type(of: lc)])
651-
expectEqual(
652-
0,
653-
lc.log._withUnsafeMutableBufferPointerIfSupportedNonNilReturns[type(of: lc)])
658+
expectEqual(0, actualWUMBPIF + actualWCMSIA)
659+
expectEqual(0, actualWUMBPIFNonNil + actualWCMSIAIFNonNil)
654660

655661
expectEqualSequence([ 1, 2, 3, 4, 5 ], extractedResult.map { $0.value })
656662
}
@@ -949,7 +955,7 @@ self.test("\(testNamePrefix).reverse()") {
949955
// partition(by:)
950956
//===----------------------------------------------------------------------===//
951957

952-
self.test("\(testNamePrefix).partition/DispatchesThrough_withUnsafeMutableBufferPointerIfSupported") {
958+
self.test("\(testNamePrefix).partition/DispatchesThroughDirectStorageAccessors") {
953959
let sequence = [ 5, 4, 3, 2, 1 ]
954960
let elements: [OpaqueValue<Int>] =
955961
zip(sequence, 0..<sequence.count).map {
@@ -965,11 +971,23 @@ self.test("\(testNamePrefix).partition/DispatchesThrough_withUnsafeMutableBuffer
965971
return !(extractValue(val).value < extractValue(first!).value)
966972
})
967973

968-
expectEqual(
969-
1, lc.log._withUnsafeMutableBufferPointerIfSupported[type(of: lc)])
974+
let actualWUMBPIF = lc.log._withUnsafeMutableBufferPointerIfSupported[type(of: lc)]
975+
let actualWCMSIA = lc.log.withContiguousMutableStorageIfAvailable[type(of: lc)]
976+
977+
let actualWUMBPIFNonNil = lc.log._withUnsafeMutableBufferPointerIfSupportedNonNilReturns[type(of: lc)]
978+
let actualWCMSIAIFNonNil = lc.log.withContiguousMutableStorageIfAvailableNonNilReturns[type(of: lc)]
979+
980+
expectEqual(1, actualWUMBPIF + actualWCMSIA)
970981
expectEqual(
971982
withUnsafeMutableBufferPointerIsSupported ? 1 : 0,
972-
lc.log._withUnsafeMutableBufferPointerIfSupportedNonNilReturns[type(of: lc)])
983+
actualWUMBPIFNonNil + actualWCMSIAIFNonNil)
984+
985+
if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) {
986+
// `partition(by:)` is expected to dispatch to the public API in releases
987+
// that contain https://github.com/apple/swift/pull/36003.
988+
expectEqual(0, actualWUMBPIF)
989+
expectEqual(0, actualWUMBPIFNonNil)
990+
}
973991

974992
expectEqual(4, lc.distance(from: lc.startIndex, to: pivot))
975993
expectEqualsUnordered([1, 2, 3, 4], lc.prefix(upTo: pivot).map { extractValue($0).value })
@@ -1279,4 +1297,3 @@ self.test("\(testNamePrefix).sort/ThrowingPredicateWithLargeNumberElements") {
12791297

12801298
} // addMutableRandomAccessCollectionTests
12811299
}
1282-

stdlib/private/StdlibCollectionUnittest/LoggingWrappers.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,7 @@ extension LoggingMutableCollection: MutableCollection {
404404
MutableCollectionLog.withContiguousMutableStorageIfAvailable[selfType] += 1
405405
let result = try base.withContiguousMutableStorageIfAvailable(body)
406406
if result != nil {
407-
Log.withContiguousMutableStorageIfAvailable[selfType] += 1
407+
Log.withContiguousMutableStorageIfAvailableNonNilReturns[selfType] += 1
408408
}
409409
return result
410410
}
@@ -618,7 +618,7 @@ extension BufferAccessLoggingMutableCollection: MutableCollection {
618618
Log.withContiguousMutableStorageIfAvailable[selfType] += 1
619619
let result = try base.withContiguousMutableStorageIfAvailable(body)
620620
if result != nil {
621-
Log.withContiguousMutableStorageIfAvailable[selfType] += 1
621+
Log.withContiguousMutableStorageIfAvailableNonNilReturns[selfType] += 1
622622
}
623623
return result
624624
}

stdlib/public/core/Array.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1356,6 +1356,7 @@ extension Array: RangeReplaceableCollection {
13561356
//===--- algorithms -----------------------------------------------------===//
13571357

13581358
@inlinable
1359+
@available(*, deprecated, renamed: "withContiguousMutableStorageIfAvailable")
13591360
public mutating func _withUnsafeMutableBufferPointerIfSupported<R>(
13601361
_ body: (inout UnsafeMutableBufferPointer<Element>) throws -> R
13611362
) rethrows -> R? {

stdlib/public/core/ArraySlice.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1079,6 +1079,7 @@ extension ArraySlice: RangeReplaceableCollection {
10791079
//===--- algorithms -----------------------------------------------------===//
10801080

10811081
@inlinable
1082+
@available(*, deprecated, renamed: "withContiguousMutableStorageIfAvailable")
10821083
public mutating func _withUnsafeMutableBufferPointerIfSupported<R>(
10831084
_ body: (inout UnsafeMutableBufferPointer<Element>) throws -> R
10841085
) rethrows -> R? {

stdlib/public/core/CollectionAlgorithms.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ extension MutableCollection where Self: BidirectionalCollection {
318318
public mutating func partition(
319319
by belongsInSecondPartition: (Element) throws -> Bool
320320
) rethrows -> Index {
321-
let maybeOffset = try _withUnsafeMutableBufferPointerIfSupported {
321+
let maybeOffset = try withContiguousMutableStorageIfAvailable {
322322
(bufferPointer) -> Int in
323323
let unsafeBufferPivot = try bufferPointer._partitionImpl(
324324
by: belongsInSecondPartition)

stdlib/public/core/ContiguousArray.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -980,6 +980,7 @@ extension ContiguousArray: RangeReplaceableCollection {
980980
//===--- algorithms -----------------------------------------------------===//
981981

982982
@inlinable
983+
@available(*, deprecated, renamed: "withContiguousMutableStorageIfAvailable")
983984
public mutating func _withUnsafeMutableBufferPointerIfSupported<R>(
984985
_ body: (inout UnsafeMutableBufferPointer<Element>) throws -> R
985986
) rethrows -> R? {

stdlib/public/core/MutableCollection.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ where SubSequence: MutableCollection
177177
/// within an algorithm, but when that fails, invoking the
178178
/// same algorithm on `body`\ 's argument lets you trade safety for
179179
/// speed.
180+
@available(*, deprecated, renamed: "withContiguousMutableStorageIfAvailable")
180181
mutating func _withUnsafeMutableBufferPointerIfSupported<R>(
181182
_ body: (inout UnsafeMutableBufferPointer<Element>) throws -> R
182183
) rethrows -> R?
@@ -199,6 +200,7 @@ where SubSequence: MutableCollection
199200
// TODO: swift-3-indexing-model - review the following
200201
extension MutableCollection {
201202
@inlinable
203+
@available(*, deprecated, renamed: "withContiguousMutableStorageIfAvailable")
202204
public mutating func _withUnsafeMutableBufferPointerIfSupported<R>(
203205
_ body: (inout UnsafeMutableBufferPointer<Element>) throws -> R
204206
) rethrows -> R? {

stdlib/public/core/Sort.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -246,10 +246,10 @@ extension MutableCollection where Self: RandomAccessCollection {
246246
public mutating func sort(
247247
by areInIncreasingOrder: (Element, Element) throws -> Bool
248248
) rethrows {
249-
let didSortUnsafeBuffer: Void? = try _withUnsafeMutableBufferPointerIfSupported {
250-
buffer -> Void in
249+
let didSortUnsafeBuffer: Void? =
250+
try withContiguousMutableStorageIfAvailable { buffer in
251251
try buffer._stableSortImpl(by: areInIncreasingOrder)
252-
}
252+
}
253253
if didSortUnsafeBuffer == nil {
254254
// Fallback since we can't use an unsafe buffer: sort into an outside
255255
// array, then copy elements back in.

stdlib/public/core/UnsafeBufferPointer.swift.gyb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,7 @@ extension Unsafe${Mutable}BufferPointer {
446446
}
447447

448448
@inlinable
449+
@available(*, deprecated, renamed: "withContiguousMutableStorageIfAvailable")
449450
public mutating func _withUnsafeMutableBufferPointerIfSupported<R>(
450451
_ body: (inout UnsafeMutableBufferPointer<Element>) throws -> R
451452
) rethrows -> R? {

0 commit comments

Comments
 (0)