mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
This patch removes as much checked math as I was able to find from the unsafe buffer pointers types. In particular, I removed two kinds of checked math: 1. Checked math that was provably unable to trap due to prior operations done in the same function, or in a function that must have been called before the current one. For example, in index(_:offsetBy:limitedBy:), when we do the final index addition we have already validated that it must be in-bounds. Therefore, it cannot overflow. 2. Checked math that can only fail if the user is misusing the indices. As previously discussed with Karoy and Andrew, the unsafe raw buffer types are not obligated to crash if you misuse their indices, they are free to invoke undefined behaviour. In these cases, I added defensive overflow checks in debug mode. The result of this change should be reductions in code size in almost all usage sites of the raw buffer types.
809 lines
31 KiB
Swift
809 lines
31 KiB
Swift
//===--- UnsafeBufferPointer.swift.gyb ------------------------*- swift -*-===//
|
||
//
|
||
// This source file is part of the Swift.org open source project
|
||
//
|
||
// Copyright (c) 2014 - 2017 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
|
||
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||
//
|
||
//===----------------------------------------------------------------------===//
|
||
|
||
|
||
% for mutable in (True, False):
|
||
% Self = 'UnsafeMutableBufferPointer' if mutable else 'UnsafeBufferPointer'
|
||
% Mutable = 'Mutable' if mutable else ''
|
||
/// A nonowning collection interface to a buffer of ${Mutable.lower()}
|
||
/// elements stored contiguously in memory.
|
||
///
|
||
/// You can use an `${Self}` instance in low level operations to eliminate
|
||
/// uniqueness checks and, in release mode, bounds checks. Bounds checks are
|
||
/// always performed in debug mode.
|
||
///
|
||
/// ${Self} Semantics
|
||
/// =================
|
||
///
|
||
/// An `${Self}` instance is a view into memory and does not own the memory
|
||
/// that it references. Copying a value of type `${Self}` does not copy the
|
||
/// instances stored in the underlying memory. However, initializing another
|
||
/// collection with an `${Self}` instance copies the instances out of the
|
||
/// referenced memory and into the new collection.
|
||
// FIXME: rdar://18157434 - until this is fixed, this has to be fixed layout
|
||
// to avoid a hang in Foundation, which has the following setup:
|
||
// struct A { struct B { let x: UnsafeMutableBufferPointer<...> } let b: B }
|
||
@frozen // unsafe-performance
|
||
public struct Unsafe${Mutable}BufferPointer<Element> {
|
||
|
||
@usableFromInline
|
||
let _position: Unsafe${Mutable}Pointer<Element>?
|
||
|
||
/// The number of elements in the buffer.
|
||
///
|
||
/// If the `baseAddress` of this buffer is `nil`, the count is zero. However,
|
||
/// a buffer can have a `count` of zero even with a non-`nil` base address.
|
||
public let count: Int
|
||
}
|
||
|
||
%if not mutable:
|
||
extension UnsafeBufferPointer {
|
||
/// An iterator for the elements in the buffer referenced by an
|
||
/// `UnsafeBufferPointer` or `UnsafeMutableBufferPointer` instance.
|
||
@frozen // unsafe-performance
|
||
public struct Iterator {
|
||
@usableFromInline
|
||
internal var _position, _end: UnsafePointer<Element>?
|
||
|
||
@inlinable // unsafe-performance
|
||
public init(_position: UnsafePointer<Element>?, _end: UnsafePointer<Element>?) {
|
||
self._position = _position
|
||
self._end = _end
|
||
}
|
||
}
|
||
}
|
||
|
||
extension UnsafeBufferPointer.Iterator: IteratorProtocol {
|
||
/// Advances to the next element and returns it, or `nil` if no next element
|
||
/// exists.
|
||
///
|
||
/// Once `nil` has been returned, all subsequent calls return `nil`.
|
||
@inlinable // unsafe-performance
|
||
public mutating func next() -> Element? {
|
||
guard let start = _position else {
|
||
return nil
|
||
}
|
||
_internalInvariant(_end != nil, "inconsistent _position, _end pointers")
|
||
|
||
if start == _end._unsafelyUnwrappedUnchecked { return nil }
|
||
|
||
let result = start.pointee
|
||
_position = start + 1
|
||
return result
|
||
}
|
||
}
|
||
%else:
|
||
extension UnsafeMutableBufferPointer {
|
||
public typealias Iterator = UnsafeBufferPointer<Element>.Iterator
|
||
}
|
||
%end
|
||
|
||
extension Unsafe${Mutable}BufferPointer: Sequence {
|
||
/// Returns an iterator over the elements of this buffer.
|
||
///
|
||
/// - Returns: An iterator over the elements of this buffer.
|
||
@inlinable // unsafe-performance
|
||
public func makeIterator() -> Iterator {
|
||
guard let start = _position else {
|
||
return Iterator(_position: nil, _end: nil)
|
||
}
|
||
return Iterator(_position: start, _end: start + count)
|
||
}
|
||
|
||
/// Initializes the memory at `destination.baseAddress` with elements of `self`,
|
||
/// stopping when either `self` or `destination` is exhausted.
|
||
///
|
||
/// - Returns: an iterator over any remaining elements of `self` and the
|
||
/// number of elements initialized.
|
||
@inlinable // unsafe-performance
|
||
public func _copyContents(
|
||
initializing destination: UnsafeMutableBufferPointer<Element>
|
||
) -> (Iterator, UnsafeMutableBufferPointer<Element>.Index) {
|
||
guard !isEmpty && !destination.isEmpty else { return (makeIterator(), 0) }
|
||
let s = self.baseAddress._unsafelyUnwrappedUnchecked
|
||
let d = destination.baseAddress._unsafelyUnwrappedUnchecked
|
||
let n = Swift.min(destination.count, self.count)
|
||
d.initialize(from: s, count: n)
|
||
return (Iterator(_position: s + n, _end: s + count), n)
|
||
}
|
||
}
|
||
|
||
extension Unsafe${Mutable}BufferPointer: ${Mutable}Collection, RandomAccessCollection {
|
||
public typealias Index = Int
|
||
public typealias Indices = Range<Int>
|
||
|
||
/// The index of the first element in a nonempty buffer.
|
||
///
|
||
/// The `startIndex` property of an `Unsafe${Mutable}BufferPointer` instance
|
||
/// is always zero.
|
||
@inlinable // unsafe-performance
|
||
public var startIndex: Int { return 0 }
|
||
|
||
/// The "past the end" position---that is, the position one greater than the
|
||
/// last valid subscript argument.
|
||
///
|
||
/// The `endIndex` property of an `Unsafe${Mutable}BufferPointer` instance is
|
||
/// always identical to `count`.
|
||
@inlinable // unsafe-performance
|
||
public var endIndex: Int { return count }
|
||
|
||
@inlinable // unsafe-performance
|
||
public func index(after i: Int) -> Int {
|
||
// NOTE: this is a manual specialization of index movement for a Strideable
|
||
// index that is required for UnsafeBufferPointer performance. The
|
||
// optimizer is not capable of creating partial specializations yet.
|
||
// NOTE: Range checks are not performed here, because it is done later by
|
||
// the subscript function.
|
||
// NOTE: Unchecked math because unsafe pointers are not required to
|
||
// behave sensibly if you misuse their indices. We validate in
|
||
// debug mode.
|
||
let result = i.addingReportingOverflow(1)
|
||
_debugPrecondition(!result.overflow)
|
||
return result.partialValue
|
||
}
|
||
|
||
@inlinable // unsafe-performance
|
||
public func formIndex(after i: inout Int) {
|
||
// NOTE: this is a manual specialization of index movement for a Strideable
|
||
// index that is required for UnsafeBufferPointer performance. The
|
||
// optimizer is not capable of creating partial specializations yet.
|
||
// NOTE: Range checks are not performed here, because it is done later by
|
||
// the subscript function.
|
||
// NOTE: Unchecked math because unsafe pointers are not required to
|
||
// behave sensibly if you misuse their indices. We validate in
|
||
// debug mode.
|
||
let result = i.addingReportingOverflow(1)
|
||
_debugPrecondition(!result.overflow)
|
||
i = result.partialValue
|
||
}
|
||
|
||
@inlinable // unsafe-performance
|
||
public func index(before i: Int) -> Int {
|
||
// NOTE: this is a manual specialization of index movement for a Strideable
|
||
// index that is required for UnsafeBufferPointer performance. The
|
||
// optimizer is not capable of creating partial specializations yet.
|
||
// NOTE: Range checks are not performed here, because it is done later by
|
||
// the subscript function.
|
||
// NOTE: Unchecked math because unsafe pointers are not required to
|
||
// behave sensibly if you misuse their indices. We validate in
|
||
// debug mode.
|
||
let result = i.subtractingReportingOverflow(1)
|
||
_debugPrecondition(!result.overflow)
|
||
return result.partialValue
|
||
}
|
||
|
||
@inlinable // unsafe-performance
|
||
public func formIndex(before i: inout Int) {
|
||
// NOTE: this is a manual specialization of index movement for a Strideable
|
||
// index that is required for UnsafeBufferPointer performance. The
|
||
// optimizer is not capable of creating partial specializations yet.
|
||
// NOTE: Range checks are not performed here, because it is done later by
|
||
// the subscript function.
|
||
// NOTE: Unchecked math because unsafe pointers are not required to
|
||
// behave sensibly if you misuse their indices. We validate in
|
||
// debug mode.
|
||
let result = i.subtractingReportingOverflow(1)
|
||
_debugPrecondition(!result.overflow)
|
||
i = result.partialValue
|
||
}
|
||
|
||
@inlinable // unsafe-performance
|
||
public func index(_ i: Int, offsetBy n: Int) -> Int {
|
||
// NOTE: this is a manual specialization of index movement for a Strideable
|
||
// index that is required for UnsafeBufferPointer performance. The
|
||
// optimizer is not capable of creating partial specializations yet.
|
||
// NOTE: Range checks are not performed here, because it is done later by
|
||
// the subscript function.
|
||
// NOTE: Unchecked math because unsafe pointers are not required to
|
||
// behave sensibly if you misuse their indices. We validate in
|
||
// debug mode.
|
||
let result = i.addingReportingOverflow(n)
|
||
_debugPrecondition(!result.overflow)
|
||
return result.partialValue
|
||
}
|
||
|
||
@inlinable // unsafe-performance
|
||
public func index(_ i: Int, offsetBy n: Int, limitedBy limit: Int) -> Int? {
|
||
// NOTE: this is a manual specialization of index movement for a Strideable
|
||
// index that is required for UnsafeBufferPointer performance. The
|
||
// optimizer is not capable of creating partial specializations yet.
|
||
// NOTE: Range checks are not performed here, because it is done later by
|
||
// the subscript function.
|
||
// NOTE: Unchecked math because unsafe pointers are not required to
|
||
// behave sensibly if you misuse their indices. We validate in
|
||
// debug mode.
|
||
let maxOffset = limit.subtractingReportingOverflow(i)
|
||
_debugPrecondition(!maxOffset.overflow)
|
||
let l = maxOffset.partialValue
|
||
|
||
if n > 0 ? l >= 0 && l < n : l <= 0 && n < l {
|
||
return nil
|
||
}
|
||
|
||
// No need to check here, for the same index misuse reasons.
|
||
return i &+ n
|
||
}
|
||
|
||
@inlinable // unsafe-performance
|
||
public func distance(from start: Int, to end: Int) -> Int {
|
||
// NOTE: this is a manual specialization of index movement for a Strideable
|
||
// index that is required for UnsafeBufferPointer performance. The
|
||
// optimizer is not capable of creating partial specializations yet.
|
||
// NOTE: Range checks are not performed here, because it is done later by
|
||
// the subscript function.
|
||
// NOTE: We allow the subtraction to silently overflow in release builds
|
||
// to eliminate a superflous check when `start` and `end` are both valid
|
||
// indices. (The operation can only overflow if `start` is negative, which
|
||
// implies it's an invalid index.) `Collection` does not specify what
|
||
// `distance` should return when given an invalid index pair.
|
||
let result = end.subtractingReportingOverflow(start)
|
||
_debugPrecondition(!result.overflow)
|
||
return result.partialValue
|
||
}
|
||
|
||
@inlinable // unsafe-performance
|
||
public func _failEarlyRangeCheck(_ index: Int, bounds: Range<Int>) {
|
||
// NOTE: In release mode, this method is a no-op for performance reasons.
|
||
_debugPrecondition(index >= bounds.lowerBound)
|
||
_debugPrecondition(index < bounds.upperBound)
|
||
}
|
||
|
||
@inlinable // unsafe-performance
|
||
public func _failEarlyRangeCheck(_ range: Range<Int>, bounds: Range<Int>) {
|
||
// NOTE: In release mode, this method is a no-op for performance reasons.
|
||
_debugPrecondition(range.lowerBound >= bounds.lowerBound)
|
||
_debugPrecondition(range.upperBound <= bounds.upperBound)
|
||
}
|
||
|
||
@inlinable // unsafe-performance
|
||
public var indices: Indices {
|
||
// Not checked because init forbids negative count.
|
||
return Indices(uncheckedBounds: (startIndex, endIndex))
|
||
}
|
||
|
||
/// Accesses the element at the specified position.
|
||
///
|
||
%if Mutable:
|
||
/// The following example uses the buffer pointer's subscript to access and
|
||
/// modify the elements of a mutable buffer pointing to the contiguous
|
||
/// contents of an array:
|
||
///
|
||
/// var numbers = [1, 2, 3, 4, 5]
|
||
/// numbers.withUnsafeMutableBufferPointer { buffer in
|
||
/// for i in stride(from: buffer.startIndex, to: buffer.endIndex - 1, by: 2) {
|
||
/// let x = buffer[i]
|
||
/// buffer[i + 1] = buffer[i]
|
||
/// buffer[i] = x
|
||
/// }
|
||
/// }
|
||
/// print(numbers)
|
||
/// // Prints "[2, 1, 4, 3, 5]"
|
||
%else:
|
||
/// The following example uses the buffer pointer's subscript to access every
|
||
/// other element of the buffer:
|
||
///
|
||
/// let numbers = [1, 2, 3, 4, 5]
|
||
/// let sum = numbers.withUnsafeBufferPointer { buffer -> Int in
|
||
/// var result = 0
|
||
/// for i in stride(from: buffer.startIndex, to: buffer.endIndex, by: 2) {
|
||
/// result += buffer[i]
|
||
/// }
|
||
/// return result
|
||
/// }
|
||
/// // 'sum' == 9
|
||
%end
|
||
///
|
||
/// - Note: Bounds checks for `i` are performed only in debug mode.
|
||
///
|
||
/// - Parameter i: The position of the element to access. `i` must be in the
|
||
/// range `0..<count`.
|
||
@inlinable // unsafe-performance
|
||
public subscript(i: Int) -> Element {
|
||
get {
|
||
_debugPrecondition(i >= 0)
|
||
_debugPrecondition(i < endIndex)
|
||
return _position._unsafelyUnwrappedUnchecked[i]
|
||
}
|
||
%if Mutable:
|
||
nonmutating _modify {
|
||
_debugPrecondition(i >= 0)
|
||
_debugPrecondition(i < endIndex)
|
||
yield &_position._unsafelyUnwrappedUnchecked[i]
|
||
}
|
||
%end
|
||
}
|
||
|
||
// Skip all debug and runtime checks
|
||
|
||
@inlinable // unsafe-performance
|
||
internal subscript(_unchecked i: Int) -> Element {
|
||
get {
|
||
_internalInvariant(i >= 0)
|
||
_internalInvariant(i < endIndex)
|
||
return _position._unsafelyUnwrappedUnchecked[i]
|
||
}
|
||
%if Mutable:
|
||
nonmutating _modify {
|
||
_internalInvariant(i >= 0)
|
||
_internalInvariant(i < endIndex)
|
||
yield &_position._unsafelyUnwrappedUnchecked[i]
|
||
}
|
||
%end
|
||
}
|
||
|
||
/// Accesses a contiguous subrange of the buffer's elements.
|
||
///
|
||
/// The accessed slice uses the same indices for the same elements as the
|
||
/// original buffer uses. Always use the slice's `startIndex` property
|
||
/// instead of assuming that its indices start at a particular value.
|
||
///
|
||
/// This example demonstrates getting a slice from a buffer of strings, finding
|
||
/// the index of one of the strings in the slice, and then using that index
|
||
/// in the original buffer.
|
||
///
|
||
%if Mutable:
|
||
/// var streets = ["Adams", "Bryant", "Channing", "Douglas", "Evarts"]
|
||
/// streets.withUnsafeMutableBufferPointer { buffer in
|
||
/// let streetSlice = buffer[2..<buffer.endIndex]
|
||
/// print(Array(streetSlice))
|
||
/// // Prints "["Channing", "Douglas", "Evarts"]"
|
||
/// let index = streetSlice.firstIndex(of: "Evarts") // 4
|
||
/// buffer[index!] = "Eustace"
|
||
/// }
|
||
/// print(streets.last!)
|
||
/// // Prints "Eustace"
|
||
%else:
|
||
/// let streets = ["Adams", "Bryant", "Channing", "Douglas", "Evarts"]
|
||
/// streets.withUnsafeBufferPointer { buffer in
|
||
/// let streetSlice = buffer[2..<buffer.endIndex]
|
||
/// print(Array(streetSlice))
|
||
/// // Prints "["Channing", "Douglas", "Evarts"]"
|
||
/// let index = streetSlice.firstIndex(of: "Evarts") // 4
|
||
/// print(buffer[index!])
|
||
/// // Prints "Evarts"
|
||
/// }
|
||
%end
|
||
///
|
||
/// - Note: Bounds checks for `bounds` are performed only in debug mode.
|
||
///
|
||
/// - Parameter bounds: A range of the buffer's indices. The bounds of
|
||
/// the range must be valid indices of the buffer.
|
||
@inlinable // unsafe-performance
|
||
public subscript(bounds: Range<Int>)
|
||
-> Slice<Unsafe${Mutable}BufferPointer<Element>>
|
||
{
|
||
get {
|
||
_debugPrecondition(bounds.lowerBound >= startIndex)
|
||
_debugPrecondition(bounds.upperBound <= endIndex)
|
||
return Slice(
|
||
base: self, bounds: bounds)
|
||
}
|
||
% if Mutable:
|
||
nonmutating set {
|
||
_debugPrecondition(bounds.lowerBound >= startIndex)
|
||
_debugPrecondition(bounds.upperBound <= endIndex)
|
||
_debugPrecondition(bounds.count == newValue.count)
|
||
|
||
// FIXME: swift-3-indexing-model: tests.
|
||
if !newValue.isEmpty {
|
||
(_position! + bounds.lowerBound).assign(
|
||
from: newValue.base._position! + newValue.startIndex,
|
||
count: newValue.count)
|
||
}
|
||
}
|
||
% end
|
||
}
|
||
% if mutable:
|
||
|
||
/// Exchanges the values at the specified indices of the buffer.
|
||
///
|
||
/// Both parameters must be valid indices of the buffer, and not
|
||
/// equal to `endIndex`. Passing the same index as both `i` and `j` has no
|
||
/// effect.
|
||
///
|
||
/// - Parameters:
|
||
/// - i: The index of the first value to swap.
|
||
/// - j: The index of the second value to swap.
|
||
@inlinable // unsafe-performance
|
||
public func swapAt(_ i: Int, _ j: Int) {
|
||
guard i != j else { return }
|
||
_debugPrecondition(i >= 0 && j >= 0)
|
||
_debugPrecondition(i < endIndex && j < endIndex)
|
||
let pi = (_position! + i)
|
||
let pj = (_position! + j)
|
||
let tmp = pi.move()
|
||
pi.moveInitialize(from: pj, count: 1)
|
||
pj.initialize(to: tmp)
|
||
}
|
||
% end # mutable
|
||
}
|
||
|
||
extension Unsafe${Mutable}BufferPointer {
|
||
// This works around _debugPrecondition() impacting the performance of
|
||
// optimized code. (rdar://72246338)
|
||
@_alwaysEmitIntoClient
|
||
internal init(
|
||
@_nonEphemeral _uncheckedStart start: Unsafe${Mutable}Pointer<Element>?,
|
||
count: Int
|
||
) {
|
||
_position = start
|
||
self.count = count
|
||
}
|
||
|
||
/// Creates a new buffer pointer over the specified number of contiguous
|
||
/// instances beginning at the given pointer.
|
||
///
|
||
/// - Parameters:
|
||
/// - start: A pointer to the start of the buffer, or `nil`. If `start` is
|
||
/// `nil`, `count` must be zero. However, `count` may be zero even for a
|
||
/// non-`nil` `start`. The pointer passed as `start` must be aligned to
|
||
/// `MemoryLayout<Element>.alignment`.
|
||
/// - count: The number of instances in the buffer. `count` must not be
|
||
/// negative.
|
||
@inlinable // unsafe-performance
|
||
public init(
|
||
@_nonEphemeral start: Unsafe${Mutable}Pointer<Element>?, count: Int
|
||
) {
|
||
_debugPrecondition(
|
||
count >= 0, "Unsafe${Mutable}BufferPointer with negative count")
|
||
_debugPrecondition(
|
||
count == 0 || start != nil,
|
||
"Unsafe${Mutable}BufferPointer has a nil start and nonzero count")
|
||
self.init(_uncheckedStart: start, count: _assumeNonNegative(count))
|
||
}
|
||
|
||
@inlinable // unsafe-performance
|
||
public init(_empty: ()) {
|
||
_position = nil
|
||
count = 0
|
||
}
|
||
|
||
% 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.
|
||
@inlinable // unsafe-performance
|
||
public init(mutating other: UnsafeBufferPointer<Element>) {
|
||
_position = UnsafeMutablePointer<Element>(mutating: other._position)
|
||
count = other.count
|
||
}
|
||
|
||
@inlinable
|
||
@available(*, deprecated, renamed: "withContiguousMutableStorageIfAvailable")
|
||
public mutating func _withUnsafeMutableBufferPointerIfSupported<R>(
|
||
_ body: (inout UnsafeMutableBufferPointer<Element>) throws -> R
|
||
) rethrows -> R? {
|
||
return try body(&self)
|
||
}
|
||
|
||
@inlinable
|
||
public mutating func withContiguousMutableStorageIfAvailable<R>(
|
||
_ body: (inout UnsafeMutableBufferPointer<Element>) throws -> R
|
||
) rethrows -> R? {
|
||
let (oldBase, oldCount) = (self.baseAddress, self.count)
|
||
defer {
|
||
_debugPrecondition((oldBase, oldCount) == (self.baseAddress, self.count),
|
||
"UnsafeMutableBufferPointer.withUnsafeMutableBufferPointer: replacing the buffer is not allowed")
|
||
}
|
||
return try body(&self)
|
||
}
|
||
|
||
@inlinable
|
||
public func withContiguousStorageIfAvailable<R>(
|
||
_ body: (UnsafeBufferPointer<Element>) throws -> R
|
||
) rethrows -> R? {
|
||
return try body(UnsafeBufferPointer(self))
|
||
}
|
||
|
||
% 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.
|
||
@inlinable // unsafe-performance
|
||
public init(_ other: UnsafeMutableBufferPointer<Element>) {
|
||
_position = UnsafePointer<Element>(other._position)
|
||
count = other.count
|
||
}
|
||
|
||
@inlinable
|
||
public func withContiguousStorageIfAvailable<R>(
|
||
_ body: (UnsafeBufferPointer<Element>) throws -> R
|
||
) rethrows -> R? {
|
||
return try body(self)
|
||
}
|
||
|
||
% 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
|
||
/// indexed starting at zero instead of sharing indices with the original
|
||
/// buffer. For example:
|
||
///
|
||
/// let buffer = returnsABuffer()
|
||
/// let n = 5
|
||
/// let slice = buffer[n...]
|
||
/// let rebased = UnsafeBufferPointer(rebasing: slice)
|
||
///
|
||
/// After rebasing `slice` as the `rebased` buffer, the following are true:
|
||
///
|
||
/// - `rebased.startIndex == 0`
|
||
/// - `rebased[0] == slice[n]`
|
||
/// - `rebased[0] == buffer[n]`
|
||
/// - `rebased.count == slice.count`
|
||
///
|
||
/// - Parameter slice: The buffer slice to rebase.
|
||
@inlinable // unsafe-performance
|
||
public init(rebasing slice: Slice<UnsafeBufferPointer<Element>>) {
|
||
// NOTE: `Slice` does not guarantee that its start/end indices are valid
|
||
// in `base` -- it merely ensures that `startIndex <= endIndex`.
|
||
// We need manually check that we aren't given an invalid slice,
|
||
// or the resulting collection would allow access that was
|
||
// out-of-bounds with respect to the original base buffer.
|
||
// We only do this in debug builds to prevent a measurable performance
|
||
// degradation wrt passing around pointers not wrapped in a BufferPointer
|
||
// construct.
|
||
_debugPrecondition(
|
||
slice.startIndex >= 0 && slice.endIndex <= slice.base.count,
|
||
"Invalid slice")
|
||
let base = slice.base.baseAddress?.advanced(by: slice.startIndex)
|
||
let count = slice.endIndex &- slice.startIndex
|
||
self.init(start: base, count: count)
|
||
}
|
||
|
||
% end
|
||
|
||
/// 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
|
||
/// indexed starting at zero instead of sharing indices with the original
|
||
/// buffer. For example:
|
||
///
|
||
/// let buffer = returnsABuffer()
|
||
/// let n = 5
|
||
/// let slice = buffer[n...]
|
||
/// let rebased = Unsafe${Mutable}BufferPointer(rebasing: slice)
|
||
///
|
||
/// After rebasing `slice` as the `rebased` buffer, the following are true:
|
||
///
|
||
/// - `rebased.startIndex == 0`
|
||
/// - `rebased[0] == slice[n]`
|
||
/// - `rebased[0] == buffer[n]`
|
||
/// - `rebased.count == slice.count`
|
||
///
|
||
/// - Parameter slice: The buffer slice to rebase.
|
||
@inlinable // unsafe-performance
|
||
public init(rebasing slice: Slice<UnsafeMutableBufferPointer<Element>>) {
|
||
let base = slice.base.baseAddress?.advanced(by: slice.startIndex)
|
||
let count = slice.endIndex &- slice.startIndex
|
||
self.init(start: base, count: count)
|
||
}
|
||
|
||
/// 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.
|
||
@inlinable // unsafe-performance
|
||
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`.
|
||
@inlinable // unsafe-performance
|
||
public static func allocate(capacity count: Int)
|
||
-> UnsafeMutableBufferPointer<Element> {
|
||
let size = MemoryLayout<Element>.stride * count
|
||
// For any alignment <= _minAllocationAlignment, force alignment = 0.
|
||
// This forces the runtime's "aligned" allocation path so that
|
||
// deallocation does not require the original alignment.
|
||
//
|
||
// The runtime guarantees:
|
||
//
|
||
// align == 0 || align > _minAllocationAlignment:
|
||
// Runtime uses "aligned allocation".
|
||
//
|
||
// 0 < align <= _minAllocationAlignment:
|
||
// Runtime may use either malloc or "aligned allocation".
|
||
var align = Builtin.alignof(Element.self)
|
||
if Int(align) <= _minAllocationAlignment() {
|
||
align = (0)._builtinWordValue
|
||
}
|
||
let raw = Builtin.allocRaw(size._builtinWordValue, align)
|
||
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.
|
||
@inlinable // unsafe-performance
|
||
public func initialize(repeating repeatedValue: Element) {
|
||
guard let dstBase = _position else {
|
||
return
|
||
}
|
||
|
||
dstBase.initialize(repeating: repeatedValue, count: count)
|
||
}
|
||
|
||
/// 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`.
|
||
@inlinable // unsafe-performance
|
||
public func assign(repeating repeatedValue: Element) {
|
||
guard let dstBase = _position else {
|
||
return
|
||
}
|
||
|
||
dstBase.assign(repeating: repeatedValue, count: count)
|
||
}
|
||
|
||
% 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.
|
||
///
|
||
/// - Note: Only use this method to rebind the buffer's memory to a type
|
||
/// with the same size and stride as the currently bound `Element` type.
|
||
/// To bind a region of memory to a type that is a different size, convert
|
||
/// the buffer to a raw buffer and use the `bindMemory(to:)` method.
|
||
///
|
||
/// - Parameters:
|
||
/// - type: The type to temporarily bind the memory referenced by this
|
||
/// buffer. The type `T` must have the same size 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.
|
||
@inlinable // unsafe-performance
|
||
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.
|
||
///
|
||
/// If the `baseAddress` of this buffer is `nil`, the count is zero. However,
|
||
/// a buffer can have a `count` of zero even with a non-`nil` base address.
|
||
@inlinable // unsafe-performance
|
||
public var baseAddress: Unsafe${Mutable}Pointer<Element>? {
|
||
return _position
|
||
}
|
||
}
|
||
|
||
extension Unsafe${Mutable}BufferPointer: CustomDebugStringConvertible {
|
||
/// A textual representation of the buffer, suitable for debugging.
|
||
public var debugDescription: String {
|
||
return "Unsafe${Mutable}BufferPointer"
|
||
+ "(start: \(_position.map(String.init(describing:)) ?? "nil"), count: \(count))"
|
||
}
|
||
}
|
||
%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<S: Sequence>(from source: S) -> (S.Iterator, Index)
|
||
where S.Element == Element {
|
||
return source._copyContents(initializing: self)
|
||
}
|
||
}
|
||
|
||
extension UnsafeBufferPointer: Sendable { }
|
||
extension UnsafeBufferPointer.Iterator: Sendable { }
|
||
extension UnsafeMutableBufferPointer: Sendable { }
|
||
|
||
// ${'Local Variables'}:
|
||
// eval: (read-only-mode 1)
|
||
// End:
|