mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
implement SE 184: add allocation methods to Unsafe buffer pointers, drop all parameters from deallocation, adjust namings, and add repeated-value assignment methods
This commit is contained in:
committed by
Andrew Trick
parent
c7d33e70d3
commit
c85880899d
@@ -3315,7 +3315,7 @@ internal class _TypedNative${Self}Storage<${TypeParameters}> :
|
||||
if !_isPOD(Key.self) {
|
||||
for i in 0 ..< capacity {
|
||||
if initializedEntries[i] {
|
||||
(keys+i).deinitialize()
|
||||
(keys+i).deinitialize(count: 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3324,7 +3324,7 @@ internal class _TypedNative${Self}Storage<${TypeParameters}> :
|
||||
if !_isPOD(Value.self) {
|
||||
for i in 0 ..< capacity {
|
||||
if initializedEntries[i] {
|
||||
(values+i).deinitialize()
|
||||
(values+i).deinitialize(count: 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3729,9 +3729,9 @@ internal struct _Native${Self}Buffer<${TypeParameters}> {
|
||||
_sanityCheck(isInitializedEntry(at: i))
|
||||
defer { _fixLifetime(self) }
|
||||
|
||||
(keys + i).deinitialize()
|
||||
(keys + i).deinitialize(count: 1)
|
||||
%if Self == 'Dictionary':
|
||||
(values + i).deinitialize()
|
||||
(values + i).deinitialize(count: 1)
|
||||
%end
|
||||
_storage.initializedEntries[i] = false
|
||||
}
|
||||
|
||||
@@ -1526,7 +1526,7 @@ internal struct KeyPathBuffer {
|
||||
src: UnsafeMutableRawPointer(mutating: raw.baseAddress.unsafelyUnwrapped),
|
||||
size: UInt(MemoryLayout<T>.size))
|
||||
let result = resultBuf.pointee
|
||||
resultBuf.deallocate(capacity: 1)
|
||||
resultBuf.deallocate()
|
||||
return result
|
||||
}
|
||||
@_inlineable // FIXME(sil-serialize-all)
|
||||
|
||||
@@ -162,7 +162,7 @@ open class ManagedBuffer<Header, Element> {
|
||||
/// Manager(unsafeBufferObject: self).withUnsafeMutablePointers {
|
||||
/// (pointerToHeader, pointerToElements) -> Void in
|
||||
/// pointerToElements.deinitialize(count: self.count)
|
||||
/// pointerToHeader.deinitialize()
|
||||
/// pointerToHeader.deinitialize(count: 1)
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
|
||||
@@ -69,7 +69,7 @@ internal func _withUninitializedString<R>(
|
||||
let stringPtr = UnsafeMutablePointer<String>.allocate(capacity: 1)
|
||||
let bodyResult = body(stringPtr)
|
||||
let stringResult = stringPtr.move()
|
||||
stringPtr.deallocate(capacity: 1)
|
||||
stringPtr.deallocate()
|
||||
return (bodyResult, stringResult)
|
||||
}
|
||||
|
||||
|
||||
@@ -718,8 +718,8 @@ extension _StringCore : RangeReplaceableCollection {
|
||||
let tailStart = rangeStart + (replacedCount &<< elementShift)
|
||||
|
||||
if growth > 0 {
|
||||
(tailStart + (growth &<< elementShift)).copyBytes(
|
||||
from: tailStart, count: tailCount &<< elementShift)
|
||||
(tailStart + (growth &<< elementShift)).copyMemory(
|
||||
from: tailStart, byteCount: tailCount &<< elementShift)
|
||||
}
|
||||
|
||||
if _fastPath(elementWidth == 1) {
|
||||
@@ -738,8 +738,8 @@ extension _StringCore : RangeReplaceableCollection {
|
||||
}
|
||||
|
||||
if growth < 0 {
|
||||
(tailStart + (growth &<< elementShift)).copyBytes(
|
||||
from: tailStart, count: tailCount &<< elementShift)
|
||||
(tailStart + (growth &<< elementShift)).copyMemory(
|
||||
from: tailStart, byteCount: tailCount &<< elementShift)
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -101,9 +101,9 @@ extension _SwiftNativeNSArrayWithContiguousStorage : _NSArrayCore {
|
||||
// These objects are "returned" at +0, so treat them as pointer values to
|
||||
// avoid retains. Copy bytes via a raw pointer to circumvent reference
|
||||
// counting while correctly aliasing with all other pointer types.
|
||||
UnsafeMutableRawPointer(aBuffer).copyBytes(
|
||||
UnsafeMutableRawPointer(aBuffer).copyMemory(
|
||||
from: objects.baseAddress! + range.location,
|
||||
count: range.length * MemoryLayout<AnyObject>.stride)
|
||||
byteCount: range.length * MemoryLayout<AnyObject>.stride)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -121,7 +121,7 @@ internal func _destroyTLS(_ ptr: UnsafeMutableRawPointer?) {
|
||||
let tlsPtr = ptr!.assumingMemoryBound(to: _ThreadLocalStorage.self)
|
||||
__swift_stdlib_ubrk_close(tlsPtr[0].uBreakIterator)
|
||||
tlsPtr.deinitialize(count: 1)
|
||||
tlsPtr.deallocate(capacity: 1)
|
||||
tlsPtr.deallocate()
|
||||
|
||||
#if INTERNAL_CHECKS_ENABLED
|
||||
// Log the fact we've destroyed our storage
|
||||
@@ -167,4 +167,3 @@ internal func _initializeThreadLocalStorage()
|
||||
_sanityCheck(success == 0, "setspecific failed")
|
||||
return tlsPtr
|
||||
}
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ struct _UnsafeBitMap {
|
||||
@_inlineable // FIXME(sil-serialize-all)
|
||||
public // @testable
|
||||
func initializeToZero() {
|
||||
values.initialize(to: 0, count: numberOfWords)
|
||||
values.initialize(repeating: 0, count: numberOfWords)
|
||||
}
|
||||
|
||||
@_inlineable // FIXME(sil-serialize-all)
|
||||
@@ -82,4 +82,3 @@ struct _UnsafeBitMap {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -303,8 +303,35 @@ public struct Unsafe${Mutable}BufferPointer<Element>
|
||||
_position = Unsafe${Mutable}Pointer._max
|
||||
_end = _position
|
||||
}
|
||||
|
||||
% if Mutable:
|
||||
|
||||
/// Creates a mutable typed buffer pointer referencing the same memory as the
|
||||
/// given immutable buffer pointer.
|
||||
///
|
||||
/// - Parameter other: The immutable buffer pointer to convert.
|
||||
@_inlineable
|
||||
public init(mutating other: UnsafeBufferPointer<Element>) {
|
||||
_position = UnsafeMutablePointer<Element>(mutating: other._position)
|
||||
_end = UnsafeMutablePointer<Element>(mutating: other._end)
|
||||
}
|
||||
|
||||
% else:
|
||||
|
||||
/// Creates an immutable typed buffer pointer referencing the same memory as the
|
||||
/// given mutable buffer pointer.
|
||||
///
|
||||
/// - Parameter other: The mutable buffer pointer to convert.
|
||||
@_inlineable
|
||||
public init(_ other: UnsafeMutableBufferPointer<Element>) {
|
||||
_position = UnsafePointer<Element>(other._position)
|
||||
_end = UnsafePointer<Element>(other._end)
|
||||
}
|
||||
|
||||
% end
|
||||
|
||||
% if not Mutable:
|
||||
|
||||
/// Creates a buffer over the same memory as the given buffer slice.
|
||||
///
|
||||
/// The new buffer represents the same region of memory as `slice`, but is
|
||||
@@ -329,7 +356,8 @@ public struct Unsafe${Mutable}BufferPointer<Element>
|
||||
self.init(start: slice.base.baseAddress! + slice.startIndex,
|
||||
count: slice.count)
|
||||
}
|
||||
% end # !mutable
|
||||
|
||||
% end
|
||||
|
||||
/// Creates a buffer over the same memory as the given buffer slice.
|
||||
///
|
||||
@@ -366,6 +394,143 @@ public struct Unsafe${Mutable}BufferPointer<Element>
|
||||
public func makeIterator() -> UnsafeBufferPointerIterator<Element> {
|
||||
return UnsafeBufferPointerIterator(_position: _position, _end: _end)
|
||||
}
|
||||
|
||||
/// Deallocates the memory block previously allocated at this buffer pointer’s
|
||||
/// base address.
|
||||
///
|
||||
/// This buffer pointer's `baseAddress` must be `nil` or a pointer to a memory
|
||||
/// block previously returned by a Swift allocation method. If `baseAddress` is
|
||||
/// `nil`, this function does nothing. Otherwise, the memory must not be initialized
|
||||
/// or `Pointee` must be a trivial type. This buffer pointer's `count` must
|
||||
/// be equal to the originally allocated size of the memory block.
|
||||
@_inlineable
|
||||
public func deallocate() {
|
||||
_position?.deallocate()
|
||||
}
|
||||
|
||||
% if Mutable:
|
||||
|
||||
/// Allocates uninitialized memory for the specified number of instances of
|
||||
/// type `Element`.
|
||||
///
|
||||
/// The resulting buffer references a region of memory that is bound to
|
||||
/// `Element` and is `count * MemoryLayout<Element>.stride` bytes in size.
|
||||
///
|
||||
/// The following example allocates a buffer that can store four `Int`
|
||||
/// instances and then initializes that memory with the elements of a range:
|
||||
///
|
||||
/// let buffer = UnsafeMutableBufferPointer<Int>.allocate(capacity: 4)
|
||||
/// _ = buffer.initialize(from: 1...4)
|
||||
/// print(buffer[2])
|
||||
/// // Prints "3"
|
||||
///
|
||||
/// When you allocate memory, always remember to deallocate once you're
|
||||
/// finished.
|
||||
///
|
||||
/// buffer.deallocate()
|
||||
///
|
||||
/// - Parameter count: The amount of memory to allocate, counted in instances
|
||||
/// of `Element`.
|
||||
@_inlineable
|
||||
public static func allocate(capacity count: Int)
|
||||
-> UnsafeMutableBufferPointer<Element> {
|
||||
let size = MemoryLayout<Element>.stride * count
|
||||
let raw = Builtin.allocRaw(size._builtinWordValue, Builtin.alignof(Element.self))
|
||||
Builtin.bindMemory(raw, count._builtinWordValue, Element.self)
|
||||
return UnsafeMutableBufferPointer(
|
||||
start: UnsafeMutablePointer(raw), count: count)
|
||||
}
|
||||
|
||||
/// 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
|
||||
/// entire region of memory referenced by this buffer is initialized.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - repeatedValue: The instance to initialize this buffer's memory with.
|
||||
@_inlineable
|
||||
public func initialize(repeating repeatedValue: Element) {
|
||||
guard let dstBase = _position else {
|
||||
return
|
||||
}
|
||||
|
||||
dstBase.initialize(repeating: repeatedValue, count: _end! - dstBase)
|
||||
}
|
||||
|
||||
/// Assigns every element in this buffer's memory to a copy of the given value.
|
||||
///
|
||||
/// The buffer’s memory must be initialized or the buffer's `Element`
|
||||
/// must be a trivial type.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - repeatedValue: The instance to assign this buffer's memory to.
|
||||
///
|
||||
/// Warning: All buffer elements must be initialized before calling this.
|
||||
/// Assigning to part of the buffer must be done using the `assign(repeating:count:)``
|
||||
/// method on the buffer’s `baseAddress`.
|
||||
@_inlineable
|
||||
public func assign(repeating repeatedValue: Element) {
|
||||
guard let dstBase = _position else {
|
||||
return
|
||||
}
|
||||
|
||||
dstBase.assign(repeating: repeatedValue, count: _end! - dstBase)
|
||||
}
|
||||
|
||||
% end
|
||||
|
||||
/// Executes the given closure while temporarily binding the memory referenced
|
||||
/// by this buffer to the given type.
|
||||
///
|
||||
/// Use this method when you have a buffer of memory bound to one type and
|
||||
/// you need to access that memory as a buffer of another type. Accessing
|
||||
/// memory as type `T` requires that the memory be bound to that type. A
|
||||
/// memory location may only be bound to one type at a time, so accessing
|
||||
/// the same memory as an unrelated type without first rebinding the memory
|
||||
/// is undefined.
|
||||
///
|
||||
/// The entire region of memory referenced by this buffer must be initialized.
|
||||
///
|
||||
/// Because this buffer's memory is no longer bound to its `Element` type
|
||||
/// while the `body` closure executes, do not access memory using the
|
||||
/// original buffer 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.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - type: The type to temporarily bind the memory referenced by this
|
||||
/// buffer. The type `T` must have the same stride and be layout compatible
|
||||
/// with the pointer's `Element` type.
|
||||
/// - body: A closure that takes a ${Mutable.lower()} typed buffer to the
|
||||
/// same memory as this buffer, only bound to type `T`. The buffer argument
|
||||
/// contains the same number of complete instances of `T` as the original
|
||||
/// buffer’s `count`. 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.
|
||||
/// - Returns: The return value, if any, of the `body` closure parameter.
|
||||
@_inlineable
|
||||
public func withMemoryRebound<T, Result>(
|
||||
to type: T.Type, _ body: (${Self}<T>) throws -> Result
|
||||
) rethrows -> Result {
|
||||
if let base = _position {
|
||||
_debugPrecondition(MemoryLayout<Element>.stride == MemoryLayout<T>.stride)
|
||||
Builtin.bindMemory(base._rawValue, count._builtinWordValue, T.self)
|
||||
defer {
|
||||
Builtin.bindMemory(base._rawValue, count._builtinWordValue, Element.self)
|
||||
}
|
||||
|
||||
return try body(${Self}<T>(
|
||||
start: Unsafe${Mutable}Pointer<T>(base._rawValue), count: count))
|
||||
}
|
||||
else {
|
||||
return try body(${Self}<T>(start: nil, count: 0))
|
||||
}
|
||||
}
|
||||
|
||||
/// A pointer to the first element of the buffer.
|
||||
///
|
||||
@@ -382,12 +547,11 @@ public struct Unsafe${Mutable}BufferPointer<Element>
|
||||
/// a buffer can have a `count` of zero even with a non-`nil` base address.
|
||||
@_inlineable
|
||||
public var count: Int {
|
||||
switch(_position, _end) {
|
||||
case (.some(let pos), .some(let end)):
|
||||
return (end - pos)
|
||||
case _:
|
||||
guard let start = _position, let end = _end else {
|
||||
return 0
|
||||
}
|
||||
|
||||
return end - start
|
||||
}
|
||||
|
||||
@_versioned
|
||||
|
||||
@@ -412,8 +412,6 @@ public struct ${Self}<Pointee>
|
||||
///
|
||||
/// The resulting pointer references a region of memory that is bound to
|
||||
/// `Pointee` and is `count * MemoryLayout<Pointee>.stride` bytes in size.
|
||||
/// You must eventually deallocate the memory referenced by the returned
|
||||
/// pointer.
|
||||
///
|
||||
/// The following example allocates enough new memory to store four `Int`
|
||||
/// instances and then initializes that memory with the elements of a range.
|
||||
@@ -426,7 +424,7 @@ public struct ${Self}<Pointee>
|
||||
/// When you allocate memory, always remember to deallocate once you're
|
||||
/// finished.
|
||||
///
|
||||
/// intPointer.deallocate(capacity: 4)
|
||||
/// intPointer.deallocate()
|
||||
///
|
||||
/// - Parameter count: The amount of memory to allocate, counted in instances
|
||||
/// of `Pointee`.
|
||||
@@ -439,23 +437,23 @@ public struct ${Self}<Pointee>
|
||||
Builtin.bindMemory(rawPtr, count._builtinWordValue, Pointee.self)
|
||||
return UnsafeMutablePointer(rawPtr)
|
||||
}
|
||||
|
||||
/// Deallocates memory that was allocated for `count` instances of `Pointee`.
|
||||
///
|
||||
/// The memory region that is deallocated is
|
||||
/// `capacity * MemoryLayout<Pointee>.stride` bytes in size. The memory must
|
||||
/// not be initialized or `Pointee` must be a trivial type.
|
||||
///
|
||||
/// - Parameter capacity: The amount of memory to deallocate, counted in
|
||||
/// instances of `Pointee`.
|
||||
@_inlineable
|
||||
public func deallocate(capacity: Int) {
|
||||
let size = MemoryLayout<Pointee>.stride * capacity
|
||||
Builtin.deallocRaw(
|
||||
_rawValue, size._builtinWordValue, Builtin.alignof(Pointee.self))
|
||||
|
||||
@available(swift, deprecated: 4.1, obsoleted: 5.0.0, message: "Swift currently only supports freeing entire heap blocks, use deallocate() instead")
|
||||
public func deallocate(capacity _: Int) {
|
||||
self.deallocate()
|
||||
}
|
||||
|
||||
% end
|
||||
|
||||
/// Deallocates the memory block previously allocated at this pointer.
|
||||
///
|
||||
/// This pointer must be a pointer to the start of a previously allocated memory
|
||||
/// block. The memory must not be initialized or `Pointee` must be a trivial type.
|
||||
@_inlineable
|
||||
public func deallocate() {
|
||||
Builtin.deallocRaw(_rawValue, (-1)._builtinWordValue, (-1)._builtinWordValue)
|
||||
}
|
||||
|
||||
/// Accesses the instance referenced by this pointer.
|
||||
///
|
||||
% if mutable:
|
||||
@@ -488,28 +486,48 @@ public struct ${Self}<Pointee>
|
||||
}
|
||||
|
||||
% if mutable:
|
||||
@available(swift, deprecated: 4.1, obsoleted: 5.0.0, renamed: "initialize(repeating:count:)")
|
||||
public func initialize(to newValue: Pointee, count: Int = 1) {
|
||||
initialize(repeating: newValue, count: count)
|
||||
}
|
||||
|
||||
/// Initializes this pointer's memory with the specified number of
|
||||
/// consecutive copies of the given value.
|
||||
///
|
||||
/// The destination memory must be uninitialized or the pointer's `Pointee`
|
||||
/// must be a trivial type. After a call to `initialize(to:count:)`, the
|
||||
/// must be a trivial type. After a call to `initialize(repeating:count:)`, the
|
||||
/// memory referenced by this pointer is initialized.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - newValue: The instance to initialize this pointer's memory with.
|
||||
/// - repeatedValue: The instance to initialize this pointer's memory with.
|
||||
/// - count: The number of consecutive copies of `newValue` to initialize.
|
||||
/// `count` must not be negative. The default is `1`.
|
||||
/// `count` must not be negative.
|
||||
@_inlineable
|
||||
public func initialize(to newValue: Pointee, count: Int = 1) {
|
||||
public func initialize(repeating repeatedValue: Pointee, count: Int) {
|
||||
// FIXME: add tests (since the `count` has been added)
|
||||
_debugPrecondition(count >= 0,
|
||||
"${Self}.initialize(to:): negative count")
|
||||
"${Self}.initialize(repeating:count:): negative count")
|
||||
// Must not use `initializeFrom` with a `Collection` as that will introduce
|
||||
// a cycle.
|
||||
for offset in 0..<count {
|
||||
Builtin.initialize(newValue, (self + offset)._rawValue)
|
||||
Builtin.initialize(repeatedValue, (self + offset)._rawValue)
|
||||
}
|
||||
}
|
||||
|
||||
/// Initializes this pointer's memory with a single instance of the given value.
|
||||
///
|
||||
/// The destination memory must be uninitialized or the pointer's `Pointee`
|
||||
/// must be a trivial type. After a call to `initialize(to:)`, the
|
||||
/// memory referenced by this pointer is initialized. Calling this method is
|
||||
/// roughly equivalent to calling `initialize(repeating:count:)` with a
|
||||
/// `count` of 1.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - value: The instance to initialize this pointer's pointee to.
|
||||
@_inlineable
|
||||
public func initialize(to value: Pointee) {
|
||||
Builtin.initialize(value, self._rawValue)
|
||||
}
|
||||
|
||||
/// Retrieves and returns the referenced instance, returning the pointer's
|
||||
/// memory to an uninitialized state.
|
||||
@@ -519,7 +537,7 @@ public struct ${Self}<Pointee>
|
||||
/// incidental side effects of copying and destroying the value:
|
||||
///
|
||||
/// let value: T = {
|
||||
/// defer { p.deinitialize() }
|
||||
/// defer { p.deinitialize(count: 1) }
|
||||
/// return p.pointee
|
||||
/// }()
|
||||
///
|
||||
@@ -532,6 +550,26 @@ public struct ${Self}<Pointee>
|
||||
return Builtin.take(_rawValue)
|
||||
}
|
||||
|
||||
/// Replaces this pointer's 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.
|
||||
///
|
||||
/// - 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.
|
||||
@_inlineable
|
||||
public func assign(repeating repeatedValue: Pointee, count: Int) {
|
||||
_debugPrecondition(count >= 0, "${Self}.assign(repeating:count:) with negative count")
|
||||
for i in 0..<count {
|
||||
self[i] = repeatedValue
|
||||
}
|
||||
}
|
||||
|
||||
/// Replaces this pointer's initialized memory with the specified number of
|
||||
/// instances from the given pointer's memory.
|
||||
///
|
||||
@@ -695,7 +733,14 @@ public struct ${Self}<Pointee>
|
||||
// self[i] = (source + i).move()
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
@available(swift, deprecated: 4.1, obsoleted: 5.0.0, message: "the default argument to deinitialize(count:) has been removed, please specify the count explicitly")
|
||||
@_inlineable
|
||||
@discardableResult
|
||||
public func deinitialize() -> UnsafeMutableRawPointer {
|
||||
return deinitialize(count: 1)
|
||||
}
|
||||
|
||||
/// Deinitializes the specified number of values starting at this pointer.
|
||||
///
|
||||
/// The region of memory starting at this pointer and covering `count`
|
||||
@@ -704,12 +749,12 @@ public struct ${Self}<Pointee>
|
||||
/// bound to the `Pointee` type.
|
||||
///
|
||||
/// - Parameter count: The number of instances to deinitialize. `count` must
|
||||
/// not be negative. The default value is `1`.
|
||||
/// not be negative.
|
||||
/// - Returns: A raw pointer to the same address as this pointer. The memory
|
||||
/// referenced by the returned raw pointer is still bound to `Pointee`.
|
||||
@_inlineable
|
||||
@discardableResult
|
||||
public func deinitialize(count: Int = 1) -> UnsafeMutableRawPointer {
|
||||
public func deinitialize(count: Int) -> UnsafeMutableRawPointer {
|
||||
_debugPrecondition(count >= 0, "${Self}.deinitialize with negative count")
|
||||
// FIXME: optimization should be implemented, where if the `count` value
|
||||
// is 1, the `Builtin.destroy(Pointee.self, _rawValue)` gets called.
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
///
|
||||
/// - `load(fromByteOffset:as:)`
|
||||
/// - `storeBytes(of:toByteOffset:as:)`
|
||||
/// - `copyBytes(from:count:)`
|
||||
/// - `copyMemory(from:)`
|
||||
% else:
|
||||
/// An `${Self}` instance is a view of the raw bytes in a region of memory.
|
||||
/// Each byte in memory is viewed as a `UInt8` value independent of the type
|
||||
@@ -134,32 +134,44 @@ public struct Unsafe${Mutable}RawBufferPointer
|
||||
}
|
||||
|
||||
% if mutable:
|
||||
@available(swift, deprecated: 4.1, obsoleted: 5.0.0, renamed: "allocate(byteCount:alignment:)")
|
||||
public static func allocate(count: Int) -> UnsafeMutableRawBufferPointer {
|
||||
return UnsafeMutableRawBufferPointer.allocate(
|
||||
byteCount: count, alignment: MemoryLayout<UInt>.alignment)
|
||||
}
|
||||
|
||||
/// Returns a newly allocated buffer with the given size, in bytes.
|
||||
///
|
||||
/// The memory referenced by the new buffer is allocated, but not
|
||||
/// initialized.
|
||||
///
|
||||
/// - Parameter size: The number of bytes to allocate.
|
||||
/// - Returns: A word-aligned buffer pointer covering a region of memory.
|
||||
/// - Parameters:
|
||||
/// - byteCount: The number of bytes to allocate.
|
||||
/// - alignment: The alignment of the new region of allocated memory, in
|
||||
/// bytes.
|
||||
/// - Returns: A buffer pointer to a newly allocated region of memory aligned
|
||||
/// to `alignment`.
|
||||
@_inlineable
|
||||
public static func allocate(count size: Int
|
||||
public static func allocate(
|
||||
byteCount: Int, alignment: Int
|
||||
) -> UnsafeMutableRawBufferPointer {
|
||||
return UnsafeMutableRawBufferPointer(
|
||||
start: UnsafeMutableRawPointer.allocate(
|
||||
bytes: size, alignedTo: MemoryLayout<UInt>.alignment),
|
||||
count: size)
|
||||
let base = UnsafeMutableRawPointer.allocate(
|
||||
byteCount: byteCount, alignment: alignment)
|
||||
return UnsafeMutableRawBufferPointer(start: base, count: byteCount)
|
||||
}
|
||||
% end # mutable
|
||||
|
||||
/// Deallocates the memory viewed by this buffer pointer.
|
||||
/// Deallocates the memory block previously allocated at this buffer pointer’s
|
||||
/// base address.
|
||||
///
|
||||
/// The memory to be deallocated must not be initialized or must be
|
||||
/// initialized to a trivial type. For a buffer pointer `p`, all `p.count`
|
||||
/// bytes referenced by `p` are deallocated.
|
||||
/// This buffer pointer's `baseAddress` must be `nil` or a pointer to a memory
|
||||
/// block previously returned by a Swift allocation method. If `baseAddress` is
|
||||
/// `nil`, this function does nothing. Otherwise, the memory must not be initialized
|
||||
/// or `Pointee` must be a trivial type. This buffer pointer's byte `count` must
|
||||
/// be equal to the originally allocated size of the memory block.
|
||||
@_inlineable
|
||||
public func deallocate() {
|
||||
_position?.deallocate(
|
||||
bytes: count, alignedTo: MemoryLayout<UInt>.alignment)
|
||||
_position?.deallocate()
|
||||
}
|
||||
|
||||
/// Returns a new instance of the given type, read from the buffer pointer's
|
||||
@@ -233,6 +245,10 @@ public struct Unsafe${Mutable}RawBufferPointer
|
||||
baseAddress!.storeBytes(of: value, toByteOffset: offset, as: T.self)
|
||||
}
|
||||
|
||||
@available(swift, deprecated: 4.1, obsoleted: 5.0.0, renamed: "copyMemory(from:)")
|
||||
public func copyBytes(from source: UnsafeRawBufferPointer) {
|
||||
copyMemory(from: source)
|
||||
}
|
||||
/// Copies the bytes from the given buffer to this buffer's memory.
|
||||
///
|
||||
/// If the `source.count` bytes of memory referenced by this buffer are bound
|
||||
@@ -240,17 +256,17 @@ public struct Unsafe${Mutable}RawBufferPointer
|
||||
/// must be properly aligned for accessing `T`, and `source.count` must be a
|
||||
/// multiple of `MemoryLayout<T>.stride`.
|
||||
///
|
||||
/// After calling `copyBytes(from:)`, the first `source.count` bytes of
|
||||
/// After calling `copyMemory(from:)`, the first `source.count` bytes of
|
||||
/// memory referenced by this buffer are initialized to raw bytes. If the
|
||||
/// memory is bound to type `T`, then it contains values of type `T`.
|
||||
///
|
||||
/// - Parameter source: A buffer of raw bytes from which to copy.
|
||||
/// `source.count` must be less than or equal to this buffer's `count`.
|
||||
@_inlineable
|
||||
public func copyBytes(from source: UnsafeRawBufferPointer) {
|
||||
public func copyMemory(from source: UnsafeRawBufferPointer) {
|
||||
_debugPrecondition(source.count <= self.count,
|
||||
"${Self}.copyBytes source has too many elements")
|
||||
baseAddress?.copyBytes(from: source.baseAddress!, count: source.count)
|
||||
"${Self}.copyMemory source has too many elements")
|
||||
baseAddress?.copyMemory(from: source.baseAddress!, byteCount: source.count)
|
||||
}
|
||||
|
||||
/// Copies from a collection of `UInt8` into this buffer's memory.
|
||||
@@ -468,9 +484,9 @@ public struct Unsafe${Mutable}RawBufferPointer
|
||||
_debugPrecondition(bounds.count == newValue.count)
|
||||
|
||||
if !newValue.isEmpty {
|
||||
(baseAddress! + bounds.lowerBound).copyBytes(
|
||||
(baseAddress! + bounds.lowerBound).copyMemory(
|
||||
from: newValue.base.baseAddress! + newValue.startIndex,
|
||||
count: newValue.count)
|
||||
byteCount: newValue.count)
|
||||
}
|
||||
}
|
||||
% end # mutable
|
||||
@@ -504,6 +520,42 @@ public struct Unsafe${Mutable}RawBufferPointer
|
||||
}
|
||||
|
||||
% if mutable:
|
||||
|
||||
/// Initializes the memory referenced by this buffer with the given value,
|
||||
/// binds the memory to the value's type, and returns a typed buffer of the
|
||||
/// initialized memory.
|
||||
///
|
||||
/// The memory referenced by this buffer must be uninitialized or
|
||||
/// initialized to a trivial type, and must be properly aligned for
|
||||
/// accessing `T`.
|
||||
///
|
||||
/// After calling this method on a raw buffer with non-nil `baseAddress` `b`,
|
||||
/// the region starting at `b` and continuing up to
|
||||
/// `b + self.count - self.count % MemoryLayout<T>.stride` is bound to type `T` and
|
||||
/// initialized. If `T` is a nontrivial type, you must eventually deinitialize
|
||||
/// or move the values in this region to avoid leaks. If `baseAddress` is
|
||||
/// `nil`, this function does nothing and returns an empty buffer pointer.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - type: The type to bind this buffer’s memory to.
|
||||
/// - repeatedValue: The instance to copy into memory.
|
||||
/// - Returns: A typed buffer of the memory referenced by this raw buffer.
|
||||
/// The typed buffer contains `self.count / MemoryLayout<T>.stride`
|
||||
/// instances of `T`.
|
||||
@_inlineable
|
||||
@discardableResult
|
||||
public func initializeMemory<T>(as type: T.Type, repeating repeatedValue: T)
|
||||
-> UnsafeMutableBufferPointer<T> {
|
||||
guard let base = _position else {
|
||||
return UnsafeMutableBufferPointer<T>(start: nil, count: 0)
|
||||
}
|
||||
|
||||
let count = (_end! - base) / MemoryLayout<T>.stride
|
||||
let typed = base.initializeMemory(
|
||||
as: type, repeating: repeatedValue, count: count)
|
||||
return UnsafeMutableBufferPointer<T>(start: typed, count: count)
|
||||
}
|
||||
|
||||
/// Initializes the buffer's memory with the given elements, binding the
|
||||
/// initialized memory to the elements' type.
|
||||
///
|
||||
@@ -555,7 +607,7 @@ public struct Unsafe${Mutable}RawBufferPointer
|
||||
// underflow is permitted -- e.g. a sequence into
|
||||
// the spare capacity of an Array buffer
|
||||
guard let x = it.next() else { break }
|
||||
p.initializeMemory(as: S.Element.self, to: x)
|
||||
p.initializeMemory(as: S.Element.self, repeating: x, count: 1)
|
||||
formIndex(&idx, offsetBy: elementStride)
|
||||
}
|
||||
|
||||
@@ -565,6 +617,39 @@ public struct Unsafe${Mutable}RawBufferPointer
|
||||
}
|
||||
% end # mutable
|
||||
|
||||
/// Binds this buffer’s memory to the specified type and returns a typed buffer
|
||||
/// of the bound memory.
|
||||
///
|
||||
/// Use the `bindMemory(to:)` method to bind the memory referenced
|
||||
/// by this buffer to the type `T`. The memory must be uninitialized or
|
||||
/// initialized to a type that is layout compatible with `T`. If the memory
|
||||
/// is uninitialized, it is still uninitialized after being bound to `T`.
|
||||
///
|
||||
/// - Warning: A memory location may only be bound to one type at a time. The
|
||||
/// behavior of accessing memory as a type unrelated to its bound type is
|
||||
/// undefined.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - type: The type `T` to bind the memory to.
|
||||
/// - Returns: A typed buffer of the newly bound memory. The memory in this
|
||||
/// region is bound to `T`, but has not been modified in any other way.
|
||||
/// The typed buffer references `self.count / MemoryLayout<T>.stride` instances of `T`.
|
||||
@_inlineable // FIXME(sil-serialize-all)
|
||||
@_transparent
|
||||
@discardableResult
|
||||
public func bindMemory<T>(
|
||||
to type: T.Type
|
||||
) -> Unsafe${Mutable}BufferPointer<T> {
|
||||
guard let base = _position else {
|
||||
return Unsafe${Mutable}BufferPointer<T>(start: nil, count: 0)
|
||||
}
|
||||
|
||||
let capacity = count / MemoryLayout<T>.stride
|
||||
Builtin.bindMemory(base._rawValue, capacity._builtinWordValue, type)
|
||||
return Unsafe${Mutable}BufferPointer<T>(
|
||||
start: Unsafe${Mutable}Pointer<T>(base._rawValue), count: capacity)
|
||||
}
|
||||
|
||||
@_versioned
|
||||
internal let _position, _end: Unsafe${Mutable}RawPointer?
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@
|
||||
/// offset by that number of bytes. The following example allocates four bytes
|
||||
/// of memory and stores `0xFF` in all four bytes:
|
||||
///
|
||||
/// let bytesPointer = UnsafeMutableRawPointer.allocate(bytes: 4, alignedTo: 1)
|
||||
/// let bytesPointer = UnsafeMutableRawPointer.allocate(byteCount: 4, alignment: 1)
|
||||
/// bytesPointer.storeBytes(of: 0xFFFF_FFFF, as: UInt32.self)
|
||||
///
|
||||
/// // Load a value from the memory referenced by 'bytesPointer'
|
||||
@@ -115,7 +115,7 @@
|
||||
///
|
||||
/// Always remember to deallocate any memory that you allocate yourself.
|
||||
///
|
||||
/// bytesPointer.deallocate(bytes: 4, alignedTo: 1)
|
||||
/// bytesPointer.deallocate()
|
||||
///
|
||||
/// Implicit Casting and Bridging
|
||||
/// =============================
|
||||
@@ -426,6 +426,15 @@ public struct Unsafe${Mutable}RawPointer : Strideable, Hashable, _Pointer {
|
||||
% end # !mutable
|
||||
|
||||
% if mutable:
|
||||
|
||||
@available(swift, deprecated: 4.1, obsoleted: 5.0.0, renamed: "allocate(byteCount:alignment:)")
|
||||
@_inlineable
|
||||
public static func allocate(
|
||||
bytes size: Int, alignedTo alignment: Int
|
||||
) -> UnsafeMutableRawPointer {
|
||||
return UnsafeMutableRawPointer.allocate(byteCount: size, alignment: alignment)
|
||||
}
|
||||
|
||||
/// Allocates uninitialized memory with the specified size and alignment.
|
||||
///
|
||||
/// You are in charge of managing the allocated memory. Be sure to deallocate
|
||||
@@ -437,33 +446,32 @@ public struct Unsafe${Mutable}RawPointer : Strideable, Hashable, _Pointer {
|
||||
/// `UnsafeMutablePointer.allocate(capacity:)` static method instead.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - size: The number of bytes to allocate. `size` must not be negative.
|
||||
/// - alignedTo: The alignment of the new region of allocated memory, in
|
||||
/// - byteCount: The number of bytes to allocate. `byteCount` must not be negative.
|
||||
/// - alignment: The alignment of the new region of allocated memory, in
|
||||
/// bytes.
|
||||
/// - Returns: A pointer to a newly allocated region of memory. The memory is
|
||||
/// allocated, but not initialized.
|
||||
@_inlineable
|
||||
public static func allocate(
|
||||
bytes size: Int, alignedTo: Int
|
||||
byteCount: Int, alignment: Int
|
||||
) -> UnsafeMutableRawPointer {
|
||||
return UnsafeMutableRawPointer(Builtin.allocRaw(
|
||||
size._builtinWordValue, alignedTo._builtinWordValue))
|
||||
byteCount._builtinWordValue, alignment._builtinWordValue))
|
||||
}
|
||||
% end # mutable
|
||||
|
||||
/// Deallocates memory referenced by the pointer with the specified size and
|
||||
/// alignment.
|
||||
@available(swift, deprecated: 4.1, obsoleted: 5.0.0, message: "Swift currently only supports freeing entire heap blocks, use deallocate() instead")
|
||||
public func deallocate(bytes _: Int, alignedTo _: Int) {
|
||||
self.deallocate()
|
||||
}
|
||||
|
||||
/// Deallocates the previously allocated memory block referenced by this pointer.
|
||||
///
|
||||
/// The memory to be deallocated must be uninitialized or initialized to a
|
||||
/// trivial type.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - size: The number of bytes to deallocate.
|
||||
/// - alignedTo: The alignment of the region to be deallocated, in bytes.
|
||||
@_inlineable
|
||||
public func deallocate(bytes size: Int, alignedTo: Int) {
|
||||
Builtin.deallocRaw(
|
||||
_rawValue, size._builtinWordValue, alignedTo._builtinWordValue)
|
||||
public func deallocate() {
|
||||
Builtin.deallocRaw(_rawValue, (-1)._builtinWordValue, (-1)._builtinWordValue)
|
||||
}
|
||||
|
||||
/// Binds the memory to the specified type and returns a typed pointer to the
|
||||
@@ -530,6 +538,16 @@ public struct Unsafe${Mutable}RawPointer : Strideable, Hashable, _Pointer {
|
||||
}
|
||||
|
||||
% if mutable:
|
||||
|
||||
@available(swift, deprecated: 4.1, obsoleted: 5.0.0, renamed: "initializeMemory(as:repeating:count:)")
|
||||
@discardableResult
|
||||
public func initializeMemory<T>(
|
||||
as type: T.Type, at offset: Int = 0, count: Int = 1, to repeatedValue: T
|
||||
) -> UnsafeMutablePointer<T> {
|
||||
return (self + offset * MemoryLayout<T>.stride).initializeMemory(
|
||||
as: type, repeating: repeatedValue, count: count)
|
||||
}
|
||||
|
||||
/// 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.
|
||||
@@ -539,49 +557,42 @@ public struct Unsafe${Mutable}RawPointer : Strideable, Hashable, _Pointer {
|
||||
/// accessing `T`.
|
||||
///
|
||||
/// The following example allocates enough raw memory to hold four instances
|
||||
/// of `Int8`, and then uses the `initializeMemory(as:at:count:to:)` method
|
||||
/// of `Int8`, and then uses the `initializeMemory(as:repeating:count:)` method
|
||||
/// to initialize the allocated memory.
|
||||
///
|
||||
/// let count = 4
|
||||
/// let bytesPointer = UnsafeMutableRawPointer.allocate(
|
||||
/// bytes: count * MemoryLayout<Int8>.stride,
|
||||
/// alignedTo: MemoryLayout<Int8>.alignment)
|
||||
/// byteCount: count * MemoryLayout<Int8>.stride,
|
||||
/// alignment: MemoryLayout<Int8>.alignment)
|
||||
/// let int8Pointer = myBytes.initializeMemory(
|
||||
/// as: Int8.self, count: count, value: 0)
|
||||
/// as: Int8.self, repeating: 0, count: count)
|
||||
///
|
||||
/// // After using 'int8Pointer':
|
||||
/// int8Pointer.deallocate(count)
|
||||
/// int8Pointer.deallocate()
|
||||
///
|
||||
/// After calling this method on a raw pointer `p`, the region starting at
|
||||
/// `p + index * MemoryLayout<T>.stride` and continuing up to
|
||||
/// `p + (index + count) * MemoryLayout<T>.stride` is bound to type `T` and
|
||||
/// initialized. If `T` is a nontrivial type, you must eventually deinitialize
|
||||
/// or move from the values in this region to avoid leaks.
|
||||
/// `self` and continuing up to `p + count * MemoryLayout<T>.stride` is bound
|
||||
/// to type `T` and initialized. If `T` is a nontrivial type, you must
|
||||
/// eventually deinitialize or move from the values in this region to avoid leaks.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - type: The type to bind this memory to.
|
||||
/// - index: The offset from this pointer to the region of memory to be
|
||||
/// initialized with `value`, in the stride of type `T`. `index` must
|
||||
/// not be negative. The default is zero.
|
||||
/// - repeatedValue: The instance to copy into memory.
|
||||
/// - count: The number of copies of `value` to copy into memory. `count`
|
||||
/// must not be negative. The default is `1`.
|
||||
/// - value: The instance to copy into memory.
|
||||
/// - Returns: A typed pointer to the memory referenced by this raw pointer,
|
||||
/// offset by `index * MemoryLayout<T>.stride` bytes.
|
||||
/// must not be negative.
|
||||
/// - Returns: A typed pointer to the memory referenced by this raw pointer.
|
||||
@_inlineable
|
||||
@discardableResult
|
||||
public func initializeMemory<T>(as type: T.Type, at index: Int = 0,
|
||||
count: Int = 1, to value: T
|
||||
public func initializeMemory<T>(
|
||||
as type: T.Type, repeating repeatedValue: T, count: Int
|
||||
) -> UnsafeMutablePointer<T> {
|
||||
_debugPrecondition(index >= 0,
|
||||
"UnsafeMutableRawPointer.initializeMemory: negative index")
|
||||
_debugPrecondition(count >= 0,
|
||||
"UnsafeMutableRawPointer.initializeMemory: negative count")
|
||||
|
||||
Builtin.bindMemory(_rawValue, count._builtinWordValue, type)
|
||||
var nextPtr = self + index &* MemoryLayout<T>.stride
|
||||
var nextPtr = self
|
||||
for _ in 0..<count {
|
||||
Builtin.initialize(value, nextPtr._rawValue)
|
||||
Builtin.initialize(repeatedValue, nextPtr._rawValue)
|
||||
nextPtr += MemoryLayout<T>.stride
|
||||
}
|
||||
return UnsafeMutablePointer(_rawValue)
|
||||
@@ -702,8 +713,10 @@ public struct Unsafe${Mutable}RawPointer : Strideable, Hashable, _Pointer {
|
||||
) -> UnsafeMutablePointer<C.Element> {
|
||||
// TODO: Optimize where `C` is a `ContiguousArrayBuffer`.
|
||||
// Initialize and bind each element of the container.
|
||||
for (index, element) in source.enumerated() {
|
||||
self.initializeMemory(as: C.Element.self, at: index, to: element)
|
||||
var ptr = self
|
||||
for element in source {
|
||||
ptr.initializeMemory(as: C.Element.self, repeating: element, count: 1)
|
||||
ptr += MemoryLayout<C.Element>.stride
|
||||
}
|
||||
return UnsafeMutablePointer(_rawValue)
|
||||
}
|
||||
@@ -852,29 +865,34 @@ public struct Unsafe${Mutable}RawPointer : Strideable, Hashable, _Pointer {
|
||||
}
|
||||
}
|
||||
|
||||
@available(swift, deprecated: 4.1, obsoleted: 5.0.0, renamed: "copyMemory(from:byteCount:)")
|
||||
public func copyBytes(from source: UnsafeRawPointer, count: Int) {
|
||||
copyMemory(from: source, byteCount: count)
|
||||
}
|
||||
|
||||
/// Copies the specified number of bytes from the given raw pointer's memory
|
||||
/// into this pointer's memory.
|
||||
///
|
||||
/// If the `count` bytes of memory referenced by this pointer are bound to a
|
||||
/// type `T`, then `T` must be a trivial type, this pointer and `source`
|
||||
/// must be properly aligned for accessing `T`, and `count` must be a
|
||||
/// If the `byteCount` bytes of memory referenced by this pointer are bound to
|
||||
/// a type `T`, then `T` must be a trivial type, this pointer and `source`
|
||||
/// must be properly aligned for accessing `T`, and `byteCount` must be a
|
||||
/// multiple of `MemoryLayout<T>.stride`.
|
||||
///
|
||||
/// After calling `copyBytes(from:count:)`, the `count` bytes of memory
|
||||
/// After calling `copyMemory(from:byteCount:)`, the `byteCount` bytes of memory
|
||||
/// referenced by this pointer are initialized to raw bytes. If the memory
|
||||
/// is bound to type `T`, then it contains values of type `T`.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - source: A pointer to the memory to copy bytes from. The memory in the
|
||||
/// region `source..<(source + count)` must be initialized to a trivial
|
||||
/// region `source..<(source + byteCount)` must be initialized to a trivial
|
||||
/// type.
|
||||
/// - count: The number of bytes to copy. `count` must not be negative.
|
||||
/// - byteCount: The number of bytes to copy. `byteCount` must not be negative.
|
||||
@_inlineable
|
||||
public func copyBytes(from source: UnsafeRawPointer, count: Int) {
|
||||
public func copyMemory(from source: UnsafeRawPointer, byteCount: Int) {
|
||||
_debugPrecondition(
|
||||
count >= 0, "UnsafeMutableRawPointer.copyBytes with negative count")
|
||||
byteCount >= 0, "UnsafeMutableRawPointer.copyMemory with negative count")
|
||||
|
||||
_memmove(dest: self, src: source, size: UInt(count))
|
||||
_memmove(dest: self, src: source, size: UInt(byteCount))
|
||||
}
|
||||
% end # mutable
|
||||
|
||||
|
||||
Reference in New Issue
Block a user