Skip to content

Commit 7c76e4d

Browse files
[5.0][stdlib] Add withContiguousStorageIfAvailable (#21138)
* [stdlib] Add withContiguous{Mutable}StorageIfAvailable (#21092) * Add MutableCollection.withContiguousMutableStorageIfAvailable * Add withContiguousMutableStorageIfAvailable impls * Add tests on concrete types * Add Sequence.withContiguousStorageIfAvailable * Implement withContiguousStorageIfAvailable in concrete types * Add tests for withContiguousStorageIfAvailable
1 parent 7e4dfb7 commit 7c76e4d

14 files changed

+332
-19
lines changed

stdlib/private/StdlibCollectionUnittest/CheckMutableCollectionType.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -438,13 +438,13 @@ if resiliencyChecks.subscriptRangeOnOutOfBoundsRangesBehavior != .none {
438438
}
439439

440440
//===----------------------------------------------------------------------===//
441-
// _withUnsafeMutableBufferPointerIfSupported()
441+
// withContiguousMutableStorageIfAvailable()
442442
//===----------------------------------------------------------------------===//
443443

444-
self.test("\(testNamePrefix)._withUnsafeMutableBufferPointerIfSupported()/semantics") {
444+
self.test("\(testNamePrefix).withContiguousMutableStorageIfAvailable()/semantics") {
445445
for test in subscriptRangeTests {
446446
var c = makeWrappedCollection(test.collection)
447-
var result = c._withUnsafeMutableBufferPointerIfSupported {
447+
var result = c.withContiguousMutableStorageIfAvailable {
448448
(bufferPointer) -> OpaqueValue<Array<OpaqueValue<Int>>> in
449449
let value = OpaqueValue(bufferPointer.map(extractValue))
450450
return value

stdlib/private/StdlibCollectionUnittest/LoggingWrappers.swift

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ public class SequenceLog {
8383
public static var prefixWhile = TypeIndexed(0)
8484
public static var prefixMaxLength = TypeIndexed(0)
8585
public static var suffixMaxLength = TypeIndexed(0)
86+
public static var withContiguousStorageIfAvailable = TypeIndexed(0)
8687
public static var _customContainsEquatableElement = TypeIndexed(0)
8788
public static var _copyToContiguousArray = TypeIndexed(0)
8889
public static var _copyContents = TypeIndexed(0)
@@ -112,6 +113,9 @@ public class SequenceLog {
112113
public static var _withUnsafeMutableBufferPointerIfSupported = TypeIndexed(0)
113114
public static var _withUnsafeMutableBufferPointerIfSupportedNonNilReturns =
114115
TypeIndexed(0)
116+
public static var withContiguousMutableStorageIfAvailable = TypeIndexed(0)
117+
public static var withContiguousMutableStorageIfAvailableNonNilReturns =
118+
TypeIndexed(0)
115119
// RangeReplaceableCollection
116120
public static var init_ = TypeIndexed(0)
117121
public static var initRepeating = TypeIndexed(0)
@@ -210,6 +214,13 @@ extension LoggingSequence: Sequence {
210214
SequenceLog.underestimatedCount[selfType] += 1
211215
return base.underestimatedCount
212216
}
217+
218+
public func withContiguousStorageIfAvailable<R>(
219+
_ body: (UnsafeBufferPointer<Element>) throws -> R
220+
) rethrows -> R? {
221+
SequenceLog.withContiguousStorageIfAvailable[selfType] += 1
222+
return try base.withContiguousStorageIfAvailable(body)
223+
}
213224

214225
public func _customContainsEquatableElement(_ element: Element) -> Bool? {
215226
SequenceLog._customContainsEquatableElement[selfType] += 1
@@ -385,6 +396,17 @@ extension LoggingMutableCollection: MutableCollection {
385396
return result
386397
}
387398

399+
public mutating func withContiguousMutableStorageIfAvailable<R>(
400+
_ body: (inout UnsafeMutableBufferPointer<Element>) throws -> R
401+
) rethrows -> R? {
402+
MutableCollectionLog.withContiguousMutableStorageIfAvailable[selfType] += 1
403+
let result = try base.withContiguousMutableStorageIfAvailable(body)
404+
if result != nil {
405+
Log.withContiguousMutableStorageIfAvailable[selfType] += 1
406+
}
407+
return result
408+
}
409+
388410
}
389411

390412
public typealias LoggingMutableBidirectionalCollection<
@@ -501,10 +523,10 @@ public typealias LoggingRangeReplaceableRandomAccessCollection<
501523
> = LoggingRangeReplaceableCollection<Base>
502524

503525
//===----------------------------------------------------------------------===//
504-
// Collections that count calls to `_withUnsafeMutableBufferPointerIfSupported`
526+
// Collections that count calls to `withContiguousMutableStorageIfAvailable`
505527
//===----------------------------------------------------------------------===//
506528

507-
/// Interposes between `_withUnsafeMutableBufferPointerIfSupported` method calls
529+
/// Interposes between `withContiguousMutableStorageIfAvailable` method calls
508530
/// to increment a counter. Calls to this method from within dispatched methods
509531
/// are uncounted by the standard logging collection wrapper.
510532
public struct BufferAccessLoggingMutableCollection<
@@ -587,6 +609,17 @@ extension BufferAccessLoggingMutableCollection: MutableCollection {
587609
}
588610
return result
589611
}
612+
613+
public mutating func withContiguousMutableStorageIfAvailable<R>(
614+
_ body: (inout UnsafeMutableBufferPointer<Element>) throws -> R
615+
) rethrows -> R? {
616+
Log.withContiguousMutableStorageIfAvailable[selfType] += 1
617+
let result = try base.withContiguousMutableStorageIfAvailable(body)
618+
if result != nil {
619+
Log.withContiguousMutableStorageIfAvailable[selfType] += 1
620+
}
621+
return result
622+
}
590623
}
591624

592625
public typealias BufferAccessLoggingMutableBidirectionalCollection<

stdlib/public/core/Array.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1281,6 +1281,26 @@ extension Array: RangeReplaceableCollection {
12811281
}
12821282
}
12831283

1284+
@inlinable
1285+
public mutating func withContiguousMutableStorageIfAvailable<R>(
1286+
_ body: (inout UnsafeMutableBufferPointer<Element>) throws -> R
1287+
) rethrows -> R? {
1288+
return try withUnsafeMutableBufferPointer {
1289+
(bufferPointer) -> R in
1290+
return try body(&bufferPointer)
1291+
}
1292+
}
1293+
1294+
@inlinable
1295+
public func withContiguousStorageIfAvailable<R>(
1296+
_ body: (UnsafeBufferPointer<Element>) throws -> R
1297+
) rethrows -> R? {
1298+
return try withUnsafeBufferPointer {
1299+
(bufferPointer) -> R in
1300+
return try body(bufferPointer)
1301+
}
1302+
}
1303+
12841304
@inlinable
12851305
public __consuming func _copyToContiguousArray() -> ContiguousArray<Element> {
12861306
if let n = _buffer.requestNativeBuffer() {

stdlib/public/core/ArraySlice.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1075,6 +1075,26 @@ extension ArraySlice: RangeReplaceableCollection {
10751075
}
10761076
}
10771077

1078+
@inlinable
1079+
public mutating func withContiguousMutableStorageIfAvailable<R>(
1080+
_ body: (inout UnsafeMutableBufferPointer<Element>) throws -> R
1081+
) rethrows -> R? {
1082+
return try withUnsafeMutableBufferPointer {
1083+
(bufferPointer) -> R in
1084+
return try body(&bufferPointer)
1085+
}
1086+
}
1087+
1088+
@inlinable
1089+
public func withContiguousStorageIfAvailable<R>(
1090+
_ body: (UnsafeBufferPointer<Element>) throws -> R
1091+
) rethrows -> R? {
1092+
return try withUnsafeBufferPointer {
1093+
(bufferPointer) -> R in
1094+
return try body(bufferPointer)
1095+
}
1096+
}
1097+
10781098
@inlinable
10791099
public __consuming func _copyToContiguousArray() -> ContiguousArray<Element> {
10801100
if let n = _buffer.requestNativeBuffer() {

stdlib/public/core/ContiguousArray.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -923,6 +923,26 @@ extension ContiguousArray: RangeReplaceableCollection {
923923
}
924924
}
925925

926+
@inlinable
927+
public mutating func withContiguousMutableStorageIfAvailable<R>(
928+
_ body: (inout UnsafeMutableBufferPointer<Element>) throws -> R
929+
) rethrows -> R? {
930+
return try withUnsafeMutableBufferPointer {
931+
(bufferPointer) -> R in
932+
return try body(&bufferPointer)
933+
}
934+
}
935+
936+
@inlinable
937+
public func withContiguousStorageIfAvailable<R>(
938+
_ body: (UnsafeBufferPointer<Element>) throws -> R
939+
) rethrows -> R? {
940+
return try withUnsafeBufferPointer {
941+
(bufferPointer) -> R in
942+
return try body(bufferPointer)
943+
}
944+
}
945+
926946
@inlinable
927947
public __consuming func _copyToContiguousArray() -> ContiguousArray<Element> {
928948
if let n = _buffer.requestNativeBuffer() {

stdlib/public/core/MutableCollection.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,20 @@ where SubSequence: MutableCollection
180180
mutating func _withUnsafeMutableBufferPointerIfSupported<R>(
181181
_ body: (inout UnsafeMutableBufferPointer<Element>) throws -> R
182182
) rethrows -> R?
183+
184+
/// Call `body(p)`, where `p` is a pointer to the collection's
185+
/// mutable contiguous storage. If no such storage exists, it is
186+
/// first created. If the collection does not support an internal
187+
/// representation in a form of mutable contiguous storage, `body` is not
188+
/// called and `nil` is returned.
189+
///
190+
/// Often, the optimizer can eliminate bounds- and uniqueness-checks
191+
/// within an algorithm, but when that fails, invoking the
192+
/// same algorithm on `body`\ 's argument lets you trade safety for
193+
/// speed.
194+
mutating func withContiguousMutableStorageIfAvailable<R>(
195+
_ body: (inout UnsafeMutableBufferPointer<Element>) throws -> R
196+
) rethrows -> R?
183197
}
184198

185199
// TODO: swift-3-indexing-model - review the following
@@ -191,6 +205,13 @@ extension MutableCollection {
191205
return nil
192206
}
193207

208+
@inlinable
209+
public mutating func withContiguousMutableStorageIfAvailable<R>(
210+
_ body: (inout UnsafeMutableBufferPointer<Element>) throws -> R
211+
) rethrows -> R? {
212+
return nil
213+
}
214+
194215
/// Accesses a contiguous subrange of the collection's elements.
195216
///
196217
/// The accessed slice uses the same indices for the same elements as the

stdlib/public/core/Sequence.swift

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,10 @@ public protocol Sequence {
362362
__consuming func _copyContents(
363363
initializing ptr: UnsafeMutableBufferPointer<Element>
364364
) -> (Iterator,UnsafeMutableBufferPointer<Element>.Index)
365+
366+
func withContiguousStorageIfAvailable<R>(
367+
_ body: (UnsafeBufferPointer<Element>) throws -> R
368+
) rethrows -> R?
365369
}
366370

367371
// Provides a default associated type witness for Iterator when the
@@ -1092,17 +1096,24 @@ extension Sequence {
10921096
public __consuming func _copyContents(
10931097
initializing buffer: UnsafeMutableBufferPointer<Element>
10941098
) -> (Iterator,UnsafeMutableBufferPointer<Element>.Index) {
1095-
var it = self.makeIterator()
1096-
guard var ptr = buffer.baseAddress else { return (it,buffer.startIndex) }
1097-
for idx in buffer.startIndex..<buffer.count {
1098-
guard let x = it.next() else {
1099-
return (it, idx)
1100-
}
1101-
ptr.initialize(to: x)
1102-
ptr += 1
1099+
var it = self.makeIterator()
1100+
guard var ptr = buffer.baseAddress else { return (it,buffer.startIndex) }
1101+
for idx in buffer.startIndex..<buffer.count {
1102+
guard let x = it.next() else {
1103+
return (it, idx)
11031104
}
1104-
return (it,buffer.endIndex)
1105+
ptr.initialize(to: x)
1106+
ptr += 1
11051107
}
1108+
return (it,buffer.endIndex)
1109+
}
1110+
1111+
@inlinable
1112+
public func withContiguousStorageIfAvailable<R>(
1113+
_ body: (UnsafeBufferPointer<Element>) throws -> R
1114+
) rethrows -> R? {
1115+
return nil
1116+
}
11061117
}
11071118

11081119
// FIXME(ABI)#182

stdlib/public/core/UnsafeBufferPointer.swift.gyb

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,25 @@ extension Unsafe${Mutable}BufferPointer {
432432
return try body(&self)
433433
}
434434

435+
@inlinable
436+
public mutating func withContiguousMutableStorageIfAvailable<R>(
437+
_ body: (inout UnsafeMutableBufferPointer<Element>) throws -> R
438+
) rethrows -> R? {
439+
let (oldBase, oldCount) = (self.baseAddress, self.count)
440+
defer {
441+
_debugPrecondition((oldBase, oldCount) == (self.baseAddress, self.count),
442+
"UnsafeMutableBufferPointer.withUnsafeMutableBufferPointer: replacing the buffer is not allowed")
443+
}
444+
return try body(&self)
445+
}
446+
447+
@inlinable
448+
public func withContiguousStorageIfAvailable<R>(
449+
_ body: (UnsafeBufferPointer<Element>) throws -> R
450+
) rethrows -> R? {
451+
return try body(UnsafeBufferPointer(self))
452+
}
453+
435454
% else:
436455

437456
/// Creates an immutable typed buffer pointer referencing the same memory as the
@@ -444,6 +463,13 @@ extension Unsafe${Mutable}BufferPointer {
444463
count = other.count
445464
}
446465
466+
@inlinable
467+
public func withContiguousStorageIfAvailable<R>(
468+
_ body: (UnsafeBufferPointer<Element>) throws -> R
469+
) rethrows -> R? {
470+
return try body(self)
471+
}
472+
447473
% end
448474

449475
% if not Mutable:

test/api-digester/Outputs/stability-stdlib-abi.swift.expected

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,3 +541,6 @@ Class _StringStorage has changed its super class from _AbstractStringStorage to
541541
Constructor _AbstractStringStorage.init() has been removed
542542
Func _AbstractStringStorage.copy(with:) has been removed
543543
Func _AbstractStringStorage.getOrComputeBreadcrumbs() has been removed
544+
545+
Func MutableCollection.withContiguousMutableStorageIfAvailable(_:) has been added as a protocol requirement
546+
Func Sequence.withContiguousStorageIfAvailable(_:) has been added as a protocol requirement

test/api-digester/Outputs/stability-stdlib-source.swift.expected

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,3 +213,6 @@ Func LazyCollectionProtocol.reversed() has been removed
213213
Var LazyCollectionProtocol.lazy has declared type change from LazyCollection<Self.Elements> to LazySequence<Self.Elements>
214214

215215
Func Sequence.reduce(into:_:) has parameter 0 changing from Default to Owned
216+
217+
Func MutableCollection.withContiguousMutableStorageIfAvailable(_:) has been added as a protocol requirement
218+
Func Sequence.withContiguousStorageIfAvailable(_:) has been added as a protocol requirement

0 commit comments

Comments
 (0)