- Proposal: SE-NNNN Better Buffer Slices (and Partial Initialization of Buffers)
- Author: Guillaume Lessard
- Review Manager: TBD
- Status: pending
- Implementation: Draft Pull Request
- Bugs: rdar://51817146
- Previous Revision: none
Sub-sequences of the UnsafeBufferPointer
family have all the [Mutable]Collection
API of UnsafeBufferPointer
,
but have none of their buffer-specific API.
This makes partial initialization of a buffer difficult, among other tasks.
Swift-evolution thread: Pitch thread
An example of partial initialization is inserting elements in the middle of a collection,
one of the possible operations needed in an implementation of RangeReplaceableCollection.replaceSubrange(_:with:)
.
Given a RangeReplaceableCollection
whose unique storage can be represented by a partially-initialized UnsafeMutableBufferPointer
:
mutating func replaceSubrange<C>(_ subrange: Range<Index>, with newElements: C)
where C: Collection, Element == C.Element {
// obtain unique storage as UnsafeMutableBufferPointer
let buffer: UnsafeMutableBufferPointer<Element> = self.myUniqueStorage()
let oldCount = self.count
let growth = newElements.count - subrange.count
let newCount = oldCount + growth
if growth > 0 {
assert(newCount < buffer.count)
let oldTail = subrange.upperBound..<oldCount
let newTail = subrange.upperBound+growth..<newCount
let oldTailBase = buffer.baseAddress!.advanced(by: oldTail.lowerBound)
let newTailBase = buffer.baseAddress!.advanced(by: newTail.lowerBound)
newTailBase.moveInitialize(from: oldTailBase,
count: oldCount - subrange.upperBound)
// Update still-initialized values in the original subrange
var j = newElements.startIndex
for i in subrange {
buffer[i] = newElements[j]
newElements.formIndex(after: &j)
}
// Initialize the remaining range
for i in subrange.upperBound..<newTail.lowerBound {
buffer.baseAddress!.advanced(by: i).initialize(to: newElements[j])
newElements.formIndex(after: &j)
}
assert(newElements.distance(from: newElements.startIndex, to: j) == newElements.count)
}
... // other situations
}
Here, we had to convert to UnsafeMutablePointer
to use some of its API,
as well as resort to element-by-element copying and initialization.
With API enabling buffer operations on the slices of buffers,
we could simplify things greatly:
mutating func replaceSubrange<C>(_ subrange: Range<Index>, with newElements: C)
where C: Collection, Element == C.Element {
// obtain unique storage as UnsafeMutableBufferPointer
let buffer: UnsafeMutableBufferPointer<Element> = self.myUniqueStorage()
let oldCount = self.count
let growth = newElements.count - subrange.count
let newCount = oldCount + growth
if growth > 0 {
assert(newCount < buffer.count)
let oldTail = subrange.upperBound..<count
let newTail = subrange.upperBound+growth..<newCount
var m = buffer[newTail].moveInitialize(fromElements: buffer[oldTail])
// Update still-initialized values in the original subrange
m = buffer[subrange].update(fromElements: newElements)
// Initialize the remaining range
m = buffer[m..<newTail.lowerBound].initialize(
fromElements: newElements.dropFirst(m - subrange.lowerBound)
)
assert(m == newTail.lowerBound)
}
... // other situations
}
In addition to simplifying the implementation,
the new methods have the advantage of having the same bounds-checking behaviour as UnsafeMutableBufferPointer
,
relieving the implementation from being required to do its own bounds checking.
We propose to add to slices of Unsafe[Mutable][Raw]BufferPointer
all the BufferPointer
-specific methods of their Base
.
Note: many of these methods were recently pitched here.
Addition to Slice<UnsafeBufferPointer<T>>
:
public func withMemoryRebound<T, Result>(
to type: T.Type,
_ body: (UnsafeBufferPointer<T>) throws -> Result
) rethrows -> Result
Additions to Slice<UnsafeMutableBufferPointer<T>>
:
func initialize(repeating repeatedValue: Element)
func initialize<S: Sequence>(from source: S) -> (S.Iterator, Index)
where S.Element == Element
func initialize<C: Collection>(fromElements: C) -> Index
where C.Element == Element
func update(repeating repeatedValue: Element)
func update<S: Sequence>(
from source: S
) -> (iterator: S.Iterator, updated: Index) where S.Element == Element
func update<C: Collection>(
fromElements: C
) -> Index where C.Element == Element
func moveInitialize(fromElements source: UnsafeMutableBufferPointer<Element>) -> Index
func moveInitialize(fromElements source: Slice<UnsafeMutableBufferPointer<Element>>) -> Index
func moveUpdate(fromElements source: UnsafeMutableBufferPointer<Element>) -> Index
func moveUpdate(fromElements source: Slice<UnsafeMutableBufferPointer<Element>>) -> Index
func deinitialize() -> UnsafeMutableRawBufferPointer
func initializeElement(at index: Index, to value: Element)
func updateElement(at index: Index, to value: Element)
func moveElement(at index: Index) -> Element
func deinitializeElement(at index: Index)
func withMemoryRebound<T, Result>(
to type: T.Type,
_ body: (UnsafeMutableBufferPointer<T>) throws -> Result
) rethrows -> Result
Additions to Slice<UnsafeRawBufferPointer>
:
func bindMemory<T>(to type: T.Type) -> UnsafeBufferPointer<T>
func withMemoryRebound<T, Result>(
to type: T.Type, _ body: (UnsafeBufferPointer<T>) throws -> Result
) rethrows -> Result
func assumingMemoryBound<T>(to type: T.Type) -> UnsafeBufferPointer<T>
Additions to Slice<UnsafeMutableRawBufferPointer>
:
func copyMemory(from source: UnsafeRawBufferPointer)
func copyBytes<C: Collection>(from source: C) where C.Element == UInt8
func initializeMemory<T>(
as type: T.Type, repeating repeatedValue: T
) -> UnsafeMutableBufferPointer<T>
func initializeMemory<S: Sequence>(
as type: S.Element.Type, from source: S
) -> (unwritten: S.Iterator, initialized: UnsafeMutableBufferPointer<S.Element>)
func initializeMemory<C: Collection>(
as type: C.Element.Type, fromElements: C
) -> UnsafeMutableBufferPointer<C.Element>
func moveInitializeMemory<T>(
as type: T.Type, fromElements: UnsafeMutableBufferPointer<T>
) -> UnsafeMutableBufferPointer<T>
func moveInitializeMemory<T>(
as type: T.Type, fromElements: Slice<UnsafeMutableBufferPointer<T>>
) -> UnsafeMutableBufferPointer<T>
func bindMemory<T>(to type: T.Type) -> UnsafeMutableBufferPointer<T>
func withMemoryRebound<T, Result>(
to type: T.Type,
_ body: (UnsafeMutableBufferPointer<T>) throws -> Result
) rethrows -> Result
func assumingMemoryBound<T>(to type: T.Type) -> UnsafeMutableBufferPointer<T>
First, some underscored protocols are necessary in order to generalize over the element type of Unsafe[Mutable]BufferPointer
.
These are necessary because "parameterized extensions" do not exist yet.
protocol _RebasableCollection: Collection {
init(rebasing slice: SubSequence)
}
extension UnsafeBufferPointer: _RebasableCollection {}
extension UnsafeMutableBufferPointer: _RebasableCollection {}
protocol _MutableBaseAddressProtocol: MutableCollection {
var baseAddress: UnsafeMutablePointer<Element>? { get }
}
extension UnsafeMutableBufferPointer: _MutableBaseAddressProtocol {}
Changes to Slice<UnsafeBufferPointer<T>
:
extension Slice where Base: _RebasableCollection, Base.SubSequence == Self {
/// Executes the given closure while temporarily binding the memory referenced
/// by this buffer slice to the given type.
///
/// Use this method when you have a buffer of memory bound to one type and
/// you need to access that memory as a buffer of another type. Accessing
/// memory as type `T` requires that the memory be bound to that type. A
/// memory location may only be bound to one type at a time, so accessing
/// the same memory as an unrelated type without first rebinding the memory
/// is undefined.
///
/// The number of instances of `T` referenced by the rebound buffer may be
/// different than the number of instances of `Element` referenced by the
/// original buffer slice. The number of instances of `T` will be calculated
/// at runtime.
///
/// Any instance of `T` within the re-bound region may be initialized or
/// uninitialized. Every instance of `Pointee` overlapping with a given
/// instance of `T` should have the same initialization state (i.e.
/// initialized or uninitialized.) Accessing a `T` whose underlying
/// `Pointee` storage is in a mixed initialization state shall be
/// undefined behaviour.
///
/// Because this range of memory is no longer bound to its `Element` type
/// while the `body` closure executes, do not access memory using the
/// original buffer slice from within `body`. Instead,
/// use the `body` closure's buffer argument to access the values
/// in memory as instances of type `T`.
///
/// After executing `body`, this method rebinds memory back to the original
/// `Element` type.
///
/// - Note: Only use this method to rebind the buffer's memory to a type
/// that is layout compatible with the currently bound `Element` type.
/// The stride of the temporary type (`T`) may be an integer multiple
/// or a whole fraction of `Element`'s stride.
/// To bind a region of memory to a type that does not match these
/// requirements, convert the buffer to a raw buffer and use the
/// `bindMemory(to:)` method.
/// If `T` and `Element` have different alignments, this buffer's
/// `baseAddress` must be aligned with the larger of the two alignments.
///
/// - Parameters:
/// - type: The type to temporarily bind the memory referenced by this
/// buffer. The type `T` must be layout compatible
/// with the pointer's `Element` type.
/// - body: A closure that takes a typed buffer to the
/// same memory as this buffer, only bound to type `T`. The buffer
/// parameter contains a number of complete instances of `T` based
/// on the capacity of the original buffer and the stride of `Element`.
/// The closure's buffer argument is valid only for the duration of the
/// closure's execution. If `body` has a return value, that value
/// is also used as the return value for the `withMemoryRebound(to:_:)`
/// method.
/// - buffer: The buffer temporarily bound to `T`.
/// - Returns: The return value, if any, of the `body` closure parameter.
public func withMemoryRebound<T, Result>(
to type: T.Type, _ body: (UnsafeBufferPointer<T>) throws -> Result
) rethrows -> Result
}
Changes for Slice<UnsafeMutableBufferPointer<T>>
:
extension Slice where Base: _RebasableCollection & _MutableBaseAddressProtocol,
Base.SubSequence == Self {
/// Initializes every element in this buffer slice's memory to
/// a copy of the given value.
///
/// The destination memory must be uninitialized or the buffer's `Element`
/// must be a trivial type. After a call to `initialize(repeating:)`, the
/// entire region of memory referenced by this buffer slice is initialized.
///
/// - Parameter repeatedValue: The value with which to initialize this
/// buffer slice's memory.
public func initialize(repeating repeatedValue: Base.Element)
/// Initializes the buffer slice's memory with the given elements.
///
/// Prior to calling the `initialize(from:)` method on a buffer slice,
/// the memory it references must be uninitialized,
/// or the `Element` type must be a trivial type. After the call,
/// the memory referenced by the buffer slice up to, but not including,
/// the returned index is initialized.
/// The buffer must contain sufficient memory to accommodate
/// `source.underestimatedCount`.
///
/// The returned index is the position of the next uninitialized element
/// in the buffer slice, which is one past the last element written.
/// If `source` contains no elements, the returned index is equal to
/// the buffer's `startIndex`. If `source` contains an equal or greater number
/// of elements than the buffer slice can hold, the returned index is equal to
/// the buffer's `endIndex`.
///
/// - Parameter source: A sequence of elements with which to initialize the
/// buffer.
/// - Returns: An iterator to any elements of `source` that didn't fit in the
/// buffer, and an index to the next uninitialized element in the buffer.
public func initialize<S>(
from source: S
) -> (S.Iterator, Index) where S: Sequence, Base.Element == S.Element
/// Initializes the buffer slice's memory with the given elements.
///
/// Prior to calling the `initialize(fromElements:)` method on a buffer slice,
/// the memory it references must be uninitialized,
/// or the `Element` type must be a trivial type. After the call,
/// the memory referenced by the buffer slice up to, but not including,
/// the returned index is initialized.
///
/// The returned index is the position of the next uninitialized element
/// in the buffer slice, which is one past the last element written.
/// If `fromElements` contains no elements, the returned index is equal to
/// the buffer's `startIndex`. If `fromElements` contains an equal or greater
/// of elements than the buffer slice can hold, the returned index is equal to
/// to the buffer's `endIndex`.
///
/// - Parameter fromElements: A collection of elements to be used to
/// initialize the buffer's storage.
/// - Returns: An index to the next uninitialized element in the buffer,
/// or `endIndex`.
public func initialize<C>(
fromElements source: C
) -> Int where C : Collection, Base.Element == C.Element
/// Updates every element of this buffer slice's initialized memory.
///
/// The buffer slice’s memory must be initialized or its `Element`
/// must be a trivial type.
///
/// - Note: All buffer elements must already be initialized.
///
/// - Parameters:
/// - repeatedValue: The value used when updating this pointer's memory.
public func update(repeating repeatedValue: Base.Element)
/// Updates the buffer slice's initialized memory with the given elements.
///
/// The buffer slice's memory must be initialized or its `Element` type
/// must be a trivial type.
///
/// - Parameter source: A sequence of elements to be used to update
/// the buffer's contents.
/// - Returns: An iterator to any elements of `source` that didn't fit in the
/// buffer, and the index one past the last updated element in the buffer.
public func update<S: Sequence>(
from source: S
) -> (iterator: S.Iterator, updated: Index) where S.Element == Element
/// Updates the buffer slice's initialized memory with the given elements.
///
/// The buffer slice's memory must be initialized or the buffer's `Element` type
/// must be a trivial type.
///
/// - Parameter fromElements: A collection of elements to be used to update
/// the buffer's contents.
/// - Returns: An index one past the last updated element in the buffer,
/// or `endIndex`.
public func update<C: Collection>(
fromElements source: C
) -> Index where C.Element == Element
/// Moves every element of an initialized source buffer into the
/// uninitialized memory referenced by this buffer slice, leaving the
/// source memory uninitialized and this buffer slice's memory initialized.
///
/// The region of memory starting at the beginning of this buffer and
/// covering `source.count` instances of its `Element` type must be
/// uninitialized, or `Element` must be a trivial type. After calling
/// `moveInitialize(fromElements:)`, the region is initialized and
/// the region of memory underlying `source` is uninitialized.
///
/// - Parameter source: A buffer containing the values to copy. The memory
/// region underlying `source` must be initialized. The memory regions
/// referenced by `source` and this buffer may overlap.
/// - Returns: An index to the next uninitialized element in the buffer,
/// or `endIndex`.
public func moveInitialize(from source: Self) -> Index
/// Moves every element of an initialized source buffer slice into the
/// uninitialized memory referenced by this buffer slice, leaving the
/// source memory uninitialized and this buffer slice's memory initialized.
///
/// The region of memory starting at the beginning of this buffer slice and
/// covering `source.count` instances of its `Element` type must be
/// uninitialized, or `Element` must be a trivial type. After calling
/// `moveInitialize(fromElements:)`, the region is initialized and
/// the region of memory underlying `source` is uninitialized.
///
/// - Parameter source: A buffer containing the values to copy. The memory
/// region underlying `source` must be initialized. The memory regions
/// referenced by `source` and this buffer may overlap.
/// - Returns: An index one past the last replaced element in the buffer,
/// or `endIndex`.
public func moveInitialize(from source: Slice<Self>) -> Index
/// Updates this buffer slice's initialized memory initialized memory by
/// moving every element from the source buffer,
/// leaving the source memory uninitialized.
///
/// The region of memory starting at the beginning of this buffer slice and
/// covering `fromElements.count` instances of its `Element` type must be
/// initialized, or `Element` must be a trivial type. After calling
/// `moveUpdate(fromElements:)`,
/// the region of memory underlying `source` is uninitialized.
///
/// - Parameter source: A buffer containing the values to move.
/// The memory region underlying `source` must be initialized. The
/// memory regions referenced by `source` and this pointer must not overlap.
/// - Returns: An index one past the last updated element in the buffer,
/// or `endIndex`.
public func moveUpdate(
fromElements source: UnsafeMutableBufferPointer<Base.Element>
) -> Index
/// Updates this buffer slice's initialized memory initialized memory by
/// moving every element from the source buffer slice,
/// leaving the source memory uninitialized.
///
/// The region of memory starting at the beginning of this buffer slice and
/// covering `fromElements.count` instances of its `Element` type must be
/// initialized, or `Element` must be a trivial type. After calling
/// `moveUpdate(fromElements:)`,
/// the region of memory underlying `source` is uninitialized.
///
/// - Parameter source: A buffer containing the values to move.
/// The memory region underlying `source` must be initialized. The
/// memory regions referenced by `source` and this pointer must not overlap.
/// - Returns: An index one past the last updated element in the buffer,
/// or `endIndex`.
public func moveUpdate(
fromElements source: Slice<UnsafeMutableBufferPointer<Base.Element>>
) -> Index
/// Deinitializes every instance in this buffer slice.
///
/// The region of memory underlying this buffer slice must be fully
/// initialized. After calling `deinitialize(count:)`, the memory
/// is uninitialized, but still bound to the `Element` type.
///
/// - Note: All buffer elements must already be initialized.
///
/// - Returns: A raw buffer to the same range of memory as this buffer.
/// The range of memory is still bound to `Element`.
public func deinitialize() -> UnsafeMutableRawBufferPointer
/// Initializes the element at `index` to the given value.
///
/// The memory underlying the destination element must be uninitialized,
/// or `Element` must be a trivial type. After a call to `initialize(to:)`,
/// the memory underlying this element of the buffer slice is initialized.
///
/// - Parameters:
/// - value: The value used to initialize the buffer element's memory.
/// - index: The index of the element to initialize
public func initializeElement(at index: Int, to value: Element)
/// Updates the initialized element at `index` to the given value.
///
/// The memory underlying the destination element must be initialized,
/// or `Element` must be a trivial type. This method is equivalent to:
///
/// self[index] = value
///
/// - Parameters:
/// - value: The value used to update the buffer element's memory.
/// - index: The index of the element to update
public func updateElement(at index: Index, to value: Element)
/// Retrieves and returns the element at `index`,
/// leaving that element's underlying memory uninitialized.
///
/// The memory underlying the element at `index` must be initialized.
/// After calling `moveElement(from:)`, the memory underlying this element
/// of the buffer slice is uninitialized, and still bound to type `Element`.
///
/// - Parameters:
/// - index: The index of the buffer element to retrieve and deinitialize.
/// - Returns: The instance referenced by this index in this buffer.
public func moveElement(at index: Index) -> Element
/// Deinitializes the memory underlying the element at `index`.
///
/// The memory underlying the element at `index` must be initialized.
/// After calling `deinitializeElement()`, the memory underlying this element
/// of the buffer slice is uninitialized, and still bound to type `Element`.
///
/// - Parameters:
/// - index: The index of the buffer element to deinitialize.
public func deinitializeElement(at index: Base.Index)
/// Executes the given closure while temporarily binding the memory referenced
/// by this buffer slice to the given type.
///
/// Use this method when you have a buffer of memory bound to one type and
/// you need to access that memory as a buffer of another type. Accessing
/// memory as type `T` requires that the memory be bound to that type. A
/// memory location may only be bound to one type at a time, so accessing
/// the same memory as an unrelated type without first rebinding the memory
/// is undefined.
///
/// The number of instances of `T` referenced by the rebound buffer may be
/// different than the number of instances of `Element` referenced by the
/// original buffer slice. The number of instances of `T` will be calculated
/// at runtime.
///
/// Any instance of `T` within the re-bound region may be initialized or
/// uninitialized. Every instance of `Pointee` overlapping with a given
/// instance of `T` should have the same initialization state (i.e.
/// initialized or uninitialized.) Accessing a `T` whose underlying
/// `Pointee` storage is in a mixed initialization state shall be
/// undefined behaviour.
///
/// Because this range of memory is no longer bound to its `Element` type
/// while the `body` closure executes, do not access memory using the
/// original buffer slice from within `body`. Instead,
/// use the `body` closure's buffer argument to access the values
/// in memory as instances of type `T`.
///
/// After executing `body`, this method rebinds memory back to the original
/// `Element` type.
///
/// - Note: Only use this method to rebind the buffer's memory to a type
/// that is layout compatible with the currently bound `Element` type.
/// The stride of the temporary type (`T`) may be an integer multiple
/// or a whole fraction of `Element`'s stride.
/// To bind a region of memory to a type that does not match these
/// requirements, convert the buffer to a raw buffer and use the
/// `bindMemory(to:)` method.
/// If `T` and `Element` have different alignments, this buffer's
/// `baseAddress` must be aligned with the larger of the two alignments.
///
/// - Parameters:
/// - type: The type to temporarily bind the memory referenced by this
/// buffer. The type `T` must be layout compatible
/// with the pointer's `Element` type.
/// - body: A closure that takes a ${Mutable.lower()} typed buffer to the
/// same memory as this buffer, only bound to type `T`. The buffer
/// parameter contains a number of complete instances of `T` based
/// on the capacity of the original buffer and the stride of `Element`.
/// The closure's buffer argument is valid only for the duration of the
/// closure's execution. If `body` has a return value, that value
/// is also used as the return value for the `withMemoryRebound(to:_:)`
/// method.
/// - buffer: The buffer temporarily bound to `T`.
/// - Returns: The return value, if any, of the `body` closure parameter.
public func withMemoryRebound<T, Result>(
to type: T.Type, _ body: (UnsafeMutableBufferPointer<T>) throws -> Result
) rethrows -> Result
}
Changes for Slice<UnsafeRawBufferPointer>
:
extension Slice where Base: UnsafeRawBufferPointer {
/// Binds this buffer’s memory to the specified type and returns a typed buffer
/// of the bound memory.
///
/// Use the `bindMemory(to:)` method to bind the memory referenced
/// by this buffer to the type `T`. The memory must be uninitialized or
/// initialized to a type that is layout compatible with `T`. If the memory
/// is uninitialized, it is still uninitialized after being bound to `T`.
///
/// - Warning: A memory location may only be bound to one type at a time. The
/// behavior of accessing memory as a type unrelated to its bound type is
/// undefined.
///
/// - Parameters:
/// - type: The type `T` to bind the memory to.
/// - Returns: A typed buffer of the newly bound memory. The memory in this
/// region is bound to `T`, but has not been modified in any other way.
/// The typed buffer references `self.count / MemoryLayout<T>.stride` instances of `T`.
public func bindMemory<T>(to type: T.Type) -> UnsafeBufferPointer<T>
/// Executes the given closure while temporarily binding the buffer to
/// instances of type `T`.
///
/// Use this method when you have a buffer to raw memory and you need
/// to access that memory as instances of a given type `T`. Accessing
/// memory as a type `T` requires that the memory be bound to that type.
/// A memory location may only be bound to one type at a time, so accessing
/// the same memory as an unrelated type without first rebinding the memory
/// is undefined.
///
/// Any instance of `T` within the re-bound region may be initialized or
/// uninitialized. The memory underlying any individual instance of `T`
/// must have the same initialization state (i.e. initialized or
/// uninitialized.) Accessing a `T` whose underlying memory
/// is in a mixed initialization state shall be undefined behaviour.
///
/// If the byte count of the original buffer is not a multiple of
/// the stride of `T`, then the re-bound buffer is shorter
/// than the original buffer.
///
/// After executing `body`, this method rebinds memory back to its original
/// binding state. This can be unbound memory, or bound to a different type.
///
/// - Note: The buffer's base address must match the
/// alignment of `T` (as reported by `MemoryLayout<T>.alignment`).
/// That is, `Int(bitPattern: self.baseAddress) % MemoryLayout<T>.alignment`
/// must equal zero.
///
/// - Note: A raw buffer may represent memory that has been bound to a type.
/// If that is the case, then `T` must be layout compatible with the
/// type to which the memory has been bound. This requirement does not
/// apply if the raw buffer represents memory that has not been bound
/// to any type.
///
/// - Parameters:
/// - type: The type to temporarily bind the memory referenced by this
/// pointer. This pointer must be a multiple of this type's alignment.
/// - body: A closure that takes a typed pointer to the
/// same memory as this pointer, only bound to type `T`. The closure's
/// pointer argument is valid only for the duration of the closure's
/// execution. If `body` has a return value, that value is also used as
/// the return value for the `withMemoryRebound(to:capacity:_:)` method.
/// - buffer: The buffer temporarily bound to instances of `T`.
/// - Returns: The return value, if any, of the `body` closure parameter.
func withMemoryRebound<T, Result>(
to type: T.Type, _ body: (UnsafeBufferPointer<T>) throws -> Result
) rethrows -> Result
/// Returns a typed buffer to the memory referenced by this buffer,
/// assuming that the memory is already bound to the specified type.
///
/// Use this method when you have a raw buffer to memory that has already
/// been bound to the specified type. The memory starting at this pointer
/// must be bound to the type `T`. Accessing memory through the returned
/// pointer is undefined if the memory has not been bound to `T`. To bind
/// memory to `T`, use `bindMemory(to:capacity:)` instead of this method.
///
/// - Note: The buffer's base address must match the
/// alignment of `T` (as reported by `MemoryLayout<T>.alignment`).
/// That is, `Int(bitPattern: self.baseAddress) % MemoryLayout<T>.alignment`
/// must equal zero.
///
/// - Parameter to: The type `T` that the memory has already been bound to.
/// - Returns: A typed pointer to the same memory as this raw pointer.
func assumingMemoryBound<T>(to type: T.Type) -> UnsafeBufferPointer<T>
}
Changes for Slice<UnsafeMutableRawBufferPointer>
:
extension Slice where Base == UnsafeMutableRawBufferPointer {
/// Copies the bytes from the given buffer to this buffer slice's memory.
///
/// If the `source.count` bytes of memory referenced by this buffer are bound
/// to a type `T`, then `T` must be a trivial type, the underlying pointer
/// must be properly aligned for accessing `T`, and `source.count` must be a
/// multiple of `MemoryLayout<T>.stride`.
///
/// The memory referenced by `source` may overlap with the memory referenced
/// by this buffer.
///
/// After calling `copyMemory(from:)`, the first `source.count` bytes of
/// memory referenced by this buffer are initialized to raw bytes. If the
/// memory is bound to type `T`, then it contains values of type `T`.
///
/// - Parameter source: A buffer of raw bytes. `source.count` must
/// be less than or equal to this buffer slice's `count`.
func copyMemory(from source: UnsafeRawBufferPointer)
/// Copies from a collection of `UInt8` into this buffer slice's memory.
///
/// If the `source.count` bytes of memory referenced by this buffer are bound
/// to a type `T`, then `T` must be a trivial type, the underlying pointer
/// must be properly aligned for accessing `T`, and `source.count` must be a
/// multiple of `MemoryLayout<T>.stride`.
///
/// After calling `copyBytes(from:)`, the first `source.count` bytes of memory
/// referenced by this buffer are initialized to raw bytes. If the memory is
/// bound to type `T`, then it contains values of type `T`.
///
/// - Parameter source: A collection of `UInt8` elements. `source.count` must
/// be less than or equal to this buffer slice's `count`.
public func copyBytes<C: Collection>(from source: C) where C.Element == UInt8
/// Initializes the memory referenced by this buffer with the given value,
/// binds the memory to the value's type, and returns a typed buffer of the
/// initialized memory.
///
/// The memory referenced by this buffer must be uninitialized or
/// initialized to a trivial type, and must be properly aligned for
/// accessing `T`.
///
/// After calling this method on a raw buffer with non-nil `baseAddress` `b`,
/// the region starting at `b` and continuing up to
/// `b + self.count - self.count % MemoryLayout<T>.stride` is bound to type `T` and
/// initialized. If `T` is a nontrivial type, you must eventually deinitialize
/// or move the values in this region to avoid leaks. If `baseAddress` is
/// `nil`, this function does nothing and returns an empty buffer pointer.
///
/// - Parameters:
/// - type: The type to bind this buffer’s memory to.
/// - repeatedValue: The instance to copy into memory.
/// - Returns: A typed buffer of the memory referenced by this raw buffer.
/// The typed buffer contains `self.count / MemoryLayout<T>.stride`
/// instances of `T`.
func initializeMemory<T>(as type: T.Type, repeating repeatedValue: T) -> UnsafeMutableBufferPointer<T>
/// Initializes the buffer's memory with the given elements, binding the
/// initialized memory to the elements' type.
///
/// When calling the `initializeMemory(as:from:)` method on a buffer `b`,
/// the memory referenced by `b` must be uninitialized or initialized to a
/// trivial type, and must be properly aligned for accessing `S.Element`.
/// The buffer must contain sufficient memory to accommodate
/// `source.underestimatedCount`.
///
/// This method initializes the buffer with elements from `source` until
/// `source` is exhausted or, if `source` is a sequence but not a
/// collection, the buffer has no more room for its elements. After calling
/// `initializeMemory(as:from:)`, the memory referenced by the returned
/// `UnsafeMutableBufferPointer` instance is bound and initialized to type
/// `S.Element`.
///
/// - Parameters:
/// - type: The type of element to which this buffer's memory will be bound.
/// - source: A sequence of elements with which to initialize the buffer.
/// - Returns: An iterator to any elements of `source` that didn't fit in the
/// buffer, and a typed buffer of the written elements. The returned
/// buffer references memory starting at the same base address as this
/// buffer.
public func initializeMemory<S: Sequence>(
as type: S.Element.Type, from source: S
) -> (unwritten: S.Iterator, initialized: UnsafeMutableBufferPointer<S.Element>)
/// Initializes the buffer's memory with the given elements, binding the
/// initialized memory to the elements' type.
///
/// When calling the `initializeMemory(as:fromElements:)` method on a buffer
/// `b`, the memory referenced by `b` must be uninitialized, or initialized
/// to a trivial type. `b` must be properly aligned for accessing `C.Element`.
///
/// This method initializes the buffer with the contents of `fromElements`
/// until `fromElements` is exhausted or the buffer runs out of available
/// space. After calling `initializeMemory(as:fromElements:)`, the memory
/// referenced by the returned `UnsafeMutableBufferPointer` instance is bound
/// and initialized to type `C.Element`. This method does not change
/// the binding state of the unused portion of `b`, if any.
///
/// - Parameters:
/// - type: The type of element to which this buffer's memory will be bound.
/// - fromElements: A collection of elements to be used to
/// initialize the buffer's storage.
/// - Returns: A typed buffer of the initialized elements. The returned
/// buffer references memory starting at the same base address as this
/// buffer, and its count indicates the number of elements copied from
/// the collection `elements`.
func initializeMemory<C: Collection>(
as type: C.Element.Type,
fromElements source: C
) -> UnsafeMutableBufferPointer<C.Element>
/// Moves instances from an initialized source buffer into the
/// uninitialized memory referenced by this buffer, leaving the source memory
/// uninitialized and this buffer's memory initialized.
///
/// When calling the `moveInitializeMemory(as:from:)` method on a buffer `b`,
/// the memory referenced by `b` must be uninitialized, or initialized to a
/// trivial type. `b` must be properly aligned for accessing `C.Element`.
///
/// The region of memory starting at this pointer and covering
/// `fromElements.count` instances of the buffer's `Element` type
/// must be uninitialized, or `Element` must be a trivial type. After
/// calling `moveInitialize(as:from:)`, the region is initialized and the
/// memory region underlying `source` is uninitialized.
///
/// - Parameters:
/// - type: The type of element to which this buffer's memory will be bound.
/// - fromElements: A buffer containing the values to copy.
/// The memory region underlying `source` must be initialized.
/// The memory regions referenced by `source` and this buffer may overlap.
/// - Returns: A typed buffer of the initialized elements. The returned
/// buffer references memory starting at the same base address as this
/// buffer, and its count indicates the number of elements copied from
/// `source`.
func moveInitializeMemory<T>(
as type: T.Type,
fromElements source: UnsafeMutableBufferPointer<T>
) -> UnsafeMutableBufferPointer<T>
/// Moves instances from an initialized source buffer slice into the
/// uninitialized memory referenced by this buffer, leaving the source memory
/// uninitialized and this buffer's memory initialized.
///
/// The region of memory starting at this pointer and covering
/// `fromElements.count` instances of the buffer's `Element` type
/// must be uninitialized, or `Element` must be a trivial type. After
/// calling `moveInitialize(as:from:)`, the region is initialized and the
/// memory region underlying `source[..<source.endIndex]` is uninitialized.
///
/// - Parameters:
/// - type: The type of element to which this buffer's memory will be bound.
/// - fromElements: A buffer containing the values to copy.
/// The memory region underlying `source` must be initialized.
/// The memory regions referenced by `source` and this buffer may overlap.
/// - Returns: A typed buffer of the initialized elements. The returned
/// buffer references memory starting at the same base address as this
/// buffer, and its count indicates the number of elements copied from
/// `source`.
func moveInitializeMemory<T>(
as type: T.Type,
fromElements source: Slice<UnsafeMutableBufferPointer<T>>
) -> UnsafeMutableBufferPointer<T>
/// Binds this buffer’s memory to the specified type and returns a typed buffer
/// of the bound memory.
///
/// Use the `bindMemory(to:)` method to bind the memory referenced
/// by this buffer to the type `T`. The memory must be uninitialized or
/// initialized to a type that is layout compatible with `T`. If the memory
/// is uninitialized, it is still uninitialized after being bound to `T`.
///
/// - Warning: A memory location may only be bound to one type at a time. The
/// behavior of accessing memory as a type unrelated to its bound type is
/// undefined.
///
/// - Parameters:
/// - type: The type `T` to bind the memory to.
/// - Returns: A typed buffer of the newly bound memory. The memory in this
/// region is bound to `T`, but has not been modified in any other way.
/// The typed buffer references `self.count / MemoryLayout<T>.stride` instances of `T`.
public func bindMemory<T>(to type: T.Type) -> UnsafeMutableBufferPointer<T>
/// Executes the given closure while temporarily binding the buffer to
/// instances of type `T`.
///
/// Use this method when you have a buffer to raw memory and you need
/// to access that memory as instances of a given type `T`. Accessing
/// memory as a type `T` requires that the memory be bound to that type.
/// A memory location may only be bound to one type at a time, so accessing
/// the same memory as an unrelated type without first rebinding the memory
/// is undefined.
///
/// Any instance of `T` within the re-bound region may be initialized or
/// uninitialized. The memory underlying any individual instance of `T`
/// must have the same initialization state (i.e. initialized or
/// uninitialized.) Accessing a `T` whose underlying memory
/// is in a mixed initialization state shall be undefined behaviour.
///
/// If the byte count of the original buffer is not a multiple of
/// the stride of `T`, then the re-bound buffer is shorter
/// than the original buffer.
///
/// After executing `body`, this method rebinds memory back to its original
/// binding state. This can be unbound memory, or bound to a different type.
///
/// - Note: The buffer's base address must match the
/// alignment of `T` (as reported by `MemoryLayout<T>.alignment`).
/// That is, `Int(bitPattern: self.baseAddress) % MemoryLayout<T>.alignment`
/// must equal zero.
///
/// - Note: A raw buffer may represent memory that has been bound to a type.
/// If that is the case, then `T` must be layout compatible with the
/// type to which the memory has been bound. This requirement does not
/// apply if the raw buffer represents memory that has not been bound
/// to any type.
///
/// - Parameters:
/// - type: The type to temporarily bind the memory referenced by this
/// pointer. This pointer must be a multiple of this type's alignment.
/// - body: A closure that takes a typed pointer to the
/// same memory as this pointer, only bound to type `T`. The closure's
/// pointer argument is valid only for the duration of the closure's
/// execution. If `body` has a return value, that value is also used as
/// the return value for the `withMemoryRebound(to:capacity:_:)` method.
/// - buffer: The buffer temporarily bound to instances of `T`.
/// - Returns: The return value, if any, of the `body` closure parameter.
func withMemoryRebound<T, Result>(
to type: T.Type, _ body: (UnsafeMutableBufferPointer<T>) throws -> Result
) rethrows -> Result
/// Returns a typed buffer to the memory referenced by this buffer,
/// assuming that the memory is already bound to the specified type.
///
/// Use this method when you have a raw buffer to memory that has already
/// been bound to the specified type. The memory starting at this pointer
/// must be bound to the type `T`. Accessing memory through the returned
/// pointer is undefined if the memory has not been bound to `T`. To bind
/// memory to `T`, use `bindMemory(to:capacity:)` instead of this method.
///
/// - Note: The buffer's base address must match the
/// alignment of `T` (as reported by `MemoryLayout<T>.alignment`).
/// That is, `Int(bitPattern: self.baseAddress) % MemoryLayout<T>.alignment`
/// must equal zero.
///
/// - Parameter to: The type `T` that the memory has already been bound to.
/// - Returns: A typed pointer to the same memory as this raw pointer.
func assumingMemoryBound<T>(to type: T.Type) -> UnsafeMutableBufferPointer<T>
}
This proposal consists solely of additions and is therefore source compatible.
The functions proposed here generally small wrappers around existing functionality.
They will be implemented as @_alwaysEmitIntoClient
functions,
which means they will have no ABI impact.
All functionality implemented as @_alwaysEmitIntoClient
will back-deploy.
None.