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/CMakeLists.txt b/stdlib/public/core/CMakeLists.txt index 2419c9926d745..0ff94278675f4 100644 --- a/stdlib/public/core/CMakeLists.txt +++ b/stdlib/public/core/CMakeLists.txt @@ -227,6 +227,7 @@ set(SWIFTLIB_SOURCES CommandLine.swift SliceBuffer.swift UnfoldSequence.swift + UnsafeBufferPointerSlice.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..b266b17c2f46f 100644 --- a/stdlib/public/core/GroupInfo.json +++ b/stdlib/public/core/GroupInfo.json @@ -187,6 +187,7 @@ "UnsafePointer.swift", "UnsafeRawPointer.swift", "UnsafeBufferPointer.swift", + "UnsafeBufferPointerSlice.swift", "UnsafeRawBufferPointer.swift" ], "Protocols": [ 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 966508c07a96d..21db8f2461fb9 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: @@ -450,7 +454,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) } @@ -632,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 @@ -648,27 +653,423 @@ 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) { + @_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) + } + + /// 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, + /// 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, 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` + /// + /// - 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 + /// by this function. + @inlinable + @_alwaysEmitIntoClient + 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 + } + _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) + } + + var (iterator, copied) = source._copySequenceContents(initializing: self) + _precondition( + iterator.next() == nil, + "buffer cannot contain every element from source." + ) + return startIndex.advanced(by: copied) + } + + /// Updates every element of this buffer's initialized memory. + /// + /// The buffer’s memory must be initialized or its `Element` type + /// must be a trivial type. + /// + /// - Note: All buffer elements must already be initialized. + /// + /// - Parameters: + /// - repeatedValue: The value used when updating this pointer's memory. + @inlinable // unsafe-performance + @_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) } - + + @inlinable + @_alwaysEmitIntoClient + @available(*, deprecated, renamed: "update(repeating:)") + @_silgen_name("_swift_se0370_UnsafeMutableBufferPointer_assign_repeating") + public func assign(repeating repeatedValue: Element) { + update(repeating: repeatedValue) + } + + /// 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 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. + @inlinable + @_alwaysEmitIntoClient + public func update( + from source: S + ) -> (unwritten: S.Iterator, index: Index) where S.Element == Element { + var iterator = source.makeIterator() + 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, index) + } + + /// 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 + /// initialized, or the buffer's `Element` type must be a trivial type. + /// 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`. + /// + /// - 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 + /// the buffer's contents. + /// - Returns: An index one past the index of the last element updated. + @inlinable + @_alwaysEmitIntoClient + public func update( + fromContentsOf source: C + ) -> Index where C.Element == Element { + 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) + } + + if self.isEmpty { + _precondition( + source.isEmpty, + "buffer cannot contain every element from source." + ) + return startIndex + } + _internalInvariant(_position != nil) + var iterator = source.makeIterator() + var index = startIndex + while let value = iterator.next() { + guard index < endIndex else { + _preconditionFailure( + "buffer cannot contain every element from source." + ) + break + } + _position._unsafelyUnwrappedUnchecked[index] = value + formIndex(after: &index) + } + return index + } + + /// 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`. + /// + /// - 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. + /// - Returns: The index one past the last element of the buffer initialized + /// by this function. + @inlinable + @_alwaysEmitIntoClient + public func moveInitialize(fromContentsOf source: Self) -> Index { + 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) + } + + /// 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`. + /// + /// - 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. + /// - Returns: The index one past the last element of the buffer initialized + /// by this function. + @inlinable + @_alwaysEmitIntoClient + 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. + /// + /// 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`. + /// + /// - 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. + /// - Returns: An index one past the index of the last element updated. + @inlinable + @_alwaysEmitIntoClient + public func moveUpdate(fromContentsOf source: Self) -> Index { + 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) + } + + /// Updates this buffer's initialized memory initialized memory by + /// moving every element from the source buffer slice, + /// leaving the source memory 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`. + /// + /// - 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. + /// - Returns: An index one past the index of the last element updated. + @inlinable + @_alwaysEmitIntoClient + public func moveUpdate(fromContentsOf source: Slice) -> Index { + return moveUpdate(fromContentsOf: 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 + @inlinable + @_alwaysEmitIntoClient + 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 + @inlinable + @_alwaysEmitIntoClient + public func initializeElement(at index: Index, to value: Element) { + _debugPrecondition(startIndex <= index && index < endIndex) + let p = baseAddress._unsafelyUnwrappedUnchecked.advanced(by: index) + p.initialize(to: 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. + @inlinable + @_alwaysEmitIntoClient + public func moveElement(from index: Index) -> Element { + _debugPrecondition(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. + @inlinable + @_alwaysEmitIntoClient + public func deinitializeElement(at index: Index) { + _debugPrecondition(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 @@ -708,7 +1109,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. /// @@ -802,34 +1203,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: diff --git a/stdlib/public/core/UnsafeBufferPointerSlice.swift b/stdlib/public/core/UnsafeBufferPointerSlice.swift new file mode 100644 index 0000000000000..70b7c1723767b --- /dev/null +++ b/stdlib/public/core/UnsafeBufferPointerSlice.swift @@ -0,0 +1,1144 @@ +//===----------------------------------------------------------*- 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 from a collection of `UInt8` into this buffer slice's memory. + /// + /// 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 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`. + @inlinable + @_alwaysEmitIntoClient + 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 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 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 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 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. + /// - 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`. + @discardableResult + @inlinable + @_alwaysEmitIntoClient + public 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 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 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`. + /// + /// - 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 + @_alwaysEmitIntoClient + 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 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 + /// 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. + /// - 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, + fromContentsOf source: C + ) -> UnsafeMutableBufferPointer { + let buffer = Base(rebasing: self) + return buffer.initializeMemory(as: C.Element.self, fromContentsOf: source) + } + + /// 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. + /// - source: A buffer referencing the values to copy. + /// The memory region underlying `source` must be initialized. + /// 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`. + @discardableResult + @inlinable + @_alwaysEmitIntoClient + public func moveInitializeMemory( + as type: T.Type, + fromContentsOf source: UnsafeMutableBufferPointer + ) -> UnsafeMutableBufferPointer { + let buffer = Base(rebasing: self) + return buffer.moveInitializeMemory(as: T.self, fromContentsOf: source) + } + + /// 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. + /// + /// 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. + /// - 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 slice, and its count is equal to `source.count`. + @discardableResult + @inlinable + @_alwaysEmitIntoClient + public func moveInitializeMemory( + as type: T.Type, + fromContentsOf source: Slice> + ) -> UnsafeMutableBufferPointer { + let buffer = Base(rebasing: self) + return buffer.moveInitializeMemory(as: T.self, fromContentsOf: source) + } + + /// 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 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`. + /// + /// - 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 + @inlinable + @_alwaysEmitIntoClient + 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 slice to + /// instances of type `T`. + /// + /// 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 + /// 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 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 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 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 + /// 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 + /// 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. + @inlinable + @_alwaysEmitIntoClient + public 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 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 + /// 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 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. + /// - Returns: A typed pointer to the same memory as this raw pointer. + @inlinable + @_alwaysEmitIntoClient + public func assumingMemoryBound( + to type: T.Type + ) -> UnsafeMutableBufferPointer { + 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, toByteOffset offset: Int = 0, as type: T.Type + ) { + let buffer = Base(rebasing: self) + buffer.storeBytes(of: value, toByteOffset: offset, as: T.self) + } +} + +extension Slice where Base == UnsafeRawBufferPointer { + + /// 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 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`. + /// + /// - 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 + @inlinable + @_alwaysEmitIntoClient + 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 slice to + /// instances of type `T`. + /// + /// 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 + /// 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 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 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 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 + /// 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 + /// 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. + @inlinable + @_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) + } + + /// 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 + /// 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 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. + /// - Returns: A typed pointer to the same memory as this raw pointer. + @inlinable + @_alwaysEmitIntoClient + public func assumingMemoryBound( + to type: T.Type + ) -> UnsafeBufferPointer { + 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 { + /// 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 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 + /// 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 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 + /// `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 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 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 + /// 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 + @_alwaysEmitIntoClient + public func withMemoryRebound( + to type: T.Type, _ body: (UnsafeBufferPointer) throws -> Result + ) rethrows -> Result where Base == UnsafeBufferPointer { + let rebased = UnsafeBufferPointer(rebasing: self) + return try rebased.withMemoryRebound(to: T.self, body) + } +} + +extension Slice { + + /// 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. + @inlinable + @_alwaysEmitIntoClient + public func initialize(repeating repeatedValue: Element) + where Base == UnsafeMutableBufferPointer { + 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 slice 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. + @inlinable + @_alwaysEmitIntoClient + public func initialize( + from source: S + ) -> (unwritten: S.Iterator, index: 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) + return (iterator, startIndex.advanced(by: distance)) + } + + /// 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 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` + /// + /// - 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 + /// initialized by this function. + @inlinable + @_alwaysEmitIntoClient + 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) + 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. + @inlinable + @_alwaysEmitIntoClient + public func update(repeating repeatedValue: Element) + where Base == UnsafeMutableBufferPointer { + 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 contents of the buffer slice. + /// - Returns: An iterator to any elements of `source` that didn't fit in the + /// buffer slice, and the index one past the last updated element. + @inlinable + @_alwaysEmitIntoClient + public func update( + from source: S + ) -> (unwritten: S.Iterator, index: 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) + return (iterator, startIndex.advanced(by: distance)) + } + + /// 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 `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 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`. + /// + /// - 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 + /// the buffer's contents. + /// - Returns: An index one past the index of the last element updated. + @inlinable + @_alwaysEmitIntoClient + 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) + 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. + /// + /// 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. + /// + /// 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`. + /// + /// - 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. + /// - Returns: The index one past the last element of the buffer slice + /// initialized by this function. + @inlinable + @_alwaysEmitIntoClient + public func moveInitialize( + fromContentsOf source: UnsafeMutableBufferPointer + ) -> Index where Base == UnsafeMutableBufferPointer { + let buffer = Base(rebasing: self) + let index = buffer.moveInitialize(fromContentsOf: 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. + /// + /// 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. + /// + /// 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`. + /// + /// - 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. + /// - Returns: The index one past the last element of the buffer slice + /// initialized by this function. + @inlinable + @_alwaysEmitIntoClient + public func moveInitialize( + fromContentsOf source: Slice> + ) -> Index where Base == UnsafeMutableBufferPointer { + let buffer = Base(rebasing: self) + let index = buffer.moveInitialize(fromContentsOf: 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 `source.count` instances of its `Element` type must be + /// 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 + /// 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. + /// - Returns: An index one past the index of the last element updated. + @inlinable + @_alwaysEmitIntoClient + public func moveUpdate( + fromContentsOf source: UnsafeMutableBufferPointer + ) -> Index where Base == UnsafeMutableBufferPointer { + let buffer = Base(rebasing: self) + let index = buffer.moveUpdate(fromContentsOf: 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 `source.count` instances of its `Element` type must be + /// 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 + /// 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. + /// - Returns: An index one past the index of the last element updated. + @inlinable + @_alwaysEmitIntoClient + public func moveUpdate( + fromContentsOf source: Slice> + ) -> Index where Base == UnsafeMutableBufferPointer { + let buffer = Base(rebasing: self) + let index = buffer.moveUpdate(fromContentsOf: 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 + @inlinable + @_alwaysEmitIntoClient + public func deinitialize() -> UnsafeMutableRawBufferPointer + where Base == UnsafeMutableBufferPointer { + 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 + @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) + } + + /// 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. + @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() + } + + /// 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. + @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) + } + + /// 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 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 + /// 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 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 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 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 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 + /// 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 + @_alwaysEmitIntoClient + public func withMemoryRebound( + to type: T.Type, _ body: (UnsafeMutableBufferPointer) throws -> Result + ) rethrows -> Result where Base == UnsafeMutableBufferPointer { + try Base(rebasing: self).withMemoryRebound(to: T.self, body) + } + + @inlinable + @_alwaysEmitIntoClient + public func withContiguousMutableStorageIfAvailable( + _ body: (_ buffer: inout UnsafeMutableBufferPointer) throws -> 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) + let (b,c) = (slice.baseAddress, slice.count) + defer { + _precondition( + slice.baseAddress == b && slice.count == c, + "withContiguousMutableStorageIfAvailable: replacing the buffer is not allowed") + } + return try body(&slice) + } + } +} diff --git a/stdlib/public/core/UnsafePointer.swift b/stdlib/public/core/UnsafePointer.swift index 86b7e405c6fd2..d8d82e90c084e 100644 --- a/stdlib/public/core/UnsafePointer.swift +++ b/stdlib/public/core/UnsafePointer.swift @@ -687,16 +687,16 @@ 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 - /// 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 { @@ -766,33 +766,42 @@ 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` /// 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) { - _debugPrecondition(count >= 0, "UnsafeMutablePointer.assign(repeating:count:) with negative count") + @_silgen_name("$sSp6assign9repeating5countyx_SitF") + public func update(repeating repeatedValue: Pointee, count: Int) { + _debugPrecondition(count >= 0, "UnsafeMutablePointer.update(repeating:count:) with negative count") for i in 0..: _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( @@ -828,6 +838,14 @@ public struct UnsafeMutablePointer: _Pointer { } } + @inlinable + @_alwaysEmitIntoClient + @available(*, deprecated, renamed: "update(from:count:)") + @_silgen_name("_swift_se0370_UnsafeMutablePointer_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. @@ -880,6 +898,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 @@ -902,30 +922,34 @@ 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 /// `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: @@ -933,7 +957,17 @@ public struct UnsafeMutablePointer: _Pointer { // self[i] = (source + i).move() // } } - + + @inlinable + @_alwaysEmitIntoClient + @available(*, deprecated, renamed: "moveUpdate(from:count:)") + @_silgen_name("_swift_se0370_UnsafeMutablePointer_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` @@ -1055,16 +1089,16 @@ 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 - /// 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. diff --git a/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb b/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb index 1df4cff6dba8a..00faf550475e4 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, @@ -522,28 +522,29 @@ 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 `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`. /// /// - 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 + public func copyBytes( + from source: C ) where C.Element == UInt8 { - _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 + (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) } @@ -552,6 +553,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) } @@ -695,10 +698,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 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. /// /// - Parameters: /// - type: The type to bind this buffer’s memory to. @@ -711,13 +715,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 count = (_end._unsafelyUnwrappedUnchecked-base) / MemoryLayout.stride + 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 @@ -730,14 +735,15 @@ 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`. + /// `S.Element`. This method does not change + /// the binding state of the unused portion of `b`, if any. /// /// - 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 @@ -747,8 +753,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 @@ -763,6 +767,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 @@ -780,6 +789,185 @@ extension Unsafe${Mutable}RawBufferPointer { start: base.assumingMemoryBound(to: S.Element.self), count: idx / elementStride)) } + + /// 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 + /// 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 + /// initialize the buffer's storage. + /// - 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 initializeMemory( + as type: C.Element.Type, + fromContentsOf source: C + ) -> UnsafeMutableBufferPointer { + 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 + } + + guard let base = baseAddress else { + _precondition( + source.isEmpty, + "buffer cannot contain every element from source collection." + ) + return .init(start: nil, count: 0) + } + _internalInvariant(_end != nil) + _debugPrecondition( + Int(bitPattern: baseAddress) % MemoryLayout.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 + } + _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 + /// uninitialized memory referenced by this buffer, leaving the source memory + /// uninitialized and this buffer's memory initialized. + /// + /// 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. + /// + /// - 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. + /// - 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, + fromContentsOf source: UnsafeMutableBufferPointer + ) -> UnsafeMutableBufferPointer { + guard let sourceAddress = source.baseAddress, !source.isEmpty else { + return .init(start: nil, count: 0) + } + _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 + ) + return .init(start: initialized, count: 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. + /// + /// 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. + /// + /// - 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. + /// - 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, + fromContentsOf source: Slice> + ) -> UnsafeMutableBufferPointer { + let rebased = UnsafeMutableBufferPointer(rebasing: source) + return moveInitializeMemory(as: T.self, fromContentsOf: rebased) + } + % end # mutable /// Binds this buffer’s memory to the specified type and returns a typed buffer @@ -798,7 +986,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( @@ -850,7 +1039,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 diff --git a/stdlib/public/core/UnsafeRawPointer.swift b/stdlib/public/core/UnsafeRawPointer.swift index b41895574a83a..cf2490a93f2a3 100644 --- a/stdlib/public/core/UnsafeRawPointer.swift +++ b/stdlib/public/core/UnsafeRawPointer.swift @@ -959,6 +959,46 @@ 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. + @discardableResult + @inlinable + @_alwaysEmitIntoClient + 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. diff --git a/test/api-digester/stability-stdlib-abi-without-asserts.test b/test/api-digester/stability-stdlib-abi-without-asserts.test index dd35103b989b3..15d3b5d8214e9 100644 --- a/test/api-digester/stability-stdlib-abi-without-asserts.test +++ b/test/api-digester/stability-stdlib-abi-without-asserts.test @@ -95,6 +95,19 @@ 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 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. +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 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() diff --git a/validation-test/stdlib/UnsafeBufferPointerSlices.swift b/validation-test/stdlib/UnsafeBufferPointerSlices.swift new file mode 100644 index 0000000000000..5296d4b7c4518 --- /dev/null +++ b/validation-test/stdlib/UnsafeBufferPointerSlices.swift @@ -0,0 +1,638 @@ +// RUN: %target-run-simple-swift +// REQUIRES: executable_test +// END. + +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.fromContentsOf.Collection" +) { + let c = 4 + let mb = UnsafeMutableBufferPointer.allocate(capacity: c) + defer { mb.deallocate() } + + 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(fromContentsOf: (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(fromContentsOf: (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(fromContentsOf: source) + expectEqual(i, c) + i = a.moveInitialize(fromContentsOf: buffer) + expectEqual(i, c) + expectTrue(a.elementsEqual(source)) + i = buffer.initialize(fromContentsOf: source) + expectEqual(i, c) + i = b[...].moveInitialize(fromContentsOf: buffer) + expectEqual(i, c) + expectTrue(b.elementsEqual(source)) + + i = buffer.initialize(fromContentsOf: source.prefix(n)) + expectEqual(i, n) + i = a.moveInitialize(fromContentsOf: 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(fromContentsOf: source) + expectEqual(i, c) + i = a.withContiguousMutableStorageIfAvailable { + $0.moveUpdate(fromContentsOf: buffer) + } + expectEqual(i, c) + expectEqual(a, source) + i = buffer.initialize(fromContentsOf: source) + expectEqual(i, c) + i = b.withContiguousMutableStorageIfAvailable { + $0[...].moveUpdate(fromContentsOf: buffer) + } + expectEqual(i, c) + expectEqual(a, b) + + i = buffer.initialize(fromContentsOf: source.prefix(n)) + expectEqual(i, n) + i = a.withContiguousMutableStorageIfAvailable { + $0.moveUpdate(fromContentsOf: 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) + + expectEqual(a.moveElement(from: n), s) + expectEqual(b[...].moveElement(from: n), s) + + a.initializeElement(at: 0, to: t) + a.deinitializeElement(at: 0) + b.initializeElement(at: 0, to: t) + b[...].deinitializeElement(at: 0) +} + +UnsafeMutableBufferPointerSliceTests.test( + "slice.of.UnsafeMutableBufferpointer.withContiguousMutableStorageIfAvailable" +) { + let c = 4 + + var a = UnsafeMutableBufferPointer.allocate(capacity: c) + defer { a.deallocate() } + var i: Int? = a.initialize(fromContentsOf: Array(repeating: ".", count: c)) + defer { a.deinitialize() } + expectEqual(i, c) + expectTrue(a.allSatisfy({ $0 == "." })) + + i = a.withContiguousMutableStorageIfAvailable { + $0.update(fromContentsOf: Array(repeating: " ", count: c)) + } + expectEqual(i, c) + expectTrue(a.allSatisfy({ $0 == " " })) + + i = a[...].withContiguousMutableStorageIfAvailable { + $0.update(fromContentsOf: 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, fromContentsOf: 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(fromContentsOf: source), c) + var tba = rba.moveInitializeMemory(as: Int.self, fromContentsOf: buffer) + expectEqual(tba.count, c) + expectTrue(tba.elementsEqual(source)) + + expectEqual(buffer.initialize(fromContentsOf: source), c) + var tbb = rbb[...].moveInitializeMemory(as: Int.self, fromContentsOf: 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(fromContentsOf: source.prefix(n)), n) + tba = rba.moveInitializeMemory(as: Int.self, fromContentsOf: buffer.prefix(n)) + expectEqual(tba.count, n) + expectTrue(tba.elementsEqual(source.prefix(n))) + + expectEqual(buffer.initialize(fromContentsOf: source.prefix(n)), n) + tbb = rbb[...].moveInitializeMemory(as: Int.self, fromContentsOf: 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...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()