//===--- SliceBuffer.swift - Backing storage for ArraySlice ------===// // // 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 // //===----------------------------------------------------------------------===// /// Buffer type for `ArraySlice`. public // @testable struct _SliceBuffer : _ArrayBufferProtocol { internal typealias NativeStorage = _ContiguousArrayStorage public typealias NativeBuffer = _ContiguousArrayBuffer init( owner: AnyObject, subscriptBaseAddress: UnsafeMutablePointer, indices: Range, hasNativeBuffer: Bool ) { self.owner = owner self.subscriptBaseAddress = subscriptBaseAddress self.startIndex = indices.startIndex let bufferFlag = UInt(hasNativeBuffer ? 1 : 0) self.endIndexAndFlags = (UInt(indices.endIndex) << 1) | bufferFlag _invariantCheck() } public init() { let empty = _ContiguousArrayBuffer() self.owner = empty.owner self.subscriptBaseAddress = empty.firstElementAddress self.startIndex = empty.startIndex self.endIndexAndFlags = 1 _invariantCheck() } public init(_ buffer: NativeBuffer, shiftedToStartIndex: Int) { let shift = buffer.startIndex - shiftedToStartIndex self.init( owner: buffer.owner, subscriptBaseAddress: buffer.subscriptBaseAddress + shift, indices: shiftedToStartIndex..( subRange subRange: Range, with insertCount: Int, elementsOf newValues: C ) { _invariantCheck() _sanityCheck(insertCount <= numericCast(newValues.count)) _sanityCheck(_hasNativeBuffer && isUniquelyReferenced()) let eraseCount = subRange.count let growth = insertCount - eraseCount let oldCount = count var native = nativeBuffer let hiddenElementCount = firstElementAddress - native.firstElementAddress _sanityCheck(native.count + growth <= native.capacity) let start = subRange.startIndex - startIndex + hiddenElementCount let end = subRange.endIndex - startIndex + hiddenElementCount native.replace( subRange: start.. { return UnsafePointer(firstElementAddress) } /// An object that keeps the elements stored in this buffer alive. public var owner: AnyObject public let subscriptBaseAddress: UnsafeMutablePointer public var firstElementAddress: UnsafeMutablePointer { return subscriptBaseAddress + startIndex } /// [63:1: 63-bit index][0: has a native buffer] var endIndexAndFlags: UInt //===--- Non-essential bits ---------------------------------------------===// @warn_unused_result public mutating func requestUniqueMutableBackingBuffer( minimumCapacity minimumCapacity: Int ) -> NativeBuffer? { _invariantCheck() if _fastPath(_hasNativeBuffer && isUniquelyReferenced()) { if capacity >= minimumCapacity { // Since we have the last reference, drop any inaccessible // trailing elements in the underlying storage. That will // tend to reduce shuffling of later elements. Since this // function isn't called for subscripting, this won't slow // down that case. var native = nativeBuffer let offset = self.firstElementAddress - native.firstElementAddress let backingCount = native.count let myCount = count if _slowPath(backingCount > myCount + offset) { native.replace( subRange: (myCount+offset).. Bool { return _hasNativeBuffer && isUniquelyReferenced() } @warn_unused_result public mutating func isMutableAndUniquelyReferencedOrPinned() -> Bool { return _hasNativeBuffer && isUniquelyReferencedOrPinned() } /// If this buffer is backed by a `_ContiguousArrayBuffer` /// containing the same number of elements as `self`, return it. /// Otherwise, return `nil`. @warn_unused_result public func requestNativeBuffer() -> _ContiguousArrayBuffer? { _invariantCheck() if _fastPath(_hasNativeBuffer && nativeBuffer.count == count) { return nativeBuffer } return nil } public func _copyContents( subRange bounds: Range, initializing target: UnsafeMutablePointer ) -> UnsafeMutablePointer { _invariantCheck() _sanityCheck(bounds.startIndex >= startIndex) _sanityCheck(bounds.endIndex >= bounds.startIndex) _sanityCheck(bounds.endIndex <= endIndex) let c = bounds.count target.initializeFrom(subscriptBaseAddress + bounds.startIndex, count: c) return target + c } /// True, if the array is native and does not need a deferred type check. var arrayPropertyIsNativeTypeChecked : Bool { return _hasNativeBuffer } public var count: Int { get { return endIndex - startIndex } set { let growth = newValue - count if growth != 0 { nativeBuffer.count += growth self.endIndex += growth } _invariantCheck() } } /// Traps unless the given `index` is valid for subscripting, i.e. /// `startIndex ≤ index < endIndex` internal func _checkValidSubscript(index : Int) { _precondition( index >= startIndex && index < endIndex, "Index out of bounds") } public var capacity: Int { let count = self.count if _slowPath(!_hasNativeBuffer) { return count } let n = nativeBuffer let nativeEnd = n.firstElementAddress + n.count if (firstElementAddress + count) == nativeEnd { return count + (n.capacity - n.count) } return count } @warn_unused_result mutating func isUniquelyReferenced() -> Bool { return isUniquelyReferencedNonObjC(&owner) } @warn_unused_result mutating func isUniquelyReferencedOrPinned() -> Bool { return isUniquelyReferencedOrPinnedNonObjC(&owner) } @warn_unused_result func getElement(i: Int) -> Element { _sanityCheck(i >= startIndex, "negative slice index is out of range") _sanityCheck(i < endIndex, "slice index out of range") return subscriptBaseAddress[i] } /// Access the element at `position`. /// /// - Precondition: `position` is a valid position in `self` and /// `position != endIndex`. public subscript(position: Int) -> Element { get { return getElement(position) } nonmutating set { _sanityCheck(position >= startIndex, "negative slice index is out of range") _sanityCheck(position < endIndex, "slice index out of range") subscriptBaseAddress[position] = newValue } } public subscript(bounds: Range) -> _SliceBuffer { get { _sanityCheck(bounds.startIndex >= startIndex) _sanityCheck(bounds.endIndex >= bounds.startIndex) _sanityCheck(bounds.endIndex <= endIndex) return _SliceBuffer( owner: owner, subscriptBaseAddress: subscriptBaseAddress, indices: bounds, hasNativeBuffer: _hasNativeBuffer) } set { fatalError("not implemented") } } //===--- Collection conformance -------------------------------------===// /// The position of the first element in a non-empty collection. /// /// In an empty collection, `startIndex == endIndex`. public var startIndex: Int /// The collection's "past the end" position. /// /// `endIndex` is not a valid argument to `subscript`, and is always /// reachable from `startIndex` by zero or more applications of /// `successor()`. public var endIndex: Int { get { return Int(endIndexAndFlags >> 1) } set { endIndexAndFlags = (UInt(newValue) << 1) | (_hasNativeBuffer ? 1 : 0) } } //===--- misc -----------------------------------------------------------===// /// Call `body(p)`, where `p` is an `UnsafeBufferPointer` over the /// underlying contiguous storage. public func withUnsafeBufferPointer( @noescape body: (UnsafeBufferPointer) throws -> R ) rethrows -> R { defer { _fixLifetime(self) } return try body(UnsafeBufferPointer(start: firstElementAddress, count: count)) } /// Call `body(p)`, where `p` is an `UnsafeMutableBufferPointer` /// over the underlying contiguous storage. public mutating func withUnsafeMutableBufferPointer( @noescape body: (UnsafeMutableBufferPointer) throws -> R ) rethrows -> R { defer { _fixLifetime(self) } return try body( UnsafeMutableBufferPointer(start: firstElementAddress, count: count)) } } extension _SliceBuffer { public func _copyToNativeArrayBuffer() -> _ContiguousArrayBuffer { if _hasNativeBuffer { let n = nativeBuffer if count == n.count { return n } } let result = _ContiguousArrayBuffer( uninitializedCount: count, minimumCapacity: 0) result.firstElementAddress.initializeFrom(firstElementAddress, count: count) return result } }