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 diff --git a/stdlib/public/core/UnsafeBufferPointer.swift.gyb b/stdlib/public/core/UnsafeBufferPointer.swift.gyb index fd1ae2eda8c35..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) } @@ -621,27 +621,321 @@ 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. + + /// 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`. /// - /// 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`. + /// - 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 assign(repeating repeatedValue: Element) { + 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, updated: 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 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.update(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 `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: 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) + 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 `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 { + return moveUpdate(fromElements: 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 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. + /// + /// 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 @@ -721,34 +1015,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 { } diff --git a/stdlib/public/core/UnsafePointer.swift b/stdlib/public/core/UnsafePointer.swift index 03ecd957f6f83..29b1c764b2b03 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,33 +705,55 @@ 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` /// 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 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) { + @_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 { /// - 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( @@ -767,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. @@ -819,6 +849,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 @@ -841,30 +873,34 @@ 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 /// `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. + /// /// - 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 /// 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: @@ -872,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` @@ -952,14 +997,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:)`. /// 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 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.