//===--- ArrayBufferProtocol.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 // //===----------------------------------------------------------------------===// /// The underlying buffer for an ArrayType conforms to /// `_ArrayBufferProtocol`. This buffer does not provide value semantics. @usableFromInline internal protocol _ArrayBufferProtocol : MutableCollection, RandomAccessCollection where Indices == Range { /// Create an empty buffer. init() /// Adopt the entire buffer, presenting it at the provided `startIndex`. init(_buffer: _ContiguousArrayBuffer, shiftedToStartIndex: Int) init(copying buffer: Self) /// Copy the elements in `bounds` from this buffer into uninitialized /// memory starting at `target`. Return a pointer "past the end" of the /// just-initialized memory. @discardableResult __consuming func _copyContents( subRange bounds: Range, initializing target: UnsafeMutablePointer ) -> UnsafeMutablePointer /// If this buffer is backed by a uniquely-referenced mutable /// `_ContiguousArrayBuffer` that can be grown in-place to allow the `self` /// buffer store `minimumCapacity` elements, returns that buffer. /// Otherwise, returns `nil`. /// /// - Note: The result's firstElementAddress may not match ours, if we are a /// _SliceBuffer. /// /// - Note: This function must remain mutating; otherwise the buffer /// may acquire spurious extra references, which will cause /// unnecessary reallocation. mutating func requestUniqueMutableBackingBuffer( minimumCapacity: Int ) -> _ContiguousArrayBuffer? /// Returns `true` if this buffer is backed by a uniquely-referenced mutable /// _ContiguousArrayBuffer; otherwise, returns `false`. /// /// - Note: This function must remain mutating; otherwise the buffer /// may acquire spurious extra references, which will cause /// unnecessary reallocation. mutating func isMutableAndUniquelyReferenced() -> Bool /// If this buffer is backed by a `_ContiguousArrayBuffer` /// containing the same number of elements as `self`, return it. /// Otherwise, return `nil`. func requestNativeBuffer() -> _ContiguousArrayBuffer? /// Replace the given `subRange` with the first `newCount` elements of /// the given collection. /// /// - Precondition: This buffer is backed by a uniquely-referenced /// `_ContiguousArrayBuffer`. mutating func replaceSubrange( _ subrange: Range, with newCount: Int, elementsOf newValues: __owned C ) where C: Collection, C.Element == Element /// Returns a `_SliceBuffer` containing the elements in `bounds`. subscript(bounds: Range) -> _SliceBuffer { get } #if !$Embedded // Superseded by the typed-throws version of this function, but retained // for ABI reasons. func withUnsafeBufferPointer( _ body: (UnsafeBufferPointer) throws -> R ) rethrows -> R #endif /// Call `body(p)`, where `p` is an `UnsafeBufferPointer` over the /// underlying contiguous storage. If no such storage exists, it is /// created on-demand. @available(SwiftStdlib 6.1, *) func withUnsafeBufferPointer( _ body: (UnsafeBufferPointer) throws(E) -> R ) throws(E) -> R #if !$Embedded // Superseded by the typed-throws version of this function, but retained // for ABI reasons. mutating func withUnsafeMutableBufferPointer( _ body: (UnsafeMutableBufferPointer) throws -> R ) rethrows -> R #endif /// Call `body(p)`, where `p` is an `UnsafeMutableBufferPointer` /// over the underlying contiguous storage. /// /// - Precondition: Such contiguous storage exists or the buffer is empty. @available(SwiftStdlib 6.1, *) mutating func withUnsafeMutableBufferPointer( _ body: (UnsafeMutableBufferPointer) throws(E) -> R ) throws(E) -> R /// The number of elements the buffer stores. override var count: Int { get set } /// The number of elements the buffer can store without reallocation. var capacity: Int { get } #if $Embedded typealias AnyObject = Builtin.NativeObject #endif /// An object that keeps the elements stored in this buffer alive. var owner: AnyObject { get } /// A pointer to the first element. /// /// - Precondition: The elements are known to be stored contiguously. var firstElementAddress: UnsafeMutablePointer { get } /// If the elements are stored contiguously, a pointer to the first /// element. Otherwise, `nil`. var firstElementAddressIfContiguous: UnsafeMutablePointer? { get } /// Returns a base address to which you can add an index `i` to get the /// address of the corresponding element at `i`. var subscriptBaseAddress: UnsafeMutablePointer { get } /// A value that identifies the storage used by the buffer. Two /// buffers address the same elements when they have the same /// identity and count. var identity: UnsafeRawPointer { get } } extension _ArrayBufferProtocol { @inlinable internal var subscriptBaseAddress: UnsafeMutablePointer { return unsafe firstElementAddress } // Make sure the compiler does not inline _copyBuffer to reduce code size. @inline(never) @inlinable // This code should be specializable such that copying an array is // fast and does not end up in an unspecialized entry point. internal init(copying buffer: Self) { let newBuffer = _ContiguousArrayBuffer( _uninitializedCount: buffer.count, minimumCapacity: buffer.count) unsafe buffer._copyContents( subRange: buffer.indices, initializing: newBuffer.firstElementAddress) self = Self( _buffer: newBuffer, shiftedToStartIndex: buffer.startIndex) } @inlinable internal mutating func replaceSubrange( _ subrange: Range, with newCount: Int, elementsOf newValues: __owned C ) where C: Collection, C.Element == Element { _internalInvariant(startIndex == 0, "_SliceBuffer should override this function.") let elements = unsafe self.firstElementAddress // erase all the elements we're replacing to create a hole let holeStart = unsafe elements + subrange.lowerBound let holeEnd = unsafe holeStart + newCount let eraseCount = subrange.count unsafe holeStart.deinitialize(count: eraseCount) let growth = newCount - eraseCount if growth != 0 { let tailStart = unsafe elements + subrange.upperBound let tailCount = self.count - subrange.upperBound unsafe holeEnd.moveInitialize(from: tailStart, count: tailCount) self.count += growth } // don't use UnsafeMutableBufferPointer.initialize(fromContentsOf:) // since it behaves differently on collections that misreport count, // and breaks validation tests for those usecases / potentially // breaks ABI guarantees. if newCount > 0 { let done: Void? = newValues.withContiguousStorageIfAvailable { _precondition( $0.count == newCount, "invalid Collection: count differed in successive traversals" ) unsafe holeStart.initialize(from: $0.baseAddress!, count: newCount) } if done == nil { var place = unsafe holeStart var i = newValues.startIndex while unsafe place < holeEnd { unsafe place.initialize(to: newValues[i]) unsafe place += 1 newValues.formIndex(after: &i) } _expectEnd(of: newValues, is: i) } } } }