From e95cf588a2f3c0a52f5ff4de780dc1e30c7fb303 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Mon, 29 Nov 2021 16:15:47 -0500 Subject: [PATCH 01/18] proposal for pointer family initialization improvements --- ...ffer-family-initialization-improvements.md | 1511 +++++++++++++++++ 1 file changed, 1511 insertions(+) create mode 100644 proposals/NNNN-buffer-family-initialization-improvements.md diff --git a/proposals/NNNN-buffer-family-initialization-improvements.md b/proposals/NNNN-buffer-family-initialization-improvements.md new file mode 100644 index 0000000000..4c3fa81aad --- /dev/null +++ b/proposals/NNNN-buffer-family-initialization-improvements.md @@ -0,0 +1,1511 @@ +# Buffer Family Initialization Improvements & Better Buffer Slices + +* Proposal: [SE-NNNN Buffer Family Initialization Improvements & Better Buffer Slices][proposal] +* Author: [Guillaume Lessard](https://github.com/glessard) +* Review Manager: TBD +* Status: pending +* Implementation: [Draft Pull Request][draft-pr] +* Bugs: rdar://51817146 +* Previous Revision: [pitch A](https://gist.github.com/glessard/3bb47dce974aa483fd6df072d265005c ), [pitch B](https://gist.github.com/glessard/cefa5686696b0e30ac18eb4899213c65) + +[proposal]: https://gist.github.com/glessard/cefa5686696b0e30ac18eb4899213c65 +[draft-pr]: https://github.com/apple/swift/pull/40337 +[pitch-thread]: https://forums.swift.org/t/53795 + + +## Introduction + +The types in the `UnsafeMutablePointer` family typically require manual management of memory allocations, +including the management of their initialization state. +The states involved are, after allocation: + +1. Unbound and uninitialized (as returned from `UnsafeMutableRawPointer.allocate()`) +2. Bound to a type, and uninitialized (as returned from `UnsafeMutablePointer.allocate()`) +3. Bound to a type, and initialized + +Memory can be safely deallocated whenever it is uninitialized. + +Unfortunately, not every relevant type in the family has the necessary functionality to fully manage the initialization state of the memory it represents. +We intend to round out initialization functionality for every relevant member of that family:`UnsafeMutablePointer`, `UnsafeMutableRawPointer`, `UnsafeMutableBufferPointer`, `UnsafeMutableRawBufferPointer`, `Slice` and `Slice`. The functionality will allow managing initialization state in a much greater variety of situations, including easier partial initialization of buffers. + +Swift-evolution thread: [Pitch thread][pitch-thread] + +## Motivation + +Memory allocated using `UnsafeMutablePointer`, `UnsafeMutableRawPointer`, +`UnsafeMutableBufferPointer` and `UnsafeMutableRawBufferPointer` is passed to the user in an uninitialized state. +In the general case, such memory needs to be initialized before it is used in Swift. +Memory can be "initialized" or "uninitialized". +We hereafter refer to this as a memory region's "initialization state". + +The methods of `UnsafeMutablePointer` that interact with initialization state are: + +- `func initialize(to value: Pointee)` +- `func initialize(repeating repeatedValue: Pointee, count: Int)` +- `func initialize(from source: UnsafePointer, count: Int)` +- `func assign(repeating repeatedValue: Pointee, count: Int)` +- `func assign(from source: UnsafePointer, count: Int)` +- `func move() -> Pointee` +- `func moveInitialize(from source: UnsafeMutablePointer, count: Int)` +- `func moveAssign(from source: UnsafeMutablePointer, count: Int)` +- `func deinitialize(count: Int) -> UnsafeMutableRawPointer` + +This is a fairly complete set. + +- The `initialize` functions change the state of memory locations from uninitialized to initialized, + then assign the corresponding value(s). +- The `assign` functions update the values stored at memory locations that have previously been initialized. +- `deinitialize` changes the state of a range of memory from initialized to uninitialized. +- The `move()` function deinitializes a memory location, then returns its current contents. +- The `move` prefix means that the `source` range of memory will be deinitialized after the function returns. + +Unfortunately, `UnsafeMutablePointer` is the only one of the list of types listed in the introduction to allow full control of initialization state, and this means that complex use cases such as partial initialization of a buffer become overly complicated. + +An example of partial initialization is the insertion of elements in the middle of a collection. This is +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(_ subrange: Range, with newElements: C) + where C: Collection, Element == C.Element { + + // obtain unique storage as UnsafeMutableBufferPointer + let buffer: UnsafeMutableBufferPointer = 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..(_ subrange: Range, with newElements: C) + where C: Collection, Element == C.Element { + + // obtain unique storage as UnsafeMutableBufferPointer + let buffer: UnsafeMutableBufferPointer = 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..` and `Slice`. + + +## Proposed solution + +Note: the pseudo-diffs presented in this section denotes added functions with `+++` and renamed functions with `---`. Unmarked functions are unchanged. + +##### `UnsafeMutableBufferPointer` + +We propose to modify `UnsafeMutableBufferPointer` as follows: + +```swift +extension UnsafeMutableBufferPointer { + func initialize(repeating repeatedValue: Element) + func initialize(from source: S) -> (S.Iterator, Index) where S: Sequence, S.Element == Element ++++ func initialize(fromElements: C) -> Index where C: Collection, C.Element == Element +--- func assign(repeating repeatedValue: Element) ++++ func update(repeating repeatedValue: Element) ++++ func update(from source: S) -> (unwritten: S.Iterator, updated: Index) where S: Sequence, S.Element == Element ++++ func update(fromElements: C) -> Index where C: Collection, C.Element == Element ++++ func moveInitialize(fromElements: UnsafeMutableBufferPointer) -> Index ++++ func moveInitialize(fromElements: Slice) -> Index ++++ func moveUpdate(fromElements: `Self`) -> Index ++++ func moveUpdate(fromElements: Slice<`Self`>) -> Index ++++ func deinitialize() -> UnsafeMutableRawBufferPointer + ++++ func initializeElement(at index: Index, to value: Element) ++++ func updateElement(at index: Index, to value: Element) ++++ func moveElement(from index: Index) -> Element ++++ func deinitializeElement(at index: Index) +} +``` + + + +We would like to use the verb `update` instead of `assign`, in order to better communicate the intent of the API. It is currently a common programmer error to use one of the existing `assign` functions for uninitialized memory; using the verb `update` instead would express the precondition in the API itself. + +The methods that initialize or update from a `Collection` will have forgiving semantics, +and copy the number of elements that they can, be that every available element or none, +and then return the index in the buffer that follows the last element copied, which is cheaper than returning an iterator and a count. Unlike the existing `Sequence` functions, +they include no preconditions beyond having a valid `Collection` and valid buffer, +with the understanding that if a user needs stricter behaviour, +it can be composed from these functions. + +The above changes include a method to update a single element. +Evidently that is a synonym for the `subscript(_ i: Index)` setter. +We hope that documenting the update action specifically will help clarify the requirements of that action, namely that the buffer element must already be initialized. +Experience shows that the initialization requirement of the subscript setter is frequently missed by users in the current situation, where it is only documented along with the subscript getter. + +##### `UnsafeMutablePointer` + +The proposed modifications to `UnsafeMutablePointer` are renamings: + +```swift +extension UnsafeMutablePointer { + func initialize(to value: Pointee) + func initialize(repeating repeatedValue: Pointee, count: Int) + func initialize(from source: UnsafePointer, count: Int) ++++ func update(to value: Pointee) +--- func assign(repeating repeatedValue: Pointee, count: Int) ++++ func update(repeating repeatedValue: Pointee, count: Int) +--- func assign(from source: UnsafePointer, count: Int) ++++ func update(from source: UnsafePointer, count: Int) + func move() -> Pointee + func moveInitialize(from source: UnsafeMutablePointer, count: Int) +--- func moveAssign(from source: UnsafeMutablePointer, count: Int) ++++ func moveUpdate(from source: UnsafeMutablePointer, count: Int) + func deinitialize(count: Int) -> UnsafeMutableRawPointer +} +``` + +The motivation for these renamings are explained above. + +##### `UnsafeMutableRawBufferPointer` + +We propose to add new functions to initialize memory referenced by `UnsafeMutableRawBufferPointer` instances. + +```swift +extension UnsafeMutableRawBufferPointer { + func initializeMemory( + as type: T.Type, repeating repeatedValue: T + ) -> UnsafeMutableBufferPointer + + func initializeMemory( + as type: S.Element.Type, from source: S + ) -> (unwritten: S.Iterator, initialized: UnsafeMutableBufferPointer) where S: Sequence + ++++ func initializeMemory( + as type: C.Element.Type, fromElements: C + ) -> UnsafeMutableBufferPointer where C: Collection + ++++ func moveInitializeMemory( + as type: T.Type, fromElements: UnsafeMutableBufferPointer + ) -> UnsafeMutableBufferPointer + ++++ func moveInitializeMemory( + as type: T.Type, fromElements: Slice> + ) -> UnsafeMutableBufferPointer +} +``` + +The first addition will initialize raw memory from a `Collection` and have similar behaviour as `UnsafeMutableBufferPointer.initialize(fromElements:)`, described above. The other two initialize raw memory by moving data from another range of memory, leaving that other range of memory deinitialized. + +##### UnsafeMutableRawPointer + +```swift +extension UnsafeMutableRawPointer { ++++ func initializeMemory(as type: T.Type, to value: T) -> UnsafeMutablePointer + + func initializeMemory( + as type: T.Type, repeating repeatedValue: T, count: Int + ) -> UnsafeMutablePointer + + func initializeMemory( + as type: T.Type, from source: UnsafePointer, count: Int + ) -> UnsafeMutablePointer + + func moveInitializeMemory( + as type: T.Type, from source: UnsafeMutablePointer, count: Int + ) -> UnsafeMutablePointer +} +``` + +The addition here initializes a single value. + +##### Slices of BufferPointer + +We propose to add to slices of `Unsafe[Mutable][Raw]BufferPointer` all the `BufferPointer`-specific methods of their `Base`. The following declarations detail the additions, which are all intended to behave exactly as the functions on the base BufferPointer types: + +```swift +extension Slice> { + public func withMemoryRebound( + to type: T.Type, + _ body: (UnsafeBufferPointer) throws -> Result + ) rethrows -> Result +} +``` + +```swift +extension Slice> { + func initialize(repeating repeatedValue: Element) + + func initialize(from source: S) -> (S.Iterator, Index) + where S.Element == Element + + func initialize(fromElements: C) -> Index + where C.Element == Element + + func update(repeating repeatedValue: Element) + + func update( + from source: S + ) -> (iterator: S.Iterator, updated: Index) where S.Element == Element + + func update( + fromElements: C + ) -> Index where C.Element == Element + + func moveInitialize(fromElements source: UnsafeMutableBufferPointer) -> Index + func moveInitialize(fromElements source: Slice>) -> Index + func moveUpdate(fromElements source: UnsafeMutableBufferPointer) -> Index + func moveUpdate(fromElements source: Slice>) -> 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( + to type: T.Type, + _ body: (UnsafeMutableBufferPointer) throws -> Result + ) rethrows -> Result +} +``` + +```swift +extension Slice { + func bindMemory(to type: T.Type) -> UnsafeBufferPointer + func assumingMemoryBound(to type: T.Type) -> UnsafeBufferPointer + + func withMemoryRebound( + to type: T.Type, _ body: (UnsafeBufferPointer) throws -> Result + ) rethrows -> Result +} +``` + +```swift +extension Slice { + func copyMemory(from source: UnsafeRawBufferPointer) + func copyBytes(from source: C) where C.Element == UInt8 + + func initializeMemory( + as type: T.Type, repeating repeatedValue: T + ) -> UnsafeMutableBufferPointer + + func initializeMemory( + as type: S.Element.Type, from source: S + ) -> (unwritten: S.Iterator, initialized: UnsafeMutableBufferPointer) + + func initializeMemory( + as type: C.Element.Type, fromElements: C + ) -> UnsafeMutableBufferPointer + + func moveInitializeMemory( + as type: T.Type, fromElements: UnsafeMutableBufferPointer + ) -> UnsafeMutableBufferPointer + + func moveInitializeMemory( + as type: T.Type, fromElements: Slice> + ) -> UnsafeMutableBufferPointer + + func bindMemory(to type: T.Type) -> UnsafeMutableBufferPointer + func assumingMemoryBound(to type: T.Type) -> UnsafeMutableBufferPointer + + func withMemoryRebound( + to type: T.Type, + _ body: (UnsafeMutableBufferPointer) throws -> Result + ) rethrows -> Result +} +``` + +## Detailed design + +```swift +extension UnsafeMutableBufferPointer { + /// Initializes the buffer's memory with the given elements. + /// + /// Initializes the buffer's memory with the given elements. + /// + /// Prior to calling the `initialize(fromElements:)` method on a buffer, + /// the memory referenced by the buffer must be uninitialized, + /// or the `Element` type must be a trivial type. After the call, + /// the memory referenced by the buffer up to, but not including, + /// the returned index is initialized. + /// + /// The returned index is the position of the next uninitialized element + /// in the buffer, 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 + /// number of elements than the buffer can hold, the returned index is equal + /// 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`. + func initialize(fromElements source: C) -> Index + where C: Collection, C.Element == Element + + /// Updates every element of this buffer's initialized memory. + /// + /// The buffer’s memory must be initialized or the buffer's `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: Element) + + /// Updates the buffer's initialized memory with the given elements. + /// + /// The buffer's memory must be initialized or the buffer's `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(from source: S) -> (unwritten: S.Iterator, assigned: Index) + where S: Sequence, S.Element == Element + + /// Updates the buffer's initialized memory with the given elements. + /// + /// The buffer'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(fromElements source: C) -> Index + where C: Collection, C.Element == 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. + /// + /// The region of memory starting at this pointer and covering `source.count` + /// instances of the buffer's `Element` type must be uninitialized, or + /// `Element` must be a trivial type. After calling + /// `moveInitialize(fromElements:)`, the region is initialized and the memory + /// region 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(fromElements: Self) -> Index + + /// 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 `source.count` + /// instances of the buffer's `Element` type must be uninitialized, or + /// `Element` must be a trivial type. After calling + /// `moveInitialize(fromElements:)`, the region is initialized and the memory + /// region underlying `source[..) -> Index + + /// Updates this buffer's initialized memory initialized memory by moving + /// all the elements from the source buffer, leaving the source memory + /// uninitialized. + /// + /// The region of memory starting at this pointer and covering + /// `fromElements.count` instances of the buffer's `Element` type + /// must be initialized, or `Element` must be a trivial type. After calling + /// `moveUpdate(fromElements:)`, the memory region 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: `Self`) -> Index + + /// Updates this buffer's initialized memory initialized memory by moving + /// all the elements from the source buffer slice, leaving the source memory + /// uninitialized. + /// + /// The region of memory starting at this pointer and covering + /// `fromElements.count` instances of the buffer's `Element` type + /// must be initialized, or `Element` must be a trivial type. After calling + /// `moveUpdate(fromElements:)`, the memory region underlying + /// `source[..) -> Index + + /// Deinitializes every instance in this buffer. + /// + /// The region of memory underlying this buffer 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 buffer element at `index` to the given value. + /// + /// The destination element must be uninitialized or the buffer's `Element` + /// must be a trivial type. After a call to `initialize(to:)`, the + /// memory underlying this element of the buffer 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: Index, to value: Element) + + /// Updates the initialized buffer element at `index` with the given value. + /// + /// 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 buffer element at `index`, + /// leaving that element's memory uninitialized. + /// + /// The memory underlying buffer the element at `index` must be initialized. + /// After calling `moveElement(from:)`, the memory underlying the buffer + /// element at `index` 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(from index: Index) -> Element + + /// Deinitializes the buffer element at `index`. + /// + /// The memory underlying the buffer element at `index` must be initialized. + /// After calling `deinitializeElement()`, the memory underlying the buffer + /// element at `index` is uninitialized, and still bound to type `Element`. + /// + /// - Parameters: + /// - index: The index of the buffer element to deinitialize. + public func deinitializeElement(at index: Index) +} +``` + +```swift +extension UnsafeMutablePointer { + /// Update this pointer's initialized memory. + /// + /// The range of memory starting at this pointer and covering one instance + /// of `Pointee` must be initialized, or `Pointee` must be a trivial type. + /// This method is equivalent to: + /// + /// self.pointee = value + /// + /// - Parameters: + /// - value: The value used to update this pointer's memory. + public func update(_ value: Pointee) +} + + /// Update this pointer's initialized memory with the specified number of + /// instances, copied from the given pointer's memory. + /// + /// The region of memory starting at this pointer and covering `count` + /// instances of the pointer's `Pointee` type must be initialized or + /// `Pointee` must be a trivial type. After calling + /// `update(from:count:)`, the region is initialized. + /// + /// - Note: Returns without performing work if `self` and `source` are equal. + /// + /// - Parameters: + /// - source: A pointer to at least `count` initialized instances of type + /// `Pointee`. The memory regions referenced by `source` and this + /// pointer may overlap. + /// - count: The number of instances to copy from the memory referenced by + /// `source` to this pointer's memory. `count` must not be negative. + public func update(from source: UnsafePointer, count: Int) + + /// Update this pointer's initialized memory by moving the specified number + /// of instances the source pointer's memory, leaving the source memory + /// uninitialized. + /// + /// The region of memory starting at this pointer and covering `count` + /// instances of the pointer's `Pointee` type must be initialized or + /// `Pointee` must be a trivial type. After calling + /// `moveUpdate(from:count:)`, the region is initialized and the memory + /// region `source..<(source + count)` is uninitialized. + /// + /// - Note: The source and destination memory regions must not overlap. + /// + /// - Parameters: + /// - source: A pointer to the values to be moved. The memory region + /// `source..<(source + count)` must be initialized. The memory regions + /// referenced by `source` and this pointer must not overlap. + /// - count: The number of instances to move from `source` to this + /// pointer's memory. `count` must not be negative. + public func moveUpdate(from source: UnsafeMutablePointer, count: Int) +``` + +``` +extension UnsafeMutableRawPointer { + /// Initializes the memory referenced by this pointer with the given value, + /// binds the memory to the value's type, and returns a typed pointer to the + /// initialized memory. + /// + /// The memory referenced by this pointer must be uninitialized or + /// initialized to a trivial type, and must be properly aligned for + /// accessing `T`. + /// + /// The following example allocates raw memory for one instance of `UInt`, + /// and then uses the `initializeMemory(as:to:)` method + /// to initialize the allocated memory. + /// + /// let bytePointer = UnsafeMutableRawPointer.allocate( + /// byteCount: MemoryLayout.stride, + /// alignment: MemoryLayout.alignment) + /// let int8Pointer = bytePointer.initializeMemory(as: UInt.self, to: 0) + /// + /// // After using 'int8Pointer': + /// int8Pointer.deallocate() + /// + /// After calling this method on a raw pointer `p`, the region starting at + /// `self` and continuing up to `p + MemoryLayout.stride` is bound + /// to type `T` and initialized. If `T` is a nontrivial type, you must + /// eventually deinitialize the memory in this region to avoid memory leaks. + /// + /// - Parameters: + /// - type: The type to which this memory will be bound. + /// - value: The value used to initialize this memory. + /// - Returns: A typed pointer to the memory referenced by this raw pointer. + public func initializeMemory(as type: T.Type, to value: T) -> UnsafeMutablePointer +} +``` + +```swift +extension UnsafeMutableRawBufferPointer { + /// 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(as: C.Element.Type, fromElements: C) -> UnsafeMutableBufferPointer + where C: Collection + + /// 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( + as type: T.Type, + fromElements: UnsafeMutableBufferPointer + ) -> UnsafeMutableBufferPointer + + /// 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[..( + as type: T.Type, + fromElements: Slice> + ) -> UnsafeMutableBufferPointer +} +``` + + + +For `Slice`, 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. + +```swift +protocol _RebasableCollection: Collection { + init(rebasing slice: SubSequence) +} + +extension UnsafeBufferPointer: _RebasableCollection {} +extension UnsafeMutableBufferPointer: _RebasableCollection {} +``` + +```swift +protocol _MutableBaseAddressProtocol: MutableCollection { + var baseAddress: UnsafeMutablePointer? { get } +} + +extension UnsafeMutableBufferPointer: _MutableBaseAddressProtocol {} +``` + +Changes to `Slice`: +```swift +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( + to type: T.Type, _ body: (UnsafeBufferPointer) throws -> Result + ) rethrows -> Result +} +``` + +Changes for `Slice>`: +```swift +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( + 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( + 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( + 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( + 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) -> 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 + ) -> 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> + ) -> 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( + to type: T.Type, _ body: (UnsafeMutableBufferPointer) throws -> Result + ) rethrows -> Result +} +``` + +Changes for `Slice`: +```swift +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.stride` instances of `T`. + public func bindMemory(to type: T.Type) -> UnsafeBufferPointer + + /// 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.alignment`). + /// That is, `Int(bitPattern: self.baseAddress) % MemoryLayout.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( + to type: T.Type, _ body: (UnsafeBufferPointer) 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.alignment`). + /// That is, `Int(bitPattern: self.baseAddress) % MemoryLayout.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(to type: T.Type) -> UnsafeBufferPointer +} +``` + +Changes for `Slice`: +```swift +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.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.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(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.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.stride` + /// instances of `T`. + func initializeMemory(as type: T.Type, repeating repeatedValue: T) -> UnsafeMutableBufferPointer + + /// 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( + as type: S.Element.Type, from source: S + ) -> (unwritten: S.Iterator, initialized: UnsafeMutableBufferPointer) + + /// 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( + as type: C.Element.Type, + fromElements source: C + ) -> UnsafeMutableBufferPointer + + /// 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( + as type: T.Type, + fromElements source: UnsafeMutableBufferPointer + ) -> UnsafeMutableBufferPointer + + /// 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[..( + as type: T.Type, + fromElements source: Slice> + ) -> UnsafeMutableBufferPointer + + /// 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.stride` instances of `T`. + public func bindMemory(to type: T.Type) -> UnsafeMutableBufferPointer + + /// 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.alignment`). + /// That is, `Int(bitPattern: self.baseAddress) % MemoryLayout.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( + to type: T.Type, _ body: (UnsafeMutableBufferPointer) 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.alignment`). + /// That is, `Int(bitPattern: self.baseAddress) % MemoryLayout.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(to type: T.Type) -> UnsafeMutableBufferPointer +} +``` + +## Source compatibility + +This proposal consists mostly of additions, which are by definition source compatible. + +The proposal includes the renaming of four existing functions from `assign` to `update`. +The existing function names would be deprecated, producing a warning. +A fixit will support an easy transition to the renamed versions of these functions. + + +## Effect on ABI stability + +The functions proposed here are generally small wrappers around existing functionality. +We expect to implement them as `@_alwaysEmitIntoClient` functions, +which means they would have no ABI impact. + +The renamed functions can reuse the existing symbol, +while the deprecated functions can forward using an `@_alwaysEmitIntoClient` stub to support the functionality under its previous name. This means they would have no ABI impact. + + +## Effect on API resilience + +All functionality implemented as `@_alwaysEmitIntoClient` will back-deploy. +Renamed functions that reuse a previous symbol will also back-deploy. + + +## Alternatives considered + +##### Single element update functions + +The single-element update functions, +`UnsafeMutablePointer.update(to:)` and `UnsafeMutableBufferPointer.updateElement(at:to:)`, +are synonyms for the setters of `UnsafeMutablePointer.pointee` and `UnsafeMutableBufferPointer.subscript(_ i: Index)`, respectively. +Clearly we can elect to not add them. +The setters in question, like the update functions, +have a required precondition that the memory they refer to must be initialized. +Somehow this precondition is often overlooked and leads to bug reports. +The proposed names and cross-references should help clarify the requirements to users. + +##### Renaming `assign` to `update` + +The renaming of `assign` to `update` could be omitted entirely, +although we believe that `update` communicates intent much better than `assign` does. +In _The Swift Programming Language_, the `=` symbol is named "the assignment operator", and its function is described as to either initialize or to update a value. The current name (`assign`) is not as clear as the documentation in *TSPL*, while the proposed name (`update`) builds on it. + +There are only four current symbols to be renamed by this proposal, +and their replacements are easily migrated by a fixit. +For context, this renaming would change only 6 lines of code in the standard library, outside of the function definitions. +If the renaming is omitted, the four new functions proposed in the family should use the name `assign` as well. +The two single-element versions would be `assign(_ value:)` and `assignElement(at:_ value:)`. + +##### Element-by-element copies from `Collection` inputs + +The initialization and updating functions that copy from `Collection` inputs use the argument label `fromElements`. +This is different from the pre-existing functions that copy from `Sequence` inputs. +We could use the same argument label (`from`) as with the `Sequence` inputs, +but that would mean that we must return the `Iterator` for the `Collection` versions, +and that is generally not desirable, especially if a particular `Iterator` cannot be copied cheaply. +If we did not return `Iterator`, then the `Sequence` and `Collection` versions of the `initialize(from:)` would be overloaded by their return type, +and that would be source-breaking: +an existing use of the current function that doesn't destructure the returned tuple on assignment could now pick up the `Collection` overload, +which would have a return value incompatible with the existing code which assumes that the return value is of type `(Iterator, Int)`. + +## Acknowledgments + +[Kelvin Ma](https://github.com/kelvin13) (aka [Taylor Swift](https://forums.swift.org/u/taylorswift/summary))'s initial versions of the pitch that became SE-0184 included more functions to manipulate initialization state. +These were deferred, but much of the deferred functionality has not been pitched again until now. + +Members of the Swift Standard Library team for valuable discussions. + From ced5ee6f071718f397a59eee47fa626e8c167b69 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Tue, 1 Mar 2022 14:42:22 -0700 Subject: [PATCH 02/18] Correct links to pull requests. --- ...NNNN-pointer-family-initialization-improvements.md} | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) rename proposals/{NNNN-buffer-family-initialization-improvements.md => NNNN-pointer-family-initialization-improvements.md} (99%) diff --git a/proposals/NNNN-buffer-family-initialization-improvements.md b/proposals/NNNN-pointer-family-initialization-improvements.md similarity index 99% rename from proposals/NNNN-buffer-family-initialization-improvements.md rename to proposals/NNNN-pointer-family-initialization-improvements.md index 4c3fa81aad..5dfdac471b 100644 --- a/proposals/NNNN-buffer-family-initialization-improvements.md +++ b/proposals/NNNN-pointer-family-initialization-improvements.md @@ -1,6 +1,6 @@ -# Buffer Family Initialization Improvements & Better Buffer Slices +# Pointer Family Initialization Improvements & Better Buffer Slices -* Proposal: [SE-NNNN Buffer Family Initialization Improvements & Better Buffer Slices][proposal] +* Proposal: [SE-NNNN Pointer Family Initialization Improvements & Better Buffer Slices][proposal] * Author: [Guillaume Lessard](https://github.com/glessard) * Review Manager: TBD * Status: pending @@ -8,9 +8,9 @@ * Bugs: rdar://51817146 * Previous Revision: [pitch A](https://gist.github.com/glessard/3bb47dce974aa483fd6df072d265005c ), [pitch B](https://gist.github.com/glessard/cefa5686696b0e30ac18eb4899213c65) -[proposal]: https://gist.github.com/glessard/cefa5686696b0e30ac18eb4899213c65 -[draft-pr]: https://github.com/apple/swift/pull/40337 -[pitch-thread]: https://forums.swift.org/t/53795 +[proposal]: https://github.com/apple/swift-evolution/blob/e95cf588a2f3c0a52f5ff4de780dc1e30c7fb303/proposals/NNNN-buffer-family-initialization-improvements.md +[draft-pr]: https://github.com/apple/swift/pull/41608 + ## Introduction From d581d27c7b4165308fdd2632037250b21210042e Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Tue, 1 Mar 2022 14:44:15 -0700 Subject: [PATCH 03/18] fix link to proposal --- proposals/NNNN-pointer-family-initialization-improvements.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/NNNN-pointer-family-initialization-improvements.md b/proposals/NNNN-pointer-family-initialization-improvements.md index 5dfdac471b..c76033f746 100644 --- a/proposals/NNNN-pointer-family-initialization-improvements.md +++ b/proposals/NNNN-pointer-family-initialization-improvements.md @@ -8,7 +8,7 @@ * Bugs: rdar://51817146 * Previous Revision: [pitch A](https://gist.github.com/glessard/3bb47dce974aa483fd6df072d265005c ), [pitch B](https://gist.github.com/glessard/cefa5686696b0e30ac18eb4899213c65) -[proposal]: https://github.com/apple/swift-evolution/blob/e95cf588a2f3c0a52f5ff4de780dc1e30c7fb303/proposals/NNNN-buffer-family-initialization-improvements.md +[proposal]: https://github.com/apple/swift-evolution/blob/pointer-family-initialization/proposals/NNNN-pointer-family-initialization-improvements.md [draft-pr]: https://github.com/apple/swift/pull/41608 From a5bbc9b9ccc2726d52aa49f13782c1523aa27bdc Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Wed, 2 Mar 2022 12:40:23 -0700 Subject: [PATCH 04/18] =?UTF-8?q?fixes=20for=20discourse=E2=80=99s=20markd?= =?UTF-8?q?own=20parser?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...nter-family-initialization-improvements.md | 90 +++++-------------- 1 file changed, 21 insertions(+), 69 deletions(-) diff --git a/proposals/NNNN-pointer-family-initialization-improvements.md b/proposals/NNNN-pointer-family-initialization-improvements.md index c76033f746..bc90b17bc3 100644 --- a/proposals/NNNN-pointer-family-initialization-improvements.md +++ b/proposals/NNNN-pointer-family-initialization-improvements.md @@ -15,9 +15,7 @@ ## Introduction -The types in the `UnsafeMutablePointer` family typically require manual management of memory allocations, -including the management of their initialization state. -The states involved are, after allocation: +The types in the `UnsafeMutablePointer` family typically require manual management of memory allocations, including the management of their initialization state. Unfortunately, not every relevant type in the family has the necessary functionality to fully manage the initialization state of the memory it represents. The states involved are, after allocation: 1. Unbound and uninitialized (as returned from `UnsafeMutableRawPointer.allocate()`) 2. Bound to a type, and uninitialized (as returned from `UnsafeMutablePointer.allocate()`) @@ -25,18 +23,13 @@ The states involved are, after allocation: Memory can be safely deallocated whenever it is uninitialized. -Unfortunately, not every relevant type in the family has the necessary functionality to fully manage the initialization state of the memory it represents. -We intend to round out initialization functionality for every relevant member of that family:`UnsafeMutablePointer`, `UnsafeMutableRawPointer`, `UnsafeMutableBufferPointer`, `UnsafeMutableRawBufferPointer`, `Slice` and `Slice`. The functionality will allow managing initialization state in a much greater variety of situations, including easier partial initialization of buffers. +We intend to round out initialization functionality for every relevant member of that family: `UnsafeMutablePointer`, `UnsafeMutableRawPointer`, `UnsafeMutableBufferPointer`, `UnsafeMutableRawBufferPointer`, `Slice` and `Slice`. The functionality will allow managing initialization state in a much greater variety of situations, including easier handling of partially-initialized buffers. Swift-evolution thread: [Pitch thread][pitch-thread] ## Motivation -Memory allocated using `UnsafeMutablePointer`, `UnsafeMutableRawPointer`, -`UnsafeMutableBufferPointer` and `UnsafeMutableRawBufferPointer` is passed to the user in an uninitialized state. -In the general case, such memory needs to be initialized before it is used in Swift. -Memory can be "initialized" or "uninitialized". -We hereafter refer to this as a memory region's "initialization state". +Memory allocated using `UnsafeMutablePointer`, `UnsafeMutableRawPointer`, `UnsafeMutableBufferPointer` and `UnsafeMutableRawBufferPointer` is passed to the user in an uninitialized state. In the general case, such memory needs to be initialized before it is used in Swift. Memory can be "initialized" or "uninitialized". We hereafter refer to this as a memory region's "initialization state". The methods of `UnsafeMutablePointer` that interact with initialization state are: @@ -61,9 +54,7 @@ This is a fairly complete set. Unfortunately, `UnsafeMutablePointer` is the only one of the list of types listed in the introduction to allow full control of initialization state, and this means that complex use cases such as partial initialization of a buffer become overly complicated. -An example of partial initialization is the insertion of elements in the middle of a collection. This is -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`: +An example of partial initialization is the insertion of elements in the middle of a collection. This is 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(_ subrange: Range, with newElements: C) @@ -100,10 +91,7 @@ mutating func replaceSubrange(_ subrange: Range, with newElements: C) } ``` -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: +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(_ subrange: Range, with newElements: C) where C: Collection, Element == C.Element { @@ -131,9 +119,7 @@ mutating func replaceSubrange(_ subrange: Range, with newElements: C) ... } ``` -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. +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. This proposal aims to add API to control initialization state and improve multiple-element copies for `UnsafeMutableBufferPointer`, `UnsafeMutableRawBufferPointer`, `Slice` and `Slice`. @@ -172,17 +158,9 @@ extension UnsafeMutableBufferPointer { We would like to use the verb `update` instead of `assign`, in order to better communicate the intent of the API. It is currently a common programmer error to use one of the existing `assign` functions for uninitialized memory; using the verb `update` instead would express the precondition in the API itself. -The methods that initialize or update from a `Collection` will have forgiving semantics, -and copy the number of elements that they can, be that every available element or none, -and then return the index in the buffer that follows the last element copied, which is cheaper than returning an iterator and a count. Unlike the existing `Sequence` functions, -they include no preconditions beyond having a valid `Collection` and valid buffer, -with the understanding that if a user needs stricter behaviour, -it can be composed from these functions. +The methods that initialize or update from a `Collection` will have forgiving semantics, and copy the number of elements that they can, be that every available element or none, and then return the index in the buffer that follows the last element copied, which is cheaper than returning an iterator and a count. Unlike the existing `Sequence` functions, they include no preconditions beyond having a valid `Collection` and valid buffer, with the understanding that if a user needs stricter behaviour, it can be composed from these functions. -The above changes include a method to update a single element. -Evidently that is a synonym for the `subscript(_ i: Index)` setter. -We hope that documenting the update action specifically will help clarify the requirements of that action, namely that the buffer element must already be initialized. -Experience shows that the initialization requirement of the subscript setter is frequently missed by users in the current situation, where it is only documented along with the subscript getter. +The above changes include a method to update a single element. Evidently that is a synonym for the `subscript(_ i: Index)` setter. We hope that documenting the update action specifically will help clarify the requirements of that action, namely that the buffer element must already be initialized. Experience shows that the initialization requirement of the subscript setter is frequently missed by users in the current situation, where it is only documented along with the subscript getter. ##### `UnsafeMutablePointer` @@ -1444,68 +1422,42 @@ extension Slice where Base == UnsafeMutableRawBufferPointer { This proposal consists mostly of additions, which are by definition source compatible. -The proposal includes the renaming of four existing functions from `assign` to `update`. -The existing function names would be deprecated, producing a warning. -A fixit will support an easy transition to the renamed versions of these functions. +The proposal includes the renaming of four existing functions from `assign` to `update`. The existing function names would be deprecated, producing a warning. A fixit will support an easy transition to the renamed versions of these functions. ## Effect on ABI stability -The functions proposed here are generally small wrappers around existing functionality. -We expect to implement them as `@_alwaysEmitIntoClient` functions, -which means they would have no ABI impact. +The functions proposed here are generally small wrappers around existing functionality. We expect to implement them as `@_alwaysEmitIntoClient` functions, which means they would have no ABI impact. -The renamed functions can reuse the existing symbol, -while the deprecated functions can forward using an `@_alwaysEmitIntoClient` stub to support the functionality under its previous name. This means they would have no ABI impact. +The renamed functions can reuse the existing symbol, while the deprecated functions can forward using an `@_alwaysEmitIntoClient` stub to support the functionality under its previous name. This means they would have no ABI impact. ## Effect on API resilience -All functionality implemented as `@_alwaysEmitIntoClient` will back-deploy. -Renamed functions that reuse a previous symbol will also back-deploy. +All functionality implemented as `@_alwaysEmitIntoClient` will back-deploy. Renamed functions that reuse a previous symbol will also back-deploy. ## Alternatives considered ##### Single element update functions -The single-element update functions, -`UnsafeMutablePointer.update(to:)` and `UnsafeMutableBufferPointer.updateElement(at:to:)`, -are synonyms for the setters of `UnsafeMutablePointer.pointee` and `UnsafeMutableBufferPointer.subscript(_ i: Index)`, respectively. -Clearly we can elect to not add them. -The setters in question, like the update functions, -have a required precondition that the memory they refer to must be initialized. -Somehow this precondition is often overlooked and leads to bug reports. -The proposed names and cross-references should help clarify the requirements to users. +The single-element update functions, `UnsafeMutablePointer.update(to:)` and `UnsafeMutableBufferPointer.updateElement(at:to:)`, are synonyms for the setters of `UnsafeMutablePointer.pointee` and `UnsafeMutableBufferPointer.subscript(_ i: Index)`, respectively. Clearly we can elect to not add them. + +The setters in question, like the update functions, have a required precondition that the memory they refer to must be initialized. Somehow this precondition is often overlooked and leads to bug reports. The proposed names and cross-references should help clarify the requirements to users. ##### Renaming `assign` to `update` -The renaming of `assign` to `update` could be omitted entirely, -although we believe that `update` communicates intent much better than `assign` does. -In _The Swift Programming Language_, the `=` symbol is named "the assignment operator", and its function is described as to either initialize or to update a value. The current name (`assign`) is not as clear as the documentation in *TSPL*, while the proposed name (`update`) builds on it. +The renaming of `assign` to `update` could be omitted entirely, although we believe that `update` communicates intent much better than `assign` does. In _The Swift Programming Language_, the `=` symbol is named "the assignment operator", and its function is described as to either initialize or to update a value. The current name (`assign`) is not as clear as the documentation in *TSPL*, while the proposed name (`update`) builds on it. -There are only four current symbols to be renamed by this proposal, -and their replacements are easily migrated by a fixit. -For context, this renaming would change only 6 lines of code in the standard library, outside of the function definitions. -If the renaming is omitted, the four new functions proposed in the family should use the name `assign` as well. -The two single-element versions would be `assign(_ value:)` and `assignElement(at:_ value:)`. +There are only four current symbols to be renamed by this proposal, and their replacements are easily migrated by a fixit. For context, this renaming would change only 6 lines of code in the standard library, outside of the function definitions. If the renaming is omitted, the four new functions proposed in the family should use the name `assign` as well. The two single-element versions would be `assign(_ value:)` and `assignElement(at:_ value:)`. ##### Element-by-element copies from `Collection` inputs -The initialization and updating functions that copy from `Collection` inputs use the argument label `fromElements`. -This is different from the pre-existing functions that copy from `Sequence` inputs. -We could use the same argument label (`from`) as with the `Sequence` inputs, -but that would mean that we must return the `Iterator` for the `Collection` versions, -and that is generally not desirable, especially if a particular `Iterator` cannot be copied cheaply. -If we did not return `Iterator`, then the `Sequence` and `Collection` versions of the `initialize(from:)` would be overloaded by their return type, -and that would be source-breaking: -an existing use of the current function that doesn't destructure the returned tuple on assignment could now pick up the `Collection` overload, -which would have a return value incompatible with the existing code which assumes that the return value is of type `(Iterator, Int)`. +The initialization and updating functions that copy from `Collection` inputs use the argument label `fromElements`. This is different from the pre-existing functions that copy from `Sequence` inputs. We could use the same argument label (`from`) as with the `Sequence` inputs, but that would mean that we must return the `Iterator` for the `Collection` versions, and that is generally not desirable, especially if a particular `Iterator` cannot be copied cheaply. If we did not return `Iterator`, then the `Sequence` and `Collection` versions of the `initialize(from:)` would be overloaded by their return type, and that would be source-breaking: +an existing use of the current function that doesn't destructure the returned tuple on assignment could now pick up the `Collection` overload, which would have a return value incompatible with the existing code which assumes that the return value is of type `(Iterator, Int)`. ## Acknowledgments -[Kelvin Ma](https://github.com/kelvin13) (aka [Taylor Swift](https://forums.swift.org/u/taylorswift/summary))'s initial versions of the pitch that became SE-0184 included more functions to manipulate initialization state. -These were deferred, but much of the deferred functionality has not been pitched again until now. - -Members of the Swift Standard Library team for valuable discussions. +[Kelvin Ma](https://github.com/kelvin13) (aka [Taylor Swift](https://forums.swift.org/u/taylorswift/summary))'s initial versions of the pitch that became SE-0184 included more functions to manipulate initialization state. These were deferred, but much of the deferred functionality has not been pitched again until now. +Members of the Swift Standard Library team for valuable discussions. \ No newline at end of file From 498bbf07508b2ee461bdde274284b3716c511068 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Wed, 2 Mar 2022 14:27:00 -0700 Subject: [PATCH 05/18] add link to pitch thread on forums --- proposals/NNNN-pointer-family-initialization-improvements.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/NNNN-pointer-family-initialization-improvements.md b/proposals/NNNN-pointer-family-initialization-improvements.md index bc90b17bc3..8cff804dc0 100644 --- a/proposals/NNNN-pointer-family-initialization-improvements.md +++ b/proposals/NNNN-pointer-family-initialization-improvements.md @@ -10,7 +10,7 @@ [proposal]: https://github.com/apple/swift-evolution/blob/pointer-family-initialization/proposals/NNNN-pointer-family-initialization-improvements.md [draft-pr]: https://github.com/apple/swift/pull/41608 - +[pitch-thread]: https://forums.swift.org/t/55689 ## Introduction From 209e77aa5b714b597c491c26fa48cacd251eb702 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Wed, 9 Mar 2022 12:39:04 -0700 Subject: [PATCH 06/18] specify that code block contains swift --- proposals/NNNN-pointer-family-initialization-improvements.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/NNNN-pointer-family-initialization-improvements.md b/proposals/NNNN-pointer-family-initialization-improvements.md index 8cff804dc0..13f8fe6099 100644 --- a/proposals/NNNN-pointer-family-initialization-improvements.md +++ b/proposals/NNNN-pointer-family-initialization-improvements.md @@ -580,7 +580,7 @@ extension UnsafeMutablePointer { public func moveUpdate(from source: UnsafeMutablePointer, count: Int) ``` -``` +```swift extension UnsafeMutableRawPointer { /// Initializes the memory referenced by this pointer with the given value, /// binds the memory to the value's type, and returns a typed pointer to the From 9fa2aad3a336271c6a45fd063c9623f60cbea97e Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Wed, 9 Mar 2022 12:39:36 -0700 Subject: [PATCH 07/18] improve doc-comment --- ...NNN-pointer-family-initialization-improvements.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/proposals/NNNN-pointer-family-initialization-improvements.md b/proposals/NNNN-pointer-family-initialization-improvements.md index 13f8fe6099..3c4700f4d8 100644 --- a/proposals/NNNN-pointer-family-initialization-improvements.md +++ b/proposals/NNNN-pointer-family-initialization-improvements.md @@ -635,11 +635,13 @@ extension UnsafeMutableRawBufferPointer { /// - 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(as: C.Element.Type, fromElements: C) -> UnsafeMutableBufferPointer + /// - Returns: A typed buffer containing 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( + as: C.Element.Type, fromElements: C + ) -> UnsafeMutableBufferPointer where C: Collection /// Moves instances from an initialized source buffer into the From 08850a88b1f431733dab03b4f93082969678865f Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Mon, 28 Mar 2022 13:53:22 -0600 Subject: [PATCH 08/18] update detailed design for Slice --- ...nter-family-initialization-improvements.md | 98 ++++++++++--------- 1 file changed, 50 insertions(+), 48 deletions(-) diff --git a/proposals/NNNN-pointer-family-initialization-improvements.md b/proposals/NNNN-pointer-family-initialization-improvements.md index 3c4700f4d8..ebdde185ef 100644 --- a/proposals/NNNN-pointer-family-initialization-improvements.md +++ b/proposals/NNNN-pointer-family-initialization-improvements.md @@ -700,30 +700,11 @@ extension UnsafeMutableRawBufferPointer { -For `Slice`, 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. - -```swift -protocol _RebasableCollection: Collection { - init(rebasing slice: SubSequence) -} - -extension UnsafeBufferPointer: _RebasableCollection {} -extension UnsafeMutableBufferPointer: _RebasableCollection {} -``` - -```swift -protocol _MutableBaseAddressProtocol: MutableCollection { - var baseAddress: UnsafeMutablePointer? { get } -} - -extension UnsafeMutableBufferPointer: _MutableBaseAddressProtocol {} -``` +For `Slice`, the functions need to add an additional generic parameter, which is immediately restricted in the `where` clause. This is necessary because "parameterized extensions" are not yet a Swift feature. Eventually, these functions should be able to have exactly the same generic signatures as the counterpart function on their `UnsafeBufferPointer`-family base. This change will be neither source-breaking nor ABI-breaking. Changes to `Slice`: ```swift -extension Slice where Base: _RebasableCollection, Base.SubSequence == Self { - +extension Slice { /// Executes the given closure while temporarily binding the memory referenced /// by this buffer slice to the given type. /// @@ -779,17 +760,16 @@ extension Slice where Base: _RebasableCollection, Base.SubSequence == Self { /// method. /// - buffer: The buffer temporarily bound to `T`. /// - Returns: The return value, if any, of the `body` closure parameter. - public func withMemoryRebound( + public func withMemoryRebound( to type: T.Type, _ body: (UnsafeBufferPointer) throws -> Result - ) rethrows -> Result + ) rethrows -> Result + where Base == UnsafeBufferPointer } ``` Changes for `Slice>`: ```swift -extension Slice where Base: _RebasableCollection & _MutableBaseAddressProtocol, - Base.SubSequence == Self { - +extension Slice { /// Initializes every element in this buffer slice's memory to /// a copy of the given value. /// @@ -799,7 +779,8 @@ extension Slice where Base: _RebasableCollection & _MutableBaseAddressProtocol, /// /// - Parameter repeatedValue: The value with which to initialize this /// buffer slice's memory. - public func initialize(repeating repeatedValue: Base.Element) + public func initialize(repeating repeatedValue: Element) + where Base == UnsafeMutableBufferPointer /// Initializes the buffer slice's memory with the given elements. /// @@ -824,7 +805,8 @@ extension Slice where Base: _RebasableCollection & _MutableBaseAddressProtocol, /// buffer, and an index to the next uninitialized element in the buffer. public func initialize( from source: S - ) -> (S.Iterator, Index) where S: Sequence, Base.Element == S.Element + ) -> (S.Iterator, Index) + where S: Sequence, Base == UnsafeMutableBufferPointer /// Initializes the buffer slice's memory with the given elements. /// @@ -847,7 +829,8 @@ extension Slice where Base: _RebasableCollection & _MutableBaseAddressProtocol, /// or `endIndex`. public func initialize( fromElements source: C - ) -> Int where C : Collection, Base.Element == C.Element + ) -> Index + where C : Collection, Base == UnsafeMutableBufferPointer /// Updates every element of this buffer slice's initialized memory. /// @@ -858,7 +841,8 @@ extension Slice where Base: _RebasableCollection & _MutableBaseAddressProtocol, /// /// - Parameters: /// - repeatedValue: The value used when updating this pointer's memory. - public func update(repeating repeatedValue: Base.Element) + public func update(repeating repeatedValue: Element) + where Base == UnsafeMutableBufferPointer /// Updates the buffer slice's initialized memory with the given elements. /// @@ -869,9 +853,10 @@ extension Slice where Base: _RebasableCollection & _MutableBaseAddressProtocol, /// 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( + public func update( from source: S - ) -> (iterator: S.Iterator, updated: Index) where S.Element == Element + ) -> (unwritten: S.Iterator, updated: Index) + where S: Sequence, Base == UnsafeMutableBufferPointer /// Updates the buffer slice's initialized memory with the given elements. /// @@ -882,9 +867,10 @@ extension Slice where Base: _RebasableCollection & _MutableBaseAddressProtocol, /// the buffer's contents. /// - Returns: An index one past the last updated element in the buffer, /// or `endIndex`. - public func update( + public func update( fromElements source: C - ) -> Index where C.Element == Element + ) -> Index + where C: Collection, Base == UnsafeMutableBufferPointer /// Moves every element of an initialized source buffer into the /// uninitialized memory referenced by this buffer slice, leaving the @@ -901,8 +887,11 @@ extension Slice where Base: _RebasableCollection & _MutableBaseAddressProtocol, /// 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 - + public func moveInitialize( + fromElements source: UnsafeMutableBufferPointer + ) -> Index + where Base == UnsafeMutableBufferPointer + /// 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. @@ -918,7 +907,10 @@ extension Slice where Base: _RebasableCollection & _MutableBaseAddressProtocol, /// 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) -> Index + public func moveInitialize( + fromElements source: Slice> + ) -> Index + where Base == UnsafeMutableBufferPointer /// Updates this buffer slice's initialized memory initialized memory by /// moving every element from the source buffer, @@ -935,9 +927,10 @@ extension Slice where Base: _RebasableCollection & _MutableBaseAddressProtocol, /// 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 + public func moveUpdate( + fromElements source: UnsafeMutableBufferPointer ) -> Index + where Base == UnsafeMutableBufferPointer /// Updates this buffer slice's initialized memory initialized memory by /// moving every element from the source buffer slice, @@ -954,9 +947,10 @@ extension Slice where Base: _RebasableCollection & _MutableBaseAddressProtocol, /// 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> + public func moveUpdate( + fromElements source: Slice> ) -> Index + where Base == UnsafeMutableBufferPointer /// Deinitializes every instance in this buffer slice. /// @@ -968,7 +962,8 @@ extension Slice where Base: _RebasableCollection & _MutableBaseAddressProtocol, /// /// - 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 + public func deinitialize() -> UnsafeMutableRawBufferPointer + where Base == UnsafeMutableBufferPointer /// Initializes the element at `index` to the given value. /// @@ -979,7 +974,8 @@ extension Slice where Base: _RebasableCollection & _MutableBaseAddressProtocol, /// - 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) + public func initializeElement(at index: Int, to value: Element) + where Base == UnsafeMutableBufferPointer /// Updates the initialized element at `index` to the given value. /// @@ -991,7 +987,8 @@ extension Slice where Base: _RebasableCollection & _MutableBaseAddressProtocol, /// - 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) + public func updateElement(at index: Index, to value: Element) + where Base == UnsafeMutableBufferPointer /// Retrieves and returns the element at `index`, /// leaving that element's underlying memory uninitialized. @@ -1003,7 +1000,8 @@ extension Slice where Base: _RebasableCollection & _MutableBaseAddressProtocol, /// - 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 + public func moveElement(from index: Index) -> Element + where Base == UnsafeMutableBufferPointer /// Deinitializes the memory underlying the element at `index`. /// @@ -1013,7 +1011,8 @@ extension Slice where Base: _RebasableCollection & _MutableBaseAddressProtocol, /// /// - Parameters: /// - index: The index of the buffer element to deinitialize. - public func deinitializeElement(at index: Base.Index) + public func deinitializeElement(at index: Base.Index) + where Base == UnsafeMutableBufferPointer /// Executes the given closure while temporarily binding the memory referenced /// by this buffer slice to the given type. @@ -1070,9 +1069,10 @@ extension Slice where Base: _RebasableCollection & _MutableBaseAddressProtocol, /// method. /// - buffer: The buffer temporarily bound to `T`. /// - Returns: The return value, if any, of the `body` closure parameter. - public func withMemoryRebound( + public func withMemoryRebound( to type: T.Type, _ body: (UnsafeMutableBufferPointer) throws -> Result ) rethrows -> Result + where Base == UnsafeMutableBufferPointer } ``` @@ -1225,7 +1225,9 @@ extension Slice where Base == UnsafeMutableRawBufferPointer { /// - Returns: A typed buffer of the memory referenced by this raw buffer. /// The typed buffer contains `self.count / MemoryLayout.stride` /// instances of `T`. - func initializeMemory(as type: T.Type, repeating repeatedValue: T) -> UnsafeMutableBufferPointer + func initializeMemory( + as type: T.Type, repeating repeatedValue: T + ) -> UnsafeMutableBufferPointer /// Initializes the buffer's memory with the given elements, binding the /// initialized memory to the elements' type. From 787cd07e6334c34182f5c0908afcfb4b82052a74 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Tue, 31 May 2022 15:08:09 -0600 Subject: [PATCH 09/18] add load, loadUnaligned and storeBytes to raw buffer slices --- ...nter-family-initialization-improvements.md | 175 +++++++++++++++++- 1 file changed, 174 insertions(+), 1 deletion(-) diff --git a/proposals/NNNN-pointer-family-initialization-improvements.md b/proposals/NNNN-pointer-family-initialization-improvements.md index ebdde185ef..4ebf3d9c61 100644 --- a/proposals/NNNN-pointer-family-initialization-improvements.md +++ b/proposals/NNNN-pointer-family-initialization-improvements.md @@ -5,7 +5,7 @@ * Review Manager: TBD * Status: pending * Implementation: [Draft Pull Request][draft-pr] -* Bugs: rdar://51817146 +* Bugs: [rdar://51817146](rdar://51817146) * Previous Revision: [pitch A](https://gist.github.com/glessard/3bb47dce974aa483fd6df072d265005c ), [pitch B](https://gist.github.com/glessard/cefa5686696b0e30ac18eb4899213c65) [proposal]: https://github.com/apple/swift-evolution/blob/pointer-family-initialization/proposals/NNNN-pointer-family-initialization-improvements.md @@ -290,6 +290,7 @@ extension Slice> { } ``` +Slices of `Unsafe[Mutable]RawBufferPointer` will add memory binding functions, memory initialization functions, and variants of `load`, `loadUnaligned` and `storeBytes` that always load from the beginning of the slice. ```swift extension Slice { func bindMemory(to type: T.Type) -> UnsafeBufferPointer @@ -298,6 +299,9 @@ extension Slice { func withMemoryRebound( to type: T.Type, _ body: (UnsafeBufferPointer) throws -> Result ) rethrows -> Result + + func load(as type: T.Type) -> T + func loadUnaligned(as type: T.Type) -> T } ``` @@ -333,6 +337,10 @@ extension Slice { to type: T.Type, _ body: (UnsafeMutableBufferPointer) throws -> Result ) rethrows -> Result + + func load(as type: T.Type) -> T + func loadUnaligned(as type: T.Type) -> T + func storeBytes(of value: T, as type: T.Type) } ``` @@ -1164,6 +1172,70 @@ extension Slice where Base: UnsafeRawBufferPointer { /// - 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(to type: T.Type) -> UnsafeBufferPointer + + /// Returns a new instance of the given type, read from the + /// specified offset into the buffer pointer slice's raw memory. + /// + /// The memory at `offset` bytes into this buffer pointer slice + /// must be properly aligned for accessing `T` and initialized to `T` or + /// another type that is layout compatible with `T`. + /// + /// You can use this method to create new values from the underlying + /// buffer pointer's bytes. The following example creates two new `Int32` + /// instances from the memory referenced by the buffer pointer `someBytes`. + /// The bytes for `a` are copied from the first four bytes of `someBytes`, + /// and the bytes for `b` are copied from the next four bytes. + /// + /// let a = someBytes[0..<4].load(as: Int32.self) + /// let b = someBytes[4..<8].load(as: Int32.self) + /// + /// The memory to read for the new instance must not extend beyond the + /// memory region represented by the buffer pointer slice---that is, + /// `offset + MemoryLayout.size` must be less than or equal + /// to the slice's `count`. + /// + /// - Parameters: + /// - offset: The offset into the slice's memory, in bytes, at + /// which to begin reading data for the new instance. The default is zero. + /// - type: The type to use for the newly constructed instance. The memory + /// must be initialized to a value of a type that is layout compatible + /// with `type`. + /// - Returns: A new instance of type `T`, copied from the buffer pointer + /// slice's memory. + func load(fromByteOffset offset: Int = 0, as type: T.Type) -> T + + /// Returns a new instance of the given type, read from the + /// specified offset into the buffer pointer slice's raw memory. + /// + /// This function only supports loading trivial types. + /// A trivial type does not contain any reference-counted property + /// within its in-memory stored representation. + /// The memory at `offset` bytes into the buffer slice must be laid out + /// identically to the in-memory representation of `T`. + /// + /// You can use this method to create new values from the buffer pointer's + /// underlying bytes. The following example creates two new `Int32` + /// instances from the memory referenced by the buffer pointer `someBytes`. + /// The bytes for `a` are copied from the first four bytes of `someBytes`, + /// and the bytes for `b` are copied from the fourth through seventh bytes. + /// + /// let a = someBytes[..<4].loadUnaligned(as: Int32.self) + /// let b = someBytes[3...].loadUnaligned(as: Int32.self) + /// + /// The memory to read for the new instance must not extend beyond the + /// memory region represented by the buffer pointer slice---that is, + /// `offset + MemoryLayout.size` must be less than or equal + /// to the slice's `count`. + /// + /// - Parameters: + /// - offset: The offset into the slice's memory, in bytes, at + /// which to begin reading data for the new instance. The default is zero. + /// - type: The type to use for the newly constructed instance. The memory + /// must be initialized to a value of a type that is layout compatible + /// with `type`. + /// - Returns: A new instance of type `T`, copied from the buffer pointer's + /// memory. + func loadUnaligned(fromByteOffset offset: Int = 0, as type: T.Type) -> T } ``` @@ -1419,6 +1491,107 @@ extension Slice where Base == UnsafeMutableRawBufferPointer { /// - 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(to type: T.Type) -> UnsafeMutableBufferPointer + + /// Returns a new instance of the given type, read from the + /// specified offset into the buffer pointer slice's raw memory. + /// + /// The memory at `offset` bytes into this buffer pointer slice + /// must be properly aligned for accessing `T` and initialized to `T` or + /// another type that is layout compatible with `T`. + /// + /// You can use this method to create new values from the underlying + /// buffer pointer's bytes. The following example creates two new `Int32` + /// instances from the memory referenced by the buffer pointer `someBytes`. + /// The bytes for `a` are copied from the first four bytes of `someBytes`, + /// and the bytes for `b` are copied from the next four bytes. + /// + /// let a = someBytes[0..<4].load(as: Int32.self) + /// let b = someBytes[4..<8].load(as: Int32.self) + /// + /// The memory to read for the new instance must not extend beyond the + /// memory region represented by the buffer pointer slice---that is, + /// `offset + MemoryLayout.size` must be less than or equal + /// to the slice's `count`. + /// + /// - Parameters: + /// - offset: The offset into the slice's memory, in bytes, at + /// which to begin reading data for the new instance. The default is zero. + /// - type: The type to use for the newly constructed instance. The memory + /// must be initialized to a value of a type that is layout compatible + /// with `type`. + /// - Returns: A new instance of type `T`, copied from the buffer pointer + /// slice's memory. + func load(fromByteOffset offset: Int = 0, as type: T.Type) -> T + + /// Returns a new instance of the given type, read from the + /// specified offset into the buffer pointer slice's raw memory. + /// + /// This function only supports loading trivial types. + /// A trivial type does not contain any reference-counted property + /// within its in-memory stored representation. + /// The memory at `offset` bytes into the buffer slice must be laid out + /// identically to the in-memory representation of `T`. + /// + /// You can use this method to create new values from the buffer pointer's + /// underlying bytes. The following example creates two new `Int32` + /// instances from the memory referenced by the buffer pointer `someBytes`. + /// The bytes for `a` are copied from the first four bytes of `someBytes`, + /// and the bytes for `b` are copied from the fourth through seventh bytes. + /// + /// let a = someBytes[..<4].loadUnaligned(as: Int32.self) + /// let b = someBytes[3...].loadUnaligned(as: Int32.self) + /// + /// The memory to read for the new instance must not extend beyond the + /// memory region represented by the buffer pointer slice---that is, + /// `offset + MemoryLayout.size` must be less than or equal + /// to the slice's `count`. + /// + /// - Parameters: + /// - offset: The offset into the slice's memory, in bytes, at + /// which to begin reading data for the new instance. The default is zero. + /// - type: The type to use for the newly constructed instance. The memory + /// must be initialized to a value of a type that is layout compatible + /// with `type`. + /// - Returns: A new instance of type `T`, copied from the buffer pointer's + /// memory. + func loadUnaligned(fromByteOffset offset: Int = 0, as type: T.Type) -> T + + /// Stores a value's bytes into the buffer pointer slice's raw memory at the + /// specified byte offset. + /// + /// The type `T` to be stored must be a trivial type. The memory must also be + /// uninitialized, initialized to `T`, or initialized to another trivial + /// type that is layout compatible with `T`. + /// + /// The memory written to must not extend beyond + /// the memory region represented by the buffer pointer slice---that is, + /// `offset + MemoryLayout.size` must be less than or equal + /// to the slice's `count`. + /// + /// After calling `storeBytes(of:toByteOffset:as:)`, the memory is + /// initialized to the raw bytes of `value`. If the memory is bound to a + /// type `U` that is layout compatible with `T`, then it contains a value of + /// type `U`. Calling `storeBytes(of:toByteOffset:as:)` does not change the + /// bound type of the memory. + /// + /// - Note: A trivial type can be copied with just a bit-for-bit copy without + /// any indirection or reference-counting operations. Generally, native + /// Swift types that do not contain strong or weak references or other + /// forms of indirection are trivial, as are imported C structs and enums. + /// + /// If you need to store into memory a copy of a value of a type that isn't + /// trivial, you cannot use the `storeBytes(of:toByteOffset:as:)` method. + /// Instead, you must know either initialize the memory or, + /// if you know the memory was already bound to `type`, assign to the memory. + /// + /// - Parameters: + /// - value: The value to store as raw bytes. + /// - offset: The offset in bytes into the buffer pointer slice's memory + /// to begin writing bytes from the value. The default is zero. + /// - type: The type to use for the newly constructed instance. The memory + /// must be initialized to a value of a type that is layout compatible + /// with `type`. + func storeBytes(of value: T, toByteOffset offset: Int = 0, as type: T.Type) } ``` From 801071609206b0773a3da299b5cd8f1cf159df5b Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Fri, 8 Jul 2022 16:59:25 -0600 Subject: [PATCH 10/18] wording improvements --- ...inter-family-initialization-improvements.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/proposals/NNNN-pointer-family-initialization-improvements.md b/proposals/NNNN-pointer-family-initialization-improvements.md index 4ebf3d9c61..732ec6f61a 100644 --- a/proposals/NNNN-pointer-family-initialization-improvements.md +++ b/proposals/NNNN-pointer-family-initialization-improvements.md @@ -52,7 +52,7 @@ This is a fairly complete set. - The `move()` function deinitializes a memory location, then returns its current contents. - The `move` prefix means that the `source` range of memory will be deinitialized after the function returns. -Unfortunately, `UnsafeMutablePointer` is the only one of the list of types listed in the introduction to allow full control of initialization state, and this means that complex use cases such as partial initialization of a buffer become overly complicated. +Unfortunately, `UnsafeMutablePointer` is the only one of the list of types listed in the introduction to allow full control of initialization state, and this means that complex use cases such as partial initialization of a buffer become needlessly difficult. An example of partial initialization is the insertion of elements in the middle of a collection. This is 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`: @@ -156,11 +156,11 @@ extension UnsafeMutableBufferPointer { -We would like to use the verb `update` instead of `assign`, in order to better communicate the intent of the API. It is currently a common programmer error to use one of the existing `assign` functions for uninitialized memory; using the verb `update` instead would express the precondition in the API itself. +We would like to use the verb `update` instead of `assign`, in order to better communicate the intent of the API. It is currently a common programmer error to use one of the existing `assign` functions for uninitialized memory; using the verb `update` instead would express the precondition in the API name itself. The methods that initialize or update from a `Collection` will have forgiving semantics, and copy the number of elements that they can, be that every available element or none, and then return the index in the buffer that follows the last element copied, which is cheaper than returning an iterator and a count. Unlike the existing `Sequence` functions, they include no preconditions beyond having a valid `Collection` and valid buffer, with the understanding that if a user needs stricter behaviour, it can be composed from these functions. -The above changes include a method to update a single element. Evidently that is a synonym for the `subscript(_ i: Index)` setter. We hope that documenting the update action specifically will help clarify the requirements of that action, namely that the buffer element must already be initialized. Experience shows that the initialization requirement of the subscript setter is frequently missed by users in the current situation, where it is only documented along with the subscript getter. +The above changes include a method to update a single element. Evidently that is a synonym for the `subscript(_ i: Index)` setter. We hope that documenting the update action specifically will help clarify the requirements of that action, namely that the buffer element must already be initialized. Experience shows that the initialization requirement of the subscript setter is frequently not noticed by users in the current situation, where it is only documented along with the subscript getter. ##### `UnsafeMutablePointer` @@ -1604,9 +1604,9 @@ The proposal includes the renaming of four existing functions from `assign` to ` ## Effect on ABI stability -The functions proposed here are generally small wrappers around existing functionality. We expect to implement them as `@_alwaysEmitIntoClient` functions, which means they would have no ABI impact. +The functions proposed here are generally small wrappers around existing functionality. They are implemented as `@_alwaysEmitIntoClient` functions, which means they have no ABI impact. -The renamed functions can reuse the existing symbol, while the deprecated functions can forward using an `@_alwaysEmitIntoClient` stub to support the functionality under its previous name. This means they would have no ABI impact. +The renamed functions can reuse the existing symbol, while the deprecated functions can forward using an `@_alwaysEmitIntoClient` stub to support the functionality under its previous name. The renamings would therefore have no ABI impact. ## Effect on API resilience @@ -1620,18 +1620,18 @@ All functionality implemented as `@_alwaysEmitIntoClient` will back-deploy. Rena The single-element update functions, `UnsafeMutablePointer.update(to:)` and `UnsafeMutableBufferPointer.updateElement(at:to:)`, are synonyms for the setters of `UnsafeMutablePointer.pointee` and `UnsafeMutableBufferPointer.subscript(_ i: Index)`, respectively. Clearly we can elect to not add them. -The setters in question, like the update functions, have a required precondition that the memory they refer to must be initialized. Somehow this precondition is often overlooked and leads to bug reports. The proposed names and cross-references should help clarify the requirements to users. +The setters in question, like the update functions, have a required precondition that the memory they refer to must be initialized. This precondition is often overlooked and leads to programmer errors and bug reports. The proposed names and cross-references should help clarify the requirements to users. ##### Renaming `assign` to `update` -The renaming of `assign` to `update` could be omitted entirely, although we believe that `update` communicates intent much better than `assign` does. In _The Swift Programming Language_, the `=` symbol is named "the assignment operator", and its function is described as to either initialize or to update a value. The current name (`assign`) is not as clear as the documentation in *TSPL*, while the proposed name (`update`) builds on it. +The renaming of `assign` to `update` could be omitted entirely, although we believe the word "update" communicates the API's intent much better than does the word "assign". In _The Swift Programming Language_ (_TSPL_,) the `=` symbol is named "the assignment operator", and its function is described as to either "initialize" or "update" a value. The current name (`assign`) seemingly conflates the two roles of `=` as described in *TSPL*, while the proposed name (`update`) builds on _TSPL_. There are only four current symbols to be renamed by this proposal, and their replacements are easily migrated by a fixit. For context, this renaming would change only 6 lines of code in the standard library, outside of the function definitions. If the renaming is omitted, the four new functions proposed in the family should use the name `assign` as well. The two single-element versions would be `assign(_ value:)` and `assignElement(at:_ value:)`. ##### Element-by-element copies from `Collection` inputs -The initialization and updating functions that copy from `Collection` inputs use the argument label `fromElements`. This is different from the pre-existing functions that copy from `Sequence` inputs. We could use the same argument label (`from`) as with the `Sequence` inputs, but that would mean that we must return the `Iterator` for the `Collection` versions, and that is generally not desirable, especially if a particular `Iterator` cannot be copied cheaply. If we did not return `Iterator`, then the `Sequence` and `Collection` versions of the `initialize(from:)` would be overloaded by their return type, and that would be source-breaking: -an existing use of the current function that doesn't destructure the returned tuple on assignment could now pick up the `Collection` overload, which would have a return value incompatible with the existing code which assumes that the return value is of type `(Iterator, Int)`. +The initialization and updating functions that copy from `Collection` inputs use the argument label `fromElements`. This is a different label than used by the pre-existing functions that copy from `Sequence` inputs. We could use the same argument label (`from`) as with the `Sequence` inputs, but that would mean that we must return the `Iterator` for the `Collection` versions, and that is not necessarily desirable, especially if a particular `Iterator` cannot be copied cheaply. If we used the same argument label (`from`) and did not return `Iterator`, then the `Sequence` and `Collection` versions of the `initialize(from:)` would be overloaded by their return type, and that would be source-breaking: +an existing use of the current function that doesn't destructure the returned tuple on assignment could now pick up the `Collection` overload, which would have a return value incompatible with the subsequent code which assumes that the return value is of type `(Iterator, Int)`. ## Acknowledgments From 163e488b350edb2c8d4a00db22258ae630f21581 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Wed, 10 Aug 2022 15:55:15 -0600 Subject: [PATCH 11/18] add missing links, change to inline links --- .../NNNN-pointer-family-initialization-improvements.md | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/proposals/NNNN-pointer-family-initialization-improvements.md b/proposals/NNNN-pointer-family-initialization-improvements.md index 732ec6f61a..9eb28acea5 100644 --- a/proposals/NNNN-pointer-family-initialization-improvements.md +++ b/proposals/NNNN-pointer-family-initialization-improvements.md @@ -1,17 +1,13 @@ # Pointer Family Initialization Improvements & Better Buffer Slices -* Proposal: [SE-NNNN Pointer Family Initialization Improvements & Better Buffer Slices][proposal] +* Proposal: [SE-NNNN Pointer Family Initialization Improvements & Better Buffer Slices](https://github.com/apple/swift-evolution/blob/pointer-family-initialization/proposals/NNNN-pointer-family-initialization-improvements.md) * Author: [Guillaume Lessard](https://github.com/glessard) * Review Manager: TBD * Status: pending -* Implementation: [Draft Pull Request][draft-pr] +* Implementation: [Draft Pull Request](https://github.com/apple/swift/pull/41608) * Bugs: [rdar://51817146](rdar://51817146) * Previous Revision: [pitch A](https://gist.github.com/glessard/3bb47dce974aa483fd6df072d265005c ), [pitch B](https://gist.github.com/glessard/cefa5686696b0e30ac18eb4899213c65) -[proposal]: https://github.com/apple/swift-evolution/blob/pointer-family-initialization/proposals/NNNN-pointer-family-initialization-improvements.md -[draft-pr]: https://github.com/apple/swift/pull/41608 -[pitch-thread]: https://forums.swift.org/t/55689 - ## Introduction @@ -25,7 +21,7 @@ Memory can be safely deallocated whenever it is uninitialized. We intend to round out initialization functionality for every relevant member of that family: `UnsafeMutablePointer`, `UnsafeMutableRawPointer`, `UnsafeMutableBufferPointer`, `UnsafeMutableRawBufferPointer`, `Slice` and `Slice`. The functionality will allow managing initialization state in a much greater variety of situations, including easier handling of partially-initialized buffers. -Swift-evolution thread: [Pitch thread][pitch-thread] +Swift-evolution thread: [Pitch thread](https://forums.swift.org/t/55689), previous pitch threads [A](https://forums.swift.org/t/53168), [B](https://forums.swift.org/t/53795) ## Motivation From 677536cf02114f7a1f8dc23dc54d7f9c1c0fb3ff Mon Sep 17 00:00:00 2001 From: John McCall Date: Thu, 11 Aug 2022 22:55:57 -0400 Subject: [PATCH 12/18] Assign myself as the review manager --- ...N-pointer-family-initialization-improvements.md | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/proposals/NNNN-pointer-family-initialization-improvements.md b/proposals/NNNN-pointer-family-initialization-improvements.md index 9eb28acea5..fd713cec99 100644 --- a/proposals/NNNN-pointer-family-initialization-improvements.md +++ b/proposals/NNNN-pointer-family-initialization-improvements.md @@ -1,13 +1,11 @@ -# Pointer Family Initialization Improvements & Better Buffer Slices +# Pointer Family Initialization Improvements and Better Buffer Slices -* Proposal: [SE-NNNN Pointer Family Initialization Improvements & Better Buffer Slices](https://github.com/apple/swift-evolution/blob/pointer-family-initialization/proposals/NNNN-pointer-family-initialization-improvements.md) +* Proposal: [SE-NNNN](https://github.com/apple/swift-evolution/blob/pointer-family-initialization/proposals/NNNN-pointer-family-initialization-improvements.md) * Author: [Guillaume Lessard](https://github.com/glessard) -* Review Manager: TBD -* Status: pending +* Review Manager: [John McCall](https://github.com/rjmccall) +* Status: **Awaiting Review** * Implementation: [Draft Pull Request](https://github.com/apple/swift/pull/41608) -* Bugs: [rdar://51817146](rdar://51817146) -* Previous Revision: [pitch A](https://gist.github.com/glessard/3bb47dce974aa483fd6df072d265005c ), [pitch B](https://gist.github.com/glessard/cefa5686696b0e30ac18eb4899213c65) - +* Review: ([first pitch](https://forums.swift.org/t/pitch-pointer-family-initialization-improvements/53168)) ([second pitch](https://forums.swift.org/t/pitch-buffer-partial-initialization-better-buffer-slices/53795)) ([third pitch](https://forums.swift.org/t/pitch-pointer-family-initialization-improvements-better-buffer-slices/55689)) ## Introduction @@ -1633,4 +1631,4 @@ an existing use of the current function that doesn't destructure the returned tu [Kelvin Ma](https://github.com/kelvin13) (aka [Taylor Swift](https://forums.swift.org/u/taylorswift/summary))'s initial versions of the pitch that became SE-0184 included more functions to manipulate initialization state. These were deferred, but much of the deferred functionality has not been pitched again until now. -Members of the Swift Standard Library team for valuable discussions. \ No newline at end of file +Members of the Swift Standard Library team for valuable discussions. From 3f39a2c3581d5ed07a9d3facea1101bd18aeea17 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Fri, 12 Aug 2022 18:58:00 -0600 Subject: [PATCH 13/18] fix inconsistency with load/store functions on slices --- ...NNN-pointer-family-initialization-improvements.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/proposals/NNNN-pointer-family-initialization-improvements.md b/proposals/NNNN-pointer-family-initialization-improvements.md index fd713cec99..853ec3e21e 100644 --- a/proposals/NNNN-pointer-family-initialization-improvements.md +++ b/proposals/NNNN-pointer-family-initialization-improvements.md @@ -284,7 +284,7 @@ extension Slice> { } ``` -Slices of `Unsafe[Mutable]RawBufferPointer` will add memory binding functions, memory initialization functions, and variants of `load`, `loadUnaligned` and `storeBytes` that always load from the beginning of the slice. +Slices of `Unsafe[Mutable]RawBufferPointer` will add memory binding functions, memory initialization functions, and variants of `load`, `loadUnaligned` and `storeBytes`. ```swift extension Slice { func bindMemory(to type: T.Type) -> UnsafeBufferPointer @@ -294,8 +294,8 @@ extension Slice { to type: T.Type, _ body: (UnsafeBufferPointer) throws -> Result ) rethrows -> Result - func load(as type: T.Type) -> T - func loadUnaligned(as type: T.Type) -> T + func load(fromByteOffset offset: Int = 0, as type: T.Type) -> T + func loadUnaligned(fromByteOffset offset: Int = 0, as type: T.Type) -> T } ``` @@ -332,9 +332,9 @@ extension Slice { _ body: (UnsafeMutableBufferPointer) throws -> Result ) rethrows -> Result - func load(as type: T.Type) -> T - func loadUnaligned(as type: T.Type) -> T - func storeBytes(of value: T, as type: T.Type) + func load(fromByteOffset offset: Int = 0, as type: T.Type) -> T + func loadUnaligned(fromByteOffset offset: Int = 0, as type: T.Type) -> T + func storeBytes(of value: T, toByteOffset offset: Int = 0, as type: T.Type) } ``` From 25fd3610be4aaf1766cc2c36b54ccc621d133bab Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Fri, 12 Aug 2022 18:59:07 -0600 Subject: [PATCH 14/18] fix wording and markup --- .../NNNN-pointer-family-initialization-improvements.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/proposals/NNNN-pointer-family-initialization-improvements.md b/proposals/NNNN-pointer-family-initialization-improvements.md index 853ec3e21e..e87f4f0cda 100644 --- a/proposals/NNNN-pointer-family-initialization-improvements.md +++ b/proposals/NNNN-pointer-family-initialization-improvements.md @@ -19,7 +19,7 @@ Memory can be safely deallocated whenever it is uninitialized. We intend to round out initialization functionality for every relevant member of that family: `UnsafeMutablePointer`, `UnsafeMutableRawPointer`, `UnsafeMutableBufferPointer`, `UnsafeMutableRawBufferPointer`, `Slice` and `Slice`. The functionality will allow managing initialization state in a much greater variety of situations, including easier handling of partially-initialized buffers. -Swift-evolution thread: [Pitch thread](https://forums.swift.org/t/55689), previous pitch threads [A](https://forums.swift.org/t/53168), [B](https://forums.swift.org/t/53795) +Swift-evolution thread: [Pitch thread](https://forums.swift.org/t/55689), previous pitch threads [A](https://forums.swift.org/t/53168), [B](https://forums.swift.org/t/53795) ## Motivation @@ -210,7 +210,7 @@ extension UnsafeMutableRawBufferPointer { The first addition will initialize raw memory from a `Collection` and have similar behaviour as `UnsafeMutableBufferPointer.initialize(fromElements:)`, described above. The other two initialize raw memory by moving data from another range of memory, leaving that other range of memory deinitialized. -##### UnsafeMutableRawPointer +##### `UnsafeMutableRawPointer` ```swift extension UnsafeMutableRawPointer { @@ -234,7 +234,7 @@ The addition here initializes a single value. ##### Slices of BufferPointer -We propose to add to slices of `Unsafe[Mutable][Raw]BufferPointer` all the `BufferPointer`-specific methods of their `Base`. The following declarations detail the additions, which are all intended to behave exactly as the functions on the base BufferPointer types: +We propose to extend slices of `Unsafe[Mutable][Raw]BufferPointer` with all the `BufferPointer`-specific methods of their `Base`. The following declarations detail the additions, which are all intended to behave exactly as the functions on the base BufferPointer types: ```swift extension Slice> { From 858a9dbca689ca89b9f1aaddab7015906e49acc9 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Fri, 12 Aug 2022 19:24:01 -0600 Subject: [PATCH 15/18] remove single-element update functions --- .../NNNN-pointer-family-initialization-improvements.md | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/proposals/NNNN-pointer-family-initialization-improvements.md b/proposals/NNNN-pointer-family-initialization-improvements.md index e87f4f0cda..026106fe77 100644 --- a/proposals/NNNN-pointer-family-initialization-improvements.md +++ b/proposals/NNNN-pointer-family-initialization-improvements.md @@ -142,7 +142,6 @@ extension UnsafeMutableBufferPointer { +++ func deinitialize() -> UnsafeMutableRawBufferPointer +++ func initializeElement(at index: Index, to value: Element) -+++ func updateElement(at index: Index, to value: Element) +++ func moveElement(from index: Index) -> Element +++ func deinitializeElement(at index: Index) } @@ -154,7 +153,7 @@ We would like to use the verb `update` instead of `assign`, in order to better c The methods that initialize or update from a `Collection` will have forgiving semantics, and copy the number of elements that they can, be that every available element or none, and then return the index in the buffer that follows the last element copied, which is cheaper than returning an iterator and a count. Unlike the existing `Sequence` functions, they include no preconditions beyond having a valid `Collection` and valid buffer, with the understanding that if a user needs stricter behaviour, it can be composed from these functions. -The above changes include a method to update a single element. Evidently that is a synonym for the `subscript(_ i: Index)` setter. We hope that documenting the update action specifically will help clarify the requirements of that action, namely that the buffer element must already be initialized. Experience shows that the initialization requirement of the subscript setter is frequently not noticed by users in the current situation, where it is only documented along with the subscript getter. +We also add functions to manipulate the initialization state for single elements of the buffer. There is no `buffer.updateElement(at index: Index, to value: Element)`, because it can already be expressed as `buffer[index] = value`. ##### `UnsafeMutablePointer` @@ -165,7 +164,6 @@ extension UnsafeMutablePointer { func initialize(to value: Pointee) func initialize(repeating repeatedValue: Pointee, count: Int) func initialize(from source: UnsafePointer, count: Int) -+++ func update(to value: Pointee) --- func assign(repeating repeatedValue: Pointee, count: Int) +++ func update(repeating repeatedValue: Pointee, count: Int) --- func assign(from source: UnsafePointer, count: Int) @@ -273,7 +271,6 @@ extension Slice> { 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) @@ -1612,9 +1609,7 @@ All functionality implemented as `@_alwaysEmitIntoClient` will back-deploy. Rena ##### Single element update functions -The single-element update functions, `UnsafeMutablePointer.update(to:)` and `UnsafeMutableBufferPointer.updateElement(at:to:)`, are synonyms for the setters of `UnsafeMutablePointer.pointee` and `UnsafeMutableBufferPointer.subscript(_ i: Index)`, respectively. Clearly we can elect to not add them. - -The setters in question, like the update functions, have a required precondition that the memory they refer to must be initialized. This precondition is often overlooked and leads to programmer errors and bug reports. The proposed names and cross-references should help clarify the requirements to users. +An earlier version of this proposal included single-element update functions, `UnsafeMutablePointer.update(to:)` and `UnsafeMutableBufferPointer.updateElement(at:to:)`. These are synonyms for the setters of `UnsafeMutablePointer.pointee` and `UnsafeMutableBufferPointer.subscript(_ i: Index)`, respectively. They were intended to improve the documentation for that operation, in particular the often overlooked initialization requirement. ##### Renaming `assign` to `update` From c8a0d7d42019a95c8c88ca8d14a302a41245372f Mon Sep 17 00:00:00 2001 From: John McCall Date: Mon, 15 Aug 2022 18:49:01 -0400 Subject: [PATCH 16/18] Update NNNN-pointer-family-initialization-improvements.md Remove pitch links from the main body, since they're in the `Review` header field. --- proposals/NNNN-pointer-family-initialization-improvements.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/proposals/NNNN-pointer-family-initialization-improvements.md b/proposals/NNNN-pointer-family-initialization-improvements.md index 026106fe77..d3dcf4dcd6 100644 --- a/proposals/NNNN-pointer-family-initialization-improvements.md +++ b/proposals/NNNN-pointer-family-initialization-improvements.md @@ -19,8 +19,6 @@ Memory can be safely deallocated whenever it is uninitialized. We intend to round out initialization functionality for every relevant member of that family: `UnsafeMutablePointer`, `UnsafeMutableRawPointer`, `UnsafeMutableBufferPointer`, `UnsafeMutableRawBufferPointer`, `Slice` and `Slice`. The functionality will allow managing initialization state in a much greater variety of situations, including easier handling of partially-initialized buffers. -Swift-evolution thread: [Pitch thread](https://forums.swift.org/t/55689), previous pitch threads [A](https://forums.swift.org/t/53168), [B](https://forums.swift.org/t/53795) - ## Motivation Memory allocated using `UnsafeMutablePointer`, `UnsafeMutableRawPointer`, `UnsafeMutableBufferPointer` and `UnsafeMutableRawBufferPointer` is passed to the user in an uninitialized state. In the general case, such memory needs to be initialized before it is used in Swift. Memory can be "initialized" or "uninitialized". We hereafter refer to this as a memory region's "initialization state". From edc9754b032f913e45ee5721483d78ede4fec2e4 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Tue, 16 Aug 2022 11:10:00 -0600 Subject: [PATCH 17/18] remove another single-element update function --- ...NN-pointer-family-initialization-improvements.md | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/proposals/NNNN-pointer-family-initialization-improvements.md b/proposals/NNNN-pointer-family-initialization-improvements.md index d3dcf4dcd6..54c2670435 100644 --- a/proposals/NNNN-pointer-family-initialization-improvements.md +++ b/proposals/NNNN-pointer-family-initialization-improvements.md @@ -525,19 +525,6 @@ extension UnsafeMutableBufferPointer { ```swift extension UnsafeMutablePointer { - /// Update this pointer's initialized memory. - /// - /// The range of memory starting at this pointer and covering one instance - /// of `Pointee` must be initialized, or `Pointee` must be a trivial type. - /// This method is equivalent to: - /// - /// self.pointee = value - /// - /// - Parameters: - /// - value: The value used to update this pointer's memory. - public func update(_ value: Pointee) -} - /// Update this pointer's initialized memory with the specified number of /// instances, copied from the given pointer's memory. /// From c3ddea79e2804825ff44fca3a4181fa18ae7c273 Mon Sep 17 00:00:00 2001 From: John McCall Date: Wed, 17 Aug 2022 17:04:39 -0400 Subject: [PATCH 18/18] Assign SE-0370 to the pointer API improvements proposal and put it in review --- ....md => 0370-pointer-family-initialization-improvements.md} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename proposals/{NNNN-pointer-family-initialization-improvements.md => 0370-pointer-family-initialization-improvements.md} (99%) diff --git a/proposals/NNNN-pointer-family-initialization-improvements.md b/proposals/0370-pointer-family-initialization-improvements.md similarity index 99% rename from proposals/NNNN-pointer-family-initialization-improvements.md rename to proposals/0370-pointer-family-initialization-improvements.md index 54c2670435..dd58d178ce 100644 --- a/proposals/NNNN-pointer-family-initialization-improvements.md +++ b/proposals/0370-pointer-family-initialization-improvements.md @@ -1,9 +1,9 @@ # Pointer Family Initialization Improvements and Better Buffer Slices -* Proposal: [SE-NNNN](https://github.com/apple/swift-evolution/blob/pointer-family-initialization/proposals/NNNN-pointer-family-initialization-improvements.md) +* Proposal: [SE-0370](0370-pointer-family-initialization-improvements.md) * Author: [Guillaume Lessard](https://github.com/glessard) * Review Manager: [John McCall](https://github.com/rjmccall) -* Status: **Awaiting Review** +* Status: **Active Review (August 17...29th, 2022)** * Implementation: [Draft Pull Request](https://github.com/apple/swift/pull/41608) * Review: ([first pitch](https://forums.swift.org/t/pitch-pointer-family-initialization-improvements/53168)) ([second pitch](https://forums.swift.org/t/pitch-buffer-partial-initialization-better-buffer-slices/53795)) ([third pitch](https://forums.swift.org/t/pitch-pointer-family-initialization-improvements-better-buffer-slices/55689))