//===--- SwiftNativeNSArray.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 // //===----------------------------------------------------------------------===// // // _ContiguousArrayStorageBase supplies the implementation of the // _NSArrayCore API (and thus, NSArray the API) for our // _ContiguousArrayStorage. We can't put this implementation // directly on _ContiguousArrayStorage because generic classes can't // override Objective-C selectors. // //===----------------------------------------------------------------------===// #if _runtime(_ObjC) import SwiftShims /// Returns `true` iff the given `index` is valid as a position, i.e. `0 /// ≤ index ≤ count`. @_versioned @_transparent internal func _isValidArrayIndex(_ index: Int, count: Int) -> Bool { return (index >= 0) && (index <= count) } /// Returns `true` iff the given `index` is valid for subscripting, i.e. /// `0 ≤ index < count`. @_versioned @_transparent internal func _isValidArraySubscript(_ index: Int, count: Int) -> Bool { return (index >= 0) && (index < count) } /// An `NSArray` with Swift-native reference counting and contiguous /// storage. @_versioned internal class _SwiftNativeNSArrayWithContiguousStorage : _SwiftNativeNSArray { // Provides NSArray inheritance and native refcounting // Operate on our contiguous storage @_inlineable @_versioned internal func withUnsafeBufferOfObjects( _ body: (UnsafeBufferPointer) throws -> R ) rethrows -> R { _sanityCheckFailure( "Must override withUnsafeBufferOfObjects in derived classes") } } // Implement the APIs required by NSArray extension _SwiftNativeNSArrayWithContiguousStorage : _NSArrayCore { @_inlineable @_versioned @objc internal var count: Int { return withUnsafeBufferOfObjects { $0.count } } @_inlineable @_versioned @objc(objectAtIndex:) internal func objectAt(_ index: Int) -> AnyObject { return withUnsafeBufferOfObjects { objects in _precondition( _isValidArraySubscript(index, count: objects.count), "Array index out of range") return objects[index] } } @_inlineable @_versioned @objc internal func getObjects( _ aBuffer: UnsafeMutablePointer, range: _SwiftNSRange ) { return withUnsafeBufferOfObjects { objects in _precondition( _isValidArrayIndex(range.location, count: objects.count), "Array index out of range") _precondition( _isValidArrayIndex( range.location + range.length, count: objects.count), "Array index out of range") if objects.isEmpty { return } // These objects are "returned" at +0, so treat them as pointer values to // avoid retains. Copy bytes via a raw pointer to circumvent reference // counting while correctly aliasing with all other pointer types. UnsafeMutableRawPointer(aBuffer).copyBytes( from: objects.baseAddress! + range.location, count: range.length * MemoryLayout.stride) } } @_inlineable @_versioned @objc(countByEnumeratingWithState:objects:count:) internal func countByEnumerating( with state: UnsafeMutablePointer<_SwiftNSFastEnumerationState>, objects: UnsafeMutablePointer?, count: Int ) -> Int { var enumerationState = state.pointee if enumerationState.state != 0 { return 0 } return withUnsafeBufferOfObjects { objects in enumerationState.mutationsPtr = _fastEnumerationStorageMutationsPtr enumerationState.itemsPtr = AutoreleasingUnsafeMutablePointer(objects.baseAddress) enumerationState.state = 1 state.pointee = enumerationState return objects.count } } @_inlineable @_versioned @objc(copyWithZone:) internal func copy(with _: _SwiftNSZone?) -> AnyObject { return self } } /// An `NSArray` whose contiguous storage is created and filled, upon /// first access, by bridging the elements of a Swift `Array`. /// /// Ideally instances of this class would be allocated in-line in the /// buffers used for Array storage. @_versioned @objc internal final class _SwiftDeferredNSArray : _SwiftNativeNSArrayWithContiguousStorage { // This stored property should be stored at offset zero. We perform atomic // operations on it. // // Do not access this property directly. @_versioned @nonobjc internal var _heapBufferBridged_DoNotUse: AnyObject? // When this class is allocated inline, this property can become a // computed one. @_versioned @nonobjc internal let _nativeStorage: _ContiguousArrayStorageBase @_inlineable @_versioned @nonobjc internal var _heapBufferBridgedPtr: UnsafeMutablePointer { return _getUnsafePointerToStoredProperties(self).assumingMemoryBound( to: Optional.self) } internal typealias HeapBufferStorage = _HeapBufferStorage @_inlineable @_versioned internal var _heapBufferBridged: HeapBufferStorage? { if let ref = _stdlib_atomicLoadARCRef(object: _heapBufferBridgedPtr) { return unsafeBitCast(ref, to: HeapBufferStorage.self) } return nil } @_versioned @nonobjc internal init(_nativeStorage: _ContiguousArrayStorageBase) { self._nativeStorage = _nativeStorage } @_inlineable @_versioned internal func _destroyBridgedStorage(_ hb: HeapBufferStorage?) { if let bridgedStorage = hb { let heapBuffer = _HeapBuffer(bridgedStorage) let count = heapBuffer.value heapBuffer.baseAddress.deinitialize(count: count) } } deinit { _destroyBridgedStorage(_heapBufferBridged) } @_inlineable @_versioned internal override func withUnsafeBufferOfObjects( _ body: (UnsafeBufferPointer) throws -> R ) rethrows -> R { while true { var buffer: UnsafeBufferPointer // If we've already got a buffer of bridged objects, just use it if let bridgedStorage = _heapBufferBridged { let heapBuffer = _HeapBuffer(bridgedStorage) buffer = UnsafeBufferPointer( start: heapBuffer.baseAddress, count: heapBuffer.value) } // If elements are bridged verbatim, the native buffer is all we // need, so return that. else if let buf = _nativeStorage._withVerbatimBridgedUnsafeBuffer( { $0 } ) { buffer = buf } else { // Create buffer of bridged objects. let objects = _nativeStorage._getNonVerbatimBridgedHeapBuffer() // Atomically store a reference to that buffer in self. if !_stdlib_atomicInitializeARCRef( object: _heapBufferBridgedPtr, desired: objects.storage!) { // Another thread won the race. Throw out our buffer. _destroyBridgedStorage( unsafeDowncast(objects.storage!, to: HeapBufferStorage.self)) } continue // Try again } defer { _fixLifetime(self) } return try body(buffer) } } /// Returns the number of elements in the array. /// /// This override allows the count to be read without triggering /// bridging of array elements. @_inlineable @_versioned @objc internal override var count: Int { if let bridgedStorage = _heapBufferBridged { return _HeapBuffer(bridgedStorage).value } // Check if elements are bridged verbatim. return _nativeStorage._withVerbatimBridgedUnsafeBuffer { $0.count } ?? _nativeStorage._getNonVerbatimBridgedCount() } } #else // Empty shim version for non-objc platforms. @_versioned class _SwiftNativeNSArrayWithContiguousStorage { @_inlineable @_versioned init() {} } #endif /// Base class of the heap buffer backing arrays. @_versioned @_fixed_layout internal class _ContiguousArrayStorageBase : _SwiftNativeNSArrayWithContiguousStorage { @_versioned final var countAndCapacity: _ArrayBody @nonobjc init(_doNotCallMeBase: ()) { _sanityCheckFailure("creating instance of _ContiguousArrayStorageBase") } #if _runtime(_ObjC) @_inlineable @_versioned internal override func withUnsafeBufferOfObjects( _ body: (UnsafeBufferPointer) throws -> R ) rethrows -> R { if let result = try _withVerbatimBridgedUnsafeBuffer(body) { return result } _sanityCheckFailure( "Can't use a buffer of non-verbatim-bridged elements as an NSArray") } /// If the stored type is bridged verbatim, invoke `body` on an /// `UnsafeBufferPointer` to the elements and return the result. /// Otherwise, return `nil`. @_versioned internal func _withVerbatimBridgedUnsafeBuffer( _ body: (UnsafeBufferPointer) throws -> R ) rethrows -> R? { _sanityCheckFailure( "Concrete subclasses must implement _withVerbatimBridgedUnsafeBuffer") } @_versioned @nonobjc internal func _getNonVerbatimBridgedCount() -> Int { _sanityCheckFailure( "Concrete subclasses must implement _getNonVerbatimBridgedCount") } @_versioned internal func _getNonVerbatimBridgedHeapBuffer() -> _HeapBuffer { _sanityCheckFailure( "Concrete subclasses must implement _getNonVerbatimBridgedHeapBuffer") } #endif @_versioned func canStoreElements(ofDynamicType _: Any.Type) -> Bool { _sanityCheckFailure( "Concrete subclasses must implement canStoreElements(ofDynamicType:)") } /// A type that every element in the array is. @_versioned var staticElementType: Any.Type { _sanityCheckFailure( "Concrete subclasses must implement staticElementType") } deinit { _sanityCheck( self !== _emptyArrayStorage, "Deallocating empty array storage?!") } }