Skip to content

Commit 3de1eac

Browse files
committed
[stdlib] add U[M]RP.withMemoryRebound
1 parent 5f5c75d commit 3de1eac

File tree

1 file changed

+115
-0
lines changed

1 file changed

+115
-0
lines changed

stdlib/public/core/UnsafeRawPointer.swift

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,64 @@ public struct UnsafeRawPointer: _Pointer {
319319
return UnsafePointer<T>(_rawValue)
320320
}
321321

322+
/// Executes the given closure while temporarily binding memory to
323+
/// the specified number of instances of type `T`.
324+
///
325+
/// Use this method when you have a pointer to raw memory and you need
326+
/// to access that memory as instances of a given type `T`. Accessing
327+
/// memory as a type `T` requires that the memory be bound to that type. A
328+
/// memory location may only be bound to one type at a time, so accessing
329+
/// the same memory as an unrelated type without first rebinding the memory
330+
/// is undefined.
331+
///
332+
/// Any instance of `T` within the re-bound region may be initialized or
333+
/// uninitialized. If a given instance of `T` within the re-bound region
334+
/// overlaps with previously uninitialized memory, it shall be considered
335+
/// uninitialized when executing `body`.
336+
///
337+
/// The following example temporarily rebinds a raw memory pointer
338+
/// to `Int64`, then accesses a property on the signed integer.
339+
///
340+
/// let pointer: UnsafeRawPointer = fetchValue()
341+
/// let isNegative = pointer.withMemoryRebound(to: Int64.self,
342+
/// capacity: 1) {
343+
/// return $0.pointee < 0
344+
/// }
345+
///
346+
/// After executing `body`, this method rebinds memory back to its original
347+
/// binding state. This can be unbound memory, or bound to a different type.
348+
///
349+
/// - Note: The region of memory starting at this pointer must match the
350+
/// alignment of `T` (as reported by `MemoryLayout<T>.alignment`).
351+
/// That is, `Int(bitPattern: self) % MemoryLayout<T>.alignment`
352+
/// must equal zero.
353+
///
354+
/// - Parameters:
355+
/// - type: The type to temporarily bind the memory referenced by this
356+
/// pointer. This pointer must be a multiple of this type's alignment.
357+
/// - count: The number of instances of `T` in the re-bound region.
358+
/// - body: A closure that takes a typed pointer to the
359+
/// same memory as this pointer, only bound to type `T`. The closure's
360+
/// pointer argument is valid only for the duration of the closure's
361+
/// execution. If `body` has a return value, that value is also used as
362+
/// the return value for the `withMemoryRebound(to:capacity:_:)` method.
363+
/// - pointer: The pointer temporarily bound to `T`.
364+
/// - Returns: The return value, if any, of the `body` closure parameter.
365+
@inlinable
366+
@_alwaysEmitIntoClient
367+
public func withMemoryRebound<T, Result>(
368+
to type: T.Type,
369+
capacity count: Int,
370+
_ body: (_ pointer: UnsafePointer<T>) throws -> Result
371+
) rethrows -> Result {
372+
_debugPrecondition(
373+
Int(bitPattern: self) & (MemoryLayout<T>.alignment-1) == 0
374+
)
375+
let binding = Builtin.bindMemory(_rawValue, count._builtinWordValue, T.self)
376+
defer { Builtin.rebindMemory(_rawValue, binding) }
377+
return try body(.init(_rawValue))
378+
}
379+
322380
/// Returns a typed pointer to the memory referenced by this pointer,
323381
/// assuming that the memory is already bound to the specified type.
324382
///
@@ -694,6 +752,63 @@ public struct UnsafeMutableRawPointer: _Pointer {
694752
return UnsafeMutablePointer<T>(_rawValue)
695753
}
696754

755+
/// Executes the given closure while temporarily binding memory to
756+
/// the specified number of instances of type `T`.
757+
///
758+
/// Use this method when you have a pointer to raw memory and you need
759+
/// to access that memory as instances of a given type `T`. Accessing
760+
/// memory as a type `T` requires that the memory be bound to that type. A
761+
/// memory location may only be bound to one type at a time, so accessing
762+
/// the same memory as an unrelated type without first rebinding the memory
763+
/// is undefined.
764+
///
765+
/// Any instance of `T` within the re-bound region may be initialized or
766+
/// uninitialized. If a given instance of `T` within the re-bound region
767+
/// overlaps with previously uninitialized memory, it shall be considered
768+
/// uninitialized when executing `body`.
769+
///
770+
/// The following example temporarily rebinds a raw memory pointer
771+
/// to `Int64`, then modifies the signed integer.
772+
///
773+
/// let pointer: UnsafeMutableRawPointer = fetchValue()
774+
/// pointer.withMemoryRebound(to: Int64.self, capacity: 1) {
775+
/// ptr.pointee.negate()
776+
/// }
777+
///
778+
/// After executing `body`, this method rebinds memory back to its original
779+
/// binding state. This can be unbound memory, or bound to a different type.
780+
///
781+
/// - Note: The region of memory starting at this pointer must match the
782+
/// alignment of `T` (as reported by `MemoryLayout<T>.alignment`).
783+
/// That is, `Int(bitPattern: self) % MemoryLayout<T>.alignment`
784+
/// must equal zero.
785+
///
786+
/// - Parameters:
787+
/// - type: The type to temporarily bind the memory referenced by this
788+
/// pointer. This pointer must be a multiple of this type's alignment.
789+
/// - count: The number of instances of `T` in the re-bound region.
790+
/// - body: A closure that takes a typed pointer to the
791+
/// same memory as this pointer, only bound to type `T`. The closure's
792+
/// pointer argument is valid only for the duration of the closure's
793+
/// execution. If `body` has a return value, that value is also used as
794+
/// the return value for the `withMemoryRebound(to:capacity:_:)` method.
795+
/// - pointer: The pointer temporarily bound to `T`.
796+
/// - Returns: The return value, if any, of the `body` closure parameter.
797+
@inlinable
798+
@_alwaysEmitIntoClient
799+
public func withMemoryRebound<T, Result>(
800+
to type: T.Type,
801+
capacity count: Int,
802+
_ body: (_ pointer: UnsafeMutablePointer<T>) throws -> Result
803+
) rethrows -> Result {
804+
_debugPrecondition(
805+
Int(bitPattern: self) & (MemoryLayout<T>.alignment-1) == 0
806+
)
807+
let binding = Builtin.bindMemory(_rawValue, count._builtinWordValue, T.self)
808+
defer { Builtin.rebindMemory(_rawValue, binding) }
809+
return try body(.init(_rawValue))
810+
}
811+
697812
/// Returns a typed pointer to the memory referenced by this pointer,
698813
/// assuming that the memory is already bound to the specified type.
699814
///

0 commit comments

Comments
 (0)