From 65f98e24c79fe9715164bd3c7f81d1af1175e1c9 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Mon, 18 Oct 2021 21:27:07 -0600 Subject: [PATCH 01/10] [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 03ecd957f6f83..cded30f80c0ed 100644 --- a/stdlib/public/core/UnsafePointer.swift +++ b/stdlib/public/core/UnsafePointer.swift @@ -725,6 +725,20 @@ public struct UnsafeMutablePointer: _Pointer, Sendable { } } + /// 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 426bbfb4ba5315e183d7dc219716135ee5a256de Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Thu, 11 Nov 2021 16:58:25 -0700 Subject: [PATCH 02/10] [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 cded30f80c0ed..50070871cd4c9 100644 --- a/stdlib/public/core/UnsafePointer.swift +++ b/stdlib/public/core/UnsafePointer.swift @@ -626,14 +626,14 @@ public struct UnsafeMutablePointer: _Pointer, Sendable { 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 @@ -705,7 +705,7 @@ public struct UnsafeMutablePointer: _Pointer, Sendable { 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` @@ -714,9 +714,9 @@ public struct UnsafeMutablePointer: _Pointer, Sendable { /// `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") @@ -739,8 +739,8 @@ public struct UnsafeMutablePointer: _Pointer, Sendable { 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 @@ -833,6 +833,8 @@ public struct UnsafeMutablePointer: _Pointer, Sendable { /// `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 @@ -855,8 +857,9 @@ public struct UnsafeMutablePointer: _Pointer, Sendable { // } } - /// 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 @@ -864,8 +867,10 @@ public struct UnsafeMutablePointer: _Pointer, Sendable { /// `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 @@ -966,14 +971,14 @@ public struct UnsafeMutablePointer: _Pointer, Sendable { return try body(UnsafeMutablePointer(_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 5c49c229a1d5894e22770403aeb7eef658bc88c1 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Tue, 19 Oct 2021 18:32:27 -0600 Subject: [PATCH 03/10] [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 fd1ae2eda8c35..47e9668daf92a 100644 --- a/stdlib/public/core/UnsafeBufferPointer.swift.gyb +++ b/stdlib/public/core/UnsafeBufferPointer.swift.gyb @@ -621,8 +621,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 e38314e745b25535e180569605fc00a5131f73bd Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Tue, 19 Oct 2021 18:41:05 -0600 Subject: [PATCH 04/10] [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 47e9668daf92a..c2b994ac087c1 100644 --- a/stdlib/public/core/UnsafeBufferPointer.swift.gyb +++ b/stdlib/public/core/UnsafeBufferPointer.swift.gyb @@ -630,9 +630,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 4b562ea0638e559986a4db3d4d25bdae61998591 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Tue, 19 Oct 2021 18:34:02 -0600 Subject: [PATCH 05/10] [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 c2b994ac087c1..768fbebec5e74 100644 --- a/stdlib/public/core/UnsafeBufferPointer.swift.gyb +++ b/stdlib/public/core/UnsafeBufferPointer.swift.gyb @@ -622,15 +622,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. /// - /// The buffer’s memory must be initialized or the buffer's `Element` - /// must be a trivial type. + /// 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`. /// - /// - Parameters: - /// - repeatedValue: The instance to assign this buffer's memory to. + /// 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`. + /// + /// - 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 @@ -719,34 +1007,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) - } -} - extension UnsafeBufferPointer: Sendable { } extension UnsafeBufferPointer.Iterator: Sendable { } extension UnsafeMutableBufferPointer: Sendable { } From 9efa825d0c0f64f613a401dda3fc4c964dc4c8a7 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Fri, 22 Oct 2021 17:19:42 -0600 Subject: [PATCH 06/10] [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 8bb87ea5ed6e4..22e23cf48d58e 100644 --- a/stdlib/public/core/UnsafeRawPointer.swift +++ b/stdlib/public/core/UnsafeRawPointer.swift @@ -700,6 +700,45 @@ public struct UnsafeMutableRawPointer: _Pointer, Sendable { 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 f88dd1623a862a112c97cce0b8d675f94252738f Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Sat, 23 Oct 2021 18:47:12 -0600 Subject: [PATCH 07/10] [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 d08e488661e0d..b01cb7b40cf91 100644 --- a/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb +++ b/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb @@ -428,8 +428,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, @@ -444,7 +444,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`. /// @@ -631,9 +631,10 @@ extension Unsafe${Mutable}RawBufferPointer { return UnsafeMutableBufferPointer(start: nil, count: 0) } - let count = (_end! - 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) } @@ -654,7 +655,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 @@ -696,6 +697,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 c6e30b2c8d7b38539948feda4a4bcacacd83e24f Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Thu, 11 Nov 2021 16:58:50 -0700 Subject: [PATCH 08/10] =?UTF-8?q?assign=20=E2=86=92=20update=20(part=201)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- stdlib/public/core/UnsafePointer.swift | 48 ++++++++++++++++++++------ 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/stdlib/public/core/UnsafePointer.swift b/stdlib/public/core/UnsafePointer.swift index 50070871cd4c9..29b1c764b2b03 100644 --- a/stdlib/public/core/UnsafePointer.swift +++ b/stdlib/public/core/UnsafePointer.swift @@ -711,20 +711,28 @@ public struct UnsafeMutablePointer: _Pointer, Sendable { /// 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, Sendable { /// /// - Parameters: /// - value: The value used to update this pointer's memory. - public func assign(_ value: Pointee) { + public func update(_ value: Pointee) { pointee = value } @@ -745,7 +753,7 @@ public struct UnsafeMutablePointer: _Pointer, Sendable { /// 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. /// @@ -756,9 +764,10 @@ public struct UnsafeMutablePointer: _Pointer, Sendable { /// - 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( @@ -781,6 +790,13 @@ public struct UnsafeMutablePointer: _Pointer, Sendable { } } + @_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. @@ -864,7 +880,7 @@ public struct UnsafeMutablePointer: _Pointer, Sendable { /// 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. @@ -876,14 +892,15 @@ public struct UnsafeMutablePointer: _Pointer, Sendable { /// - 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: @@ -891,7 +908,16 @@ public struct UnsafeMutablePointer: _Pointer, Sendable { // 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 9b901e859701c9a1ce20054b1a22d77e74aceb77 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Mon, 15 Nov 2021 12:11:31 -0700 Subject: [PATCH 09/10] =?UTF-8?q?assign=20=E2=86=92=20update=20(part=202)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../public/core/UnsafeBufferPointer.swift.gyb | 36 +++++++++++-------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/stdlib/public/core/UnsafeBufferPointer.swift.gyb b/stdlib/public/core/UnsafeBufferPointer.swift.gyb index 768fbebec5e74..13247d398a508 100644 --- a/stdlib/public/core/UnsafeBufferPointer.swift.gyb +++ b/stdlib/public/core/UnsafeBufferPointer.swift.gyb @@ -423,7 +423,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) } @@ -700,12 +700,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. @@ -717,9 +725,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 { @@ -742,14 +750,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) @@ -812,7 +820,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. @@ -821,10 +829,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) } @@ -836,7 +844,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. @@ -845,8 +853,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. @@ -893,7 +901,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 From 60728cf897369b5c4ac5c5cc2dbd317b0b32c772 Mon Sep 17 00:00:00 2001 From: Guillaume Lessard Date: Thu, 11 Nov 2021 17:05:52 -0700 Subject: [PATCH 10/10] =?UTF-8?q?assign=20=E2=86=92=20update=20(part=203)?= 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 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/stdlib/public/core/ArrayBufferProtocol.swift b/stdlib/public/core/ArrayBufferProtocol.swift index 3dd88825b5a0a..cbf69f384ff09 100644 --- a/stdlib/public/core/ArrayBufferProtocol.swift +++ b/stdlib/public/core/ArrayBufferProtocol.swift @@ -167,7 +167,7 @@ extension _ArrayBufferProtocol where Indices == Range{ // 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] @@ -200,17 +200,17 @@ extension _ArrayBufferProtocol where Indices == Range{ 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 163b06d3b626c..2b740e898c987 100644 --- a/stdlib/public/core/StringGuts.swift +++ b/stdlib/public/core/StringGuts.swift @@ -329,7 +329,7 @@ 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