From 304a422c3e0c2d1e40f975a83593733adcc51390 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Mon, 18 Oct 2021 21:27:07 -0600 Subject: [PATCH 01/45] [stdlib] add single-element assign to UnsafeMutablePointer --- stdlib/public/core/UnsafePointer.swift | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/stdlib/public/core/UnsafePointer.swift b/stdlib/public/core/UnsafePointer.swift index 86b7e405c6fd2..212230c05c557 100644 --- a/stdlib/public/core/UnsafePointer.swift +++ b/stdlib/public/core/UnsafePointer.swift @@ -786,6 +786,20 @@ public struct UnsafeMutablePointer: _Pointer { } } + /// 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 assign(_ value: Pointee) { + pointee = value + } + /// Replaces this pointer's initialized memory with the specified number of /// instances from the given pointer's memory. /// From a7326d035302f8e66d2d6340a3bdaf69dc31e388 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Thu, 11 Nov 2021 16:58:25 -0700 Subject: [PATCH 02/45] [gardening] improve doc-comments in UnsafeMutablePointer --- stdlib/public/core/UnsafePointer.swift | 39 +++++++++++++++----------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/stdlib/public/core/UnsafePointer.swift b/stdlib/public/core/UnsafePointer.swift index 212230c05c557..40883a626c90f 100644 --- a/stdlib/public/core/UnsafePointer.swift +++ b/stdlib/public/core/UnsafePointer.swift @@ -687,14 +687,14 @@ public struct UnsafeMutablePointer: _Pointer { Builtin.deallocRaw(_rawValue, (-1)._builtinWordValue, (0)._builtinWordValue) } - /// Accesses the instance referenced by this pointer. + /// Reads or updates the instance referenced by this pointer. /// /// When reading from the `pointee` property, the instance referenced by this /// pointer must already be initialized. When `pointee` is used as the left - /// side of an assignment, the instance must be initialized or this - /// pointer's `Pointee` type must be a trivial type. + /// side of an assignment, the instance is updated. The instance must + /// be initialized or this pointer's `Pointee` type must be a trivial type. /// - /// Do not assign an instance of a nontrivial type through `pointee` to + /// Do not update an instance of a nontrivial type through `pointee` to /// uninitialized memory. Instead, use an initializing method, such as /// `initialize(repeating:count:)`. @inlinable // unsafe-performance @@ -766,7 +766,7 @@ public struct UnsafeMutablePointer: _Pointer { return Builtin.take(_rawValue) } - /// Replaces this pointer's memory with the specified number of + /// Update this pointer's initialized memory with the specified number of /// consecutive copies of the given value. /// /// The region of memory starting at this pointer and covering `count` @@ -775,9 +775,9 @@ public struct UnsafeMutablePointer: _Pointer { /// `assign(repeating:count:)`, the region is initialized. /// /// - Parameters: - /// - repeatedValue: The instance to assign this pointer's memory to. - /// - count: The number of consecutive copies of `newValue` to assign. - /// `count` must not be negative. + /// - repeatedValue: The value used when updating this pointer's memory. + /// - count: The number of consecutive elements to update. + /// `count` must not be negative. @inlinable public func assign(repeating repeatedValue: Pointee, count: Int) { _debugPrecondition(count >= 0, "UnsafeMutablePointer.assign(repeating:count:) with negative count") @@ -800,8 +800,8 @@ public struct UnsafeMutablePointer: _Pointer { pointee = value } - /// Replaces this pointer's initialized memory with the specified number of - /// instances from the given pointer's memory. + /// 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 @@ -894,6 +894,8 @@ public struct UnsafeMutablePointer: _Pointer { /// `Pointee` must be a trivial type. After calling /// `initialize(from:count:)`, the region is initialized. /// + /// - Note: The source and destination memory regions must not overlap. + /// /// - Parameters: /// - source: A pointer to the values to copy. The memory region /// `source..<(source + count)` must be initialized. The memory regions @@ -916,8 +918,9 @@ public struct UnsafeMutablePointer: _Pointer { // } } - /// Replaces the memory referenced by this pointer with the values - /// starting at the given pointer, leaving the source memory uninitialized. + /// 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 @@ -925,8 +928,10 @@ public struct UnsafeMutablePointer: _Pointer { /// `moveAssign(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 copy. The memory region + /// - 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 @@ -1069,14 +1074,14 @@ public struct UnsafeMutablePointer: _Pointer { return try body(.init(_rawValue)) } - /// Accesses the pointee at the specified offset from this pointer. + /// Reads or updates the pointee at the specified offset from this pointer. /// /// For a pointer `p`, the memory at `p + i` must be initialized when reading /// the value by using the subscript. When the subscript is used as the left - /// side of an assignment, the memory at `p + i` must be initialized or - /// the pointer's `Pointee` type must be a trivial type. + /// side of an assignment, the memory at `p + i` is updated. The memory must + /// be initialized or the pointer's `Pointee` type must be a trivial type. /// - /// Do not assign an instance of a nontrivial type through the subscript to + /// Do not update an instance of a nontrivial type through the subscript to /// uninitialized memory. Instead, use an initializing method, such as /// `initialize(repeating:count:)`. /// From 99d957fa1e202c928956822bf3cf1ace3ad817f3 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Tue, 19 Oct 2021 18:32:27 -0600 Subject: [PATCH 03/45] [gardening] improve summary line --- stdlib/public/core/UnsafeBufferPointer.swift.gyb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stdlib/public/core/UnsafeBufferPointer.swift.gyb b/stdlib/public/core/UnsafeBufferPointer.swift.gyb index 966508c07a96d..6a4ac3aade16a 100644 --- a/stdlib/public/core/UnsafeBufferPointer.swift.gyb +++ b/stdlib/public/core/UnsafeBufferPointer.swift.gyb @@ -648,8 +648,8 @@ extension Unsafe${Mutable}BufferPointer { dstBase.initialize(repeating: repeatedValue, count: count) } - - /// Assigns every element in this buffer's memory to a copy of the given value. + + /// Copies the given value to every element in this buffer's memory. /// /// The buffer’s memory must be initialized or the buffer's `Element` /// must be a trivial type. From 94d53871af2d48a997c6ac8cbd460a0e71740014 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Tue, 19 Oct 2021 18:41:05 -0600 Subject: [PATCH 04/45] [gardening] remove outdated recommendation --- stdlib/public/core/UnsafeBufferPointer.swift.gyb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/stdlib/public/core/UnsafeBufferPointer.swift.gyb b/stdlib/public/core/UnsafeBufferPointer.swift.gyb index 6a4ac3aade16a..93cae9e73d3fe 100644 --- a/stdlib/public/core/UnsafeBufferPointer.swift.gyb +++ b/stdlib/public/core/UnsafeBufferPointer.swift.gyb @@ -657,9 +657,7 @@ extension Unsafe${Mutable}BufferPointer { /// - Parameters: /// - repeatedValue: The instance to assign this buffer's memory to. /// - /// Warning: All buffer elements must be initialized before calling this. - /// Assigning to part of the buffer must be done using the `assign(repeating:count:)` - /// method on the buffer’s `baseAddress`. + /// Warning: All buffer elements must be initialized before calling this. @inlinable // unsafe-performance public func assign(repeating repeatedValue: Element) { guard let dstBase = _position else { From cff3012b372cf258052a95d727d87d4f03a47771 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Tue, 1 Mar 2022 10:36:20 -0700 Subject: [PATCH 05/45] [stdlib] additions to UMBP - add initialization from a Collection - assign to a UMBP from a Sequence or a Collection - add `moveInitialize` and `moveAssign` to UMBP - deinitialize UMBP - add single-element memory state functions in a buffer --- .../public/core/UnsafeBufferPointer.swift.gyb | 330 ++++++++++++++++-- 1 file changed, 295 insertions(+), 35 deletions(-) diff --git a/stdlib/public/core/UnsafeBufferPointer.swift.gyb b/stdlib/public/core/UnsafeBufferPointer.swift.gyb index 93cae9e73d3fe..8b2f8a2ac4d98 100644 --- a/stdlib/public/core/UnsafeBufferPointer.swift.gyb +++ b/stdlib/public/core/UnsafeBufferPointer.swift.gyb @@ -649,15 +649,83 @@ extension Unsafe${Mutable}BufferPointer { dstBase.initialize(repeating: repeatedValue, count: count) } - /// Copies the given value to every element in this buffer's memory. + /// Initializes the buffer's memory with the given elements. + /// + /// Prior to calling the `initialize(from:)` method on a buffer, + /// the memory it references must be uninitialized, + /// or its `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 buffer must contain sufficient memory to accommodate + /// `source.underestimatedCount`. /// - /// The buffer’s memory must be initialized or the buffer's `Element` - /// must be a trivial type. + /// The returned index is the position of the next uninitialized element + /// in the buffer, 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 can hold, the returned index is equal to + /// the buffer's `endIndex`. /// - /// - Parameters: - /// - repeatedValue: The instance to assign this buffer's memory to. + /// - 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. + @inlinable // unsafe-performance + public func initialize(from source: S) -> (S.Iterator, Index) + where S.Element == Element { + return source._copyContents(initializing: self) + } + + /// Initializes the buffer's memory with the given elements. + /// + /// Prior to calling the `initialize(fromElements:)` method on a buffer, + /// the memory it references must be uninitialized, + /// or its `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`. + @discardableResult + public func initialize( + fromElements source: C + ) -> Index where C.Element == Element { + let count = Swift.min(self.count, source.count) + guard count > 0, let base = baseAddress else { return startIndex } + + if let _ = source.withContiguousStorageIfAvailable({ + base.initialize( + from: $0.baseAddress._unsafelyUnwrappedUnchecked, + count: count + ) + }) { + return startIndex.advanced(by: count) + } + + for (p, e) in zip(base..( + from source: S + ) -> (unwritten: S.Iterator, assigned: Index) where S.Element == Element { + var iterator = source.makeIterator() + guard var pointer = baseAddress else { return (iterator, startIndex) } + for index in indices { + guard let element = iterator.next() else { + return (iterator, index) + } + pointer.pointee = element + pointer += 1 + } + return (iterator, endIndex) + } + + /// Updates the buffer's initialized memory with the given elements. + /// + /// The buffer’s memory must be initialized or its `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`. + @discardableResult + public func assign( + fromElements source: C + ) -> Index where C.Element == Element { + let count = Swift.min(source.count, self.count) + guard count > 0, let base = baseAddress else { return startIndex } + + if let _ = source.withContiguousStorageIfAvailable({ + base.assign(from: $0.baseAddress._unsafelyUnwrappedUnchecked, + count: count) + }) { + return startIndex.advanced(by: count) + } + + for (p, e) in zip(base.. Index { + guard let pointer = source.baseAddress, source.count > 0 else { return 0 } + _debugPrecondition(count >= source.count) + baseAddress._unsafelyUnwrappedUnchecked.moveInitialize(from: pointer, + count: source.count) + return startIndex.advanced(by: source.count) + } + + /// Moves every element of 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 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 one past the last replaced element in the buffer, + /// or `endIndex`. + @discardableResult + public func moveInitialize(fromElements source: Slice) -> Index { + return moveInitialize(fromElements: Self(rebasing: source)) + } + + /// Updates this buffer'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 and + /// covering `fromElements.count` instances of its `Element` type must be + /// initialized, or `Element` must be a trivial type. + /// After calling `moveAssign(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`. + @discardableResult + public func moveAssign(from source: Self) -> Index { + guard let pointer = source.baseAddress, source.count > 0 else { return 0 } + _debugPrecondition(count >= source.count) + baseAddress._unsafelyUnwrappedUnchecked.moveAssign(from: pointer, + count: source.count) + return startIndex.advanced(by: source.count) + } + + /// Updates this buffer'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 and + /// covering `fromElements.count` instances of its `Element` type must be + /// initialized, or `Element` must be a trivial type. + /// After calling `moveAssign(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`. + @discardableResult + public func moveAssign(from source: Slice) -> Index { + return moveAssign(from: Self(rebasing: source)) + } + + /// 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`. + @discardableResult + public func deinitialize() -> UnsafeMutableRawBufferPointer { + guard let rawValue = baseAddress?._rawValue + else { return .init(start: nil, count: 0) } + Builtin.destroyArray(Element.self, rawValue, count._builtinWordValue) + return .init(start: UnsafeMutableRawPointer(rawValue), + count: count*MemoryLayout.stride) + } + + /// 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 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) { + precondition(startIndex <= index && index < endIndex) + let p = baseAddress._unsafelyUnwrappedUnchecked.advanced(by: index) + p.initialize(to: value) + } + + /// 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 assignElement(at index: Index, _ value: Element) { + precondition(startIndex <= index && index < endIndex) + let p = baseAddress._unsafelyUnwrappedUnchecked.advanced(by: index) + p.pointee = value + } + + /// 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 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 { + precondition(startIndex <= index && index < endIndex) + return baseAddress._unsafelyUnwrappedUnchecked.advanced(by: index).move() + } + + /// 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 is uninitialized, and still bound to type `Element`. + /// + /// - Parameters: + /// - index: The index of the buffer element to deinitialize. + public func deinitializeElement(at index: Index) { + precondition(startIndex <= index && index < endIndex) + let p = baseAddress._unsafelyUnwrappedUnchecked.advanced(by: index) + p.deinitialize(count: 1) + } + % end /// Executes the given closure while temporarily binding the memory referenced @@ -800,34 +1088,6 @@ extension Unsafe${Mutable}BufferPointer: CustomDebugStringConvertible { %end -extension UnsafeMutableBufferPointer { - /// Initializes the buffer's memory with the given elements. - /// - /// When calling the `initialize(from:)` method on a buffer `b`, the memory - /// referenced by `b` must be uninitialized or the `Element` type must be a - /// trivial type. After the call, the memory referenced by this buffer 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 element in the buffer 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 can hold, the - /// returned index is equal to the buffer's `endIndex`. - /// - /// - Parameter source: A sequence of elements with which to initializer the - /// buffer. - /// - Returns: An iterator to any elements of `source` that didn't fit in the - /// buffer, and an index to the point in the buffer one past the last - /// element written. - @inlinable // unsafe-performance - public func initialize(from source: S) -> (S.Iterator, Index) - where S.Element == Element { - return source._copyContents(initializing: self) - } -} - // ${'Local Variables'}: // eval: (read-only-mode 1) // End: From bef793dd4558689e3c5b53e7eef4ec89997eb1fe Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Fri, 22 Oct 2021 17:19:42 -0600 Subject: [PATCH 06/45] [stdlib] add single-element version of `initializeMemory` to UMRP --- stdlib/public/core/UnsafeRawPointer.swift | 39 +++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/stdlib/public/core/UnsafeRawPointer.swift b/stdlib/public/core/UnsafeRawPointer.swift index b41895574a83a..52f5c4de2ff0c 100644 --- a/stdlib/public/core/UnsafeRawPointer.swift +++ b/stdlib/public/core/UnsafeRawPointer.swift @@ -959,6 +959,45 @@ public struct UnsafeMutableRawPointer: _Pointer { return UnsafeMutablePointer(_rawValue) } + /// 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. + @inlinable + @discardableResult + public func initializeMemory( + as type: T.Type, to value: T + ) -> UnsafeMutablePointer { + Builtin.bindMemory(_rawValue, (1)._builtinWordValue, type) + Builtin.initialize(value, _rawValue) + return UnsafeMutablePointer(_rawValue) + } + /// 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. From 2e3b5e66555ffc6de4ecfeeb5e60273654647dc4 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Tue, 1 Mar 2022 10:44:59 -0700 Subject: [PATCH 07/45] [stdlib] more memory initialization functions for UMRBP --- .../core/UnsafeRawBufferPointer.swift.gyb | 131 +++++++++++++++++- 1 file changed, 124 insertions(+), 7 deletions(-) diff --git a/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb b/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb index 1df4cff6dba8a..f606ff68f4ff8 100644 --- a/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb +++ b/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb @@ -509,8 +509,8 @@ extension Unsafe${Mutable}RawBufferPointer { /// 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 from which to copy. - /// `source.count` must be less than or equal to this buffer's `count`. + /// - Parameter source: A buffer of raw bytes. `source.count` must + /// be less than or equal to this buffer's `count`. @inlinable public func copyMemory(from source: UnsafeRawBufferPointer) { _debugPrecondition(source.count <= self.count, @@ -527,7 +527,7 @@ extension Unsafe${Mutable}RawBufferPointer { /// must be properly aligned for accessing `T`, and `source.count` must be a /// multiple of `MemoryLayout.stride`. /// - /// After calling `copyBytes(from:)`, the `source.count` bytes of memory + /// 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`. /// @@ -714,9 +714,10 @@ extension Unsafe${Mutable}RawBufferPointer { return UnsafeMutableBufferPointer(start: nil, count: 0) } - let count = (_end._unsafelyUnwrappedUnchecked - base) / MemoryLayout.stride - let typed = base.initializeMemory( - as: type, repeating: repeatedValue, count: count) + let count = (_end._unsafelyUnwrappedUnchecked-base) / MemoryLayout.stride + let typed = base.initializeMemory(as: type, + repeating: repeatedValue, + count: count) return UnsafeMutableBufferPointer(start: typed, count: count) } @@ -737,7 +738,7 @@ extension Unsafe${Mutable}RawBufferPointer { /// `S.Element`. /// /// - Parameters: - /// - type: The type of the elements to bind the buffer's memory to. + /// - 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 @@ -780,6 +781,122 @@ extension Unsafe${Mutable}RawBufferPointer { start: base.assumingMemoryBound(to: S.Element.self), count: idx / elementStride)) } + + /// 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`. + @discardableResult + public func initializeMemory( + as type: C.Element.Type, + fromElements source: C + ) -> UnsafeMutableBufferPointer { + var count = source.count + guard let base = _position, let end = _end, end > base, count > 0 else { + return UnsafeMutableBufferPointer(start: nil, count: 0) + } + count = Swift.min((end - base)/MemoryLayout.stride, count) + + if let start = source.withContiguousStorageIfAvailable({ + base.initializeMemory( + as: C.Element.self, + from: $0.baseAddress._unsafelyUnwrappedUnchecked, + count: count + ) + }) { + return UnsafeMutableBufferPointer(start: start, count: count) + } + + let start = base.bindMemory(to: C.Element.self, capacity: count) + for (pointer, element) in zip(start..( + as type: T.Type, + fromElements source: UnsafeMutableBufferPointer + ) -> UnsafeMutableBufferPointer { + guard let sourceBase = source.baseAddress + else { return UnsafeMutableBufferPointer(start: nil, count: 0) } + + let neededBytes = source.count*MemoryLayout.stride + guard let base = _position, count >= neededBytes + else { _debugPreconditionFailure("destination has too few bytes") } + + let initialized = base.moveInitializeMemory(as: T.self, + from: sourceBase, + count: source.count) + return UnsafeMutableBufferPointer(start: initialized, count: source.count) + } + + /// Moves every instance of an initialized source buffer slice into the + /// uninitialized memory referenced by this buffer, leaving the source memory + /// uninitialized and this buffer's memory initialized. + /// + /// When calling the `moveInitializeMemory(as:fromElements:)` method on + /// a buffer `b`, the memory referenced by `b` must be uninitialized, + /// or must be be initialized to a trivial type. The base address of `b` must + /// be properly aligned for accessing `C.Element`. After the method returns, + /// the memory referenced by the returned buffer 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 it contains every element copied from `source`. + @discardableResult + public func moveInitializeMemory( + as type: T.Type, + fromElements source: Slice> + ) -> UnsafeMutableBufferPointer { + let rebased = UnsafeMutableBufferPointer(rebasing: source) + return moveInitializeMemory(as: T.self, fromElements: rebased) + } + % end # mutable /// Binds this buffer’s memory to the specified type and returns a typed buffer From cc16a9f9974620b55a641173f7bc3a6bd7b727ea Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Thu, 11 Nov 2021 16:58:50 -0700 Subject: [PATCH 08/45] =?UTF-8?q?[stdlib]=20assign=20=E2=86=92=20update?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- stdlib/public/core/ArrayBufferProtocol.swift | 10 ++-- stdlib/public/core/Bitset.swift | 2 +- stdlib/public/core/HashTable.swift | 4 +- stdlib/public/core/StringGuts.swift | 2 +- .../public/core/UnsafeBufferPointer.swift.gyb | 36 ++++++++------ stdlib/public/core/UnsafePointer.swift | 48 ++++++++++++++----- 6 files changed, 68 insertions(+), 34 deletions(-) diff --git a/stdlib/public/core/ArrayBufferProtocol.swift b/stdlib/public/core/ArrayBufferProtocol.swift index ebdcbc3568e8e..aa77bf6953cee 100644 --- a/stdlib/public/core/ArrayBufferProtocol.swift +++ b/stdlib/public/core/ArrayBufferProtocol.swift @@ -166,7 +166,7 @@ extension _ArrayBufferProtocol { // so as not to self-clobber. newTailStart.moveInitialize(from: oldTailStart, count: tailCount) - // Assign over the original subrange + // Update the original subrange var i = newValues.startIndex for j in subrange { elements[j] = newValues[i] @@ -199,17 +199,17 @@ extension _ArrayBufferProtocol { let shrinkage = -growth if tailCount > shrinkage { // If the tail length exceeds the shrinkage - // Assign over the rest of the replaced range with the first + // Update the rest of the replaced range with the first // part of the tail. - newTailStart.moveAssign(from: oldTailStart, count: shrinkage) + newTailStart.moveUpdate(from: oldTailStart, count: shrinkage) // Slide the rest of the tail back oldTailStart.moveInitialize( from: oldTailStart + shrinkage, count: tailCount - shrinkage) } else { // Tail fits within erased elements - // Assign over the start of the replaced range with the tail - newTailStart.moveAssign(from: oldTailStart, count: tailCount) + // Update the start of the replaced range with the tail + newTailStart.moveUpdate(from: oldTailStart, count: tailCount) // Destroy elements remaining after the tail in subrange (newTailStart + tailCount).deinitialize( diff --git a/stdlib/public/core/Bitset.swift b/stdlib/public/core/Bitset.swift index 38ecbe7a9860d..7723a98f9e0ae 100644 --- a/stdlib/public/core/Bitset.swift +++ b/stdlib/public/core/Bitset.swift @@ -118,7 +118,7 @@ extension _UnsafeBitset { @inlinable @inline(__always) internal func clear() { - words.assign(repeating: .empty, count: wordCount) + words.update(repeating: .empty, count: wordCount) } } diff --git a/stdlib/public/core/HashTable.swift b/stdlib/public/core/HashTable.swift index 46f8dadecb565..922613e546ffa 100644 --- a/stdlib/public/core/HashTable.swift +++ b/stdlib/public/core/HashTable.swift @@ -416,7 +416,7 @@ extension _HashTable { @_effects(releasenone) internal func copyContents(of other: _HashTable) { _internalInvariant(bucketCount == other.bucketCount) - self.words.assign(from: other.words, count: wordCount) + self.words.update(from: other.words, count: wordCount) } /// Insert a new entry with the specified hash value into the table. @@ -446,7 +446,7 @@ extension _HashTable { // without a special case. words[0] = Word.allBits.subtracting(elementsBelow: bucketCount) } else { - words.assign(repeating: .empty, count: wordCount) + words.update(repeating: .empty, count: wordCount) } } diff --git a/stdlib/public/core/StringGuts.swift b/stdlib/public/core/StringGuts.swift index 8b1c6063121d8..ca8c0e7e824ab 100644 --- a/stdlib/public/core/StringGuts.swift +++ b/stdlib/public/core/StringGuts.swift @@ -432,7 +432,7 @@ public func _persistCString(_ p: UnsafePointer?) -> [CChar]? { guard let s = p else { return nil } let bytesToCopy = UTF8._nullCodeUnitOffset(in: s) + 1 // +1 for the terminating NUL let result = [CChar](unsafeUninitializedCapacity: bytesToCopy) { buf, initedCount in - buf.baseAddress!.assign(from: s, count: bytesToCopy) + buf.baseAddress!.update(from: s, count: bytesToCopy) initedCount = bytesToCopy } return result diff --git a/stdlib/public/core/UnsafeBufferPointer.swift.gyb b/stdlib/public/core/UnsafeBufferPointer.swift.gyb index 8b2f8a2ac4d98..9c0c8a5c85593 100644 --- a/stdlib/public/core/UnsafeBufferPointer.swift.gyb +++ b/stdlib/public/core/UnsafeBufferPointer.swift.gyb @@ -450,7 +450,7 @@ extension Unsafe${Mutable}BufferPointer: ${Mutable}Collection, RandomAccessColle // FIXME: swift-3-indexing-model: tests. if !newValue.isEmpty { - (_position! + bounds.lowerBound).assign( + (_position! + bounds.lowerBound).update( from: newValue.base._position! + newValue.startIndex, count: newValue.count) } @@ -727,12 +727,20 @@ extension Unsafe${Mutable}BufferPointer { /// - Parameters: /// - repeatedValue: The value used when updating this pointer's memory. @inlinable // unsafe-performance - public func assign(repeating repeatedValue: Element) { + @_silgen_name("$sSr6assign9repeatingyx_tF") + public func update(repeating repeatedValue: Element) { guard let dstBase = _position else { return } - dstBase.assign(repeating: repeatedValue, count: count) + dstBase.update(repeating: repeatedValue, count: count) + } + + @_alwaysEmitIntoClient + @available(*, deprecated, renamed: "update(repeating:)") + @_silgen_name("_deprecated_assign_repeating") + public func assign(repeating repeatedValue: Element) { + update(repeating: repeatedValue) } /// Updates the buffer's initialized memory with the given elements. @@ -744,9 +752,9 @@ extension Unsafe${Mutable}BufferPointer { /// 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 assign( + public func update( from source: S - ) -> (unwritten: S.Iterator, assigned: Index) where S.Element == Element { + ) -> (unwritten: S.Iterator, updated: Index) where S.Element == Element { var iterator = source.makeIterator() guard var pointer = baseAddress else { return (iterator, startIndex) } for index in indices { @@ -769,14 +777,14 @@ extension Unsafe${Mutable}BufferPointer { /// - Returns: An index one past the last updated element in the buffer, /// or `endIndex`. @discardableResult - public func assign( + public func update( fromElements source: C ) -> Index where C.Element == Element { let count = Swift.min(source.count, self.count) guard count > 0, let base = baseAddress else { return startIndex } if let _ = source.withContiguousStorageIfAvailable({ - base.assign(from: $0.baseAddress._unsafelyUnwrappedUnchecked, + base.update(from: $0.baseAddress._unsafelyUnwrappedUnchecked, count: count) }) { return startIndex.advanced(by: count) @@ -839,7 +847,7 @@ extension Unsafe${Mutable}BufferPointer { /// The region of memory starting at the beginning of this buffer and /// covering `fromElements.count` instances of its `Element` type must be /// initialized, or `Element` must be a trivial type. - /// After calling `moveAssign(fromElements:)`, + /// After calling `moveUpdate(fromElements:)`, /// the region of memory underlying `source` is uninitialized. /// /// - Parameter source: A buffer containing the values to move. @@ -848,10 +856,10 @@ extension Unsafe${Mutable}BufferPointer { /// - Returns: An index one past the last updated element in the buffer, /// or `endIndex`. @discardableResult - public func moveAssign(from source: Self) -> Index { + public func moveUpdate(fromElements source: Self) -> Index { guard let pointer = source.baseAddress, source.count > 0 else { return 0 } _debugPrecondition(count >= source.count) - baseAddress._unsafelyUnwrappedUnchecked.moveAssign(from: pointer, + baseAddress._unsafelyUnwrappedUnchecked.moveUpdate(from: pointer, count: source.count) return startIndex.advanced(by: source.count) } @@ -863,7 +871,7 @@ extension Unsafe${Mutable}BufferPointer { /// The region of memory starting at the beginning of this buffer and /// covering `fromElements.count` instances of its `Element` type must be /// initialized, or `Element` must be a trivial type. - /// After calling `moveAssign(fromElements:)`, + /// After calling `moveUpdate(fromElements:)`, /// the region of memory underlying `source` is uninitialized. /// /// - Parameter source: A buffer containing the values to move. @@ -872,8 +880,8 @@ extension Unsafe${Mutable}BufferPointer { /// - Returns: An index one past the last updated element in the buffer, /// or `endIndex`. @discardableResult - public func moveAssign(from source: Slice) -> Index { - return moveAssign(from: Self(rebasing: source)) + public func moveUpdate(fromElements source: Slice) -> Index { + return moveUpdate(fromElements: Self(rebasing: source)) } /// Deinitializes every instance in this buffer. @@ -920,7 +928,7 @@ extension Unsafe${Mutable}BufferPointer { /// - Parameters: /// - value: The value used to update the buffer element's memory. /// - index: The index of the element to update - public func assignElement(at index: Index, _ value: Element) { + public func updateElement(at index: Index, to value: Element) { precondition(startIndex <= index && index < endIndex) let p = baseAddress._unsafelyUnwrappedUnchecked.advanced(by: index) p.pointee = value diff --git a/stdlib/public/core/UnsafePointer.swift b/stdlib/public/core/UnsafePointer.swift index 40883a626c90f..f1caebcf2584f 100644 --- a/stdlib/public/core/UnsafePointer.swift +++ b/stdlib/public/core/UnsafePointer.swift @@ -772,20 +772,28 @@ public struct UnsafeMutablePointer: _Pointer { /// 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 - /// `assign(repeating:count:)`, the region is initialized. + /// `update(repeating:count:)`, the region is initialized. /// /// - Parameters: /// - repeatedValue: The value used when updating this pointer's memory. /// - count: The number of consecutive elements to update. /// `count` must not be negative. @inlinable - public func assign(repeating repeatedValue: Pointee, count: Int) { + @_silgen_name("$sSp6assign9repeating5countyx_SitF") + public func update(repeating repeatedValue: Pointee, count: Int) { _debugPrecondition(count >= 0, "UnsafeMutablePointer.assign(repeating:count:) with negative count") for i in 0..: _Pointer { /// /// - Parameters: /// - value: The value used to update this pointer's memory. - public func assign(_ value: Pointee) { + public func update(_ value: Pointee) { pointee = value } @@ -806,7 +814,7 @@ public struct UnsafeMutablePointer: _Pointer { /// 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 - /// `assign(from:count:)`, the region is initialized. + /// `update(from:count:)`, the region is initialized. /// /// - Note: Returns without performing work if `self` and `source` are equal. /// @@ -817,9 +825,10 @@ public struct UnsafeMutablePointer: _Pointer { /// - count: The number of instances to copy from the memory referenced by /// `source` to this pointer's memory. `count` must not be negative. @inlinable - public func assign(from source: UnsafePointer, count: Int) { + @_silgen_name("$sSp6assign4from5countySPyxG_SitF") + public func update(from source: UnsafePointer, count: Int) { _debugPrecondition( - count >= 0, "UnsafeMutablePointer.assign with negative count") + count >= 0, "UnsafeMutablePointer.update with negative count") if UnsafePointer(self) < source || UnsafePointer(self) >= source + count { // assign forward from a disjoint or following overlapping range. Builtin.assignCopyArrayFrontToBack( @@ -842,6 +851,13 @@ public struct UnsafeMutablePointer: _Pointer { } } + @_alwaysEmitIntoClient + @available(*, deprecated, renamed: "update(from:count:)") + @_silgen_name("_deprecated_assign_from_count") + public func assign(from source: UnsafePointer, count: Int) { + update(from: source, count: count) + } + /// Moves instances from initialized source memory into the uninitialized /// memory referenced by this pointer, leaving the source memory /// uninitialized and the memory referenced by this pointer initialized. @@ -925,7 +941,7 @@ public struct UnsafeMutablePointer: _Pointer { /// 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 - /// `moveAssign(from:count:)`, the region is initialized and the memory + /// `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. @@ -937,14 +953,15 @@ public struct UnsafeMutablePointer: _Pointer { /// - count: The number of instances to move from `source` to this /// pointer's memory. `count` must not be negative. @inlinable - public func moveAssign( + @_silgen_name("$sSp10moveAssign4from5countySpyxG_SitF") + public func moveUpdate( @_nonEphemeral from source: UnsafeMutablePointer, count: Int ) { _debugPrecondition( - count >= 0, "UnsafeMutablePointer.moveAssign(from:) with negative count") + count >= 0, "UnsafeMutablePointer.moveUpdate(from:) with negative count") _debugPrecondition( self + count <= source || source + count <= self, - "moveAssign overlapping range") + "moveUpdate overlapping range") Builtin.assignTakeArray( Pointee.self, self._rawValue, source._rawValue, count._builtinWordValue) // These builtins are equivalent to: @@ -952,7 +969,16 @@ public struct UnsafeMutablePointer: _Pointer { // self[i] = (source + i).move() // } } - + + @_alwaysEmitIntoClient + @available(*, deprecated, renamed: "moveUpdate(from:count:)") + @_silgen_name("_deprecated_moveAssign_from_count") + public func moveAssign( + @_nonEphemeral from source: UnsafeMutablePointer, count: Int + ) { + moveUpdate(from: source, count: count) + } + /// Deinitializes the specified number of values starting at this pointer. /// /// The region of memory starting at this pointer and covering `count` From fcd10c3efc192e81ad15253bb1051f4168ef98a8 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Tue, 30 Nov 2021 14:14:59 -0500 Subject: [PATCH 09/45] [stdlib] partial buffer initialization (better buffer slices) --- stdlib/public/core/CMakeLists.txt | 2 + stdlib/public/core/GroupInfo.json | 2 + .../core/UnsafeBufferPointerProtocols.swift | 82 ++ .../core/UnsafeBufferPointerSlice.swift | 847 ++++++++++++++++++ 4 files changed, 933 insertions(+) create mode 100644 stdlib/public/core/UnsafeBufferPointerProtocols.swift create mode 100644 stdlib/public/core/UnsafeBufferPointerSlice.swift diff --git a/stdlib/public/core/CMakeLists.txt b/stdlib/public/core/CMakeLists.txt index 2419c9926d745..c1eec599eb343 100644 --- a/stdlib/public/core/CMakeLists.txt +++ b/stdlib/public/core/CMakeLists.txt @@ -227,6 +227,8 @@ set(SWIFTLIB_SOURCES CommandLine.swift SliceBuffer.swift UnfoldSequence.swift + UnsafeBufferPointerSlice.swift + UnsafeBufferPointerProtocols.swift VarArgs.swift Zip.swift "${SWIFT_SOURCE_DIR}/stdlib/linker-support/magic-symbols-for-install-name.c" diff --git a/stdlib/public/core/GroupInfo.json b/stdlib/public/core/GroupInfo.json index 3d253bdb058e1..e094493bcc330 100644 --- a/stdlib/public/core/GroupInfo.json +++ b/stdlib/public/core/GroupInfo.json @@ -187,6 +187,8 @@ "UnsafePointer.swift", "UnsafeRawPointer.swift", "UnsafeBufferPointer.swift", + "UnsafeBufferPointerSlice.swift", + "UnsafeBufferPointerProtocols.swift", "UnsafeRawBufferPointer.swift" ], "Protocols": [ diff --git a/stdlib/public/core/UnsafeBufferPointerProtocols.swift b/stdlib/public/core/UnsafeBufferPointerProtocols.swift new file mode 100644 index 0000000000000..8d689112c062d --- /dev/null +++ b/stdlib/public/core/UnsafeBufferPointerProtocols.swift @@ -0,0 +1,82 @@ +//===----------------------------------------------------------*- swift -*-===// +// +// This source file is part of the Swift open source project +// +// Copyright (c) 2021 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// +//===----------------------------------------------------------------------===// + +public protocol _RebasableCollection: Collection { + init(rebasing slice: SubSequence) +} + +extension UnsafeBufferPointer: _RebasableCollection {} +extension UnsafeMutableBufferPointer: _RebasableCollection {} + + +public protocol _BufferProtocol: Collection where Index == Int { + associatedtype Element + + func withMemoryRebound( + to type: T.Type, _ body: (UnsafeBufferPointer) throws -> Result + ) rethrows -> Result +} + +extension UnsafeBufferPointer: _BufferProtocol {} + + +public protocol _MutableBaseAddressProtocol: MutableCollection { + var baseAddress: UnsafeMutablePointer? { get } +} + +extension UnsafeMutableBufferPointer: _MutableBaseAddressProtocol {} + + +public protocol _MutableBufferProtocol: MutableCollection where Index == Int { + associatedtype Element + + 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 + ) -> (unwritten: 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(from index: Index) -> Element + + func deinitializeElement(at index: Index) + + func withMemoryRebound( + to type: T.Type, _ body: (UnsafeMutableBufferPointer) throws -> Result + ) rethrows -> Result +} + +extension UnsafeMutableBufferPointer: _MutableBufferProtocol {} diff --git a/stdlib/public/core/UnsafeBufferPointerSlice.swift b/stdlib/public/core/UnsafeBufferPointerSlice.swift new file mode 100644 index 0000000000000..6726e2f9228e2 --- /dev/null +++ b/stdlib/public/core/UnsafeBufferPointerSlice.swift @@ -0,0 +1,847 @@ +//===----------------------------------------------------------*- swift -*-===// +// +// This source file is part of the Swift open source project +// +// Copyright (c) 2021 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// +//===----------------------------------------------------------------------===// + +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`. + @inlinable + func copyMemory(from source: UnsafeRawBufferPointer) { + let buffer = Base(rebasing: self) + buffer.copyMemory(from: source) + } + + /// 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`. + @inlinable + public func copyBytes( + from source: C + ) where C.Element == UInt8 { + let buffer = Base(rebasing: self) + buffer.copyBytes(from: source) + } + + /// 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`. + @inlinable + @discardableResult + func initializeMemory( + as type: T.Type, repeating repeatedValue: T + ) -> UnsafeMutableBufferPointer { + let buffer = Base(rebasing: self) + return buffer.initializeMemory(as: T.self, repeating: repeatedValue) + } + + /// 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. + @inlinable + public func initializeMemory( + as type: S.Element.Type, from source: S + ) -> (unwritten: S.Iterator, initialized: UnsafeMutableBufferPointer) { + let buffer = Base(rebasing: self) + return buffer.initializeMemory(as: S.Element.self, from: source) + } + + /// 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`. + @discardableResult + func initializeMemory( + as type: C.Element.Type, + fromElements source: C + ) -> UnsafeMutableBufferPointer { + let buffer = Base(rebasing: self) + return buffer.initializeMemory(as: C.Element.self, fromElements: source) + } + + /// 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`. + @discardableResult + func moveInitializeMemory( + as type: T.Type, + fromElements source: UnsafeMutableBufferPointer + ) -> UnsafeMutableBufferPointer { + let buffer = Base(rebasing: self) + return buffer.moveInitializeMemory(as: T.self, fromElements: source) + } + + /// 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 { + let buffer = Base(rebasing: self) + return buffer.moveInitializeMemory(as: T.self, fromElements: source) + } + + /// 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`. + @discardableResult + public func bindMemory(to type: T.Type) -> UnsafeMutableBufferPointer { + let buffer = Base(rebasing: self) + return buffer.bindMemory(to: T.self) + } + + /// 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 { + let buffer = Base(rebasing: self) + return try buffer.withMemoryRebound(to: T.self, body) + } + + /// 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 { + let buffer = Base(rebasing: self) + return buffer.assumingMemoryBound(to: T.self) + } +} + +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`. + @discardableResult + public func bindMemory(to type: T.Type) -> UnsafeBufferPointer { + let buffer = Base(rebasing: self) + return buffer.bindMemory(to: T.self) + } + + /// 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 { + let buffer = Base(rebasing: self) + return try buffer.withMemoryRebound(to: T.self, body) + } + + /// 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 { + let buffer = Base(rebasing: self) + return buffer.assumingMemoryBound(to: T.self) + } +} + +extension Slice: _BufferProtocol + where Base: _BufferProtocol & _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. + @inlinable + public func withMemoryRebound( + to type: T.Type, _ body: (UnsafeBufferPointer) throws -> Result + ) rethrows -> Result { + let buffer = Base(rebasing: self) + return try buffer.withMemoryRebound(to: T.self, body) + } +} + +extension Slice: _MutableBufferProtocol +where Base: _MutableBufferProtocol & _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) { + Base(rebasing: self).initialize(repeating: repeatedValue) + } + + /// 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 { + let buffer = Base(rebasing: self) + let (iterator, index) = buffer.initialize(from: source) + let distance = buffer.distance(from: buffer.startIndex, to: index) + return (iterator, startIndex.advanced(by: distance)) + } + + /// 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`. + @discardableResult + public func initialize( + fromElements source: C + ) -> Int where C : Collection, Base.Element == C.Element { + let buffer = Base(rebasing: self) + let index = buffer.initialize(fromElements: source) + let distance = buffer.distance(from: buffer.startIndex, to: index) + return startIndex.advanced(by: distance) + } + + /// 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) { + Base(rebasing: self).update(repeating: repeatedValue) + } + + /// 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 + ) -> (unwritten: S.Iterator, updated: Index) where S.Element == Element { + let buffer = Base(rebasing: self) + let (iterator, index) = buffer.update(from: source) + let distance = buffer.distance(from: buffer.startIndex, to: index) + return (iterator, startIndex.advanced(by: distance)) + } + + /// 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`. + @discardableResult + public func update( + fromElements source: C + ) -> Index where Base.Element == C.Element { + let buffer = Base(rebasing: self) + let index = buffer.update(fromElements: source) + let distance = buffer.distance(from: buffer.startIndex, to: index) + return startIndex.advanced(by: distance) + } + + /// 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`. + @discardableResult + public func moveInitialize( + fromElements source: UnsafeMutableBufferPointer + ) -> Index { + let buffer = Base(rebasing: self) + let index = buffer.moveInitialize(fromElements: source) + let distance = buffer.distance(from: buffer.startIndex, to: index) + return startIndex.advanced(by: distance) + } + + /// 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`. + @discardableResult + public func moveInitialize( + fromElements source: Slice> + ) -> Index { + let buffer = Base(rebasing: self) + let index = buffer.moveInitialize(fromElements: source) + let distance = buffer.distance(from: buffer.startIndex, to: index) + return startIndex.advanced(by: distance) + } + + /// 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`. + @discardableResult + public func moveUpdate( + fromElements source: UnsafeMutableBufferPointer + ) -> Index { + let buffer = Base(rebasing: self) + let index = buffer.moveUpdate(fromElements: source) + let distance = buffer.distance(from: buffer.startIndex, to: index) + return startIndex.advanced(by: distance) + } + + /// 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`. + @discardableResult + public func moveUpdate( + fromElements source: Slice> + ) -> Index { + let buffer = Base(rebasing: self) + let index = buffer.moveUpdate(fromElements: source) + let distance = buffer.distance(from: buffer.startIndex, to: index) + return startIndex.advanced(by: distance) + } + + /// 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`. + @discardableResult + public func deinitialize() -> UnsafeMutableRawBufferPointer { + Base(rebasing: self).deinitialize() + } + + /// 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) { + assert(startIndex <= index && index < endIndex) + base.baseAddress.unsafelyUnwrapped.advanced(by: index).initialize(to: value) + } + + /// 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) { + assert(startIndex <= index && index < endIndex) + base.baseAddress.unsafelyUnwrapped.advanced(by: index).pointee = value + } + + /// 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(from index: Index) -> Element { + assert(startIndex <= index && index < endIndex) + return base.baseAddress.unsafelyUnwrapped.advanced(by: index).move() + } + + /// 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) { + assert(startIndex <= index && index < endIndex) + base.baseAddress.unsafelyUnwrapped.advanced(by: index).deinitialize(count: 1) + } + + /// 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. + @inlinable + public func withMemoryRebound( + to type: T.Type, _ body: (UnsafeMutableBufferPointer) throws -> Result + ) rethrows -> Result { + try Base(rebasing: self).withMemoryRebound(to: T.self, body) + } + + @inlinable + func withContiguousMutableStorageIfAvailable( + _ body: (_ buffer: inout UnsafeMutableBufferPointer) throws -> R + ) rethrows -> R? { + try base.withContiguousStorageIfAvailable { buffer in + let start = base.baseAddress?.advanced(by: startIndex) + var slice = UnsafeMutableBufferPointer(start: start, count: count) + let (b,c) = (slice.baseAddress, slice.count) + defer { + precondition( + slice.baseAddress == b && slice.count == c, + "Slice.withContiguousMutableStorageIfAvailable: " + + "replacing the buffer is not allowed") + } + return try body(&slice) + } + } +} From 831a87fd36272e00b66b0737c2ac64debd1f7d67 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Wed, 9 Mar 2022 11:10:07 -0700 Subject: [PATCH 10/45] [stdlib] make additions non-abi --- .../public/core/UnsafeBufferPointer.swift.gyb | 26 +++++++++++++++++++ stdlib/public/core/UnsafePointer.swift | 8 ++++++ .../core/UnsafeRawBufferPointer.swift.gyb | 6 +++++ stdlib/public/core/UnsafeRawPointer.swift | 3 ++- 4 files changed, 42 insertions(+), 1 deletion(-) diff --git a/stdlib/public/core/UnsafeBufferPointer.swift.gyb b/stdlib/public/core/UnsafeBufferPointer.swift.gyb index 9c0c8a5c85593..6b53026948375 100644 --- a/stdlib/public/core/UnsafeBufferPointer.swift.gyb +++ b/stdlib/public/core/UnsafeBufferPointer.swift.gyb @@ -696,6 +696,8 @@ extension Unsafe${Mutable}BufferPointer { /// - Returns: An index to the next uninitialized element in the buffer, /// or `endIndex`. @discardableResult + @inlinable + @_alwaysEmitIntoClient public func initialize( fromElements source: C ) -> Index where C.Element == Element { @@ -727,6 +729,7 @@ extension Unsafe${Mutable}BufferPointer { /// - Parameters: /// - repeatedValue: The value used when updating this pointer's memory. @inlinable // unsafe-performance + @_alwaysEmitIntoClient @_silgen_name("$sSr6assign9repeatingyx_tF") public func update(repeating repeatedValue: Element) { guard let dstBase = _position else { @@ -736,6 +739,7 @@ extension Unsafe${Mutable}BufferPointer { dstBase.update(repeating: repeatedValue, count: count) } + @inlinable @_alwaysEmitIntoClient @available(*, deprecated, renamed: "update(repeating:)") @_silgen_name("_deprecated_assign_repeating") @@ -752,6 +756,8 @@ extension Unsafe${Mutable}BufferPointer { /// 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. + @inlinable + @_alwaysEmitIntoClient public func update( from source: S ) -> (unwritten: S.Iterator, updated: Index) where S.Element == Element { @@ -777,6 +783,8 @@ extension Unsafe${Mutable}BufferPointer { /// - Returns: An index one past the last updated element in the buffer, /// or `endIndex`. @discardableResult + @inlinable + @_alwaysEmitIntoClient public func update( fromElements source: C ) -> Index where C.Element == Element { @@ -812,6 +820,8 @@ extension Unsafe${Mutable}BufferPointer { /// - Returns: An index to the next uninitialized element in the buffer, /// or `endIndex`. @discardableResult + @inlinable + @_alwaysEmitIntoClient public func moveInitialize(fromElements source: Self) -> Index { guard let pointer = source.baseAddress, source.count > 0 else { return 0 } _debugPrecondition(count >= source.count) @@ -836,6 +846,8 @@ extension Unsafe${Mutable}BufferPointer { /// - Returns: An index one past the last replaced element in the buffer, /// or `endIndex`. @discardableResult + @inlinable + @_alwaysEmitIntoClient public func moveInitialize(fromElements source: Slice) -> Index { return moveInitialize(fromElements: Self(rebasing: source)) } @@ -856,6 +868,8 @@ extension Unsafe${Mutable}BufferPointer { /// - Returns: An index one past the last updated element in the buffer, /// or `endIndex`. @discardableResult + @inlinable + @_alwaysEmitIntoClient public func moveUpdate(fromElements source: Self) -> Index { guard let pointer = source.baseAddress, source.count > 0 else { return 0 } _debugPrecondition(count >= source.count) @@ -880,6 +894,8 @@ extension Unsafe${Mutable}BufferPointer { /// - Returns: An index one past the last updated element in the buffer, /// or `endIndex`. @discardableResult + @inlinable + @_alwaysEmitIntoClient public func moveUpdate(fromElements source: Slice) -> Index { return moveUpdate(fromElements: Self(rebasing: source)) } @@ -895,6 +911,8 @@ extension Unsafe${Mutable}BufferPointer { /// - Returns: A raw buffer to the same range of memory as this buffer. /// The range of memory is still bound to `Element`. @discardableResult + @inlinable + @_alwaysEmitIntoClient public func deinitialize() -> UnsafeMutableRawBufferPointer { guard let rawValue = baseAddress?._rawValue else { return .init(start: nil, count: 0) } @@ -912,6 +930,8 @@ extension Unsafe${Mutable}BufferPointer { /// - Parameters: /// - value: The value used to initialize the buffer element's memory. /// - index: The index of the element to initialize + @inlinable + @_alwaysEmitIntoClient public func initializeElement(at index: Index, to value: Element) { precondition(startIndex <= index && index < endIndex) let p = baseAddress._unsafelyUnwrappedUnchecked.advanced(by: index) @@ -928,6 +948,8 @@ extension Unsafe${Mutable}BufferPointer { /// - Parameters: /// - value: The value used to update the buffer element's memory. /// - index: The index of the element to update + @inlinable + @_alwaysEmitIntoClient public func updateElement(at index: Index, to value: Element) { precondition(startIndex <= index && index < endIndex) let p = baseAddress._unsafelyUnwrappedUnchecked.advanced(by: index) @@ -944,6 +966,8 @@ extension Unsafe${Mutable}BufferPointer { /// - Parameters: /// - index: The index of the buffer element to retrieve and deinitialize. /// - Returns: The instance referenced by this index in this buffer. + @inlinable + @_alwaysEmitIntoClient public func moveElement(from index: Index) -> Element { precondition(startIndex <= index && index < endIndex) return baseAddress._unsafelyUnwrappedUnchecked.advanced(by: index).move() @@ -957,6 +981,8 @@ extension Unsafe${Mutable}BufferPointer { /// /// - Parameters: /// - index: The index of the buffer element to deinitialize. + @inlinable + @_alwaysEmitIntoClient public func deinitializeElement(at index: Index) { precondition(startIndex <= index && index < endIndex) let p = baseAddress._unsafelyUnwrappedUnchecked.advanced(by: index) diff --git a/stdlib/public/core/UnsafePointer.swift b/stdlib/public/core/UnsafePointer.swift index f1caebcf2584f..5afd307c24bac 100644 --- a/stdlib/public/core/UnsafePointer.swift +++ b/stdlib/public/core/UnsafePointer.swift @@ -779,6 +779,7 @@ public struct UnsafeMutablePointer: _Pointer { /// - count: The number of consecutive elements to update. /// `count` must not be negative. @inlinable + @_alwaysEmitIntoClient @_silgen_name("$sSp6assign9repeating5countyx_SitF") public func update(repeating repeatedValue: Pointee, count: Int) { _debugPrecondition(count >= 0, "UnsafeMutablePointer.assign(repeating:count:) with negative count") @@ -787,6 +788,7 @@ public struct UnsafeMutablePointer: _Pointer { } } + @inlinable @_alwaysEmitIntoClient @available(*, deprecated, renamed: "update(repeating:count:)") @_silgen_name("_deprecated_assign_repeating_count") @@ -804,6 +806,8 @@ public struct UnsafeMutablePointer: _Pointer { /// /// - Parameters: /// - value: The value used to update this pointer's memory. + @inlinable + @_alwaysEmitIntoClient public func update(_ value: Pointee) { pointee = value } @@ -825,6 +829,7 @@ public struct UnsafeMutablePointer: _Pointer { /// - count: The number of instances to copy from the memory referenced by /// `source` to this pointer's memory. `count` must not be negative. @inlinable + @_alwaysEmitIntoClient @_silgen_name("$sSp6assign4from5countySPyxG_SitF") public func update(from source: UnsafePointer, count: Int) { _debugPrecondition( @@ -851,6 +856,7 @@ public struct UnsafeMutablePointer: _Pointer { } } + @inlinable @_alwaysEmitIntoClient @available(*, deprecated, renamed: "update(from:count:)") @_silgen_name("_deprecated_assign_from_count") @@ -953,6 +959,7 @@ public struct UnsafeMutablePointer: _Pointer { /// - count: The number of instances to move from `source` to this /// pointer's memory. `count` must not be negative. @inlinable + @_alwaysEmitIntoClient @_silgen_name("$sSp10moveAssign4from5countySpyxG_SitF") public func moveUpdate( @_nonEphemeral from source: UnsafeMutablePointer, count: Int @@ -970,6 +977,7 @@ public struct UnsafeMutablePointer: _Pointer { // } } + @inlinable @_alwaysEmitIntoClient @available(*, deprecated, renamed: "moveUpdate(from:count:)") @_silgen_name("_deprecated_moveAssign_from_count") diff --git a/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb b/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb index f606ff68f4ff8..a10dc275a82de 100644 --- a/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb +++ b/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb @@ -805,6 +805,8 @@ extension Unsafe${Mutable}RawBufferPointer { /// buffer, and its count indicates the number of elements copied from /// the collection `elements`. @discardableResult + @inlinable + @_alwaysEmitIntoClient public func initializeMemory( as type: C.Element.Type, fromElements source: C @@ -852,6 +854,8 @@ extension Unsafe${Mutable}RawBufferPointer { /// buffer references memory starting at the same base address as this /// buffer, and it contains every element copied from `source`. @discardableResult + @inlinable + @_alwaysEmitIntoClient public func moveInitializeMemory( as type: T.Type, fromElements source: UnsafeMutableBufferPointer @@ -889,6 +893,8 @@ extension Unsafe${Mutable}RawBufferPointer { /// buffer references memory starting at the same base address as this /// buffer, and it contains every element copied from `source`. @discardableResult + @inlinable + @_alwaysEmitIntoClient public func moveInitializeMemory( as type: T.Type, fromElements source: Slice> diff --git a/stdlib/public/core/UnsafeRawPointer.swift b/stdlib/public/core/UnsafeRawPointer.swift index 52f5c4de2ff0c..cf2490a93f2a3 100644 --- a/stdlib/public/core/UnsafeRawPointer.swift +++ b/stdlib/public/core/UnsafeRawPointer.swift @@ -988,8 +988,9 @@ public struct UnsafeMutableRawPointer: _Pointer { /// - 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. - @inlinable @discardableResult + @inlinable + @_alwaysEmitIntoClient public func initializeMemory( as type: T.Type, to value: T ) -> UnsafeMutablePointer { From 00aaa07daf8bb138ae52a0259d9598781c2e27eb Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Wed, 9 Mar 2022 13:58:33 -0700 Subject: [PATCH 11/45] [stdlib] improve doc-comments --- .../core/UnsafeRawBufferPointer.swift.gyb | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb b/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb index a10dc275a82de..a7ceb6d49eb72 100644 --- a/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb +++ b/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb @@ -695,10 +695,11 @@ extension Unsafe${Mutable}RawBufferPointer { /// /// 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. + /// `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. @@ -735,7 +736,8 @@ extension Unsafe${Mutable}RawBufferPointer { /// 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`. + /// `S.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. @@ -800,10 +802,10 @@ extension Unsafe${Mutable}RawBufferPointer { /// - 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`. + /// - 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`. @discardableResult @inlinable @_alwaysEmitIntoClient From 359e69d67e617e08173b8b78c506f7a3963aee85 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Wed, 9 Mar 2022 15:09:36 -0700 Subject: [PATCH 12/45] [stdlib] make more additions non-abi --- .../core/UnsafeBufferPointerSlice.swift | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/stdlib/public/core/UnsafeBufferPointerSlice.swift b/stdlib/public/core/UnsafeBufferPointerSlice.swift index 6726e2f9228e2..93b8bb49cf480 100644 --- a/stdlib/public/core/UnsafeBufferPointerSlice.swift +++ b/stdlib/public/core/UnsafeBufferPointerSlice.swift @@ -28,6 +28,7 @@ extension Slice where Base == UnsafeMutableRawBufferPointer { /// - Parameter source: A buffer of raw bytes. `source.count` must /// be less than or equal to this buffer slice's `count`. @inlinable + @_alwaysEmitIntoClient func copyMemory(from source: UnsafeRawBufferPointer) { let buffer = Base(rebasing: self) buffer.copyMemory(from: source) @@ -47,6 +48,7 @@ extension Slice where Base == UnsafeMutableRawBufferPointer { /// - Parameter source: A collection of `UInt8` elements. `source.count` must /// be less than or equal to this buffer slice's `count`. @inlinable + @_alwaysEmitIntoClient public func copyBytes( from source: C ) where C.Element == UInt8 { @@ -75,8 +77,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`. - @inlinable @discardableResult + @inlinable + @_alwaysEmitIntoClient func initializeMemory( as type: T.Type, repeating repeatedValue: T ) -> UnsafeMutableBufferPointer { @@ -108,6 +111,7 @@ extension Slice where Base == UnsafeMutableRawBufferPointer { /// buffer references memory starting at the same base address as this /// buffer. @inlinable + @_alwaysEmitIntoClient public func initializeMemory( as type: S.Element.Type, from source: S ) -> (unwritten: S.Iterator, initialized: UnsafeMutableBufferPointer) { @@ -138,6 +142,8 @@ extension Slice where Base == UnsafeMutableRawBufferPointer { /// buffer, and its count indicates the number of elements copied from /// the collection `elements`. @discardableResult + @inlinable + @_alwaysEmitIntoClient func initializeMemory( as type: C.Element.Type, fromElements source: C @@ -170,6 +176,8 @@ extension Slice where Base == UnsafeMutableRawBufferPointer { /// buffer, and its count indicates the number of elements copied from /// `source`. @discardableResult + @inlinable + @_alwaysEmitIntoClient func moveInitializeMemory( as type: T.Type, fromElements source: UnsafeMutableBufferPointer @@ -198,6 +206,8 @@ extension Slice where Base == UnsafeMutableRawBufferPointer { /// buffer, and its count indicates the number of elements copied from /// `source`. @discardableResult + @inlinable + @_alwaysEmitIntoClient func moveInitializeMemory( as type: T.Type, fromElements source: Slice> @@ -224,6 +234,8 @@ extension Slice where Base == UnsafeMutableRawBufferPointer { /// 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`. @discardableResult + @inlinable + @_alwaysEmitIntoClient public func bindMemory(to type: T.Type) -> UnsafeMutableBufferPointer { let buffer = Base(rebasing: self) return buffer.bindMemory(to: T.self) @@ -273,6 +285,8 @@ extension Slice where Base == UnsafeMutableRawBufferPointer { /// 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. + @inlinable + @_alwaysEmitIntoClient func withMemoryRebound( to type: T.Type, _ body: (UnsafeMutableBufferPointer) throws -> Result ) rethrows -> Result { @@ -296,6 +310,8 @@ 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. + @inlinable + @_alwaysEmitIntoClient func assumingMemoryBound(to type: T.Type) -> UnsafeMutableBufferPointer { let buffer = Base(rebasing: self) return buffer.assumingMemoryBound(to: T.self) @@ -322,6 +338,8 @@ extension Slice where Base == UnsafeRawBufferPointer { /// 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`. @discardableResult + @inlinable + @_alwaysEmitIntoClient public func bindMemory(to type: T.Type) -> UnsafeBufferPointer { let buffer = Base(rebasing: self) return buffer.bindMemory(to: T.self) @@ -371,6 +389,8 @@ extension Slice where Base == UnsafeRawBufferPointer { /// 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. + @inlinable + @_alwaysEmitIntoClient func withMemoryRebound( to type: T.Type, _ body: (UnsafeBufferPointer) throws -> Result ) rethrows -> Result { @@ -394,6 +414,8 @@ 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. + @inlinable + @_alwaysEmitIntoClient func assumingMemoryBound(to type: T.Type) -> UnsafeBufferPointer { let buffer = Base(rebasing: self) return buffer.assumingMemoryBound(to: T.self) From 75f64e731fc8447396e7547944540be8c3b99f31 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Wed, 9 Mar 2022 17:23:27 -0700 Subject: [PATCH 13/45] [stdlib] implement slice operations without protocols --- stdlib/public/core/CMakeLists.txt | 1 - stdlib/public/core/GroupInfo.json | 1 - .../core/UnsafeBufferPointerProtocols.swift | 82 ----------- .../core/UnsafeBufferPointerSlice.swift | 138 ++++++++++++------ 4 files changed, 91 insertions(+), 131 deletions(-) delete mode 100644 stdlib/public/core/UnsafeBufferPointerProtocols.swift diff --git a/stdlib/public/core/CMakeLists.txt b/stdlib/public/core/CMakeLists.txt index c1eec599eb343..0ff94278675f4 100644 --- a/stdlib/public/core/CMakeLists.txt +++ b/stdlib/public/core/CMakeLists.txt @@ -228,7 +228,6 @@ set(SWIFTLIB_SOURCES SliceBuffer.swift UnfoldSequence.swift UnsafeBufferPointerSlice.swift - UnsafeBufferPointerProtocols.swift VarArgs.swift Zip.swift "${SWIFT_SOURCE_DIR}/stdlib/linker-support/magic-symbols-for-install-name.c" diff --git a/stdlib/public/core/GroupInfo.json b/stdlib/public/core/GroupInfo.json index e094493bcc330..b266b17c2f46f 100644 --- a/stdlib/public/core/GroupInfo.json +++ b/stdlib/public/core/GroupInfo.json @@ -188,7 +188,6 @@ "UnsafeRawPointer.swift", "UnsafeBufferPointer.swift", "UnsafeBufferPointerSlice.swift", - "UnsafeBufferPointerProtocols.swift", "UnsafeRawBufferPointer.swift" ], "Protocols": [ diff --git a/stdlib/public/core/UnsafeBufferPointerProtocols.swift b/stdlib/public/core/UnsafeBufferPointerProtocols.swift deleted file mode 100644 index 8d689112c062d..0000000000000 --- a/stdlib/public/core/UnsafeBufferPointerProtocols.swift +++ /dev/null @@ -1,82 +0,0 @@ -//===----------------------------------------------------------*- swift -*-===// -// -// This source file is part of the Swift open source project -// -// Copyright (c) 2021 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See https://swift.org/LICENSE.txt for license information -// -//===----------------------------------------------------------------------===// - -public protocol _RebasableCollection: Collection { - init(rebasing slice: SubSequence) -} - -extension UnsafeBufferPointer: _RebasableCollection {} -extension UnsafeMutableBufferPointer: _RebasableCollection {} - - -public protocol _BufferProtocol: Collection where Index == Int { - associatedtype Element - - func withMemoryRebound( - to type: T.Type, _ body: (UnsafeBufferPointer) throws -> Result - ) rethrows -> Result -} - -extension UnsafeBufferPointer: _BufferProtocol {} - - -public protocol _MutableBaseAddressProtocol: MutableCollection { - var baseAddress: UnsafeMutablePointer? { get } -} - -extension UnsafeMutableBufferPointer: _MutableBaseAddressProtocol {} - - -public protocol _MutableBufferProtocol: MutableCollection where Index == Int { - associatedtype Element - - 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 - ) -> (unwritten: 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(from index: Index) -> Element - - func deinitializeElement(at index: Index) - - func withMemoryRebound( - to type: T.Type, _ body: (UnsafeMutableBufferPointer) throws -> Result - ) rethrows -> Result -} - -extension UnsafeMutableBufferPointer: _MutableBufferProtocol {} diff --git a/stdlib/public/core/UnsafeBufferPointerSlice.swift b/stdlib/public/core/UnsafeBufferPointerSlice.swift index 93b8bb49cf480..46a9093d1bf4d 100644 --- a/stdlib/public/core/UnsafeBufferPointerSlice.swift +++ b/stdlib/public/core/UnsafeBufferPointerSlice.swift @@ -80,7 +80,7 @@ extension Slice where Base == UnsafeMutableRawBufferPointer { @discardableResult @inlinable @_alwaysEmitIntoClient - func initializeMemory( + public func initializeMemory( as type: T.Type, repeating repeatedValue: T ) -> UnsafeMutableBufferPointer { let buffer = Base(rebasing: self) @@ -144,7 +144,7 @@ extension Slice where Base == UnsafeMutableRawBufferPointer { @discardableResult @inlinable @_alwaysEmitIntoClient - func initializeMemory( + public func initializeMemory( as type: C.Element.Type, fromElements source: C ) -> UnsafeMutableBufferPointer { @@ -178,7 +178,7 @@ extension Slice where Base == UnsafeMutableRawBufferPointer { @discardableResult @inlinable @_alwaysEmitIntoClient - func moveInitializeMemory( + public func moveInitializeMemory( as type: T.Type, fromElements source: UnsafeMutableBufferPointer ) -> UnsafeMutableBufferPointer { @@ -208,7 +208,7 @@ extension Slice where Base == UnsafeMutableRawBufferPointer { @discardableResult @inlinable @_alwaysEmitIntoClient - func moveInitializeMemory( + public func moveInitializeMemory( as type: T.Type, fromElements source: Slice> ) -> UnsafeMutableBufferPointer { @@ -287,7 +287,7 @@ extension Slice where Base == UnsafeMutableRawBufferPointer { /// - Returns: The return value, if any, of the `body` closure parameter. @inlinable @_alwaysEmitIntoClient - func withMemoryRebound( + public func withMemoryRebound( to type: T.Type, _ body: (UnsafeMutableBufferPointer) throws -> Result ) rethrows -> Result { let buffer = Base(rebasing: self) @@ -312,7 +312,9 @@ extension Slice where Base == UnsafeMutableRawBufferPointer { /// - Returns: A typed pointer to the same memory as this raw pointer. @inlinable @_alwaysEmitIntoClient - func assumingMemoryBound(to type: T.Type) -> UnsafeMutableBufferPointer { + public func assumingMemoryBound( + to type: T.Type + ) -> UnsafeMutableBufferPointer { let buffer = Base(rebasing: self) return buffer.assumingMemoryBound(to: T.self) } @@ -391,7 +393,7 @@ extension Slice where Base == UnsafeRawBufferPointer { /// - Returns: The return value, if any, of the `body` closure parameter. @inlinable @_alwaysEmitIntoClient - func withMemoryRebound( + public func withMemoryRebound( to type: T.Type, _ body: (UnsafeBufferPointer) throws -> Result ) rethrows -> Result { let buffer = Base(rebasing: self) @@ -416,15 +418,15 @@ extension Slice where Base == UnsafeRawBufferPointer { /// - Returns: A typed pointer to the same memory as this raw pointer. @inlinable @_alwaysEmitIntoClient - func assumingMemoryBound(to type: T.Type) -> UnsafeBufferPointer { + public func assumingMemoryBound( + to type: T.Type + ) -> UnsafeBufferPointer { let buffer = Base(rebasing: self) return buffer.assumingMemoryBound(to: T.self) } } -extension Slice: _BufferProtocol - where Base: _BufferProtocol & _RebasableCollection, Base.SubSequence == Self { - +extension Slice { /// Executes the given closure while temporarily binding the memory referenced /// by this buffer slice to the given type. /// @@ -481,17 +483,16 @@ extension Slice: _BufferProtocol /// - buffer: The buffer temporarily bound to `T`. /// - Returns: The return value, if any, of the `body` closure parameter. @inlinable - public func withMemoryRebound( + @_alwaysEmitIntoClient + public func withMemoryRebound( to type: T.Type, _ body: (UnsafeBufferPointer) throws -> Result - ) rethrows -> Result { - let buffer = Base(rebasing: self) - return try buffer.withMemoryRebound(to: T.self, body) + ) rethrows -> Result where Base == UnsafeBufferPointer { + let rebased = UnsafeBufferPointer(rebasing: self) + return try rebased.withMemoryRebound(to: T.self, body) } } -extension Slice: _MutableBufferProtocol -where Base: _MutableBufferProtocol & _RebasableCollection & _MutableBaseAddressProtocol, - Base.SubSequence == Self { +extension Slice { /// Initializes every element in this buffer slice's memory to /// a copy of the given value. @@ -502,7 +503,10 @@ where Base: _MutableBufferProtocol & _RebasableCollection & _MutableBaseAddressP /// /// - Parameter repeatedValue: The value with which to initialize this /// buffer slice's memory. - public func initialize(repeating repeatedValue: Base.Element) { + @inlinable + @_alwaysEmitIntoClient + public func initialize(repeating repeatedValue: Element) + where Base == UnsafeMutableBufferPointer { Base(rebasing: self).initialize(repeating: repeatedValue) } @@ -527,9 +531,12 @@ where Base: _MutableBufferProtocol & _RebasableCollection & _MutableBaseAddressP /// 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. + @inlinable + @_alwaysEmitIntoClient public func initialize( from source: S - ) -> (S.Iterator, Index) where S: Sequence, Base.Element == S.Element { + ) -> (S.Iterator, Index) + where S: Sequence, Base == UnsafeMutableBufferPointer { let buffer = Base(rebasing: self) let (iterator, index) = buffer.initialize(from: source) let distance = buffer.distance(from: buffer.startIndex, to: index) @@ -556,9 +563,12 @@ where Base: _MutableBufferProtocol & _RebasableCollection & _MutableBaseAddressP /// - Returns: An index to the next uninitialized element in the buffer, /// or `endIndex`. @discardableResult + @inlinable + @_alwaysEmitIntoClient public func initialize( fromElements source: C - ) -> Int where C : Collection, Base.Element == C.Element { + ) -> Index + where C : Collection, Base == UnsafeMutableBufferPointer { let buffer = Base(rebasing: self) let index = buffer.initialize(fromElements: source) let distance = buffer.distance(from: buffer.startIndex, to: index) @@ -574,7 +584,10 @@ where Base: _MutableBufferProtocol & _RebasableCollection & _MutableBaseAddressP /// /// - Parameters: /// - repeatedValue: The value used when updating this pointer's memory. - public func update(repeating repeatedValue: Base.Element) { + @inlinable + @_alwaysEmitIntoClient + public func update(repeating repeatedValue: Element) + where Base == UnsafeMutableBufferPointer { Base(rebasing: self).update(repeating: repeatedValue) } @@ -587,9 +600,12 @@ where Base: _MutableBufferProtocol & _RebasableCollection & _MutableBaseAddressP /// 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( + @inlinable + @_alwaysEmitIntoClient + public func update( from source: S - ) -> (unwritten: S.Iterator, updated: Index) where S.Element == Element { + ) -> (unwritten: S.Iterator, updated: Index) + where S: Sequence, Base == UnsafeMutableBufferPointer { let buffer = Base(rebasing: self) let (iterator, index) = buffer.update(from: source) let distance = buffer.distance(from: buffer.startIndex, to: index) @@ -606,9 +622,12 @@ where Base: _MutableBufferProtocol & _RebasableCollection & _MutableBaseAddressP /// - Returns: An index one past the last updated element in the buffer, /// or `endIndex`. @discardableResult - public func update( + @inlinable + @_alwaysEmitIntoClient + public func update( fromElements source: C - ) -> Index where Base.Element == C.Element { + ) -> Index + where C: Collection, Base == UnsafeMutableBufferPointer { let buffer = Base(rebasing: self) let index = buffer.update(fromElements: source) let distance = buffer.distance(from: buffer.startIndex, to: index) @@ -631,9 +650,11 @@ where Base: _MutableBufferProtocol & _RebasableCollection & _MutableBaseAddressP /// - Returns: An index to the next uninitialized element in the buffer, /// or `endIndex`. @discardableResult - public func moveInitialize( - fromElements source: UnsafeMutableBufferPointer - ) -> Index { + @inlinable + @_alwaysEmitIntoClient + public func moveInitialize( + fromElements source: UnsafeMutableBufferPointer + ) -> Index where Base == UnsafeMutableBufferPointer { let buffer = Base(rebasing: self) let index = buffer.moveInitialize(fromElements: source) let distance = buffer.distance(from: buffer.startIndex, to: index) @@ -656,9 +677,11 @@ where Base: _MutableBufferProtocol & _RebasableCollection & _MutableBaseAddressP /// - Returns: An index one past the last replaced element in the buffer, /// or `endIndex`. @discardableResult - public func moveInitialize( - fromElements source: Slice> - ) -> Index { + @inlinable + @_alwaysEmitIntoClient + public func moveInitialize( + fromElements source: Slice> + ) -> Index where Base == UnsafeMutableBufferPointer { let buffer = Base(rebasing: self) let index = buffer.moveInitialize(fromElements: source) let distance = buffer.distance(from: buffer.startIndex, to: index) @@ -681,9 +704,11 @@ where Base: _MutableBufferProtocol & _RebasableCollection & _MutableBaseAddressP /// - Returns: An index one past the last updated element in the buffer, /// or `endIndex`. @discardableResult - public func moveUpdate( - fromElements source: UnsafeMutableBufferPointer - ) -> Index { + @inlinable + @_alwaysEmitIntoClient + public func moveUpdate( + fromElements source: UnsafeMutableBufferPointer + ) -> Index where Base == UnsafeMutableBufferPointer { let buffer = Base(rebasing: self) let index = buffer.moveUpdate(fromElements: source) let distance = buffer.distance(from: buffer.startIndex, to: index) @@ -706,9 +731,11 @@ where Base: _MutableBufferProtocol & _RebasableCollection & _MutableBaseAddressP /// - Returns: An index one past the last updated element in the buffer, /// or `endIndex`. @discardableResult - public func moveUpdate( - fromElements source: Slice> - ) -> Index { + @inlinable + @_alwaysEmitIntoClient + public func moveUpdate( + fromElements source: Slice> + ) -> Index where Base == UnsafeMutableBufferPointer { let buffer = Base(rebasing: self) let index = buffer.moveUpdate(fromElements: source) let distance = buffer.distance(from: buffer.startIndex, to: index) @@ -726,7 +753,10 @@ where Base: _MutableBufferProtocol & _RebasableCollection & _MutableBaseAddressP /// - Returns: A raw buffer to the same range of memory as this buffer. /// The range of memory is still bound to `Element`. @discardableResult - public func deinitialize() -> UnsafeMutableRawBufferPointer { + @inlinable + @_alwaysEmitIntoClient + public func deinitialize() -> UnsafeMutableRawBufferPointer + where Base == UnsafeMutableBufferPointer { Base(rebasing: self).deinitialize() } @@ -739,7 +769,10 @@ where Base: _MutableBufferProtocol & _RebasableCollection & _MutableBaseAddressP /// - 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) { + @inlinable + @_alwaysEmitIntoClient + public func initializeElement(at index: Int, to value: Element) + where Base == UnsafeMutableBufferPointer { assert(startIndex <= index && index < endIndex) base.baseAddress.unsafelyUnwrapped.advanced(by: index).initialize(to: value) } @@ -754,7 +787,10 @@ where Base: _MutableBufferProtocol & _RebasableCollection & _MutableBaseAddressP /// - 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) { + @inlinable + @_alwaysEmitIntoClient + public func updateElement(at index: Index, to value: Element) + where Base == UnsafeMutableBufferPointer { assert(startIndex <= index && index < endIndex) base.baseAddress.unsafelyUnwrapped.advanced(by: index).pointee = value } @@ -769,7 +805,10 @@ where Base: _MutableBufferProtocol & _RebasableCollection & _MutableBaseAddressP /// - 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 { + @inlinable + @_alwaysEmitIntoClient + public func moveElement(from index: Index) -> Element + where Base == UnsafeMutableBufferPointer { assert(startIndex <= index && index < endIndex) return base.baseAddress.unsafelyUnwrapped.advanced(by: index).move() } @@ -782,7 +821,10 @@ where Base: _MutableBufferProtocol & _RebasableCollection & _MutableBaseAddressP /// /// - Parameters: /// - index: The index of the buffer element to deinitialize. - public func deinitializeElement(at index: Base.Index) { + @inlinable + @_alwaysEmitIntoClient + public func deinitializeElement(at index: Base.Index) + where Base == UnsafeMutableBufferPointer { assert(startIndex <= index && index < endIndex) base.baseAddress.unsafelyUnwrapped.advanced(by: index).deinitialize(count: 1) } @@ -843,16 +885,18 @@ where Base: _MutableBufferProtocol & _RebasableCollection & _MutableBaseAddressP /// - buffer: The buffer temporarily bound to `T`. /// - Returns: The return value, if any, of the `body` closure parameter. @inlinable - public func withMemoryRebound( + @_alwaysEmitIntoClient + public func withMemoryRebound( to type: T.Type, _ body: (UnsafeMutableBufferPointer) throws -> Result - ) rethrows -> Result { + ) rethrows -> Result where Base == UnsafeMutableBufferPointer{ try Base(rebasing: self).withMemoryRebound(to: T.self, body) } @inlinable - func withContiguousMutableStorageIfAvailable( + @_alwaysEmitIntoClient + public func withContiguousMutableStorageIfAvailable( _ body: (_ buffer: inout UnsafeMutableBufferPointer) throws -> R - ) rethrows -> R? { + ) rethrows -> R? where Base == UnsafeMutableBufferPointer { try base.withContiguousStorageIfAvailable { buffer in let start = base.baseAddress?.advanced(by: startIndex) var slice = UnsafeMutableBufferPointer(start: start, count: count) From 9cbc9eb000d1b02922de75e01e840336cab17a7f Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Fri, 18 Mar 2022 16:42:58 -0600 Subject: [PATCH 14/45] [stlib] remove Slice.copyMemory --- .../core/UnsafeBufferPointerSlice.swift | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/stdlib/public/core/UnsafeBufferPointerSlice.swift b/stdlib/public/core/UnsafeBufferPointerSlice.swift index 46a9093d1bf4d..1b74705904fe7 100644 --- a/stdlib/public/core/UnsafeBufferPointerSlice.swift +++ b/stdlib/public/core/UnsafeBufferPointerSlice.swift @@ -11,29 +11,6 @@ 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`. - @inlinable - @_alwaysEmitIntoClient - func copyMemory(from source: UnsafeRawBufferPointer) { - let buffer = Base(rebasing: self) - buffer.copyMemory(from: source) - } - /// 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 From b0832cb13a215245499f3aa57e3c2d39505a8da8 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Thu, 2 Jun 2022 18:09:37 -0600 Subject: [PATCH 15/45] [abi] override the judgment of the abi stability test --- test/api-digester/stability-stdlib-abi-without-asserts.test | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/api-digester/stability-stdlib-abi-without-asserts.test b/test/api-digester/stability-stdlib-abi-without-asserts.test index dd35103b989b3..7ab928c158327 100644 --- a/test/api-digester/stability-stdlib-abi-without-asserts.test +++ b/test/api-digester/stability-stdlib-abi-without-asserts.test @@ -95,6 +95,10 @@ Func UnsafeMutablePointer.withMemoryRebound(to:capacity:_:) has been removed Func UnsafePointer.withMemoryRebound(to:capacity:_:) has been removed Func UnsafeMutableRawBufferPointer.storeBytes(of:toByteOffset:as:) has been removed Func UnsafeMutableRawPointer.storeBytes(of:toByteOffset:as:) has been removed +Func UnsafeMutableBufferPointer.assign(repeating:) has been removed +Func UnsafeMutablePointer.assign(from:count:) has been removed +Func UnsafeMutablePointer.assign(repeating:count:) has been removed +Func UnsafeMutablePointer.moveAssign(from:count:) has been removed // These haven't actually been removed; they are simply marked unavailable. // This seems to be a false positive in the ABI checker. This is not an ABI From bb69e34b52e1ec52c68cb8eaf4b019ab62b0c4f4 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Fri, 11 Mar 2022 17:56:12 -0700 Subject: [PATCH 16/45] [test] initialization of slices of UnsafeBufferPointer types --- .../stdlib/UnsafeBufferPointerSlices.swift | 571 ++++++++++++++++++ 1 file changed, 571 insertions(+) create mode 100644 validation-test/stdlib/UnsafeBufferPointerSlices.swift diff --git a/validation-test/stdlib/UnsafeBufferPointerSlices.swift b/validation-test/stdlib/UnsafeBufferPointerSlices.swift new file mode 100644 index 0000000000000..b601be2a134d9 --- /dev/null +++ b/validation-test/stdlib/UnsafeBufferPointerSlices.swift @@ -0,0 +1,571 @@ +// RUN: %target-run-simple-swiftgyb +// REQUIRES: executable_test + +import StdlibUnittest + +var UnsafeBufferPointerSliceTests = TestSuite( + "UnsafeBufferPointerSliceTests" +) + +UnsafeBufferPointerSliceTests.test( + "slice.of.UnsafeBufferPointer.withMemoryRebound" +) { + let a = Array(0..<10) + let r: Bool? = a.withContiguousStorageIfAvailable { + let b: UnsafeBufferPointer = $0 + var c: UInt + c = b.withMemoryRebound(to: (UInt, UInt).self) { + $0.reduce(0, { $0 + $1.1 }) + } + expectEqual(c, 25) + let s = b[...] + c = s.withMemoryRebound(to: (UInt, UInt).self) { + $0.reduce(0, { $0 + $1.1 }) + } + expectEqual(c, 25) + return true + } + expectNotNil(r) +} + +var UnsafeMutableBufferPointerSliceTests = TestSuite( + "UnsafeMutableBufferPointerSliceTests" +) + +UnsafeMutableBufferPointerSliceTests.test( + "slice.of.UnsafeMutableBufferPointer.withMemoryRebound" +) { + var a = Array(0..<10) + let t = a.reduce(0,+) + let r: Bool? = a.withContiguousMutableStorageIfAvailable { + let mb: UnsafeMutableBufferPointer = $0 + mb.withMemoryRebound(to: (UInt, UInt).self) { + for i in $0.indices { + $0[i].0 += 1 + } + } + expectEqual(mb.reduce(0,+), t+5) + let sb: Slice = mb[...] + sb.withMemoryRebound(to: (UInt, UInt).self) { + for i in $0.indices { + $0[i].1 -= 1 + } + } + expectEqual(mb.reduce(0,+), t) + return true + } + expectNotNil(r) +} + +UnsafeMutableBufferPointerSliceTests.test( + "slice.of.UnsafeMutableBufferPointer.initialize.repeating" +) { + let c = 4 + let mb = UnsafeMutableBufferPointer.allocate(capacity: c) + defer { mb.deallocate() } + + mb.initialize(repeating: "0") + expectTrue(mb.allSatisfy({ $0 == "0" })) + var rb = mb.deinitialize() + expectEqual(rb.count, c*MemoryLayout.stride) + + mb.initializeElement(at: 0, to: "0") + mb[1...].initialize(repeating: mb[0]) + expectTrue(mb.allSatisfy({ $0 == "0" })) + rb = mb[...].deinitialize() + expectEqual(rb.count, c*MemoryLayout.stride) +} + +UnsafeMutableBufferPointerSliceTests.test( + "slice.of.UnsafeMutableBufferPointer.initialize.from.Sequence" +) { + let c = 4 + let mb = UnsafeMutableBufferPointer.allocate(capacity: c) + defer { mb.deallocate() } + + var (it, ct) = mb.initialize(from: (0...stride) + + (it, ct) = mb[...].initialize(from: (0...stride) +} + +UnsafeMutableBufferPointerSliceTests.test( + "slice.of.UnsafeMutableBufferPointer.initialize.fromElements.Collection" +) { + let c = 4 + let mb = UnsafeMutableBufferPointer.allocate(capacity: c) + defer { mb.deallocate() } + + var ct = mb.initialize(fromElements: (1...c).map(String.init)) + expectEqual(ct, c) + expectEqual(mb.compactMap(Int.init).reduce(0,+), c*(c+1)/2) + var rb = mb.deinitialize() + expectEqual(rb.count, c*MemoryLayout.stride) + + ct = mb[...].initialize(fromElements: (1...c).map(String.init)) + expectEqual(ct, c) + expectEqual(mb.compactMap(Int.init).reduce(0,+), c*(c+1)/2) + rb = mb[...].deinitialize() + expectEqual(rb.count, c*MemoryLayout.stride) +} + +UnsafeMutableBufferPointerSliceTests.test( + "slice.of.UnsafeMutableBufferPointer.update" +) { + let c = 4 + var a = Array(repeating: " ", count: c) + var b = a + + var r: Void? = a.withContiguousMutableStorageIfAvailable { + $0.update(repeating: "") + } + expectNotNil(r) + expectTrue(a.allSatisfy(\.isEmpty)) + + r = b.withContiguousMutableStorageIfAvailable { + $0[...].update(repeating: "") + } + expectNotNil(r) + expectEqual(a, b) + + var itAndCount = a.withContiguousMutableStorageIfAvailable { + $0.update(from: Array(repeating: ".", count: c)) + } + expectNotNil(itAndCount) + expectNil(itAndCount!.0.next()) + expectEqual(itAndCount?.1, c) + + itAndCount = b.withContiguousMutableStorageIfAvailable { + $0[...].update(from: Array(repeating: ".", count: c)) + } + expectNotNil(itAndCount) + expectNil(itAndCount!.0.next()) + expectEqual(a, b) + + var i = a.withContiguousMutableStorageIfAvailable { + $0.update(fromElements: (0...allocate(capacity: c) + defer { buffer.deallocate() } + + let a = UnsafeMutableBufferPointer.allocate(capacity: c) + defer { a.deallocate() } + let b = UnsafeMutableBufferPointer.allocate(capacity: c) + defer { b.deallocate() } + + var i = buffer.initialize(fromElements: source) + expectEqual(i, c) + i = a.moveInitialize(fromElements: buffer) + expectEqual(i, c) + expectTrue(a.elementsEqual(source)) + i = buffer.initialize(fromElements: source) + expectEqual(i, c) + i = b[...].moveInitialize(fromElements: buffer) + expectEqual(i, c) + expectTrue(b.elementsEqual(source)) + + i = buffer.initialize(fromElements: source.prefix(n)) + expectEqual(i, n) + i = a.moveInitialize(fromElements: buffer.prefix(n)) + expectEqual(i, n) + expectTrue(a[...allocate(capacity: c) + defer { buffer.deallocate() } + + var a = Array(repeating: "", count: c) + var b = a + + var i: Int? + i = buffer.initialize(fromElements: source) + expectEqual(i, c) + i = a.withContiguousMutableStorageIfAvailable { + $0.moveUpdate(fromElements: buffer) + } + expectEqual(i, c) + expectEqual(a, source) + i = buffer.initialize(fromElements: source) + expectEqual(i, c) + i = b.withContiguousMutableStorageIfAvailable { + $0[...].moveUpdate(fromElements: buffer) + } + expectEqual(i, c) + expectEqual(a, b) + + i = buffer.initialize(fromElements: source.prefix(n)) + expectEqual(i, n) + i = a.withContiguousMutableStorageIfAvailable { + $0.moveUpdate(fromElements: buffer[...allocate(capacity: c) + let b = UnsafeMutableBufferPointer.allocate(capacity: c) + + a.initializeElement(at: n, to: s) + expectEqual(a[n], s) + b[...].initializeElement(at: n, to: s) + expectEqual(b[n], s) + + a.updateElement(at: n, to: t) + expectEqual(a[n], t) + b[...].initializeElement(at: n, to: t) + expectEqual(b[n], t) + + expectEqual(a.moveElement(from: n), t) + expectEqual(b[...].moveElement(from: n), t) + + a.initializeElement(at: 0, to: s) + a.deinitializeElement(at: 0) + b.initializeElement(at: 0, to: s) + b[...].deinitializeElement(at: 0) +} + +UnsafeMutableBufferPointerSliceTests.test( + "slice.of.UnsafeMutableBufferpointer.withContiguousMutableStorageIfAvailable" +) { + let c = 4 + + var a = UnsafeMutableBufferPointer.allocate(capacity: c) + defer { a.deallocate() } + a.initialize(fromElements: Array(repeating: ".", count: c)) + defer { a.deinitialize() } + + var i = a.withContiguousMutableStorageIfAvailable { + $0.update(fromElements: Array(repeating: " ", count: c)) + } + expectEqual(i, c) + expectTrue(a.allSatisfy({ $0 == " " })) + + i = a[...].withContiguousMutableStorageIfAvailable { + $0.update(fromElements: Array(repeating: "?", count: c)) + } + expectEqual(i, c) + expectTrue(a.allSatisfy({ $0 == "?" })) +} + +var UnsafeRawBufferPointerSliceTests = TestSuite( + "UnsafeRawBufferPointerSliceTests" +) + +UnsafeRawBufferPointerSliceTests.test( + "slice.of.UnsafeRawBufferPointer.bindMemory" +) { + let c = 4 + let b = UnsafeMutableRawBufferPointer.allocate( + byteCount: c * MemoryLayout.stride, + alignment: MemoryLayout.alignment + ) + defer { b.deallocate() } + + let b1 = UnsafeRawBufferPointer(b).bindMemory(to: Int.self) + var i = b1[0] + expectType(Int.self, &i) + let b2 = UnsafeRawBufferPointer(b)[...].bindMemory(to: Int.self) + i = b2[0] + expectType(Int.self, &i) + expectEqual(b1.count, b2.count) +} + +UnsafeRawBufferPointerSliceTests.test( + "slice.of.UnsafeRawBufferPointer.withMemoryRebound" +) { + let c = 4 + let m = UnsafeMutableRawBufferPointer.allocate( + byteCount: c * MemoryLayout.stride, + alignment: MemoryLayout.alignment + ) + defer { m.deallocate() } + + let b = UnsafeRawBufferPointer(m) + b.withMemoryRebound(to: Int.self) { + var v = $0[0] + expectType(Int.self, &v) + expectEqual($0.count, c) + } + + b[...].withMemoryRebound(to: Int.self, { + var v = $0[0] + expectType(Int.self, &v) + expectEqual($0.count, c) + }) +} + +UnsafeRawBufferPointerSliceTests.test( + "slice.of.UnsafeRawBufferPointer.assumingMemoryBound" +) { + let c = 4 + let array = Array(0..(0...stride * c, + alignment: 16 + ) + defer { mb.deallocate() } + + var tb = mb.initializeMemory(as: Int.self, repeating: .min) + expectEqual(tb.count, c) + expectTrue(tb.allSatisfy({ $0 == .min })) + var rb = tb.deinitialize() + expectEqual(rb.baseAddress, mb.baseAddress) + expectEqual(rb.count, mb.count) + + tb = mb[...].initializeMemory(as: Int.self, repeating: 0) + expectEqual(tb.count, c) + expectTrue(tb.allSatisfy({ $0 == 0 })) + rb = tb.deinitialize() + expectEqual(rb.baseAddress, mb.baseAddress) + expectEqual(rb.count, mb.count) +} + +UnsafeMutableRawBufferPointerSliceTests.test( + "slice.of.UnsafeMutableRawBufferPointer.initializeMemory.from.Sequence" +) { + let c = 4 + let mb = UnsafeMutableRawBufferPointer.allocate( + byteCount: MemoryLayout.stride * c, + alignment: 16 + ) + defer { mb.deallocate() } + + var (it, tb) = mb.initializeMemory(as: Int.self, from: 0...stride * c, + alignment: 16 + ) + defer { mb.deallocate() } + + var tb = mb.initializeMemory(as: Int.self, fromElements: 0...allocate(capacity: c) + defer { buffer.deallocate() } + + let rba = UnsafeMutableRawBufferPointer.allocate( + byteCount: MemoryLayout.stride * c, + alignment: 16 + ) + defer { rba.deallocate() } + let rbb = UnsafeMutableRawBufferPointer.allocate( + byteCount: MemoryLayout.stride * c, + alignment: 16 + ) + defer { rbb.deallocate() } + + expectEqual(buffer.initialize(fromElements: source), c) + var tba = rba.moveInitializeMemory(as: Int.self, fromElements: buffer) + expectEqual(tba.count, c) + expectTrue(tba.elementsEqual(source)) + + expectEqual(buffer.initialize(fromElements: source), c) + var tbb = rbb[...].moveInitializeMemory(as: Int.self, fromElements: buffer) + expectEqual(tbb.count, c) + expectTrue(tbb.elementsEqual(tba)) + + var dba = tba.deinitialize() + var dbb = tbb.deinitialize() + expectEqual(dba.count, rba.count) + expectEqual(dbb.count, rbb.count) + + expectEqual(buffer.initialize(fromElements: source.prefix(n)), n) + tba = rba.moveInitializeMemory(as: Int.self, fromElements: buffer.prefix(n)) + expectEqual(tba.count, n) + expectTrue(tba.elementsEqual(source.prefix(n))) + + expectEqual(buffer.initialize(fromElements: source.prefix(n)), n) + tbb = rbb[...].moveInitializeMemory(as: Int.self, fromElements: buffer[...stride, + alignment: MemoryLayout.alignment + ) + defer { b.deallocate() } + + let b1 = b.bindMemory(to: Int.self) + expectType(Int.self, &b1[0]) + let b2 = b[...].bindMemory(to: Int.self) + expectType(Int.self, &b2[0]) + expectEqual(b1.count, b2.count) +} + +UnsafeMutableRawBufferPointerSliceTests.test( + "slice.of.UnsafeMutableRawBufferPointer.withMemoryRebound" +) { + let c = 4 + let m = UnsafeMutableRawBufferPointer.allocate( + byteCount: c * MemoryLayout.stride, + alignment: MemoryLayout.alignment + ) + defer { m.deallocate() } + + m.withMemoryRebound(to: Int.self) { + expectType(Int.self, &$0[0]) + expectEqual($0.count, c) + } + + m[...].withMemoryRebound(to: Int.self, { + expectType(Int.self, &$0[0]) + expectEqual($0.count, c) + }) +} + +UnsafeMutableRawBufferPointerSliceTests.test( + "slice.of.UnsafeMutableRawBufferPointer.assumingMemoryBound" +) { + let c = 4 + let source = Array(0.. Date: Tue, 19 Apr 2022 13:01:36 -0600 Subject: [PATCH 17/45] [gardening] typo fix --- stdlib/public/core/UnsafeBufferPointerSlice.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/public/core/UnsafeBufferPointerSlice.swift b/stdlib/public/core/UnsafeBufferPointerSlice.swift index 1b74705904fe7..87d2a32d9dc4e 100644 --- a/stdlib/public/core/UnsafeBufferPointerSlice.swift +++ b/stdlib/public/core/UnsafeBufferPointerSlice.swift @@ -865,7 +865,7 @@ extension Slice { @_alwaysEmitIntoClient public func withMemoryRebound( to type: T.Type, _ body: (UnsafeMutableBufferPointer) throws -> Result - ) rethrows -> Result where Base == UnsafeMutableBufferPointer{ + ) rethrows -> Result where Base == UnsafeMutableBufferPointer { try Base(rebasing: self).withMemoryRebound(to: T.self, body) } From 6550fb109c84f778c8984a50af182ec7a9334609 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Tue, 31 May 2022 18:16:39 -0600 Subject: [PATCH 18/45] [stdlib] add loading and storing to and from raw buffer slices --- .../core/UnsafeBufferPointerSlice.swift | 196 ++++++++++++++++++ 1 file changed, 196 insertions(+) diff --git a/stdlib/public/core/UnsafeBufferPointerSlice.swift b/stdlib/public/core/UnsafeBufferPointerSlice.swift index 87d2a32d9dc4e..9fb9f649f9864 100644 --- a/stdlib/public/core/UnsafeBufferPointerSlice.swift +++ b/stdlib/public/core/UnsafeBufferPointerSlice.swift @@ -295,6 +295,125 @@ extension Slice where Base == UnsafeMutableRawBufferPointer { let buffer = Base(rebasing: self) return buffer.assumingMemoryBound(to: T.self) } + + /// 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. + @inlinable + @_alwaysEmitIntoClient + public func load(fromByteOffset offset: Int = 0, as type: T.Type) -> T { + let buffer = Base(rebasing: self) + return buffer.load(fromByteOffset: offset, as: T.self) + } + + /// 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. + @inlinable + @_alwaysEmitIntoClient + public func loadUnaligned( + fromByteOffset offset: Int = 0, + as type: T.Type + ) -> T { + let buffer = Base(rebasing: self) + return buffer.loadUnaligned(fromByteOffset: offset, as: T.self) + } + + /// 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`. + @inlinable + @_alwaysEmitIntoClient + public func storeBytes(of value: T, as type: T.Type) { + let buffer = Base(rebasing: self) + buffer.storeBytes(of: value, toByteOffset: 0, as: T.self) + } } extension Slice where Base == UnsafeRawBufferPointer { @@ -401,6 +520,83 @@ extension Slice where Base == UnsafeRawBufferPointer { let buffer = Base(rebasing: self) return buffer.assumingMemoryBound(to: T.self) } + + /// 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. + @inlinable + @_alwaysEmitIntoClient + public func load(fromByteOffset offset: Int = 0, as type: T.Type) -> T { + let buffer = Base(rebasing: self) + return buffer.load(fromByteOffset: offset, as: T.self) + } + + /// 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. + @inlinable + @_alwaysEmitIntoClient + public func loadUnaligned( + fromByteOffset offset: Int = 0, + as type: T.Type + ) -> T { + let buffer = Base(rebasing: self) + return buffer.loadUnaligned(fromByteOffset: offset, as: T.self) + } } extension Slice { From 254a8d4af567cbce52ce172ea5022e2eac49450b Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Mon, 15 Aug 2022 10:52:20 -0600 Subject: [PATCH 19/45] [stdlib] fix inconsistency with storeBytes on slices --- stdlib/public/core/UnsafeBufferPointerSlice.swift | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/stdlib/public/core/UnsafeBufferPointerSlice.swift b/stdlib/public/core/UnsafeBufferPointerSlice.swift index 9fb9f649f9864..594a7e469b3e3 100644 --- a/stdlib/public/core/UnsafeBufferPointerSlice.swift +++ b/stdlib/public/core/UnsafeBufferPointerSlice.swift @@ -410,9 +410,11 @@ extension Slice where Base == UnsafeMutableRawBufferPointer { /// with `type`. @inlinable @_alwaysEmitIntoClient - public func storeBytes(of value: T, as type: T.Type) { + public func storeBytes( + of value: T, toByteOffset offset: Int = 0, as type: T.Type + ) { let buffer = Base(rebasing: self) - buffer.storeBytes(of: value, toByteOffset: 0, as: T.self) + buffer.storeBytes(of: value, toByteOffset: offset, as: T.self) } } From d63747f13d5fe43754ec5b91792a97429f34212b Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Tue, 16 Aug 2022 11:17:38 -0600 Subject: [PATCH 20/45] [stdlib] remove the single-element update functions - as per an update to the proposal --- .../public/core/UnsafeBufferPointer.swift.gyb | 18 ------------------ .../public/core/UnsafeBufferPointerSlice.swift | 18 ------------------ stdlib/public/core/UnsafePointer.swift | 16 ---------------- .../stdlib/UnsafeBufferPointerSlices.swift | 13 ++++--------- 4 files changed, 4 insertions(+), 61 deletions(-) diff --git a/stdlib/public/core/UnsafeBufferPointer.swift.gyb b/stdlib/public/core/UnsafeBufferPointer.swift.gyb index 6b53026948375..ab603e2e7680f 100644 --- a/stdlib/public/core/UnsafeBufferPointer.swift.gyb +++ b/stdlib/public/core/UnsafeBufferPointer.swift.gyb @@ -938,24 +938,6 @@ extension Unsafe${Mutable}BufferPointer { p.initialize(to: value) } - /// 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 - @inlinable - @_alwaysEmitIntoClient - public func updateElement(at index: Index, to value: Element) { - precondition(startIndex <= index && index < endIndex) - let p = baseAddress._unsafelyUnwrappedUnchecked.advanced(by: index) - p.pointee = value - } - /// Retrieves and returns the element at `index`, /// leaving that element's underlying memory uninitialized. /// diff --git a/stdlib/public/core/UnsafeBufferPointerSlice.swift b/stdlib/public/core/UnsafeBufferPointerSlice.swift index 594a7e469b3e3..19341afd71f1a 100644 --- a/stdlib/public/core/UnsafeBufferPointerSlice.swift +++ b/stdlib/public/core/UnsafeBufferPointerSlice.swift @@ -952,24 +952,6 @@ extension Slice { base.baseAddress.unsafelyUnwrapped.advanced(by: index).initialize(to: value) } - /// 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 - @inlinable - @_alwaysEmitIntoClient - public func updateElement(at index: Index, to value: Element) - where Base == UnsafeMutableBufferPointer { - assert(startIndex <= index && index < endIndex) - base.baseAddress.unsafelyUnwrapped.advanced(by: index).pointee = value - } - /// Retrieves and returns the element at `index`, /// leaving that element's underlying memory uninitialized. /// diff --git a/stdlib/public/core/UnsafePointer.swift b/stdlib/public/core/UnsafePointer.swift index 5afd307c24bac..7dd339b31f260 100644 --- a/stdlib/public/core/UnsafePointer.swift +++ b/stdlib/public/core/UnsafePointer.swift @@ -796,22 +796,6 @@ public struct UnsafeMutablePointer: _Pointer { update(repeating: repeatedValue, count: count) } - /// 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. - @inlinable - @_alwaysEmitIntoClient - public func update(_ value: Pointee) { - pointee = value - } - /// Update this pointer's initialized memory with the specified number of /// instances, copied from the given pointer's memory. /// diff --git a/validation-test/stdlib/UnsafeBufferPointerSlices.swift b/validation-test/stdlib/UnsafeBufferPointerSlices.swift index b601be2a134d9..a3f74a4db6b7a 100644 --- a/validation-test/stdlib/UnsafeBufferPointerSlices.swift +++ b/validation-test/stdlib/UnsafeBufferPointerSlices.swift @@ -263,17 +263,12 @@ UnsafeMutableBufferPointerSliceTests.test( b[...].initializeElement(at: n, to: s) expectEqual(b[n], s) - a.updateElement(at: n, to: t) - expectEqual(a[n], t) - b[...].initializeElement(at: n, to: t) - expectEqual(b[n], t) + expectEqual(a.moveElement(from: n), s) + expectEqual(b[...].moveElement(from: n), s) - expectEqual(a.moveElement(from: n), t) - expectEqual(b[...].moveElement(from: n), t) - - a.initializeElement(at: 0, to: s) + a.initializeElement(at: 0, to: t) a.deinitializeElement(at: 0) - b.initializeElement(at: 0, to: s) + b.initializeElement(at: 0, to: t) b[...].deinitializeElement(at: 0) } From d86b727c80803c736a572ed2d0ee90b5ef0e8b02 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Mon, 15 Aug 2022 15:50:44 -0600 Subject: [PATCH 21/45] [test] add tests for `load` and `store` from slices --- .../stdlib/UnsafeBufferPointerSlices.swift | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/validation-test/stdlib/UnsafeBufferPointerSlices.swift b/validation-test/stdlib/UnsafeBufferPointerSlices.swift index a3f74a4db6b7a..eae5200b63a4d 100644 --- a/validation-test/stdlib/UnsafeBufferPointerSlices.swift +++ b/validation-test/stdlib/UnsafeBufferPointerSlices.swift @@ -563,4 +563,73 @@ UnsafeMutableRawBufferPointerSliceTests.test( }) } +UnsafeMutableRawBufferPointerSliceTests.test( + "slice.of.UnsafeMutableRawBufferPointer.load" +) { + let count = 4 + let sizeInBytes = count * MemoryLayout.stride + let b = UnsafeMutableRawBufferPointer.allocate( + byteCount: sizeInBytes, alignment: MemoryLayout.alignment + ) + defer { + b.deallocate() + } + b.withMemoryRebound(to: Int.self) { + var (i, c) = $0.update(from: 1...count) + expectEqual(c, count) + expectNil(i.next()) + } + expectEqual( + 1, b[...].load(as: Int.self) + ) + expectEqual( + 2, b[...].load(fromByteOffset: MemoryLayout.stride, as: Int.self) + ) + expectEqual( + 3, b[MemoryLayout.stride...].load( + fromByteOffset: MemoryLayout.stride, as: Int.self + ) + ) +} + +UnsafeMutableRawBufferPointerSliceTests.test( + "slice.of.UnsafeMutableRawBufferPointer.loadUnaligned" +) { + let count = 4 + let sizeInBytes = count * MemoryLayout.stride + let b = UnsafeMutableRawBufferPointer.allocate( + byteCount: sizeInBytes, alignment: MemoryLayout.alignment + ) + defer { + b.deallocate() + } + b.copyBytes(from: 0...stride + let b = UnsafeMutableRawBufferPointer.allocate( + byteCount: sizeInBytes, alignment: MemoryLayout.alignment + ) + defer { + b.deallocate() + } + b.copyBytes(from: repeatElement(0, count: sizeInBytes)) + expectEqual(b[0], 0) + b[...].storeBytes(of: .max, as: UInt8.self) + expectEqual(b[0], .max) + expectTrue(b[3..<3+MemoryLayout.size].allSatisfy({ $0 == 0 })) + b[3...].storeBytes(of: .max, toByteOffset: 4, as: UInt.self) + expectTrue(b[7..<7+MemoryLayout.size].allSatisfy({ $0 == .max })) +} + runAllTests() From 26e5c43aa31d4818bfd3f5d7ebb14ac33869dad1 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Wed, 24 Aug 2022 12:38:14 -0600 Subject: [PATCH 22/45] [se-0370] update documentation to track proposal for the functions involving `fromContentsOf:`. --- .../public/core/UnsafeBufferPointer.swift.gyb | 191 ++++++----- .../core/UnsafeBufferPointerSlice.swift | 303 ++++++++++-------- .../core/UnsafeRawBufferPointer.swift.gyb | 95 +++--- 3 files changed, 346 insertions(+), 243 deletions(-) diff --git a/stdlib/public/core/UnsafeBufferPointer.swift.gyb b/stdlib/public/core/UnsafeBufferPointer.swift.gyb index ab603e2e7680f..9fa309d1cc06f 100644 --- a/stdlib/public/core/UnsafeBufferPointer.swift.gyb +++ b/stdlib/public/core/UnsafeBufferPointer.swift.gyb @@ -676,31 +676,32 @@ extension Unsafe${Mutable}BufferPointer { return source._copyContents(initializing: self) } - /// Initializes the buffer's memory with the given elements. + /// Initializes the buffer's memory with every element of the source. /// - /// Prior to calling the `initialize(fromElements:)` method on a buffer, - /// the memory it references must be uninitialized, - /// or its `Element` type must be a trivial type. After the call, + /// Prior to calling the `initialize(fromContentsOf:)` 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 buffer must reference enough memory to accommodate + /// `source.count` elements. /// /// 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`. + /// in the buffer, one past the index of the last element written. + /// If `source` contains no elements, the returned index is equal to the + /// buffer's `startIndex`. If `source` contains as many elements as the buffer + /// can hold, the returned index is equal to the buffer's `endIndex`. + /// + /// - Precondition: `self.count` >= `source.count` /// - /// - Parameter fromElements: A collection of elements to be used to + /// - Parameter source: 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`. - @discardableResult + /// - Returns: An index to the next uninitialized element in the buffer. @inlinable @_alwaysEmitIntoClient - public func initialize( - fromElements source: C - ) -> Index where C.Element == Element { + public func initialize( + fromContentsOf source: some Collection + ) -> Index { let count = Swift.min(self.count, source.count) guard count > 0, let base = baseAddress else { return startIndex } @@ -773,21 +774,29 @@ extension Unsafe${Mutable}BufferPointer { return (iterator, endIndex) } - /// Updates the buffer's initialized memory with the given elements. + /// Updates the buffer's initialized memory with every element of the source. /// - /// The buffer’s memory must be initialized or its `Element` type - /// must be a trivial type. + /// Prior to calling the `update(fromContentsOf:)` method on a buffer, + /// the first `source.count` elements of the buffer's memory must be + /// initialized, or the buffer's `Element` type must be a trivial type. + /// The buffer must reference enough initialized memory to accommodate + /// `source.count` elements. /// - /// - Parameter fromElements: A collection of elements to be used to update + /// The returned index is one past the index of the last element updated. + /// If `source` contains no elements, the returned index is equal to the + /// buffer's `startIndex`. If `source` contains as many elements as the buffer + /// can hold, the returned index is equal to the buffer's `endIndex`. + /// + /// - Precondition: `self.count` >= `source.count` + /// + /// - Parameter source: 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`. - @discardableResult + /// - Returns: An index one past the index of the last element updated. @inlinable @_alwaysEmitIntoClient - public func update( - fromElements source: C - ) -> Index where C.Element == Element { + public func update( + fromContentsOf source: some Collection + ) -> Index { let count = Swift.min(source.count, self.count) guard count > 0, let base = baseAddress else { return startIndex } @@ -805,24 +814,34 @@ extension Unsafe${Mutable}BufferPointer { } /// Moves every element of an initialized source buffer into the - /// uninitialized memory referenced by this buffer, leaving the - /// source memory uninitialized and this buffer's memory initialized. + /// uninitialized memory referenced by this buffer, leaving the source memory + /// uninitialized and this buffer's memory initialized. + /// + /// Prior to calling the `moveInitialize(fromContentsOf:)` method on a buffer, + /// the memory it references must be uninitialized, + /// or its `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 memory referenced by + /// `source` is uninitialized after the function returns. + /// The buffer must reference enough memory to accommodate + /// `source.count` elements. + /// + /// The returned index is the position of the next uninitialized element + /// in the buffer, one past the index of the last element written. + /// If `source` contains no elements, the returned index is equal to the + /// buffer's `startIndex`. If `source` contains as many elements as the buffer + /// can hold, the returned index is equal to the buffer's `endIndex`. /// - /// 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. + /// - Precondition: `self.count` >= `source.count` /// /// - 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. + /// 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`. - @discardableResult + /// or `endIndex`. @inlinable @_alwaysEmitIntoClient - public func moveInitialize(fromElements source: Self) -> Index { + public func moveInitialize(fromContentsOf source: Self) -> Index { guard let pointer = source.baseAddress, source.count > 0 else { return 0 } _debugPrecondition(count >= source.count) baseAddress._unsafelyUnwrappedUnchecked.moveInitialize(from: pointer, @@ -830,47 +849,63 @@ extension Unsafe${Mutable}BufferPointer { return startIndex.advanced(by: source.count) } - /// Moves every element of an initialized source buffer slice into the - /// uninitialized memory referenced by this buffer, leaving the - /// source memory uninitialized and this buffer's memory initialized. + /// Moves every element of an initialized source buffer into the + /// uninitialized memory referenced by this buffer, leaving the source memory + /// uninitialized and this buffer's memory initialized. + /// + /// Prior to calling the `moveInitialize(fromContentsOf:)` method on a buffer, + /// the memory it references must be uninitialized, + /// or its `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 memory referenced by + /// `source` is uninitialized after the function returns. + /// The buffer must reference enough memory to accommodate + /// `source.count` elements. + /// + /// The returned index is the position of the next uninitialized element + /// in the buffer, one past the index of the last element written. + /// If `source` contains no elements, the returned index is equal to the + /// buffer's `startIndex`. If `source` contains as many elements as the buffer + /// can hold, the returned index is equal to the buffer's `endIndex`. /// - /// 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. + /// - Precondition: `self.count` >= `source.count` /// /// - 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`. - @discardableResult + /// 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`. @inlinable @_alwaysEmitIntoClient - public func moveInitialize(fromElements source: Slice) -> Index { - return moveInitialize(fromElements: Self(rebasing: source)) + public func moveInitialize(fromContentsOf source: Slice) -> Index { + return moveInitialize(fromContentsOf: Self(rebasing: source)) } /// Updates this buffer'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 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. + /// Prior to calling the `moveUpdate(fromContentsOf:)` method on a buffer, + /// the first `source.count` elements of the buffer's memory must be + /// initialized, or the buffer's `Element` type must be a trivial type. + /// The memory referenced by `source` is uninitialized after the function + /// returns. The buffer must reference enough initialized memory + /// to accommodate `source.count` elements. + /// + /// The returned index is one past the index of the last element updated. + /// If `source` contains no elements, the returned index is equal to the + /// buffer's `startIndex`. If `source` contains as many elements as the buffer + /// can hold, the returned index is equal to the buffer's `endIndex`. + /// + /// - Precondition: `self.count` >= `source.count` /// /// - 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`. - @discardableResult + /// The memory region underlying `source` must be initialized. The memory + /// regions referenced by `source` and this buffer must not overlap. + /// - Returns: An index one past the index of the last element updated. @inlinable @_alwaysEmitIntoClient - public func moveUpdate(fromElements source: Self) -> Index { + public func moveUpdate(fromContentsOf source: Self) -> Index { guard let pointer = source.baseAddress, source.count > 0 else { return 0 } _debugPrecondition(count >= source.count) baseAddress._unsafelyUnwrappedUnchecked.moveUpdate(from: pointer, @@ -882,22 +917,28 @@ extension Unsafe${Mutable}BufferPointer { /// moving every element from the source buffer slice, /// leaving the source memory uninitialized. /// - /// The region of memory starting at the beginning of this buffer 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. + /// Prior to calling the `moveUpdate(fromContentsOf:)` method on a buffer, + /// the first `source.count` elements of the buffer's memory must be + /// initialized, or the buffer's `Element` type must be a trivial type. + /// The memory referenced by `source` is uninitialized after the function + /// returns. The buffer must reference enough initialized memory + /// to accommodate `source.count` elements. /// - /// - Parameter source: A buffer containing the values to move. + /// The returned index is one past the index of the last element updated. + /// If `source` contains no elements, the returned index is equal to the + /// buffer's `startIndex`. If `source` contains as many elements as the buffer + /// can hold, the returned index is equal to the buffer's `endIndex`. + /// + /// - Precondition: `self.count` >= `source.count` + /// + /// - Parameter source: A buffer slice 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`. - @discardableResult + /// - Returns: An index one past the index of the last element updated. @inlinable @_alwaysEmitIntoClient - public func moveUpdate(fromElements source: Slice) -> Index { - return moveUpdate(fromElements: Self(rebasing: source)) + public func moveUpdate(fromContentsOf source: Slice) -> Index { + return moveUpdate(fromContentsOf: Self(rebasing: source)) } /// Deinitializes every instance in this buffer. diff --git a/stdlib/public/core/UnsafeBufferPointerSlice.swift b/stdlib/public/core/UnsafeBufferPointerSlice.swift index 19341afd71f1a..a89de686c7fcc 100644 --- a/stdlib/public/core/UnsafeBufferPointerSlice.swift +++ b/stdlib/public/core/UnsafeBufferPointerSlice.swift @@ -96,101 +96,111 @@ extension Slice where Base == UnsafeMutableRawBufferPointer { return buffer.initializeMemory(as: S.Element.self, from: source) } - /// 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 + /// Initializes the buffer slice's memory with every element of the source, + /// binding the initialized memory to the elements' type. + /// + /// When calling the `initializeMemory(as:fromContentsOf:)` method, + /// the memory referenced by the buffer slice must be uninitialized, + /// or initialized to a trivial type. The buffer slice must reference + /// enough memory to store `source.count` elements, and it + /// must be properly aligned for accessing `C.Element`. + /// + /// This method initializes the buffer with the contents of `source` + /// until `source` is exhausted. + /// After calling `initializeMemory(as:fromContentsOf:)`, 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. + /// to the type of `C.Element` and is initialized. This method does not change + /// the binding state of the unused portion of the buffer slice, 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`. - @discardableResult + /// - source: A collection of elements to be used to + /// initialize the buffer slice's storage. + /// - Returns: A typed buffer referencing the initialized elements. + /// The returned buffer references memory starting at the same + /// base address as this slice, and its count is equal to `source.count` @inlinable @_alwaysEmitIntoClient public func initializeMemory( as type: C.Element.Type, - fromElements source: C + fromContentsOf source: C ) -> UnsafeMutableBufferPointer { let buffer = Base(rebasing: self) - return buffer.initializeMemory(as: C.Element.self, fromElements: source) + return buffer.initializeMemory(as: C.Element.self, fromContentsOf: source) } - /// 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 + /// Moves every element of an initialized source buffer into the + /// uninitialized memory referenced by this buffer slice, leaving + /// the source memory uninitialized and this slice's memory initialized. + /// + /// When calling the `moveInitializeMemory(as:fromContentsOf:)` method, + /// the memory referenced by the buffer slice must be uninitialized, + /// or initialized to a trivial type. The buffer slice must reference + /// enough memory to store `source.count` elements, and it must be properly + /// aligned for accessing `C.Element`. After the method returns, + /// the memory referenced by the returned buffer is initialized and the /// memory region underlying `source` is uninitialized. /// + /// This method initializes the buffer slice with the contents of `source` + /// until `source` is exhausted. + /// After calling `initializeMemory(as:fromContentsOf:)`, the memory + /// referenced by the returned `UnsafeMutableBufferPointer` instance is bound + /// to the type of `T` and is initialized. This method does not change + /// the binding state of the unused portion of the buffer slice, if any. + /// /// - Parameters: /// - type: The type of element to which this buffer's memory will be bound. - /// - fromElements: A buffer containing the values to copy. + /// - source: A buffer referencing 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`. - @discardableResult + /// The memory regions referenced by `source` and this slice may overlap. + /// - Returns: A typed buffer referencing the initialized elements. + /// The returned buffer references memory starting at the same + /// base address as this slice, and its count is equal to `source.count`. @inlinable @_alwaysEmitIntoClient public func moveInitializeMemory( as type: T.Type, - fromElements source: UnsafeMutableBufferPointer + fromContentsOf source: UnsafeMutableBufferPointer ) -> UnsafeMutableBufferPointer { let buffer = Base(rebasing: self) - return buffer.moveInitializeMemory(as: T.self, fromElements: source) + return buffer.moveInitializeMemory(as: T.self, fromContentsOf: source) } - /// 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. + /// Moves every element from an initialized source buffer slice into the + /// uninitialized memory referenced by this buffer slice, leaving + /// the source memory uninitialized and this slice's memory initialized. + /// + /// When calling the `moveInitializeMemory(as:fromContentsOf:)` method, + /// the memory referenced by the buffer slice must be uninitialized, + /// or initialized to a trivial type. The buffer slice must reference + /// enough memory to store `source.count` elements, and it must be properly + /// aligned for accessing `C.Element`. After the method returns, + /// the memory referenced by the returned buffer is initialized and the + /// memory region underlying `source` is uninitialized. /// - /// 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> + fromContentsOf source: Slice> ) -> UnsafeMutableBufferPointer { let buffer = Base(rebasing: self) - return buffer.moveInitializeMemory(as: T.self, fromElements: source) + return buffer.moveInitializeMemory(as: T.self, fromContentsOf: source) } /// Binds this buffer’s memory to the specified type and returns a typed buffer @@ -718,34 +728,33 @@ extension Slice { return (iterator, startIndex.advanced(by: distance)) } - /// Initializes the buffer slice's memory with the given elements. + /// Initializes the buffer slice's memory with with every element of the source. /// - /// Prior to calling the `initialize(fromElements:)` method on a buffer slice, - /// the memory it references must be uninitialized, + /// Prior to calling the `initialize(fromContentsOf:)` 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`. + /// The returned index is the index of the next uninitialized element + /// in the buffer slice, one past the index of the last element written. + /// If `source` contains no elements, the returned index is equal to + /// the buffer's `startIndex`. If `source` contains as many elements + /// as the buffer slice can hold, the returned index is equal to + /// to the slice'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`. - @discardableResult + /// - Parameter source: A collection of elements to be used to + /// initialize the buffer's storage. + /// - Returns: An index to the next uninitialized element in the + /// buffer slice, or `endIndex`. @discardableResult @inlinable @_alwaysEmitIntoClient public func initialize( - fromElements source: C + fromContentsOf source: C ) -> Index where C : Collection, Base == UnsafeMutableBufferPointer { let buffer = Base(rebasing: self) - let index = buffer.initialize(fromElements: source) + let index = buffer.initialize(fromContentsOf: source) let distance = buffer.distance(from: buffer.startIndex, to: index) return startIndex.advanced(by: distance) } @@ -787,24 +796,32 @@ extension Slice { return (iterator, startIndex.advanced(by: distance)) } - /// Updates the buffer slice's initialized memory with the given elements. + /// Updates the buffer slice's initialized memory with every element of the source. /// - /// The buffer slice's memory must be initialized or the buffer's `Element` type - /// must be a trivial type. + /// Prior to calling the `update(fromContentsOf:)` method on a buffer + /// slice, the first `source.count` elements of the referenced memory must be + /// initialized, or the buffer's `Element` type must be a trivial type. + /// The buffer must reference enough initialized memory to accommodate + /// `source.count` elements. /// - /// - 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`. - @discardableResult + /// The returned index is one past the index of the last element updated. + /// If `source` contains no elements, the returned index is equal to the + /// buffer's `startIndex`. If `source` contains as many elements as the buffer + /// slice can hold, the returned index is equal to the slice's `endIndex`. + /// + /// - Precondition: `self.count` >= `source.count` + /// + /// - Parameter source: A collection of elements to be used to update + /// the buffer's contents. + /// - Returns: An index one past the index of the last element updated. @inlinable @_alwaysEmitIntoClient public func update( - fromElements source: C + fromContentsOf source: C ) -> Index where C: Collection, Base == UnsafeMutableBufferPointer { let buffer = Base(rebasing: self) - let index = buffer.update(fromElements: source) + let index = buffer.update(fromContentsOf: source) let distance = buffer.distance(from: buffer.startIndex, to: index) return startIndex.advanced(by: distance) } @@ -813,25 +830,35 @@ extension Slice { /// 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. + /// Prior to calling the `moveInitialize(fromContentsOf:)` method on a + /// buffer slice, the memory it references must be uninitialized, + /// or its `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 memory referenced by + /// `source` is uninitialized after the function returns. + /// The buffer slice must reference enough memory to accommodate + /// `source.count` elements. /// - /// - 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. + /// The returned index is the position of the next uninitialized element + /// in the buffer slice, one past the index of the last element written. + /// If `source` contains no elements, the returned index is equal to the + /// slice's `startIndex`. If `source` contains as many elements as the slice + /// can hold, the returned index is equal to the slice's `endIndex`. + /// + /// - Precondition: `self.count` >= `source.count` + /// + /// - 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`. - @discardableResult + /// or `endIndex`. @inlinable @_alwaysEmitIntoClient public func moveInitialize( - fromElements source: UnsafeMutableBufferPointer + fromContentsOf source: UnsafeMutableBufferPointer ) -> Index where Base == UnsafeMutableBufferPointer { let buffer = Base(rebasing: self) - let index = buffer.moveInitialize(fromElements: source) + let index = buffer.moveInitialize(fromContentsOf: source) let distance = buffer.distance(from: buffer.startIndex, to: index) return startIndex.advanced(by: distance) } @@ -840,25 +867,35 @@ extension Slice { /// 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. + /// Prior to calling the `moveInitialize(fromContentsOf:)` method on a + /// buffer slice, the memory it references must be uninitialized, + /// or its `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 memory referenced by + /// `source` is uninitialized after the function returns. + /// The buffer slice must reference enough memory to accommodate + /// `source.count` elements. /// - /// - 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`. - @discardableResult + /// The returned index is the position of the next uninitialized element + /// in the buffer slice, one past the index of the last element written. + /// If `source` contains no elements, the returned index is equal to the + /// slice's `startIndex`. If `source` contains as many elements as the slice + /// can hold, the returned index is equal to the slice's `endIndex`. + /// + /// - Precondition: `self.count` >= `source.count` + /// + /// - Parameter source: A buffer slice containing the values to copy. + /// The memory region underlying `source` must be initialized. The memory + /// regions referenced by `source` and this buffer slice may overlap. + /// - Returns: An index to the next uninitialized element in the buffer, + /// or `endIndex`. @inlinable @_alwaysEmitIntoClient public func moveInitialize( - fromElements source: Slice> + fromContentsOf source: Slice> ) -> Index where Base == UnsafeMutableBufferPointer { let buffer = Base(rebasing: self) - let index = buffer.moveInitialize(fromElements: source) + let index = buffer.moveInitialize(fromContentsOf: source) let distance = buffer.distance(from: buffer.startIndex, to: index) return startIndex.advanced(by: distance) } @@ -868,24 +905,29 @@ extension 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 + /// covering `source.count` instances of its `Element` type must be /// initialized, or `Element` must be a trivial type. After calling - /// `moveUpdate(fromElements:)`, + /// `moveUpdate(fromContentsOf:)`, /// the region of memory underlying `source` is uninitialized. /// + /// The returned index is one past the index of the last element updated. + /// If `source` contains no elements, the returned index is equal to the + /// buffer's `startIndex`. If `source` contains as many elements as the buffer + /// slice can hold, the returned index is equal to the slice's `endIndex`. + /// + /// - Precondition: `self.count` >= `source.count` + /// /// - 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`. - @discardableResult + /// The memory region underlying `source` must be initialized. The memory + /// regions referenced by `source` and this buffer slice must not overlap. + /// - Returns: An index one past the index of the last element updated. @inlinable @_alwaysEmitIntoClient public func moveUpdate( - fromElements source: UnsafeMutableBufferPointer + fromContentsOf source: UnsafeMutableBufferPointer ) -> Index where Base == UnsafeMutableBufferPointer { let buffer = Base(rebasing: self) - let index = buffer.moveUpdate(fromElements: source) + let index = buffer.moveUpdate(fromContentsOf: source) let distance = buffer.distance(from: buffer.startIndex, to: index) return startIndex.advanced(by: distance) } @@ -895,24 +937,29 @@ extension 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 + /// covering `source.count` instances of its `Element` type must be /// initialized, or `Element` must be a trivial type. After calling - /// `moveUpdate(fromElements:)`, + /// `moveUpdate(fromContentsOf:)`, /// 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`. - @discardableResult + /// The returned index is one past the index of the last element updated. + /// If `source` contains no elements, the returned index is equal to the + /// buffer's `startIndex`. If `source` contains as many elements as the buffer + /// slice can hold, the returned index is equal to the slice's `endIndex`. + /// + /// - Precondition: `self.count` >= `source.count` + /// + /// - Parameter source: A buffer slice containing the values to move. + /// The memory region underlying `source` must be initialized. The memory + /// regions referenced by `source` and this buffer slice must not overlap. + /// - Returns: An index one past the index of the last element updated. @inlinable @_alwaysEmitIntoClient public func moveUpdate( - fromElements source: Slice> + fromContentsOf source: Slice> ) -> Index where Base == UnsafeMutableBufferPointer { let buffer = Base(rebasing: self) - let index = buffer.moveUpdate(fromElements: source) + let index = buffer.moveUpdate(fromContentsOf: source) let distance = buffer.distance(from: buffer.startIndex, to: index) return startIndex.advanced(by: distance) } diff --git a/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb b/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb index a7ceb6d49eb72..c9d96b5878a21 100644 --- a/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb +++ b/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb @@ -784,34 +784,34 @@ extension Unsafe${Mutable}RawBufferPointer { count: idx / elementStride)) } - /// 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 + /// Initializes the buffer's memory with every element of the source, + /// binding the initialized memory to the elements' type. + /// + /// When calling the `initializeMemory(as:fromContentsOf:)` method, + /// the memory referenced by the buffer must be uninitialized, or initialized + /// to a trivial type. The buffer must reference enough memory to store + /// `source.count` elements, and its `baseAddress` must be properly aligned + /// for accessing `C.Element`. + /// + /// This method initializes the buffer with the contents of `source` + /// until `source` is exhausted. + /// After calling `initializeMemory(as:fromContentsOf:)`, 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. + /// to the type `C.Element` and is initialized. This method does not change + /// the binding state of the unused portion of the buffer, 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 + /// - source: A collection of elements to be used to /// initialize the buffer's storage. - /// - Returns: A typed buffer containing the initialized elements. + /// - Returns: A typed buffer referencing 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`. - @discardableResult + /// base address as this buffer, and its count is equal to `source.count` @inlinable @_alwaysEmitIntoClient public func initializeMemory( as type: C.Element.Type, - fromElements source: C + fromContentsOf source: C ) -> UnsafeMutableBufferPointer { var count = source.count guard let base = _position, let end = _end, end > base, count > 0 else { @@ -836,31 +836,38 @@ extension Unsafe${Mutable}RawBufferPointer { return UnsafeMutableBufferPointer(start: start, count: count) } - /// Moves every instance of an initialized source buffer into the + /// Moves every element of 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:fromElements:)` method on - /// a buffer `b`, the memory referenced by `b` must be uninitialized, - /// or must be be initialized to a trivial type. The base address of `b` must - /// be properly aligned for accessing `C.Element`. After the method returns, + /// When calling the `moveInitializeMemory(as:fromContentsOf:)` method, + /// the memory referenced by the buffer must be uninitialized, or initialized + /// to a trivial type. The buffer must reference enough memory to store + /// `source.count` elements, and its `baseAddress` must be properly aligned + /// for accessing `C.Element`. After the method returns, /// the memory referenced by the returned buffer is initialized and the /// memory region underlying `source` is uninitialized. /// + /// This method initializes the buffer with the contents of `source` + /// until `source` is exhausted. + /// After calling `initializeMemory(as:fromContentsOf:)`, the memory + /// referenced by the returned `UnsafeMutableBufferPointer` instance is bound + /// to the type `T` and is initialized. This method does not change + /// the binding state of the unused portion of the buffer, if any. + /// /// - Parameters: /// - type: The type of element to which this buffer's memory will be bound. - /// - fromElements: A buffer containing the values to copy. + /// - source: A buffer referencing 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 it contains every element copied from `source`. - @discardableResult + /// - Returns: A typed buffer referencing the initialized elements. + /// The returned buffer references memory starting at the same + /// base address as this buffer, and its count is equal to `source.count`. @inlinable @_alwaysEmitIntoClient public func moveInitializeMemory( as type: T.Type, - fromElements source: UnsafeMutableBufferPointer + fromContentsOf source: UnsafeMutableBufferPointer ) -> UnsafeMutableBufferPointer { guard let sourceBase = source.baseAddress else { return UnsafeMutableBufferPointer(start: nil, count: 0) } @@ -875,34 +882,42 @@ extension Unsafe${Mutable}RawBufferPointer { return UnsafeMutableBufferPointer(start: initialized, count: source.count) } - /// Moves every instance of an initialized source buffer slice into the + /// Moves every element of an initialized source buffer slice into the /// uninitialized memory referenced by this buffer, leaving the source memory /// uninitialized and this buffer's memory initialized. /// - /// When calling the `moveInitializeMemory(as:fromElements:)` method on - /// a buffer `b`, the memory referenced by `b` must be uninitialized, - /// or must be be initialized to a trivial type. The base address of `b` must - /// be properly aligned for accessing `C.Element`. After the method returns, + /// When calling the `moveInitializeMemory(as:fromContentsOf:)` method, + /// the memory referenced by the buffer must be uninitialized, or initialized + /// to a trivial type. The buffer must reference enough memory to store + /// `source.count` elements, and its `baseAddress` must be properly aligned + /// for accessing `C.Element`. After the method returns, /// the memory referenced by the returned buffer is initialized and the /// memory region underlying `source` is uninitialized. /// + /// This method initializes the buffer with the contents of `source` + /// until `source` is exhausted. + /// After calling `initializeMemory(as:fromContentsOf:)`, the memory + /// referenced by the returned `UnsafeMutableBufferPointer` instance is bound + /// to the type `T` and is initialized. This method does not change + /// the binding state of the unused portion of the buffer, if any. + /// /// - Parameters: /// - type: The type of element to which this buffer's memory will be bound. - /// - fromElements: A buffer containing the values to copy. + /// - source: A buffer referencing 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 it contains every element copied from `source`. + /// - Returns: A typed buffer referencing the initialized elements. + /// The returned buffer references memory starting at the same + /// base address as this buffer, and its count is equal to `source.count`. @discardableResult @inlinable @_alwaysEmitIntoClient public func moveInitializeMemory( as type: T.Type, - fromElements source: Slice> + fromContentsOf source: Slice> ) -> UnsafeMutableBufferPointer { let rebased = UnsafeMutableBufferPointer(rebasing: source) - return moveInitializeMemory(as: T.self, fromElements: rebased) + return moveInitializeMemory(as: T.self, fromContentsOf: rebased) } % end # mutable From 0a78756bf487ea1f185a2389da34ae1fc500bd8f Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Tue, 23 Aug 2022 17:11:53 -0600 Subject: [PATCH 23/45] [se-0370] add element labels to a returned tuple - this is technically source-breaking, but the risk seems to be very low. --- stdlib/public/core/UnsafeBufferPointer.swift.gyb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/stdlib/public/core/UnsafeBufferPointer.swift.gyb b/stdlib/public/core/UnsafeBufferPointer.swift.gyb index 9fa309d1cc06f..a280e1c5e7a30 100644 --- a/stdlib/public/core/UnsafeBufferPointer.swift.gyb +++ b/stdlib/public/core/UnsafeBufferPointer.swift.gyb @@ -671,8 +671,10 @@ extension Unsafe${Mutable}BufferPointer { /// - 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. @inlinable // unsafe-performance - public func initialize(from source: S) -> (S.Iterator, Index) - where S.Element == Element { + @_silgen_name("$sSr10initialize4from8IteratorQyd___Sitqd___t7ElementQyd__RszSTRd__lF") + public func initialize( + from source: S + ) -> (unwritten: S.Iterator, index: Index) where S.Element == Element { return source._copyContents(initializing: self) } From 8ed1fc739ffebd95432246538b4764fe2ea57656 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Thu, 25 Aug 2022 05:08:02 -0600 Subject: [PATCH 24/45] [abi] override the judgment of the abi stability test --- test/api-digester/stability-stdlib-abi-without-asserts.test | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/api-digester/stability-stdlib-abi-without-asserts.test b/test/api-digester/stability-stdlib-abi-without-asserts.test index 7ab928c158327..6e17ea6853748 100644 --- a/test/api-digester/stability-stdlib-abi-without-asserts.test +++ b/test/api-digester/stability-stdlib-abi-without-asserts.test @@ -100,6 +100,11 @@ Func UnsafeMutablePointer.assign(from:count:) has been removed Func UnsafeMutablePointer.assign(repeating:count:) has been removed Func UnsafeMutablePointer.moveAssign(from:count:) has been removed +// These haven't actually been removed; they were renamed at the source level while +// retaining their old mangled name. The source break was accepted as part of se-0370. +Func UnsafeMutableBufferPointer.initialize(from:) has mangled name changing from 'Swift.UnsafeMutableBufferPointer.initialize(from: A1) -> (A1.Iterator, Swift.Int)' to 'Swift.UnsafeMutableBufferPointer.initialize(from: A1) -> (unwritten: A1.Iterator, index: Swift.Int)' +Func UnsafeMutableBufferPointer.initialize(from:) has return type change from (τ_1_0.Iterator, Swift.Int) to (unwritten: τ_1_0.Iterator, index: Swift.Int) + // These haven't actually been removed; they are simply marked unavailable. // This seems to be a false positive in the ABI checker. This is not an ABI // break because the symbols are still present. From 3e22d3a2bc828d8695c3cdd2dc920b231052feed Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Wed, 24 Aug 2022 21:20:48 -0600 Subject: [PATCH 25/45] [test] update to use the `fromContentsOf` argument label --- .../stdlib/UnsafeBufferPointerSlices.swift | 70 +++++++++---------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/validation-test/stdlib/UnsafeBufferPointerSlices.swift b/validation-test/stdlib/UnsafeBufferPointerSlices.swift index eae5200b63a4d..edb067f860ef0 100644 --- a/validation-test/stdlib/UnsafeBufferPointerSlices.swift +++ b/validation-test/stdlib/UnsafeBufferPointerSlices.swift @@ -99,19 +99,19 @@ UnsafeMutableBufferPointerSliceTests.test( } UnsafeMutableBufferPointerSliceTests.test( - "slice.of.UnsafeMutableBufferPointer.initialize.fromElements.Collection" + "slice.of.UnsafeMutableBufferPointer.initialize.fromContentsOf.Collection" ) { let c = 4 let mb = UnsafeMutableBufferPointer.allocate(capacity: c) defer { mb.deallocate() } - var ct = mb.initialize(fromElements: (1...c).map(String.init)) + var ct = mb.initialize(fromContentsOf: (1...c).map(String.init)) expectEqual(ct, c) expectEqual(mb.compactMap(Int.init).reduce(0,+), c*(c+1)/2) var rb = mb.deinitialize() expectEqual(rb.count, c*MemoryLayout.stride) - ct = mb[...].initialize(fromElements: (1...c).map(String.init)) + ct = mb[...].initialize(fromContentsOf: (1...c).map(String.init)) expectEqual(ct, c) expectEqual(mb.compactMap(Int.init).reduce(0,+), c*(c+1)/2) rb = mb[...].deinitialize() @@ -152,13 +152,13 @@ UnsafeMutableBufferPointerSliceTests.test( expectEqual(a, b) var i = a.withContiguousMutableStorageIfAvailable { - $0.update(fromElements: (0...allocate(capacity: c) defer { b.deallocate() } - var i = buffer.initialize(fromElements: source) + var i = buffer.initialize(fromContentsOf: source) expectEqual(i, c) - i = a.moveInitialize(fromElements: buffer) + i = a.moveInitialize(fromContentsOf: buffer) expectEqual(i, c) expectTrue(a.elementsEqual(source)) - i = buffer.initialize(fromElements: source) + i = buffer.initialize(fromContentsOf: source) expectEqual(i, c) - i = b[...].moveInitialize(fromElements: buffer) + i = b[...].moveInitialize(fromContentsOf: buffer) expectEqual(i, c) expectTrue(b.elementsEqual(source)) - i = buffer.initialize(fromElements: source.prefix(n)) + i = buffer.initialize(fromContentsOf: source.prefix(n)) expectEqual(i, n) - i = a.moveInitialize(fromElements: buffer.prefix(n)) + i = a.moveInitialize(fromContentsOf: buffer.prefix(n)) expectEqual(i, n) expectTrue(a[...allocate(capacity: c) defer { a.deallocate() } - a.initialize(fromElements: Array(repeating: ".", count: c)) + a.initialize(fromContentsOf: Array(repeating: ".", count: c)) defer { a.deinitialize() } var i = a.withContiguousMutableStorageIfAvailable { - $0.update(fromElements: Array(repeating: " ", count: c)) + $0.update(fromContentsOf: Array(repeating: " ", count: c)) } expectEqual(i, c) expectTrue(a.allSatisfy({ $0 == " " })) i = a[...].withContiguousMutableStorageIfAvailable { - $0.update(fromElements: Array(repeating: "?", count: c)) + $0.update(fromContentsOf: Array(repeating: "?", count: c)) } expectEqual(i, c) expectTrue(a.allSatisfy({ $0 == "?" })) @@ -432,7 +432,7 @@ UnsafeMutableRawBufferPointerSliceTests.test( } UnsafeMutableBufferPointerSliceTests.test( - "slice.of.UnsafeMutableRawBufferpointer.initializeMemory.fromElements" + "slice.of.UnsafeMutableRawBufferpointer.initializeMemory.fromContentsOf" ) { let c = 4 let mb = UnsafeMutableRawBufferPointer.allocate( @@ -441,14 +441,14 @@ UnsafeMutableBufferPointerSliceTests.test( ) defer { mb.deallocate() } - var tb = mb.initializeMemory(as: Int.self, fromElements: 0.. Date: Wed, 24 Aug 2022 16:38:33 -0600 Subject: [PATCH 26/45] [se-0370] fix editing errors --- stdlib/public/core/UnsafeBufferPointer.swift.gyb | 2 +- stdlib/public/core/UnsafeBufferPointerSlice.swift | 10 +++++++--- stdlib/public/core/UnsafeRawBufferPointer.swift.gyb | 1 + 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/stdlib/public/core/UnsafeBufferPointer.swift.gyb b/stdlib/public/core/UnsafeBufferPointer.swift.gyb index a280e1c5e7a30..4d890f4cb97f7 100644 --- a/stdlib/public/core/UnsafeBufferPointer.swift.gyb +++ b/stdlib/public/core/UnsafeBufferPointer.swift.gyb @@ -763,7 +763,7 @@ extension Unsafe${Mutable}BufferPointer { @_alwaysEmitIntoClient public func update( from source: S - ) -> (unwritten: S.Iterator, updated: Index) where S.Element == Element { + ) -> (unwritten: S.Iterator, index: Index) where S.Element == Element { var iterator = source.makeIterator() guard var pointer = baseAddress else { return (iterator, startIndex) } for index in indices { diff --git a/stdlib/public/core/UnsafeBufferPointerSlice.swift b/stdlib/public/core/UnsafeBufferPointerSlice.swift index a89de686c7fcc..40eb56c926339 100644 --- a/stdlib/public/core/UnsafeBufferPointerSlice.swift +++ b/stdlib/public/core/UnsafeBufferPointerSlice.swift @@ -156,6 +156,7 @@ extension Slice where Base == UnsafeMutableRawBufferPointer { /// - Returns: A typed buffer referencing the initialized elements. /// The returned buffer references memory starting at the same /// base address as this slice, and its count is equal to `source.count`. + @discardableResult @inlinable @_alwaysEmitIntoClient public func moveInitializeMemory( @@ -193,6 +194,7 @@ extension Slice where Base == UnsafeMutableRawBufferPointer { /// - Returns: A typed buffer referencing the initialized elements. /// The returned buffer references memory starting at the same /// base address as this slice, and its count is equal to `source.count`. + @discardableResult @inlinable @_alwaysEmitIntoClient public func moveInitializeMemory( @@ -720,7 +722,7 @@ extension Slice { @_alwaysEmitIntoClient public func initialize( from source: S - ) -> (S.Iterator, Index) + ) -> (unwritten: S.Iterator, index: Index) where S: Sequence, Base == UnsafeMutableBufferPointer { let buffer = Base(rebasing: self) let (iterator, index) = buffer.initialize(from: source) @@ -743,10 +745,12 @@ extension Slice { /// as the buffer slice can hold, the returned index is equal to /// to the slice's `endIndex`. /// + /// - Precondition: `self.count` >= `source.count` + /// /// - Parameter source: A collection of elements to be used to /// initialize the buffer's storage. /// - Returns: An index to the next uninitialized element in the - /// buffer slice, or `endIndex`. @discardableResult + /// buffer slice, or `endIndex`. @inlinable @_alwaysEmitIntoClient public func initialize( @@ -788,7 +792,7 @@ extension Slice { @_alwaysEmitIntoClient public func update( from source: S - ) -> (unwritten: S.Iterator, updated: Index) + ) -> (unwritten: S.Iterator, index: Index) where S: Sequence, Base == UnsafeMutableBufferPointer { let buffer = Base(rebasing: self) let (iterator, index) = buffer.update(from: source) diff --git a/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb b/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb index c9d96b5878a21..e6d3820747638 100644 --- a/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb +++ b/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb @@ -863,6 +863,7 @@ extension Unsafe${Mutable}RawBufferPointer { /// - Returns: A typed buffer referencing the initialized elements. /// The returned buffer references memory starting at the same /// base address as this buffer, and its count is equal to `source.count`. + @discardableResult @inlinable @_alwaysEmitIntoClient public func moveInitializeMemory( From c2c432c9d2700fa142cb8993436bea1b1a8038f4 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Mon, 29 Aug 2022 22:23:29 -0600 Subject: [PATCH 27/45] [se-0370] re-implement in accordance with updated proposal --- .../public/core/UnsafeBufferPointer.swift.gyb | 94 +++++++++++++------ .../core/UnsafeRawBufferPointer.swift.gyb | 93 ++++++++++++------ 2 files changed, 130 insertions(+), 57 deletions(-) diff --git a/stdlib/public/core/UnsafeBufferPointer.swift.gyb b/stdlib/public/core/UnsafeBufferPointer.swift.gyb index 4d890f4cb97f7..1a54891cbfae6 100644 --- a/stdlib/public/core/UnsafeBufferPointer.swift.gyb +++ b/stdlib/public/core/UnsafeBufferPointer.swift.gyb @@ -704,22 +704,27 @@ extension Unsafe${Mutable}BufferPointer { public func initialize( fromContentsOf source: some Collection ) -> Index { - let count = Swift.min(self.count, source.count) - guard count > 0, let base = baseAddress else { return startIndex } - - if let _ = source.withContiguousStorageIfAvailable({ - base.initialize( - from: $0.baseAddress._unsafelyUnwrappedUnchecked, - count: count + let count = source.withContiguousStorageIfAvailable { + guard let sourceAddress = $0.baseAddress, !$0.isEmpty else { + return 0 + } + _precondition( + $0.count <= self.count, + "buffer cannot contain every element from source." ) - }) { + baseAddress?.initialize(from: sourceAddress, count: $0.count) + return $0.count + } + if let count { return startIndex.advanced(by: count) } - for (p, e) in zip(base.. ) -> Index { - let count = Swift.min(source.count, self.count) - guard count > 0, let base = baseAddress else { return startIndex } - - if let _ = source.withContiguousStorageIfAvailable({ - base.update(from: $0.baseAddress._unsafelyUnwrappedUnchecked, - count: count) - }) { + let count = source.withContiguousStorageIfAvailable { + guard let sourceAddress = $0.baseAddress else { + return 0 + } + _precondition( + $0.count <= self.count, + "buffer cannot contain every element from source." + ) + baseAddress?.update(from: sourceAddress, count: $0.count) + return $0.count + } + if let count { return startIndex.advanced(by: count) } - for (p, e) in zip(base.. Index { - guard let pointer = source.baseAddress, source.count > 0 else { return 0 } - _debugPrecondition(count >= source.count) - baseAddress._unsafelyUnwrappedUnchecked.moveInitialize(from: pointer, - count: source.count) + guard let sourceAddress = source.baseAddress, !source.isEmpty else { + return startIndex + } + _precondition( + source.count <= self.count, + "buffer cannot contain every element from source." + ) + baseAddress?.moveInitialize(from: sourceAddress, count: source.count) return startIndex.advanced(by: source.count) } @@ -908,10 +938,14 @@ extension Unsafe${Mutable}BufferPointer { @inlinable @_alwaysEmitIntoClient public func moveUpdate(fromContentsOf source: Self) -> Index { - guard let pointer = source.baseAddress, source.count > 0 else { return 0 } - _debugPrecondition(count >= source.count) - baseAddress._unsafelyUnwrappedUnchecked.moveUpdate(from: pointer, - count: source.count) + guard let sourceAddress = source.baseAddress, !source.isEmpty else { + return startIndex + } + _precondition( + source.count <= self.count, + "buffer cannot contain every element from source." + ) + baseAddress?.moveUpdate(from: sourceAddress, count: source.count) return startIndex.advanced(by: source.count) } diff --git a/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb b/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb index e6d3820747638..190f4c92a9cca 100644 --- a/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb +++ b/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb @@ -766,6 +766,11 @@ extension Unsafe${Mutable}RawBufferPointer { return (it, UnsafeMutableBufferPointer(start: nil, count: 0)) } + _debugPrecondition( + Int(bitPattern: base) % MemoryLayout.stride == 0, + "buffer base address must be properly aligned to access S.Element" + ) + _internalInvariant(_end != nil) for p in stride(from: base, // only advance to as far as the last element that will fit @@ -813,27 +818,57 @@ extension Unsafe${Mutable}RawBufferPointer { as type: C.Element.Type, fromContentsOf source: C ) -> UnsafeMutableBufferPointer { - var count = source.count - guard let base = _position, let end = _end, end > base, count > 0 else { - return UnsafeMutableBufferPointer(start: nil, count: 0) + let buffer: UnsafeMutableBufferPointer? + buffer = source.withContiguousStorageIfAvailable { + guard let sourceAddress = $0.baseAddress, !$0.isEmpty else { + return .init(start: nil, count: 0) + } + _debugPrecondition( + Int(bitPattern: baseAddress) % MemoryLayout.stride == 0, + "buffer base address must be properly aligned to access C.Element" + ) + _precondition( + $0.count * MemoryLayout.stride < self.count, + "buffer cannot contain every element from source collection." + ) + let start = baseAddress?.initializeMemory( + as: C.Element.self, from: sourceAddress, count: $0.count + ) + return .init(start: start, count: $0.count) + } + if let buffer { + return buffer } - count = Swift.min((end - base)/MemoryLayout.stride, count) - if let start = source.withContiguousStorageIfAvailable({ - base.initializeMemory( - as: C.Element.self, - from: $0.baseAddress._unsafelyUnwrappedUnchecked, - count: count + guard let base = baseAddress else { + _precondition( + source.isEmpty, + "buffer cannot contain every element from source collection." ) - }) { - return UnsafeMutableBufferPointer(start: start, count: count) + return .init(start: nil, count: 0) } - - let start = base.bindMemory(to: C.Element.self, capacity: count) - for (pointer, element) in zip(start...stride == 0, + "buffer base address must be properly aligned to access C.Element" + ) + var iterator = source.makeIterator() + var element = base + var initialized = 0 + let end = _end._unsafelyUnwrappedUnchecked - MemoryLayout.stride + while element <= end { + guard let value = iterator.next() else { + return .init(start: .init(base._rawValue), count: initialized) + } + element.initializeMemory(as: C.Element.self, to: value) + element = element.advanced(by: MemoryLayout.stride) + initialized += 1 } - return UnsafeMutableBufferPointer(start: start, count: count) + _precondition( + iterator.next() == nil, + "buffer cannot contain every element from source collection." + ) + return .init(start: .init(base._rawValue), count: initialized) } /// Moves every element of an initialized source buffer into the @@ -870,17 +905,21 @@ extension Unsafe${Mutable}RawBufferPointer { as type: T.Type, fromContentsOf source: UnsafeMutableBufferPointer ) -> UnsafeMutableBufferPointer { - guard let sourceBase = source.baseAddress - else { return UnsafeMutableBufferPointer(start: nil, count: 0) } - - let neededBytes = source.count*MemoryLayout.stride - guard let base = _position, count >= neededBytes - else { _debugPreconditionFailure("destination has too few bytes") } - - let initialized = base.moveInitializeMemory(as: T.self, - from: sourceBase, - count: source.count) - return UnsafeMutableBufferPointer(start: initialized, count: source.count) + guard let sourceAddress = source.baseAddress, !source.isEmpty else { + return .init(start: nil, count: 0) + } + _precondition( + source.count * MemoryLayout.stride <= self.count, + "buffer cannot contain every element from source." + ) + _debugPrecondition( + Int(bitPattern: baseAddress) % MemoryLayout.stride == 0, + "buffer base address must be properly aligned to access T" + ) + let initialized = baseAddress?.moveInitializeMemory( + as: T.self, from: sourceAddress, count: source.count + ) + return .init(start: initialized, count: source.count) } /// Moves every element of an initialized source buffer slice into the From d24b749ac20d2f678a72d334c5697dded9b4cf3b Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Tue, 30 Aug 2022 16:45:21 -0600 Subject: [PATCH 28/45] [se-0370] improve silgen names for renamed symbols --- stdlib/public/core/UnsafeBufferPointer.swift.gyb | 3 +-- stdlib/public/core/UnsafePointer.swift | 9 +++------ 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/stdlib/public/core/UnsafeBufferPointer.swift.gyb b/stdlib/public/core/UnsafeBufferPointer.swift.gyb index 1a54891cbfae6..50961c8edc291 100644 --- a/stdlib/public/core/UnsafeBufferPointer.swift.gyb +++ b/stdlib/public/core/UnsafeBufferPointer.swift.gyb @@ -737,7 +737,6 @@ extension Unsafe${Mutable}BufferPointer { /// - Parameters: /// - repeatedValue: The value used when updating this pointer's memory. @inlinable // unsafe-performance - @_alwaysEmitIntoClient @_silgen_name("$sSr6assign9repeatingyx_tF") public func update(repeating repeatedValue: Element) { guard let dstBase = _position else { @@ -750,7 +749,7 @@ extension Unsafe${Mutable}BufferPointer { @inlinable @_alwaysEmitIntoClient @available(*, deprecated, renamed: "update(repeating:)") - @_silgen_name("_deprecated_assign_repeating") + @_silgen_name("_swift_se0370_UnsageMutableBufferPointer_assign_repeating") public func assign(repeating repeatedValue: Element) { update(repeating: repeatedValue) } diff --git a/stdlib/public/core/UnsafePointer.swift b/stdlib/public/core/UnsafePointer.swift index 7dd339b31f260..942c768a364b2 100644 --- a/stdlib/public/core/UnsafePointer.swift +++ b/stdlib/public/core/UnsafePointer.swift @@ -779,7 +779,6 @@ public struct UnsafeMutablePointer: _Pointer { /// - count: The number of consecutive elements to update. /// `count` must not be negative. @inlinable - @_alwaysEmitIntoClient @_silgen_name("$sSp6assign9repeating5countyx_SitF") public func update(repeating repeatedValue: Pointee, count: Int) { _debugPrecondition(count >= 0, "UnsafeMutablePointer.assign(repeating:count:) with negative count") @@ -791,7 +790,7 @@ public struct UnsafeMutablePointer: _Pointer { @inlinable @_alwaysEmitIntoClient @available(*, deprecated, renamed: "update(repeating:count:)") - @_silgen_name("_deprecated_assign_repeating_count") + @_silgen_name("_swift_se0370_UnsafeMutablePointer_assign_repeating_count") public func assign(repeating repeatedValue: Pointee, count: Int) { update(repeating: repeatedValue, count: count) } @@ -813,7 +812,6 @@ public struct UnsafeMutablePointer: _Pointer { /// - count: The number of instances to copy from the memory referenced by /// `source` to this pointer's memory. `count` must not be negative. @inlinable - @_alwaysEmitIntoClient @_silgen_name("$sSp6assign4from5countySPyxG_SitF") public func update(from source: UnsafePointer, count: Int) { _debugPrecondition( @@ -843,7 +841,7 @@ public struct UnsafeMutablePointer: _Pointer { @inlinable @_alwaysEmitIntoClient @available(*, deprecated, renamed: "update(from:count:)") - @_silgen_name("_deprecated_assign_from_count") + @_silgen_name("_swift_se0370_UnsafeMutablePointer_assign_from_count") public func assign(from source: UnsafePointer, count: Int) { update(from: source, count: count) } @@ -943,7 +941,6 @@ public struct UnsafeMutablePointer: _Pointer { /// - count: The number of instances to move from `source` to this /// pointer's memory. `count` must not be negative. @inlinable - @_alwaysEmitIntoClient @_silgen_name("$sSp10moveAssign4from5countySpyxG_SitF") public func moveUpdate( @_nonEphemeral from source: UnsafeMutablePointer, count: Int @@ -964,7 +961,7 @@ public struct UnsafeMutablePointer: _Pointer { @inlinable @_alwaysEmitIntoClient @available(*, deprecated, renamed: "moveUpdate(from:count:)") - @_silgen_name("_deprecated_moveAssign_from_count") + @_silgen_name("_swift_se0370_UnsafeMutablePointer_moveAssign_from_count") public func moveAssign( @_nonEphemeral from source: UnsafeMutablePointer, count: Int ) { From 285984e3ae61e62e14f1ffde58b59f689d7fb644 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Wed, 31 Aug 2022 10:46:36 -0600 Subject: [PATCH 29/45] [stdlib] simplify `update(fromContentsOf:)` - one fewer variable, one fewer return point --- .../public/core/UnsafeBufferPointer.swift.gyb | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/stdlib/public/core/UnsafeBufferPointer.swift.gyb b/stdlib/public/core/UnsafeBufferPointer.swift.gyb index 50961c8edc291..7bb853c7d2d2e 100644 --- a/stdlib/public/core/UnsafeBufferPointer.swift.gyb +++ b/stdlib/public/core/UnsafeBufferPointer.swift.gyb @@ -818,26 +818,27 @@ extension Unsafe${Mutable}BufferPointer { return startIndex.advanced(by: count) } - guard var position = baseAddress else { + if self.isEmpty { _precondition( source.isEmpty, "buffer cannot contain every element from source." ) return startIndex } + _internalInvariant(_position != nil) var iterator = source.makeIterator() - for index in indices { - guard let value = iterator.next() else { - return index + var index = startIndex + while let value = iterator.next() { + guard index < endIndex else { + _preconditionFailure( + "buffer cannot contain every element from source." + ) + break } - position.pointee = value - position = position.advanced(by: 1) + _position._unsafelyUnwrappedUnchecked[index] = value + formIndex(after: &index) } - _precondition( - iterator.next() == nil, - "buffer cannot contain every element from source." - ) - return endIndex + return index } /// Moves every element of an initialized source buffer into the From aabf2e284323bad281ca64ed26cdbd5bd5c33cdc Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Wed, 31 Aug 2022 10:50:25 -0600 Subject: [PATCH 30/45] Update stdlib/public/core/UnsafeBufferPointer.swift.gyb Co-authored-by: YR Chen --- stdlib/public/core/UnsafeBufferPointer.swift.gyb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/public/core/UnsafeBufferPointer.swift.gyb b/stdlib/public/core/UnsafeBufferPointer.swift.gyb index 7bb853c7d2d2e..bb6118cf02c39 100644 --- a/stdlib/public/core/UnsafeBufferPointer.swift.gyb +++ b/stdlib/public/core/UnsafeBufferPointer.swift.gyb @@ -749,7 +749,7 @@ extension Unsafe${Mutable}BufferPointer { @inlinable @_alwaysEmitIntoClient @available(*, deprecated, renamed: "update(repeating:)") - @_silgen_name("_swift_se0370_UnsageMutableBufferPointer_assign_repeating") + @_silgen_name("_swift_se0370_UnsafeMutableBufferPointer_assign_repeating") public func assign(repeating repeatedValue: Element) { update(repeating: repeatedValue) } From 99505d081983cb166d81cd186b8993f9466cf1c4 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Wed, 31 Aug 2022 11:49:06 -0600 Subject: [PATCH 31/45] [stdlib] simplify `update(from:)` - one fewer variable, one fewer return point - thanks @benrimmington --- stdlib/public/core/UnsafeBufferPointer.swift.gyb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/stdlib/public/core/UnsafeBufferPointer.swift.gyb b/stdlib/public/core/UnsafeBufferPointer.swift.gyb index bb6118cf02c39..036d7f8c15b5f 100644 --- a/stdlib/public/core/UnsafeBufferPointer.swift.gyb +++ b/stdlib/public/core/UnsafeBufferPointer.swift.gyb @@ -769,15 +769,15 @@ extension Unsafe${Mutable}BufferPointer { from source: S ) -> (unwritten: S.Iterator, index: Index) where S.Element == Element { var iterator = source.makeIterator() - guard var pointer = baseAddress else { return (iterator, startIndex) } - for index in indices { - guard let element = iterator.next() else { - return (iterator, index) - } - pointer.pointee = element - pointer += 1 + guard !self.isEmpty else { return (iterator, startIndex) } + _internalInvariant(_position != nil) + var index = startIndex + while index < endIndex { + guard let element = iterator.next() else { break } + _position._unsafelyUnwrappedUnchecked[index] = element + formIndex(after: &index) } - return (iterator, endIndex) + return (iterator, index) } /// Updates the buffer's initialized memory with every element of the source. From 1f4ed8d976d6ff6a7650c342ca00e45d1e806af3 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Wed, 31 Aug 2022 14:19:26 -0600 Subject: [PATCH 32/45] Update stdlib/public/core/UnsafePointer.swift Co-authored-by: Ben Rimmington --- stdlib/public/core/UnsafePointer.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/public/core/UnsafePointer.swift b/stdlib/public/core/UnsafePointer.swift index 942c768a364b2..34fc7a78c81a9 100644 --- a/stdlib/public/core/UnsafePointer.swift +++ b/stdlib/public/core/UnsafePointer.swift @@ -781,7 +781,7 @@ public struct UnsafeMutablePointer: _Pointer { @inlinable @_silgen_name("$sSp6assign9repeating5countyx_SitF") public func update(repeating repeatedValue: Pointee, count: Int) { - _debugPrecondition(count >= 0, "UnsafeMutablePointer.assign(repeating:count:) with negative count") + _debugPrecondition(count >= 0, "UnsafeMutablePointer.update(repeating:count:) with negative count") for i in 0.. Date: Wed, 31 Aug 2022 17:24:11 -0600 Subject: [PATCH 33/45] [stdlib] improve note about subscripts and initialization --- stdlib/public/core/UnsafeBufferPointer.swift.gyb | 4 ++++ stdlib/public/core/UnsafePointer.swift | 12 ++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/stdlib/public/core/UnsafeBufferPointer.swift.gyb b/stdlib/public/core/UnsafeBufferPointer.swift.gyb index 036d7f8c15b5f..29708382f98f1 100644 --- a/stdlib/public/core/UnsafeBufferPointer.swift.gyb +++ b/stdlib/public/core/UnsafeBufferPointer.swift.gyb @@ -342,6 +342,10 @@ extension Unsafe${Mutable}BufferPointer: ${Mutable}Collection, RandomAccessColle /// } /// print(numbers) /// // Prints "[2, 1, 4, 3, 5]" + /// + /// Uninitialized memory cannot be initialized to a nontrivial type + /// using this subscript. Instead, use an initializing method, such as + /// `initializeElement(at:to:)` %else: /// The following example uses the buffer pointer's subscript to access every /// other element of the buffer: diff --git a/stdlib/public/core/UnsafePointer.swift b/stdlib/public/core/UnsafePointer.swift index 34fc7a78c81a9..d8d82e90c084e 100644 --- a/stdlib/public/core/UnsafePointer.swift +++ b/stdlib/public/core/UnsafePointer.swift @@ -694,9 +694,9 @@ public struct UnsafeMutablePointer: _Pointer { /// side of an assignment, the instance is updated. The instance must /// be initialized or this pointer's `Pointee` type must be a trivial type. /// - /// Do not update an instance of a nontrivial type through `pointee` to - /// uninitialized memory. Instead, use an initializing method, such as - /// `initialize(repeating:count:)`. + /// Uninitialized memory cannot be initialized to a nontrivial type + /// using `pointee`. Instead, use an initializing method, such as + /// `initialize(to:)`. @inlinable // unsafe-performance public var pointee: Pointee { @_transparent unsafeAddress { @@ -1096,9 +1096,9 @@ public struct UnsafeMutablePointer: _Pointer { /// side of an assignment, the memory at `p + i` is updated. The memory must /// be initialized or the pointer's `Pointee` type must be a trivial type. /// - /// Do not update an instance of a nontrivial type through the subscript to - /// uninitialized memory. Instead, use an initializing method, such as - /// `initialize(repeating:count:)`. + /// Uninitialized memory cannot be initialized to a nontrivial type + /// using this subscript. Instead, use an initializing method, such as + /// `initialize(to:)`. /// /// - Parameter i: The offset from this pointer at which to access an /// instance, measured in strides of the pointer's `Pointee` type. From 83c18dee6bcbd77fcdc7048ccfa857dbceed0aeb Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Tue, 6 Sep 2022 15:10:53 -0600 Subject: [PATCH 34/45] Update validation-test/stdlib/UnsafeBufferPointerSlices.swift Co-authored-by: Ben Rimmington --- validation-test/stdlib/UnsafeBufferPointerSlices.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/validation-test/stdlib/UnsafeBufferPointerSlices.swift b/validation-test/stdlib/UnsafeBufferPointerSlices.swift index edb067f860ef0..c8af91f6508f7 100644 --- a/validation-test/stdlib/UnsafeBufferPointerSlices.swift +++ b/validation-test/stdlib/UnsafeBufferPointerSlices.swift @@ -1,5 +1,6 @@ -// RUN: %target-run-simple-swiftgyb +// RUN: %target-run-simple-swift // REQUIRES: executable_test +// END. import StdlibUnittest From 6512840469856e94d3783eb51a05465998d6aa46 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Tue, 6 Sep 2022 17:23:09 -0600 Subject: [PATCH 35/45] [stdlib] update `copyBytes` with primary associated type --- stdlib/public/core/UnsafeBufferPointerSlice.swift | 4 +--- stdlib/public/core/UnsafeRawBufferPointer.swift.gyb | 5 ++--- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/stdlib/public/core/UnsafeBufferPointerSlice.swift b/stdlib/public/core/UnsafeBufferPointerSlice.swift index 40eb56c926339..49ff315fece8c 100644 --- a/stdlib/public/core/UnsafeBufferPointerSlice.swift +++ b/stdlib/public/core/UnsafeBufferPointerSlice.swift @@ -26,9 +26,7 @@ extension Slice where Base == UnsafeMutableRawBufferPointer { /// be less than or equal to this buffer slice's `count`. @inlinable @_alwaysEmitIntoClient - public func copyBytes( - from source: C - ) where C.Element == UInt8 { + public func copyBytes(from source: some Collection) { let buffer = Base(rebasing: self) buffer.copyBytes(from: source) } diff --git a/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb b/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb index 190f4c92a9cca..c23c3646f9a05 100644 --- a/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb +++ b/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb @@ -534,8 +534,7 @@ extension Unsafe${Mutable}RawBufferPointer { /// - Parameter source: A collection of `UInt8` elements. `source.count` must /// be less than or equal to this buffer's `count`. @inlinable - public func copyBytes(from source: C - ) where C.Element == UInt8 { + public func copyBytes(from source: some Collection) { _debugPrecondition(source.count <= self.count, "${Self}.copyBytes source has too many elements") guard let position = _position else { @@ -543,7 +542,7 @@ extension Unsafe${Mutable}RawBufferPointer { } if source.withContiguousStorageIfAvailable({ - (buffer: UnsafeBufferPointer) -> Void in + (buffer: UnsafeBufferPointer) -> Void in if let base = buffer.baseAddress { position.copyMemory(from: base, byteCount: buffer.count) } From 88225a2584791ad85440e6b18493812464cb5395 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Tue, 6 Sep 2022 17:24:05 -0600 Subject: [PATCH 36/45] [se-0370] some consistency tweaks --- .../core/UnsafeRawBufferPointer.swift.gyb | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb b/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb index c23c3646f9a05..d89343424aa69 100644 --- a/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb +++ b/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb @@ -535,14 +535,14 @@ extension Unsafe${Mutable}RawBufferPointer { /// be less than or equal to this buffer's `count`. @inlinable public func copyBytes(from source: some Collection) { - _debugPrecondition(source.count <= self.count, - "${Self}.copyBytes source has too many elements") guard let position = _position else { return } if source.withContiguousStorageIfAvailable({ (buffer: UnsafeBufferPointer) -> Void in + _debugPrecondition(source.count <= self.count, + "${Self}.copyBytes source has too many elements") if let base = buffer.baseAddress { position.copyMemory(from: base, byteCount: buffer.count) } @@ -551,6 +551,8 @@ extension Unsafe${Mutable}RawBufferPointer { } for (index, byteValue) in source.enumerated() { + _debugPrecondition(index < self.count, + "${Self}.copyBytes source has too many elements") position.storeBytes( of: byteValue, toByteOffset: index, as: UInt8.self) } @@ -711,14 +713,14 @@ extension Unsafe${Mutable}RawBufferPointer { public func initializeMemory(as type: T.Type, repeating repeatedValue: T) -> UnsafeMutableBufferPointer { guard let base = _position else { - return UnsafeMutableBufferPointer(start: nil, count: 0) + return .init(start: nil, count: 0) } let count = (_end._unsafelyUnwrappedUnchecked-base) / MemoryLayout.stride - let typed = base.initializeMemory(as: type, - repeating: repeatedValue, - count: count) - return UnsafeMutableBufferPointer(start: typed, count: count) + let initialized = base.initializeMemory( + as: type, repeating: repeatedValue, count: count + ) + return .init(start: initialized, count: count) } /// Initializes the buffer's memory with the given elements, binding the @@ -749,8 +751,6 @@ extension Unsafe${Mutable}RawBufferPointer { public func initializeMemory( as type: S.Element.Type, from source: S ) -> (unwritten: S.Iterator, initialized: UnsafeMutableBufferPointer) { - // TODO: Optimize where `C` is a `ContiguousArrayBuffer`. - var it = source.makeIterator() var idx = startIndex let elementStride = MemoryLayout.stride @@ -907,14 +907,14 @@ extension Unsafe${Mutable}RawBufferPointer { guard let sourceAddress = source.baseAddress, !source.isEmpty else { return .init(start: nil, count: 0) } - _precondition( - source.count * MemoryLayout.stride <= self.count, - "buffer cannot contain every element from source." - ) _debugPrecondition( Int(bitPattern: baseAddress) % MemoryLayout.stride == 0, "buffer base address must be properly aligned to access T" ) + _precondition( + source.count * MemoryLayout.stride <= self.count, + "buffer cannot contain every element from source." + ) let initialized = baseAddress?.moveInitializeMemory( as: T.self, from: sourceAddress, count: source.count ) From 44a349f8e0552db9b87693a138ff6e05cc091000 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Tue, 6 Sep 2022 17:48:56 -0600 Subject: [PATCH 37/45] [se-0370] edit doc-comments for consistency --- .../public/core/UnsafeBufferPointer.swift.gyb | 24 +- .../core/UnsafeBufferPointerSlice.swift | 211 +++++++++--------- .../core/UnsafeRawBufferPointer.swift.gyb | 19 +- 3 files changed, 135 insertions(+), 119 deletions(-) diff --git a/stdlib/public/core/UnsafeBufferPointer.swift.gyb b/stdlib/public/core/UnsafeBufferPointer.swift.gyb index 29708382f98f1..e5f58eefee42f 100644 --- a/stdlib/public/core/UnsafeBufferPointer.swift.gyb +++ b/stdlib/public/core/UnsafeBufferPointer.swift.gyb @@ -636,7 +636,8 @@ extension Unsafe${Mutable}BufferPointer { return UnsafeMutableBufferPointer(start: base, count: count) } - /// Initializes every element in this buffer's memory to a copy of the given value. + /// Initializes every element in this buffer'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 @@ -682,7 +683,8 @@ extension Unsafe${Mutable}BufferPointer { return source._copyContents(initializing: self) } - /// Initializes the buffer's memory with every element of the source. + /// Initializes the buffer's memory with + /// every element of the source. /// /// Prior to calling the `initialize(fromContentsOf:)` method on a buffer, /// the memory referenced by the buffer must be uninitialized, @@ -701,8 +703,9 @@ extension Unsafe${Mutable}BufferPointer { /// - Precondition: `self.count` >= `source.count` /// /// - Parameter source: A collection of elements to be used to - /// initialize the buffer's storage. - /// - Returns: An index to the next uninitialized element in the buffer. + /// initialize the buffer's storage. + /// - Returns: The index one past the last element of the buffer initialized + /// by this function. @inlinable @_alwaysEmitIntoClient public func initialize( @@ -784,7 +787,8 @@ extension Unsafe${Mutable}BufferPointer { return (iterator, index) } - /// Updates the buffer's initialized memory with every element of the source. + /// Updates the buffer's initialized memory with + /// every element of the source. /// /// Prior to calling the `update(fromContentsOf:)` method on a buffer, /// the first `source.count` elements of the buffer's memory must be @@ -869,8 +873,8 @@ extension Unsafe${Mutable}BufferPointer { /// - 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`. + /// - Returns: The index one past the last element of the buffer initialized + /// by this function. @inlinable @_alwaysEmitIntoClient public func moveInitialize(fromContentsOf source: Self) -> Index { @@ -909,8 +913,8 @@ extension Unsafe${Mutable}BufferPointer { /// - 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`. + /// - Returns: The index one past the last element of the buffer initialized + /// by this function. @inlinable @_alwaysEmitIntoClient public func moveInitialize(fromContentsOf source: Slice) -> Index { @@ -1091,7 +1095,7 @@ extension Unsafe${Mutable}BufferPointer { /// 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. + /// raw buffer's `withMemoryRebound(to:)` method. /// If `T` and `Element` have different alignments, this buffer's /// `baseAddress` must be aligned with the larger of the two alignments. /// diff --git a/stdlib/public/core/UnsafeBufferPointerSlice.swift b/stdlib/public/core/UnsafeBufferPointerSlice.swift index 49ff315fece8c..af62effb6f88f 100644 --- a/stdlib/public/core/UnsafeBufferPointerSlice.swift +++ b/stdlib/public/core/UnsafeBufferPointerSlice.swift @@ -13,14 +13,14 @@ extension Slice where Base == UnsafeMutableRawBufferPointer { /// 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`. + /// If the first `source.count` bytes of memory referenced by + /// this buffer slice 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`. + /// referenced by this buffer slice 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`. @@ -31,20 +31,22 @@ extension Slice where Base == UnsafeMutableRawBufferPointer { buffer.copyBytes(from: source) } - /// 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. + /// Initializes the memory referenced by this buffer slice 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 + /// The memory referenced by this buffer slice 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`, + /// After calling this method on a raw buffer slice referencing memory + /// starting at `b = base.baseAddress + startIndex`, /// 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. + /// `b + self.count - self.count % MemoryLayout.stride` is bound + /// to type `T` and is initialized. If `T` is a nontrivial type, you must + /// eventually deinitialize or move the values in this region to avoid leaks. + /// If `base.baseAddress` is `nil`, this function does nothing + /// and returns an empty buffer pointer. /// /// - Parameters: /// - type: The type to bind this buffer’s memory to. @@ -65,15 +67,15 @@ extension Slice where Base == UnsafeMutableRawBufferPointer { /// 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`. + /// When calling the `initializeMemory(as:from:)` method on a buffer slice, + /// the memory referenced by the slice must be uninitialized or initialised + /// 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 + /// This method initializes the buffer slice with elements from `source` until + /// `source` is exhausted or, if `source` is a sequence but not a collection, + /// the buffer slice has no more room for source's elements. After calling /// `initializeMemory(as:from:)`, the memory referenced by the returned /// `UnsafeMutableBufferPointer` instance is bound and initialized to type /// `S.Element`. @@ -203,11 +205,11 @@ extension Slice where Base == UnsafeMutableRawBufferPointer { return buffer.moveInitializeMemory(as: T.self, fromContentsOf: source) } - /// Binds this buffer’s memory to the specified type and returns a typed buffer - /// of the bound memory. + /// Binds this buffer slice’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 + /// by this buffer slice 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`. /// @@ -219,7 +221,8 @@ extension Slice where Base == UnsafeMutableRawBufferPointer { /// - 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`. + /// The typed buffer references `self.count / MemoryLayout.stride` + /// instances of `T`. @discardableResult @inlinable @_alwaysEmitIntoClient @@ -228,10 +231,10 @@ extension Slice where Base == UnsafeMutableRawBufferPointer { return buffer.bindMemory(to: T.self) } - /// Executes the given closure while temporarily binding the buffer to + /// Executes the given closure while temporarily binding the buffer slice to /// instances of type `T`. /// - /// Use this method when you have a buffer to raw memory and you need + /// Use this method when you have a buffer slice 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 @@ -244,27 +247,27 @@ extension Slice where Base == UnsafeMutableRawBufferPointer { /// 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 + /// If the byte count of the original buffer slice 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` + /// - Note: The buffer slice's start address must match the + /// alignment of `T` (as reported by `MemoryLayout.alignment`). That is, + /// `Int(bitPattern: base.baseAddress+startIndex) % 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 + /// - Note: A raw buffer slice 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. + /// buffer slice. /// - 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 @@ -281,7 +284,7 @@ extension Slice where Base == UnsafeMutableRawBufferPointer { return try buffer.withMemoryRebound(to: T.self, body) } - /// Returns a typed buffer to the memory referenced by this buffer, + /// Returns a typed buffer to the memory referenced by this buffer slice, /// 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 @@ -290,9 +293,9 @@ extension Slice where Base == UnsafeMutableRawBufferPointer { /// 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` + /// - Note: The buffer slice's start address must match the + /// alignment of `T` (as reported by `MemoryLayout.alignment`). That is, + /// `Int(bitPattern: base.baseAddress+startIndex) % MemoryLayout.alignment` /// must equal zero. /// /// - Parameter to: The type `T` that the memory has already been bound to. @@ -430,11 +433,11 @@ extension Slice where Base == UnsafeMutableRawBufferPointer { extension Slice where Base == UnsafeRawBufferPointer { - /// Binds this buffer’s memory to the specified type and returns a typed buffer - /// of the bound memory. + /// Binds this buffer slice’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 + /// by this buffer slice 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`. /// @@ -446,7 +449,8 @@ extension Slice where Base == UnsafeRawBufferPointer { /// - 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`. + /// The typed buffer references `self.count / MemoryLayout.stride` + /// instances of `T`. @discardableResult @inlinable @_alwaysEmitIntoClient @@ -455,10 +459,10 @@ extension Slice where Base == UnsafeRawBufferPointer { return buffer.bindMemory(to: T.self) } - /// Executes the given closure while temporarily binding the buffer to + /// Executes the given closure while temporarily binding the buffer slice to /// instances of type `T`. /// - /// Use this method when you have a buffer to raw memory and you need + /// Use this method when you have a buffer slice 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 @@ -471,27 +475,27 @@ extension Slice where Base == UnsafeRawBufferPointer { /// 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 + /// If the byte count of the original buffer slice 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` + /// - Note: The buffer slice's start address must match the + /// alignment of `T` (as reported by `MemoryLayout.alignment`). That is, + /// `Int(bitPattern: base.baseAddress+startIndex) % 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 + /// - Note: A raw buffer slice 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. + /// buffer slice. /// - 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 @@ -508,7 +512,7 @@ extension Slice where Base == UnsafeRawBufferPointer { return try buffer.withMemoryRebound(to: T.self, body) } - /// Returns a typed buffer to the memory referenced by this buffer, + /// Returns a typed buffer to the memory referenced by this buffer slice, /// 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 @@ -517,9 +521,9 @@ extension Slice where Base == UnsafeRawBufferPointer { /// 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` + /// - Note: The buffer slice's start address must match the + /// alignment of `T` (as reported by `MemoryLayout.alignment`). That is, + /// `Int(bitPattern: base.baseAddress+startIndex) % MemoryLayout.alignment` /// must equal zero. /// /// - Parameter to: The type `T` that the memory has already been bound to. @@ -615,8 +619,8 @@ extension Slice { /// 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 + /// Use this method when you have a buffer slice 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 @@ -643,22 +647,22 @@ extension Slice { /// 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 + /// - Note: Only use this method to rebind the buffer slice'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. + /// `withMemoryRebound(to:)` method on the raw buffer. + /// If `T` and `Element` have different alignments, this buffer slice + /// 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 + /// buffer slice. 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 + /// same memory as this buffer slice, 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 @@ -702,7 +706,7 @@ extension Slice { /// 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 + /// The buffer slice must contain sufficient memory to accommodate /// `source.underestimatedCount`. /// /// The returned index is the position of the next uninitialized element @@ -728,27 +732,30 @@ extension Slice { return (iterator, startIndex.advanced(by: distance)) } - /// Initializes the buffer slice's memory with with every element of the source. + /// Initializes the buffer slice's memory with with + /// every element of the source. /// /// Prior to calling the `initialize(fromContentsOf:)` 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 slice must reference enough memory to accommodate + /// `source.count` elements. /// /// The returned index is the index of the next uninitialized element /// in the buffer slice, one past the index of the last element written. /// If `source` contains no elements, the returned index is equal to - /// the buffer's `startIndex`. If `source` contains as many elements + /// the buffer slice's `startIndex`. If `source` contains as many elements /// as the buffer slice can hold, the returned index is equal to /// to the slice's `endIndex`. /// /// - Precondition: `self.count` >= `source.count` /// /// - Parameter source: A collection of elements to be used to - /// initialize the buffer's storage. - /// - Returns: An index to the next uninitialized element in the - /// buffer slice, or `endIndex`. + /// initialize the buffer slice's storage. + /// - Returns: The index one past the last element of the buffer slice + /// initialized by this function. @inlinable @_alwaysEmitIntoClient public func initialize( @@ -783,9 +790,9 @@ extension Slice { /// must be a trivial type. /// /// - Parameter source: A sequence of elements to be used to update - /// the buffer's contents. + /// the contents of the buffer slice. /// - 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. + /// buffer slice, and the index one past the last updated element. @inlinable @_alwaysEmitIntoClient public func update( @@ -798,18 +805,19 @@ extension Slice { return (iterator, startIndex.advanced(by: distance)) } - /// Updates the buffer slice's initialized memory with every element of the source. + /// Updates the buffer slice's initialized memory with + /// every element of the source. /// /// Prior to calling the `update(fromContentsOf:)` method on a buffer /// slice, the first `source.count` elements of the referenced memory must be - /// initialized, or the buffer's `Element` type must be a trivial type. - /// The buffer must reference enough initialized memory to accommodate + /// initialized, or the `Element` type must be a trivial type. + /// The buffer slice must reference enough initialized memory to accommodate /// `source.count` elements. /// - /// The returned index is one past the index of the last element updated. - /// If `source` contains no elements, the returned index is equal to the - /// buffer's `startIndex`. If `source` contains as many elements as the buffer - /// slice can hold, the returned index is equal to the slice's `endIndex`. + /// The returned index is one past the index of the last element updated. If + /// `source` contains no elements, the returned index is the buffer slice's + /// `startIndex`. If `source` contains as many elements as the buffer slice + /// can hold, the returned index is the buffer slice's `endIndex`. /// /// - Precondition: `self.count` >= `source.count` /// @@ -818,10 +826,9 @@ extension Slice { /// - Returns: An index one past the index of the last element updated. @inlinable @_alwaysEmitIntoClient - public func update( - fromContentsOf source: C - ) -> Index - where C: Collection, Base == UnsafeMutableBufferPointer { + public func update( + fromContentsOf source: some Collection + ) -> Index where Base == UnsafeMutableBufferPointer { let buffer = Base(rebasing: self) let index = buffer.update(fromContentsOf: source) let distance = buffer.distance(from: buffer.startIndex, to: index) @@ -852,8 +859,8 @@ extension Slice { /// - 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`. + /// - Returns: The index one past the last element of the buffer slice + /// initialized by this function. @inlinable @_alwaysEmitIntoClient public func moveInitialize( @@ -889,8 +896,8 @@ extension Slice { /// - Parameter source: A buffer slice containing the values to copy. /// The memory region underlying `source` must be initialized. The memory /// regions referenced by `source` and this buffer slice may overlap. - /// - Returns: An index to the next uninitialized element in the buffer, - /// or `endIndex`. + /// - Returns: The index one past the last element of the buffer slice + /// initialized by this function. @inlinable @_alwaysEmitIntoClient public func moveInitialize( @@ -908,9 +915,11 @@ extension Slice { /// /// The region of memory starting at the beginning of this buffer slice and /// covering `source.count` instances of its `Element` type must be - /// initialized, or `Element` must be a trivial type. After calling - /// `moveUpdate(fromContentsOf:)`, + /// initialized, or its `Element` type must be a trivial type. + /// After calling `moveUpdate(fromContentsOf:)`, /// the region of memory underlying `source` is uninitialized. + /// The buffer slice must reference enough initialized memory + /// to accommodate `source.count` elements. /// /// The returned index is one past the index of the last element updated. /// If `source` contains no elements, the returned index is equal to the @@ -940,9 +949,11 @@ extension Slice { /// /// The region of memory starting at the beginning of this buffer slice and /// covering `source.count` instances of its `Element` type must be - /// initialized, or `Element` must be a trivial type. After calling - /// `moveUpdate(fromContentsOf:)`, + /// initialized, or its `Element` type must be a trivial type. + /// After calling `moveUpdate(fromContentsOf:)`, /// the region of memory underlying `source` is uninitialized. + /// The buffer slice must reference enough initialized memory + /// to accommodate `source.count` elements. /// /// The returned index is one past the index of the last element updated. /// If `source` contains no elements, the returned index is equal to the @@ -1038,8 +1049,8 @@ extension Slice { /// 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 + /// Use this method when you have a buffer slice 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 @@ -1066,22 +1077,22 @@ extension Slice { /// 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 + /// - Note: Only use this method to rebind the buffer slice'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. + /// requirements, convert the buffer slice to a raw buffer and use the + /// raw buffer's `withMemoryRebound(to:)` method. + /// If `T` and `Element` have different alignments, this buffer slice + /// 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 + /// buffer slice. 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 + /// - body: A closure that takes a typed buffer to the + /// same memory as this buffer slice, 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 diff --git a/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb b/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb index d89343424aa69..09ad255f2665d 100644 --- a/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb +++ b/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb @@ -522,10 +522,10 @@ extension Unsafe${Mutable}RawBufferPointer { /// Copies from a collection of `UInt8` into this buffer'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`. + /// If the first `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 @@ -697,7 +697,7 @@ extension Unsafe${Mutable}RawBufferPointer { /// 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 + /// to type `T` and is 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. @@ -733,8 +733,8 @@ extension Unsafe${Mutable}RawBufferPointer { /// `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 + /// `source` is exhausted or, if `source` is a sequence but not a collection, + /// the buffer has no more room for source's elements. After calling /// `initializeMemory(as:from:)`, the memory referenced by the returned /// `UnsafeMutableBufferPointer` instance is bound and initialized to type /// `S.Element`. This method does not change @@ -977,7 +977,8 @@ extension Unsafe${Mutable}RawBufferPointer { /// - 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`. + /// The typed buffer references `self.count / MemoryLayout.stride` + /// instances of `T`. @_transparent @discardableResult public func bindMemory( @@ -1029,7 +1030,7 @@ extension Unsafe${Mutable}RawBufferPointer { /// /// - Parameters: /// - type: The type to temporarily bind the memory referenced by this - /// pointer. This pointer must be a multiple of this type's alignment. + /// buffer. /// - 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 From d9a448860bbe46b01f93c7f5ac2d9ca8b3f6d4d6 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Wed, 7 Sep 2022 15:24:41 -0600 Subject: [PATCH 38/45] [se-0370] use primary associated type --- stdlib/public/core/UnsafeBufferPointerSlice.swift | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/stdlib/public/core/UnsafeBufferPointerSlice.swift b/stdlib/public/core/UnsafeBufferPointerSlice.swift index af62effb6f88f..1ddf2526829f7 100644 --- a/stdlib/public/core/UnsafeBufferPointerSlice.swift +++ b/stdlib/public/core/UnsafeBufferPointerSlice.swift @@ -758,10 +758,9 @@ extension Slice { /// initialized by this function. @inlinable @_alwaysEmitIntoClient - public func initialize( - fromContentsOf source: C - ) -> Index - where C : Collection, Base == UnsafeMutableBufferPointer { + public func initialize( + fromContentsOf source: some Collection + ) -> Index where Base == UnsafeMutableBufferPointer { let buffer = Base(rebasing: self) let index = buffer.initialize(fromContentsOf: source) let distance = buffer.distance(from: buffer.startIndex, to: index) From 559e5ed54b0e48aeb0239d6dd0ff2e30835fe415 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Wed, 7 Sep 2022 15:27:08 -0600 Subject: [PATCH 39/45] [stdlib] use the internal precondition calls --- stdlib/public/core/UnsafeBufferPointer.swift.gyb | 6 +++--- stdlib/public/core/UnsafeBufferPointerSlice.swift | 5 ++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/stdlib/public/core/UnsafeBufferPointer.swift.gyb b/stdlib/public/core/UnsafeBufferPointer.swift.gyb index e5f58eefee42f..b2a0e83123b26 100644 --- a/stdlib/public/core/UnsafeBufferPointer.swift.gyb +++ b/stdlib/public/core/UnsafeBufferPointer.swift.gyb @@ -1018,7 +1018,7 @@ extension Unsafe${Mutable}BufferPointer { @inlinable @_alwaysEmitIntoClient public func initializeElement(at index: Index, to value: Element) { - precondition(startIndex <= index && index < endIndex) + _debugPrecondition(startIndex <= index && index < endIndex) let p = baseAddress._unsafelyUnwrappedUnchecked.advanced(by: index) p.initialize(to: value) } @@ -1036,7 +1036,7 @@ extension Unsafe${Mutable}BufferPointer { @inlinable @_alwaysEmitIntoClient public func moveElement(from index: Index) -> Element { - precondition(startIndex <= index && index < endIndex) + _debugPrecondition(startIndex <= index && index < endIndex) return baseAddress._unsafelyUnwrappedUnchecked.advanced(by: index).move() } @@ -1051,7 +1051,7 @@ extension Unsafe${Mutable}BufferPointer { @inlinable @_alwaysEmitIntoClient public func deinitializeElement(at index: Index) { - precondition(startIndex <= index && index < endIndex) + _debugPrecondition(startIndex <= index && index < endIndex) let p = baseAddress._unsafelyUnwrappedUnchecked.advanced(by: index) p.deinitialize(count: 1) } diff --git a/stdlib/public/core/UnsafeBufferPointerSlice.swift b/stdlib/public/core/UnsafeBufferPointerSlice.swift index 1ddf2526829f7..8d2a1b53dc72f 100644 --- a/stdlib/public/core/UnsafeBufferPointerSlice.swift +++ b/stdlib/public/core/UnsafeBufferPointerSlice.swift @@ -1118,10 +1118,9 @@ extension Slice { var slice = UnsafeMutableBufferPointer(start: start, count: count) let (b,c) = (slice.baseAddress, slice.count) defer { - precondition( + _precondition( slice.baseAddress == b && slice.count == c, - "Slice.withContiguousMutableStorageIfAvailable: " + - "replacing the buffer is not allowed") + "withContiguousMutableStorageIfAvailable: replacing the buffer is not allowed") } return try body(&slice) } From ffa7b0e78ce6f0b9a322dd8fe23958796a423d53 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Thu, 8 Sep 2022 18:23:45 -0600 Subject: [PATCH 40/45] [se-0370] add notes regarding overlapping memory regions --- .../public/core/UnsafeBufferPointer.swift.gyb | 30 ++++++++++++++----- .../core/UnsafeBufferPointerSlice.swift | 30 ++++++++++++++----- .../core/UnsafeRawBufferPointer.swift.gyb | 11 +++++-- 3 files changed, 53 insertions(+), 18 deletions(-) diff --git a/stdlib/public/core/UnsafeBufferPointer.swift.gyb b/stdlib/public/core/UnsafeBufferPointer.swift.gyb index b2a0e83123b26..7b4552a98893c 100644 --- a/stdlib/public/core/UnsafeBufferPointer.swift.gyb +++ b/stdlib/public/core/UnsafeBufferPointer.swift.gyb @@ -702,6 +702,9 @@ extension Unsafe${Mutable}BufferPointer { /// /// - Precondition: `self.count` >= `source.count` /// + /// - Note: The memory regions referenced by `source` and this buffer + /// must not overlap. + /// /// - Parameter source: A collection of elements to be used to /// initialize the buffer's storage. /// - Returns: The index one past the last element of the buffer initialized @@ -801,6 +804,9 @@ extension Unsafe${Mutable}BufferPointer { /// buffer's `startIndex`. If `source` contains as many elements as the buffer /// can hold, the returned index is equal to the buffer's `endIndex`. /// + /// - Note: The memory regions referenced by `source` and this buffer + /// may overlap. + /// /// - Precondition: `self.count` >= `source.count` /// /// - Parameter source: A collection of elements to be used to update @@ -870,9 +876,11 @@ extension Unsafe${Mutable}BufferPointer { /// /// - Precondition: `self.count` >= `source.count` /// + /// - Note: The memory regions referenced by `source` and this buffer + /// may overlap. + /// /// - 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. + /// region underlying `source` must be initialized. /// - Returns: The index one past the last element of the buffer initialized /// by this function. @inlinable @@ -910,9 +918,11 @@ extension Unsafe${Mutable}BufferPointer { /// /// - Precondition: `self.count` >= `source.count` /// + /// - Note: The memory regions referenced by `source` and this buffer + /// may overlap. + /// /// - 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. + /// region underlying `source` must be initialized. /// - Returns: The index one past the last element of the buffer initialized /// by this function. @inlinable @@ -937,11 +947,13 @@ extension Unsafe${Mutable}BufferPointer { /// buffer's `startIndex`. If `source` contains as many elements as the buffer /// can hold, the returned index is equal to the buffer's `endIndex`. /// + /// - Note: The memory regions referenced by `source` and this buffer + /// must not overlap. + /// /// - Precondition: `self.count` >= `source.count` /// /// - 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 buffer must not overlap. + /// The memory region underlying `source` must be initialized. /// - Returns: An index one past the index of the last element updated. @inlinable @_alwaysEmitIntoClient @@ -973,11 +985,13 @@ extension Unsafe${Mutable}BufferPointer { /// buffer's `startIndex`. If `source` contains as many elements as the buffer /// can hold, the returned index is equal to the buffer's `endIndex`. /// + /// - Note: The memory regions referenced by `source` and this buffer + /// must not overlap. + /// /// - Precondition: `self.count` >= `source.count` /// /// - Parameter source: A buffer slice 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. + /// The memory region underlying `source` must be initialized. /// - Returns: An index one past the index of the last element updated. @inlinable @_alwaysEmitIntoClient diff --git a/stdlib/public/core/UnsafeBufferPointerSlice.swift b/stdlib/public/core/UnsafeBufferPointerSlice.swift index 8d2a1b53dc72f..5913423ec1e39 100644 --- a/stdlib/public/core/UnsafeBufferPointerSlice.swift +++ b/stdlib/public/core/UnsafeBufferPointerSlice.swift @@ -752,6 +752,9 @@ extension Slice { /// /// - Precondition: `self.count` >= `source.count` /// + /// - Note: The memory regions referenced by `source` and this buffer slice + /// must not overlap. + /// /// - Parameter source: A collection of elements to be used to /// initialize the buffer slice's storage. /// - Returns: The index one past the last element of the buffer slice @@ -818,6 +821,9 @@ extension Slice { /// `startIndex`. If `source` contains as many elements as the buffer slice /// can hold, the returned index is the buffer slice's `endIndex`. /// + /// - Note: The memory regions referenced by `source` and this buffer slice + /// may overlap. + /// /// - Precondition: `self.count` >= `source.count` /// /// - Parameter source: A collection of elements to be used to update @@ -853,11 +859,13 @@ extension Slice { /// slice's `startIndex`. If `source` contains as many elements as the slice /// can hold, the returned index is equal to the slice's `endIndex`. /// + /// - Note: The memory regions referenced by `source` and this buffer slice + /// may overlap. + /// /// - Precondition: `self.count` >= `source.count` /// /// - 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. + /// The memory region underlying `source` must be initialized. /// - Returns: The index one past the last element of the buffer slice /// initialized by this function. @inlinable @@ -890,11 +898,13 @@ extension Slice { /// slice's `startIndex`. If `source` contains as many elements as the slice /// can hold, the returned index is equal to the slice's `endIndex`. /// + /// - Note: The memory regions referenced by `source` and this buffer slice + /// may overlap. + /// /// - Precondition: `self.count` >= `source.count` /// /// - Parameter source: A buffer slice containing the values to copy. - /// The memory region underlying `source` must be initialized. The memory - /// regions referenced by `source` and this buffer slice may overlap. + /// The memory region underlying `source` must be initialized. /// - Returns: The index one past the last element of the buffer slice /// initialized by this function. @inlinable @@ -925,11 +935,13 @@ extension Slice { /// buffer's `startIndex`. If `source` contains as many elements as the buffer /// slice can hold, the returned index is equal to the slice's `endIndex`. /// + /// - Note: The memory regions referenced by `source` and this buffer slice + /// must not overlap. + /// /// - Precondition: `self.count` >= `source.count` /// /// - 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 buffer slice must not overlap. + /// The memory region underlying `source` must be initialized. /// - Returns: An index one past the index of the last element updated. @inlinable @_alwaysEmitIntoClient @@ -959,11 +971,13 @@ extension Slice { /// buffer's `startIndex`. If `source` contains as many elements as the buffer /// slice can hold, the returned index is equal to the slice's `endIndex`. /// + /// - Note: The memory regions referenced by `source` and this buffer slice + /// must not overlap. + /// /// - Precondition: `self.count` >= `source.count` /// /// - Parameter source: A buffer slice containing the values to move. - /// The memory region underlying `source` must be initialized. The memory - /// regions referenced by `source` and this buffer slice must not overlap. + /// The memory region underlying `source` must be initialized. /// - Returns: An index one past the index of the last element updated. @inlinable @_alwaysEmitIntoClient diff --git a/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb b/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb index 09ad255f2665d..3ec1199ed8e64 100644 --- a/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb +++ b/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb @@ -804,6 +804,9 @@ extension Unsafe${Mutable}RawBufferPointer { /// to the type `C.Element` and is initialized. This method does not change /// the binding state of the unused portion of the buffer, if any. /// + /// - Note: The memory regions referenced by `source` and this buffer + /// must not overlap. + /// /// - Parameters: /// - type: The type of element to which this buffer's memory will be bound. /// - source: A collection of elements to be used to @@ -889,11 +892,13 @@ extension Unsafe${Mutable}RawBufferPointer { /// to the type `T` and is initialized. This method does not change /// the binding state of the unused portion of the buffer, if any. /// + /// - Note: The memory regions referenced by `source` and this buffer + /// may overlap. + /// /// - Parameters: /// - type: The type of element to which this buffer's memory will be bound. /// - source: A buffer referencing 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 referencing the initialized elements. /// The returned buffer references memory starting at the same /// base address as this buffer, and its count is equal to `source.count`. @@ -940,11 +945,13 @@ extension Unsafe${Mutable}RawBufferPointer { /// to the type `T` and is initialized. This method does not change /// the binding state of the unused portion of the buffer, if any. /// + /// - Note: The memory regions referenced by `source` and this buffer + /// may overlap. + /// /// - Parameters: /// - type: The type of element to which this buffer's memory will be bound. /// - source: A buffer referencing 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 referencing the initialized elements. /// The returned buffer references memory starting at the same /// base address as this buffer, and its count is equal to `source.count`. From 56c688777d7f4d1f3b365d5876a18c6bc25b2b7b Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Fri, 9 Sep 2022 18:02:43 -0600 Subject: [PATCH 41/45] [test] test overflow preconditions in collection copies --- .../stdlib/UnsafeBufferPointer.swift.gyb | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/validation-test/stdlib/UnsafeBufferPointer.swift.gyb b/validation-test/stdlib/UnsafeBufferPointer.swift.gyb index 361e600841c06..0b9e6db317de4 100644 --- a/validation-test/stdlib/UnsafeBufferPointer.swift.gyb +++ b/validation-test/stdlib/UnsafeBufferPointer.swift.gyb @@ -1193,4 +1193,101 @@ UnsafeRawBufferPointerTestSuite.test("assumingMemoryBound") { expectEqual(mutableArray[3], array[3]+1) } +UnsafeMutableBufferPointerTestSuite.test("UMBP.initialize.collection.overflow") +.skip(.custom({ + if #available(SwiftStdlib 5.8, *) { return false } else { return true } +}, reason: "Requires standard library from Swift 5.8")) +.code { + let s = Array(0..<8) + let b = UnsafeMutableBufferPointer.allocate(capacity: s.count-1) + defer { b.deallocate() } + expectCrash { + _ = b.initialize(fromContentsOf: s) + } +} + +UnsafeMutableBufferPointerTestSuite.test("UMBP.update.collection.overflow") +.skip(.custom({ + if #available(SwiftStdlib 5.8, *) { return false } else { return true } +}, reason: "Requires standard library from Swift 5.8")) +.code { + let s = Array(0..<8) + var b = Array(repeating: 0, count: s.count-1) + b.withUnsafeMutableBufferPointer { b in + expectCrash { + _ = b.update(fromContentsOf: s) + } + } +} + +UnsafeMutableBufferPointerTestSuite.test("UMBP.moveInitialize.overflow") +.skip(.custom({ + if #available(SwiftStdlib 5.8, *) { return false } else { return true } +}, reason: "Requires standard library from Swift 5.8")) +.code { + let s = UnsafeMutableBufferPointer.allocate(capacity: 8) + defer { s.deallocate() } + s.initialize(fromContentsOf: 0...allocate(capacity: s.count-1) + defer { b.deallocate() } + expectCrash { + _ = b.moveInitialize(fromContentsOf: s) + } +} + +UnsafeMutableBufferPointerTestSuite.test("UMBP.moveUpdate.overflow") +.skip(.custom({ + if #available(SwiftStdlib 5.8, *) { return false } else { return true } +}, reason: "Requires standard library from Swift 5.8")) +.code { + let s = UnsafeMutableBufferPointer.allocate(capacity: 8) + defer { s.deallocate() } + s.initialize(fromContentsOf: 0..(0..<8) + let b = UnsafeMutableRawBufferPointer.allocate( + byteCount: MemoryLayout.stride * (s.count-1), + alignment: MemoryLayout.alignment + ) + defer { b.deallocate() } + expectCrash { + let i = b.initializeMemory(as: Int.self, fromContentsOf: s) + i.deinitialize() + } +} + +UnsafeMutableRawBufferPointerTestSuite.test("UMRBP.moveInitializeMemory.overflow") +.skip(.custom({ + if #available(SwiftStdlib 5.8, *) { return false } else { return true } +}, reason: "Requires standard library from Swift 5.8")) +.code { + let s = UnsafeMutableBufferPointer.allocate(capacity: 8) + defer { s.deallocate() } + s.initialize(fromContentsOf: 0...stride * (s.count-1), + alignment: MemoryLayout.alignment + ) + defer { b.deallocate() } + expectCrash { + let i = b.moveInitializeMemory(as: Int.self, fromContentsOf: s) + i.deinitialize() + } +} + runAllTests() From 71b6d991263a52695ff3917bd94c1a05faeb887e Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Sun, 11 Sep 2022 05:17:22 -0600 Subject: [PATCH 42/45] [test] fix a test warning --- validation-test/stdlib/UnsafeBufferPointerSlices.swift | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/validation-test/stdlib/UnsafeBufferPointerSlices.swift b/validation-test/stdlib/UnsafeBufferPointerSlices.swift index c8af91f6508f7..5296d4b7c4518 100644 --- a/validation-test/stdlib/UnsafeBufferPointerSlices.swift +++ b/validation-test/stdlib/UnsafeBufferPointerSlices.swift @@ -280,10 +280,12 @@ UnsafeMutableBufferPointerSliceTests.test( var a = UnsafeMutableBufferPointer.allocate(capacity: c) defer { a.deallocate() } - a.initialize(fromContentsOf: Array(repeating: ".", count: c)) + var i: Int? = a.initialize(fromContentsOf: Array(repeating: ".", count: c)) defer { a.deinitialize() } + expectEqual(i, c) + expectTrue(a.allSatisfy({ $0 == "." })) - var i = a.withContiguousMutableStorageIfAvailable { + i = a.withContiguousMutableStorageIfAvailable { $0.update(fromContentsOf: Array(repeating: " ", count: c)) } expectEqual(i, c) From 1152347699b85818b1357bb8c709e22c4ee80dcc Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Mon, 12 Sep 2022 14:12:32 -0600 Subject: [PATCH 43/45] [stdlib] remove primary associated type from `copyBytes` - this caused an unexpected test failure, will change separately. --- stdlib/public/core/UnsafeBufferPointerSlice.swift | 4 +++- stdlib/public/core/UnsafeRawBufferPointer.swift.gyb | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/stdlib/public/core/UnsafeBufferPointerSlice.swift b/stdlib/public/core/UnsafeBufferPointerSlice.swift index 5913423ec1e39..c5fb3354d0348 100644 --- a/stdlib/public/core/UnsafeBufferPointerSlice.swift +++ b/stdlib/public/core/UnsafeBufferPointerSlice.swift @@ -26,7 +26,9 @@ extension Slice where Base == UnsafeMutableRawBufferPointer { /// be less than or equal to this buffer slice's `count`. @inlinable @_alwaysEmitIntoClient - public func copyBytes(from source: some Collection) { + public func copyBytes( + from source: C + ) where C.Element == UInt8 { let buffer = Base(rebasing: self) buffer.copyBytes(from: source) } diff --git a/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb b/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb index 3ec1199ed8e64..00faf550475e4 100644 --- a/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb +++ b/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb @@ -534,7 +534,9 @@ extension Unsafe${Mutable}RawBufferPointer { /// - Parameter source: A collection of `UInt8` elements. `source.count` must /// be less than or equal to this buffer's `count`. @inlinable - public func copyBytes(from source: some Collection) { + public func copyBytes( + from source: C + ) where C.Element == UInt8 { guard let position = _position else { return } From dfda525ae33246b6b1a8219cb56f7db47e466535 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Mon, 12 Sep 2022 14:16:54 -0600 Subject: [PATCH 44/45] [abi] override the judgment of the abi stability test --- test/api-digester/stability-stdlib-abi-without-asserts.test | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/api-digester/stability-stdlib-abi-without-asserts.test b/test/api-digester/stability-stdlib-abi-without-asserts.test index 6e17ea6853748..15d3b5d8214e9 100644 --- a/test/api-digester/stability-stdlib-abi-without-asserts.test +++ b/test/api-digester/stability-stdlib-abi-without-asserts.test @@ -96,9 +96,13 @@ Func UnsafePointer.withMemoryRebound(to:capacity:_:) has been removed Func UnsafeMutableRawBufferPointer.storeBytes(of:toByteOffset:as:) has been removed Func UnsafeMutableRawPointer.storeBytes(of:toByteOffset:as:) has been removed Func UnsafeMutableBufferPointer.assign(repeating:) has been removed +Func UnsafeMutableBufferPointer.update(repeating:) is a new API without @available attribute Func UnsafeMutablePointer.assign(from:count:) has been removed +Func UnsafeMutablePointer.update(from:count:) is a new API without @available attribute Func UnsafeMutablePointer.assign(repeating:count:) has been removed +Func UnsafeMutablePointer.update(repeating:count:) is a new API without @available attribute Func UnsafeMutablePointer.moveAssign(from:count:) has been removed +Func UnsafeMutablePointer.moveUpdate(from:count:) is a new API without @available attribute // These haven't actually been removed; they were renamed at the source level while // retaining their old mangled name. The source break was accepted as part of se-0370. From 7f4caede9017c59d4a67214bba73d4e33f154296 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Tue, 13 Sep 2022 13:31:44 -0600 Subject: [PATCH 45/45] [stdlib] avoid primary associated type for the time being --- stdlib/public/core/UnsafeBufferPointer.swift.gyb | 12 ++++++------ stdlib/public/core/UnsafeBufferPointerSlice.swift | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/stdlib/public/core/UnsafeBufferPointer.swift.gyb b/stdlib/public/core/UnsafeBufferPointer.swift.gyb index 7b4552a98893c..21db8f2461fb9 100644 --- a/stdlib/public/core/UnsafeBufferPointer.swift.gyb +++ b/stdlib/public/core/UnsafeBufferPointer.swift.gyb @@ -711,9 +711,9 @@ extension Unsafe${Mutable}BufferPointer { /// by this function. @inlinable @_alwaysEmitIntoClient - public func initialize( - fromContentsOf source: some Collection - ) -> Index { + public func initialize( + fromContentsOf source: C + ) -> Index where C.Element == Element { let count = source.withContiguousStorageIfAvailable { guard let sourceAddress = $0.baseAddress, !$0.isEmpty else { return 0 @@ -814,9 +814,9 @@ extension Unsafe${Mutable}BufferPointer { /// - Returns: An index one past the index of the last element updated. @inlinable @_alwaysEmitIntoClient - public func update( - fromContentsOf source: some Collection - ) -> Index { + public func update( + fromContentsOf source: C + ) -> Index where C.Element == Element { let count = source.withContiguousStorageIfAvailable { guard let sourceAddress = $0.baseAddress else { return 0 diff --git a/stdlib/public/core/UnsafeBufferPointerSlice.swift b/stdlib/public/core/UnsafeBufferPointerSlice.swift index c5fb3354d0348..70b7c1723767b 100644 --- a/stdlib/public/core/UnsafeBufferPointerSlice.swift +++ b/stdlib/public/core/UnsafeBufferPointerSlice.swift @@ -763,9 +763,9 @@ extension Slice { /// initialized by this function. @inlinable @_alwaysEmitIntoClient - public func initialize( - fromContentsOf source: some Collection - ) -> Index where Base == UnsafeMutableBufferPointer { + public func initialize( + fromContentsOf source: C + ) -> Index where Base == UnsafeMutableBufferPointer { let buffer = Base(rebasing: self) let index = buffer.initialize(fromContentsOf: source) let distance = buffer.distance(from: buffer.startIndex, to: index) @@ -833,9 +833,9 @@ extension Slice { /// - Returns: An index one past the index of the last element updated. @inlinable @_alwaysEmitIntoClient - public func update( - fromContentsOf source: some Collection - ) -> Index where Base == UnsafeMutableBufferPointer { + public func update( + fromContentsOf source: C + ) -> Index where Base == UnsafeMutableBufferPointer { let buffer = Base(rebasing: self) let index = buffer.update(fromContentsOf: source) let distance = buffer.distance(from: buffer.startIndex, to: index)