//===----------------------------------------------------------------------===// // // 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 // //===----------------------------------------------------------------------===// import SwiftShims /// Class used whose sole instance is used as storage for empty /// arrays. The instance is defined in the runtime and statically /// initialized. See stdlib/runtime/GlobalObjects.cpp for details. /// Because it's statically referenced, it requires non-lazy realization /// by the Objective-C runtime. @objc_non_lazy_realization internal final class _EmptyArrayStorage : _ContiguousArrayStorageBase { init(_doNotCallMe: ()) { _sanityCheckFailure("creating instance of _EmptyArrayStorage") } var countAndCapacity: _ArrayBody #if _runtime(_ObjC) override func _withVerbatimBridgedUnsafeBuffer( @noescape body: (UnsafeBufferPointer) throws -> R ) rethrows -> R? { return try body(UnsafeBufferPointer(start: nil, count: 0)) } // FIXME(ABI): remove 'Void' arguments here and elsewhere in this file, they // are a workaround for an old compiler limitation. @warn_unused_result override func _getNonVerbatimBridgedCount(dummy: Void) -> Int { return 0 } @warn_unused_result override func _getNonVerbatimBridgedHeapBuffer( dummy: Void ) -> _HeapBuffer { return _HeapBuffer( _HeapBufferStorage.self, 0, 0) } #endif @warn_unused_result override func canStoreElements(ofDynamicType _: Any.Type) -> Bool { return false } /// A type that every element in the array is. override var staticElementType: Any.Type { return Void.self } } /// The empty array prototype. We use the same object for all empty /// `[Native]Array`s. internal var _emptyArrayStorage : _EmptyArrayStorage { return Builtin.bridgeFromRawPointer( Builtin.addressof(&_swiftEmptyArrayStorage)) } // FIXME: This whole class is a workaround for // Can't override generic method in generic // subclass. If it weren't for that bug, we'd override // _withVerbatimBridgedUnsafeBuffer directly in // _ContiguousArrayStorage. class _ContiguousArrayStorage1 : _ContiguousArrayStorageBase { #if _runtime(_ObjC) /// If the `Element` is bridged verbatim, invoke `body` on an /// `UnsafeBufferPointer` to the elements and return the result. /// Otherwise, return `nil`. final override func _withVerbatimBridgedUnsafeBuffer( @noescape body: (UnsafeBufferPointer) throws -> R ) rethrows -> R? { var result: R? = nil try self._withVerbatimBridgedUnsafeBufferImpl { result = try body($0) } return result } /// If `Element` is bridged verbatim, invoke `body` on an /// `UnsafeBufferPointer` to the elements. internal func _withVerbatimBridgedUnsafeBufferImpl( @noescape body: (UnsafeBufferPointer) throws -> Void ) rethrows { _sanityCheckFailure( "Must override _withVerbatimBridgedUnsafeBufferImpl in derived classes") } #endif } // The class that implements the storage for a ContiguousArray @_versioned final class _ContiguousArrayStorage : _ContiguousArrayStorage1 { deinit { __manager._elementPointer.deinitialize( count: __manager._valuePointer.pointee.count) __manager._valuePointer.deinitialize() _fixLifetime(__manager) } #if _runtime(_ObjC) /// If `Element` is bridged verbatim, invoke `body` on an /// `UnsafeBufferPointer` to the elements. internal final override func _withVerbatimBridgedUnsafeBufferImpl( @noescape body: (UnsafeBufferPointer) throws -> Void ) rethrows { if _isBridgedVerbatimToObjectiveC(Element.self) { let count = __manager.value.count let elements = UnsafePointer(__manager._elementPointer) defer { _fixLifetime(__manager) } try body(UnsafeBufferPointer(start: elements, count: count)) } } /// Returns the number of elements in the array. /// /// - Precondition: `Element` is bridged non-verbatim. @warn_unused_result override internal func _getNonVerbatimBridgedCount(dummy: Void) -> Int { _sanityCheck( !_isBridgedVerbatimToObjectiveC(Element.self), "Verbatim bridging should be handled separately") return __manager.value.count } /// Bridge array elements and return a new buffer that owns them. /// /// - Precondition: `Element` is bridged non-verbatim. @warn_unused_result override internal func _getNonVerbatimBridgedHeapBuffer(dummy: Void) -> _HeapBuffer { _sanityCheck( !_isBridgedVerbatimToObjectiveC(Element.self), "Verbatim bridging should be handled separately") let count = __manager.value.count let result = _HeapBuffer( _HeapBufferStorage.self, count, count) let resultPtr = result.baseAddress let p = __manager._elementPointer for i in 0.. Bool { #if _runtime(_ObjC) return proposedElementType is Element.Type #else // FIXME: Dynamic casts don't currently work without objc. // rdar://problem/18801510 return false #endif } /// A type that every element in the array is. override var staticElementType: Any.Type { return Element.self } internal // private typealias Manager = ManagedBufferPointer<_ArrayBody, Element> internal // private var __manager : Manager { return Manager(_uncheckedUnsafeBufferObject: self) } } @_fixed_layout public struct _ContiguousArrayBuffer : _ArrayBufferProtocol { /// Make a buffer with uninitialized elements. After using this /// method, you must either initialize the `count` elements at the /// result's `.firstElementAddress` or set the result's `.count` /// to zero. public init(uninitializedCount: Int, minimumCapacity: Int) { let realMinimumCapacity = Swift.max(uninitializedCount, minimumCapacity) if realMinimumCapacity == 0 { self = _ContiguousArrayBuffer() } else { __bufferPointer = ManagedBufferPointer( _uncheckedBufferClass: _ContiguousArrayStorage.self, minimumCapacity: realMinimumCapacity) _initStorageHeader( count: uninitializedCount, capacity: __bufferPointer.capacity) _fixLifetime(__bufferPointer) } } /// Initialize using the given uninitialized `storage`. /// The storage is assumed to be uninitialized. The returned buffer has the /// body part of the storage initialized, but not the elements. /// /// - Warning: The result has uninitialized elements. /// /// - Warning: storage may have been stack-allocated, so it's /// crucial not to call, e.g., `malloc_size` on it. internal init(count: Int, storage: _ContiguousArrayStorage) { __bufferPointer = ManagedBufferPointer( _uncheckedUnsafeBufferObject: storage) _initStorageHeader(count: count, capacity: count) _fixLifetime(__bufferPointer) } internal init(_ storage: _ContiguousArrayStorageBase) { __bufferPointer = ManagedBufferPointer( _uncheckedUnsafeBufferObject: storage) } /// Initialize the body part of our storage. /// /// - Warning: does not initialize elements internal func _initStorageHeader(count count: Int, capacity: Int) { #if _runtime(_ObjC) let verbatim = _isBridgedVerbatimToObjectiveC(Element.self) #else let verbatim = false #endif __bufferPointer._valuePointer.initialize(with: _ArrayBody( count: count, capacity: capacity, elementTypeIsBridgedVerbatim: verbatim)) } /// True, if the array is native and does not need a deferred type check. var arrayPropertyIsNativeTypeChecked : Bool { return true } /// If the elements are stored contiguously, a pointer to the first /// element. Otherwise, `nil`. public var firstElementAddress: UnsafeMutablePointer { return __bufferPointer._elementPointer } /// 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)) } //===--- _ArrayBufferProtocol conformance -----------------------------------===// /// Create an empty buffer. public init() { __bufferPointer = ManagedBufferPointer( _uncheckedUnsafeBufferObject: _emptyArrayStorage) } public init(_ buffer: _ContiguousArrayBuffer, shiftedToStartIndex: Int) { _sanityCheck(shiftedToStartIndex == 0, "shiftedToStartIndex must be 0") self = buffer } @warn_unused_result public mutating func requestUniqueMutableBackingBuffer( minimumCapacity minimumCapacity: Int ) -> _ContiguousArrayBuffer? { if _fastPath(isUniquelyReferenced() && capacity >= minimumCapacity) { return self } return nil } @warn_unused_result public mutating func isMutableAndUniquelyReferenced() -> Bool { return isUniquelyReferenced() } @warn_unused_result public mutating func isMutableAndUniquelyReferencedOrPinned() -> Bool { return 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? { return self } @_versioned @warn_unused_result func getElement(i: Int) -> Element { _sanityCheck(i >= 0 && i < count, "Array index out of range") return firstElementAddress[i] } /// Get or set the value of the ith element. public subscript(i: Int) -> Element { get { return getElement(i) } nonmutating set { _sanityCheck(i >= 0 && i < count, "Array index out of range") // FIXME: Manually swap because it makes the ARC optimizer happy. See // check retain/release order // firstElementAddress[i] = newValue var nv = newValue let tmp = nv nv = firstElementAddress[i] firstElementAddress[i] = tmp } } /// The number of elements the buffer stores. public var count: Int { get { return __bufferPointer.value.count } nonmutating set { _sanityCheck(newValue >= 0) _sanityCheck( newValue <= capacity, "Can't grow an array buffer past its capacity") __bufferPointer._valuePointer.pointee.count = newValue } } /// Traps unless the given `index` is valid for subscripting, i.e. /// `0 ≤ index < count`. @inline(__always) func _checkValidSubscript(index : Int) { _precondition( (index >= 0) && (index < __bufferPointer.value.count), "Index out of range" ) } /// The number of elements the buffer can store without reallocation. public var capacity: Int { return __bufferPointer.value.capacity } /// 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. public func _copyContents( subRange bounds: Range, initializing target: UnsafeMutablePointer ) -> UnsafeMutablePointer { _sanityCheck(bounds.lowerBound >= 0) _sanityCheck(bounds.upperBound >= bounds.lowerBound) _sanityCheck(bounds.upperBound <= count) let initializedCount = bounds.upperBound - bounds.lowerBound target.initializeFrom( firstElementAddress + bounds.lowerBound, count: initializedCount) _fixLifetime(owner) return target + initializedCount } /// Returns a `_SliceBuffer` containing the given `bounds` of values /// from this buffer. public subscript(bounds: Range) -> _SliceBuffer { get { return _SliceBuffer( owner: __bufferPointer.buffer, subscriptBaseAddress: subscriptBaseAddress, indices: bounds, hasNativeBuffer: true) } set { fatalError("not implemented") } } /// Returns `true` iff this buffer's storage is uniquely-referenced. /// /// - Note: This does not mean the buffer is mutable. Other factors /// may need to be considered, such as whether the buffer could be /// some immutable Cocoa container. @warn_unused_result public mutating func isUniquelyReferenced() -> Bool { return __bufferPointer.holdsUniqueReference() } /// Returns `true` iff this buffer's storage is either /// uniquely-referenced or pinned. NOTE: this does not mean /// the buffer is mutable; see the comment on isUniquelyReferenced. @warn_unused_result public mutating func isUniquelyReferencedOrPinned() -> Bool { return __bufferPointer.holdsUniqueOrPinnedReference() } #if _runtime(_ObjC) /// Convert to an NSArray. /// /// - Precondition: `Element` is bridged to Objective-C. /// /// - Complexity: O(1). @warn_unused_result public func _asCocoaArray() -> _NSArrayCore { _sanityCheck( _isBridgedToObjectiveC(Element.self), "Array element type is not bridged to Objective-C") if count == 0 { return _SwiftDeferredNSArray( _nativeStorage: _emptyArrayStorage) } return _SwiftDeferredNSArray(_nativeStorage: _storage) } #endif /// An object that keeps the elements stored in this buffer alive. public var owner: AnyObject { return _storage } /// An object that keeps the elements stored in this buffer alive. public var nativeOwner: AnyObject { return _storage } /// A value that identifies the storage used by the buffer. /// /// Two buffers address the same elements when they have the same /// identity and count. public var identity: UnsafePointer { return withUnsafeBufferPointer { UnsafePointer($0.baseAddress) } } /// Returns `true` iff we have storage for elements of the given /// `proposedElementType`. If not, we'll be treated as immutable. func canStoreElements(ofDynamicType proposedElementType: Any.Type) -> Bool { return _storage.canStoreElements(ofDynamicType: proposedElementType) } /// Returns `true` if the buffer stores only elements of type `U`. /// /// - Precondition: `U` is a class or `@objc` existential. /// /// - Complexity: O(N). @warn_unused_result func storesOnlyElementsOfType( _: U.Type ) -> Bool { _sanityCheck(_isClassOrObjCExistential(U.self)) if _fastPath(_storage.staticElementType is U.Type) { // Done in O(1) return true } // Check the elements for x in self { if !(x is U) { return false } } return true } internal var _storage: _ContiguousArrayStorageBase { return Builtin.castFromNativeObject(__bufferPointer._nativeBuffer) } var __bufferPointer: ManagedBufferPointer<_ArrayBody, Element> } /// Append the elements of `rhs` to `lhs`. public func += < Element, C : Collection where C.Iterator.Element == Element > (lhs: inout _ContiguousArrayBuffer, rhs: C) { let oldCount = lhs.count let newCount = oldCount + numericCast(rhs.count) if _fastPath(newCount <= lhs.capacity) { lhs.count = newCount (lhs.firstElementAddress + oldCount).initializeFrom(rhs) } else { var newLHS = _ContiguousArrayBuffer( uninitializedCount: newCount, minimumCapacity: _growArrayCapacity(lhs.capacity)) newLHS.firstElementAddress.moveInitializeFrom( lhs.firstElementAddress, count: oldCount) lhs.count = 0 swap(&lhs, &newLHS) (lhs.firstElementAddress + oldCount).initializeFrom(rhs) } } extension _ContiguousArrayBuffer : Collection { /// The position of the first element in a non-empty collection. /// /// In an empty collection, `startIndex == endIndex`. public var startIndex: Int { return 0 } /// 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(of:)`. public var endIndex: Int { return count } public typealias Indices = CountableRange public var indices: CountableRange { return startIndex.. _ContiguousArrayBuffer { return _copySequenceToNativeArrayBuffer(self) } } @warn_unused_result internal func _copySequenceToNativeArrayBuffer< S : Sequence >(source: S) -> _ContiguousArrayBuffer { let initialCapacity = source.underestimatedCount var builder = _UnsafePartiallyInitializedContiguousArrayBuffer( initialCapacity: initialCapacity) var iterator = source.makeIterator() // FIXME(performance): use _copyContents(initializing:). // Add elements up to the initial capacity without checking for regrowth. for _ in 0.. _ContiguousArrayBuffer { return _copyCollectionToNativeArrayBuffer(self) } } extension _ContiguousArrayBuffer { public func _copyToNativeArrayBuffer() -> _ContiguousArrayBuffer { return self } } /// This is a fast implementation of _copyToNativeArrayBuffer() for collections. /// /// It avoids the extra retain, release overhead from storing the /// ContiguousArrayBuffer into /// _UnsafePartiallyInitializedContiguousArrayBuffer. Since we do not support /// ARC loops, the extra retain, release overhead cannot be eliminated which /// makes assigning ranges very slow. Once this has been implemented, this code /// should be changed to use _UnsafePartiallyInitializedContiguousArrayBuffer. @warn_unused_result internal func _copyCollectionToNativeArrayBuffer< C : Collection >(source: C) -> _ContiguousArrayBuffer { let count: Int = numericCast(source.count) if count == 0 { return _ContiguousArrayBuffer() } let result = _ContiguousArrayBuffer( uninitializedCount: count, minimumCapacity: 0) var p = result.firstElementAddress var i = source.startIndex for _ in 0.. { internal var result: _ContiguousArrayBuffer internal var p: UnsafeMutablePointer internal var remainingCapacity: Int /// Initialize the buffer with an initial size of `initialCapacity` /// elements. @inline(__always) // For performance reasons. init(initialCapacity: Int) { if initialCapacity == 0 { result = _ContiguousArrayBuffer() } else { result = _ContiguousArrayBuffer( uninitializedCount: initialCapacity, minimumCapacity: 0) } p = result.firstElementAddress remainingCapacity = result.capacity } /// Add an element to the buffer, reallocating if necessary. @inline(__always) // For performance reasons. mutating func add(element: Element) { if remainingCapacity == 0 { // Reallocate. let newCapacity = max(_growArrayCapacity(result.capacity), 1) var newResult = _ContiguousArrayBuffer( uninitializedCount: newCapacity, minimumCapacity: 0) p = newResult.firstElementAddress + result.capacity remainingCapacity = newResult.capacity - result.capacity newResult.firstElementAddress.moveInitializeFrom( result.firstElementAddress, count: result.capacity) result.count = 0 swap(&result, &newResult) } addWithExistingCapacity(element) } /// Add an element to the buffer, which must have remaining capacity. @inline(__always) // For performance reasons. mutating func addWithExistingCapacity(element: Element) { _sanityCheck(remainingCapacity > 0, "_UnsafePartiallyInitializedContiguousArrayBuffer has no more capacity") remainingCapacity -= 1 p.initialize(with: element) p += 1 } /// Finish initializing the buffer, adjusting its count to the final /// number of elements. /// /// Returns the fully-initialized buffer. `self` is reset to contain an /// empty buffer and cannot be used afterward. @inline(__always) // For performance reasons. @warn_unused_result mutating func finish() -> _ContiguousArrayBuffer { // Adjust the initialized count of the buffer. result.count = result.capacity - remainingCapacity return finishWithOriginalCount() } /// Finish initializing the buffer, assuming that the number of elements /// exactly matches the `initialCount` for which the initialization was /// started. /// /// Returns the fully-initialized buffer. `self` is reset to contain an /// empty buffer and cannot be used afterward. @inline(__always) // For performance reasons. @warn_unused_result mutating func finishWithOriginalCount() -> _ContiguousArrayBuffer { _sanityCheck(remainingCapacity == result.capacity - result.count, "_UnsafePartiallyInitializedContiguousArrayBuffer has incorrect count") var finalResult = _ContiguousArrayBuffer() swap(&finalResult, &result) remainingCapacity = 0 return finalResult } }