Skip to content

Commit 5403129

Browse files
committed
[stdlib] add U[M]RBP.withMemoryRebound
1 parent 3de1eac commit 5403129

File tree

1 file changed

+55
-0
lines changed

1 file changed

+55
-0
lines changed

stdlib/public/core/UnsafeRawBufferPointer.swift.gyb

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -729,6 +729,61 @@ extension Unsafe${Mutable}RawBufferPointer {
729729
return Unsafe${Mutable}BufferPointer<T>(
730730
start: Unsafe${Mutable}Pointer<T>(base._rawValue), count: capacity)
731731
}
732+
733+
/// Executes the given closure while temporarily binding the buffer to
734+
/// instances of type `T`.
735+
///
736+
/// Use this method when you have a buffer to raw memory and you need
737+
/// to access that memory as instances of a given type `T`. Accessing
738+
/// memory as a type `T` requires that the memory be bound to that type.
739+
/// A memory location may only be bound to one type at a time, so accessing
740+
/// the same memory as an unrelated type without first rebinding the memory
741+
/// is undefined.
742+
///
743+
/// Any instance of `T` within the re-bound region may be initialized or
744+
/// uninitialized. If a given instance of `T` within the re-bound region
745+
/// overlaps with previously uninitialized memory, it shall be considered
746+
/// uninitialized when executing `body`.
747+
///
748+
/// After executing `body`, this method rebinds memory back to its original
749+
/// binding state. This can be unbound memory, or bound to a different type.
750+
///
751+
/// - Note: The buffer's base address must match the
752+
/// alignment of `T` (as reported by `MemoryLayout<T>.alignment`).
753+
/// That is, `Int(bitPattern: self.baseAddress) % MemoryLayout<T>.alignment`
754+
/// must equal zero.
755+
///
756+
/// - Parameters:
757+
/// - type: The type to temporarily bind the memory referenced by this
758+
/// pointer. This pointer must be a multiple of this type's alignment.
759+
/// - count: The number of instances of `T` to bind to `type`.
760+
/// - body: A closure that takes a typed pointer to the
761+
/// same memory as this pointer, only bound to type `T`. The closure's
762+
/// pointer argument is valid only for the duration of the closure's
763+
/// execution. If `body` has a return value, that value is also used as
764+
/// the return value for the `withMemoryRebound(to:capacity:_:)` method.
765+
/// - buffer: The buffer temporarily bound to instances of `T`.
766+
/// - Returns: The return value, if any, of the `body` closure parameter.
767+
@inlinable
768+
@_alwaysEmitIntoClient
769+
public func withMemoryRebound<T, Result>(
770+
to type: T.Type,
771+
_ body: (_ buffer: Unsafe${Mutable}BufferPointer<T>) throws -> Result
772+
) rethrows -> Result {
773+
guard let s = _position else {
774+
return try body(.init(start: nil, count: 0))
775+
}
776+
_debugPrecondition(
777+
Int(bitPattern: s) & (MemoryLayout<T>.alignment-1) == 0
778+
)
779+
// initializer ensures _end is nil only when _position is nil.
780+
_internalInvariant(_end != nil)
781+
let c = _assumeNonNegative(s.distance(to: _end._unsafelyUnwrappedUnchecked))
782+
let n = c / MemoryLayout<T>.stride
783+
let binding = Builtin.bindMemory(s._rawValue, n._builtinWordValue, T.self)
784+
defer { Builtin.rebindMemory(s._rawValue, binding) }
785+
return try body(.init(start: .init(s._rawValue), count: n))
786+
}
732787
}
733788

734789
extension Unsafe${Mutable}RawBufferPointer: CustomDebugStringConvertible {

0 commit comments

Comments
 (0)