Adopt typed throws for withUnsafeMutableBufferPointer

This commit is contained in:
Doug Gregor
2024-08-15 14:43:38 -07:00
parent 5c07fd9502
commit 4d037ce6ef
9 changed files with 139 additions and 59 deletions

View File

@@ -1612,42 +1612,8 @@ extension Array {
return try _buffer.withUnsafeBufferPointer(body)
}
/// Calls the given closure with a pointer to the array's mutable contiguous
/// storage.
///
/// Often, the optimizer can eliminate bounds checks within an array
/// algorithm, but when that fails, invoking the same algorithm on the
/// buffer pointer passed into your closure lets you trade safety for speed.
///
/// The following example shows how modifying the contents of the
/// `UnsafeMutableBufferPointer` argument to `body` alters the contents of
/// the array:
///
/// var numbers = [1, 2, 3, 4, 5]
/// numbers.withUnsafeMutableBufferPointer { buffer in
/// for i in stride(from: buffer.startIndex, to: buffer.endIndex - 1, by: 2) {
/// buffer.swapAt(i, i + 1)
/// }
/// }
/// print(numbers)
/// // Prints "[2, 1, 4, 3, 5]"
///
/// The pointer passed as an argument to `body` is valid only during the
/// execution of `withUnsafeMutableBufferPointer(_:)`. Do not store or
/// return the pointer for later use.
///
/// - Warning: Do not rely on anything about the array that is the target of
/// this method during execution of the `body` closure; it might not
/// appear to have its correct value. Instead, use only the
/// `UnsafeMutableBufferPointer` argument to `body`.
///
/// - Parameter body: A closure with an `UnsafeMutableBufferPointer`
/// parameter that points to the contiguous storage for the array.
/// If no such storage exists, it is created. If `body` has a return value, that value is also
/// used as the return value for the `withUnsafeMutableBufferPointer(_:)`
/// method. The pointer argument is valid only for the duration of the
/// method's execution.
/// - Returns: The return value, if any, of the `body` closure parameter.
// Superseded by the typed-throws version of this function, but retained
// for ABI reasons.
@_semantics("array.withUnsafeMutableBufferPointer")
@_effects(notEscaping self.value**)
@inlinable // FIXME(inline-always)
@@ -1655,7 +1621,8 @@ extension Array {
// caller such that we can combine the partial apply with the apply in this
// function saving on allocating a closure context. This becomes unnecessary
// once we allocate noescape closures on the stack.
public mutating func withUnsafeMutableBufferPointer<R>(
@_silgen_name("$sSa30withUnsafeMutableBufferPointeryqd__qd__SryxGzKXEKlF")
mutating func __abi_withUnsafeMutableBufferPointer<R>(
_ body: (inout UnsafeMutableBufferPointer<Element>) throws -> R
) rethrows -> R {
_makeMutableAndUnique()
@@ -1679,6 +1646,37 @@ extension Array {
return try body(&inoutBufferPointer)
}
@_semantics("array.withUnsafeMutableBufferPointer")
@_effects(notEscaping self.value**)
@_alwaysEmitIntoClient
@inline(__always) // Performance: This method should get inlined into the
// caller such that we can combine the partial apply with the apply in this
// function saving on allocating a closure context. This becomes unnecessary
// once we allocate noescape closures on the stack.
public mutating func withUnsafeMutableBufferPointer<R, E>(
_ body: (inout UnsafeMutableBufferPointer<Element>) throws(E) -> R
) throws(E) -> R {
_makeMutableAndUnique()
let count = _buffer.mutableCount
// Create an UnsafeBufferPointer that we can pass to body
let pointer = _buffer.mutableFirstElementAddress
var inoutBufferPointer = UnsafeMutableBufferPointer(
start: pointer, count: count)
defer {
_precondition(
inoutBufferPointer.baseAddress == pointer &&
inoutBufferPointer.count == count,
"Array withUnsafeMutableBufferPointer: replacing the buffer is not allowed")
_endMutation()
_fixLifetime(self)
}
// Invoke the body.
return try body(&inoutBufferPointer)
}
@inlinable
public __consuming func _copyContents(
initializing buffer: UnsafeMutableBufferPointer<Element>