[stdlib] Make protocol _NSArrayCore internal

These shadow protocols don’t add any real type safety, and exposing them in the ABI seems unnecessary.
This commit is contained in:
Karoy Lorentey
2018-11-12 15:44:09 +00:00
parent c71abaaf51
commit ee17e975ca
9 changed files with 131 additions and 106 deletions

View File

@@ -21,29 +21,76 @@
#if _runtime(_ObjC)
import SwiftShims
/// A wrapper around any `_NSArrayCore` that gives it
/// `Collection` conformance. Why not make
/// `_NSArrayCore` conform directly? It's a class, and I
/// don't want to pay for the dynamic dispatch overhead.
/// A wrapper around any `_NSArrayCore` (represented as AnyObject) that gives it
/// `Collection` conformance. Why not make `_NSArrayCore` conform directly?
/// It's a class, and I don't want to pay for the dynamic dispatch overhead.
@usableFromInline
@_fixed_layout
internal struct _CocoaArrayWrapper : RandomAccessCollection {
@usableFromInline
typealias Indices = Range<Int>
@usableFromInline
internal var buffer: AnyObject
@usableFromInline @_transparent
internal init(_ buffer: AnyObject) {
self.buffer = buffer
}
internal var core: _NSArrayCore {
@inline(__always) get {
return unsafeBitCast(buffer, to: _NSArrayCore.self)
}
}
@inlinable
internal var startIndex: Int {
return 0
}
@inlinable
@usableFromInline
internal var endIndex: Int {
return buffer.count
return core.count
}
@inlinable
@usableFromInline
internal subscript(i: Int) -> AnyObject {
return buffer.objectAt(i)
return core.objectAt(i)
}
@usableFromInline
internal subscript(bounds: Range<Int>) -> _SliceBuffer<AnyObject> {
let boundsCount = bounds.count
if boundsCount == 0 {
return _SliceBuffer(
_buffer: _ContiguousArrayBuffer<AnyObject>(),
shiftedToStartIndex: bounds.lowerBound)
}
// Look for contiguous storage in the NSArray
let cocoaStorageBaseAddress = self.contiguousStorage(self.indices)
if let cocoaStorageBaseAddress = cocoaStorageBaseAddress {
return _SliceBuffer(
owner: self.buffer,
subscriptBaseAddress: cocoaStorageBaseAddress,
indices: bounds,
hasNativeBuffer: false)
}
// No contiguous storage found; we must allocate
let result = _ContiguousArrayBuffer<AnyObject>(
_uninitializedCount: boundsCount,
minimumCapacity: 0)
// Tell Cocoa to copy the objects into our storage
core.getObjects(
UnsafeMutableRawPointer(result.firstElementAddress)
.assumingMemoryBound(to: AnyObject.self),
range: _SwiftNSRange(location: bounds.lowerBound, length: boundsCount))
return _SliceBuffer(_buffer: result, shiftedToStartIndex: bounds.lowerBound)
}
/// Returns a pointer to the first element in the given non-empty `subRange`
@@ -56,7 +103,6 @@ internal struct _CocoaArrayWrapper : RandomAccessCollection {
/// is sometimes conservative and may return `nil` even when
/// contiguous storage exists, e.g., if array doesn't have a smart
/// implementation of countByEnumerating.
@inlinable
internal func contiguousStorage(
_ subRange: Range<Int>
) -> UnsafeMutablePointer<AnyObject>?
@@ -69,9 +115,9 @@ internal struct _CocoaArrayWrapper : RandomAccessCollection {
// acceptable conservative behavior, but could potentially be
// optimized for other cases.
let contiguousCount = withUnsafeMutablePointer(to: &enumerationState) {
self.buffer.countByEnumerating(with: $0, objects: nil, count: 0)
core.countByEnumerating(with: $0, objects: nil, count: 0)
}
return contiguousCount >= subRange.upperBound
? UnsafeMutableRawPointer(enumerationState.itemsPtr!)
.assumingMemoryBound(to: AnyObject.self)
@@ -79,12 +125,25 @@ internal struct _CocoaArrayWrapper : RandomAccessCollection {
: nil
}
@usableFromInline @_transparent
internal init(_ buffer: _NSArrayCore) {
self.buffer = buffer
}
@usableFromInline
internal var buffer: _NSArrayCore
__consuming internal func _copyContents(
subRange bounds: Range<Int>,
initializing target: UnsafeMutablePointer<AnyObject>
) -> UnsafeMutablePointer<AnyObject> {
let nsSubRange = SwiftShims._SwiftNSRange(
location: bounds.lowerBound,
length: bounds.upperBound - bounds.lowerBound)
// Copies the references out of the NSArray without retaining them
core.getObjects(target, range: nsSubRange)
// Make another pass to retain the copied objects
var result = target
for _ in bounds {
result.initialize(to: result.pointee)
result += 1
}
return result
}
}
#endif