//===--- ArrayBufferProtocol.swift ----------------------------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://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. @_versioned internal protocol _ArrayBufferProtocol : MutableCollection, RandomAccessCollection { associatedtype Indices : RandomAccessCollection = CountableRange /// The type of elements stored in the buffer. associatedtype Element /// Create an empty buffer. init() /// Adopt the entire buffer, presenting it at the provided `startIndex`. init(_buffer: _ContiguousArrayBuffer, shiftedToStartIndex: Int) /// 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 func _copyContents( subRange bounds: Range, initializing target: UnsafeMutablePointer ) -> UnsafeMutablePointer /// Get or set the index'th element. subscript(index: Int) -> Element { get nonmutating set } /// 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` iff this buffer is backed by a uniquely-referenced mutable /// _ContiguousArrayBuffer. /// /// - 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: C ) where C : Collection, C.Iterator.Element == Element /// Returns a `_SliceBuffer` containing the elements in `bounds`. subscript(bounds: Range) -> _SliceBuffer { get } /// Call `body(p)`, where `p` is an `UnsafeBufferPointer` over the /// underlying contiguous storage. If no such storage exists, it is /// created on-demand. func withUnsafeBufferPointer( _ body: (UnsafeBufferPointer) throws -> R ) rethrows -> R /// Call `body(p)`, where `p` is an `UnsafeMutableBufferPointer` /// over the underlying contiguous storage. /// /// - Precondition: Such contiguous storage exists or the buffer is empty. mutating func withUnsafeMutableBufferPointer( _ body: (UnsafeMutableBufferPointer) throws -> R ) rethrows -> R /// The number of elements the buffer stores. var count: Int { get set } /// The number of elements the buffer can store without reallocation. var capacity: Int { get } /// 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 } var startIndex: Int { get } var endIndex: Int { get } } extension _ArrayBufferProtocol { internal var subscriptBaseAddress: UnsafeMutablePointer { return firstElementAddress } internal mutating func replaceSubrange( _ subrange: Range, with newCount: Int, elementsOf newValues: C ) where C : Collection, C.Iterator.Element == Element { _sanityCheck(startIndex == 0, "_SliceBuffer should override this function.") let oldCount = self.count let eraseCount = subrange.count let growth = newCount - eraseCount self.count = oldCount + growth let elements = self.subscriptBaseAddress let oldTailIndex = subrange.upperBound let oldTailStart = elements + oldTailIndex let newTailIndex = oldTailIndex + growth let newTailStart = oldTailStart + growth let tailCount = oldCount - subrange.upperBound if growth > 0 { // Slide the tail part of the buffer forwards, in reverse order // so as not to self-clobber. newTailStart.moveInitialize(from: oldTailStart, count: tailCount) // Assign over the original subrange var i = newValues.startIndex for j in CountableRange(subrange) { elements[j] = newValues[i] newValues.formIndex(after: &i) } // Initialize the hole left by sliding the tail forward for j in oldTailIndex.. shrinkage { // If the tail length exceeds the shrinkage // Assign over the rest of the replaced range with the first // part of the tail. newTailStart.moveAssign(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) // Destroy elements remaining after the tail in subrange (newTailStart + tailCount).deinitialize( count: shrinkage - tailCount) } } } }