mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Add an Array-based NSMutableArray subclass
This commit is contained in:
@@ -85,10 +85,7 @@ public protocol _ObjectiveCBridgeable {
|
|||||||
|
|
||||||
#if _runtime(_ObjC)
|
#if _runtime(_ObjC)
|
||||||
|
|
||||||
@available(macOS, introduced: 9999, deprecated)
|
@available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *)
|
||||||
@available(iOS, introduced: 9999, deprecated)
|
|
||||||
@available(watchOS, introduced: 9999, deprecated)
|
|
||||||
@available(tvOS, introduced: 9999, deprecated)
|
|
||||||
@available(*, deprecated)
|
@available(*, deprecated)
|
||||||
@_cdecl("_SwiftCreateBridgedArray")
|
@_cdecl("_SwiftCreateBridgedArray")
|
||||||
@usableFromInline
|
@usableFromInline
|
||||||
@@ -101,6 +98,19 @@ internal func _SwiftCreateBridgedArray(
|
|||||||
return Unmanaged<AnyObject>.passRetained(bridged)
|
return Unmanaged<AnyObject>.passRetained(bridged)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *)
|
||||||
|
@available(*, deprecated)
|
||||||
|
@_cdecl("_SwiftCreateBridgedMutableArray")
|
||||||
|
@usableFromInline
|
||||||
|
internal func _SwiftCreateBridgedMutableArray(
|
||||||
|
values: UnsafePointer<AnyObject>,
|
||||||
|
numValues: Int
|
||||||
|
) -> Unmanaged<AnyObject> {
|
||||||
|
let bufPtr = UnsafeBufferPointer(start: values, count: numValues)
|
||||||
|
let bridged = _SwiftNSMutableArray(Array(bufPtr))
|
||||||
|
return Unmanaged<AnyObject>.passRetained(bridged)
|
||||||
|
}
|
||||||
|
|
||||||
@_silgen_name("swift_stdlib_connectNSBaseClasses")
|
@_silgen_name("swift_stdlib_connectNSBaseClasses")
|
||||||
internal func _connectNSBaseClasses() -> Bool
|
internal func _connectNSBaseClasses() -> Bool
|
||||||
|
|
||||||
|
|||||||
@@ -276,6 +276,18 @@ internal class __SwiftNativeNSArray {
|
|||||||
deinit {}
|
deinit {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@_fixed_layout
|
||||||
|
@usableFromInline
|
||||||
|
@objc @_swift_native_objc_runtime_base(__SwiftNativeNSMutableArrayBase)
|
||||||
|
internal class _SwiftNativeNSMutableArray {
|
||||||
|
@inlinable
|
||||||
|
@nonobjc
|
||||||
|
internal init() {}
|
||||||
|
// @objc public init(coder: AnyObject) {}
|
||||||
|
@inlinable
|
||||||
|
deinit {}
|
||||||
|
}
|
||||||
|
|
||||||
@_fixed_layout
|
@_fixed_layout
|
||||||
@usableFromInline
|
@usableFromInline
|
||||||
@objc @_swift_native_objc_runtime_base(__SwiftNativeNSDictionaryBase)
|
@objc @_swift_native_objc_runtime_base(__SwiftNativeNSDictionaryBase)
|
||||||
|
|||||||
@@ -61,14 +61,16 @@ internal class __SwiftNativeNSArrayWithContiguousStorage
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private let NSNotFound: Int = .max
|
||||||
|
|
||||||
// Implement the APIs required by NSArray
|
// Implement the APIs required by NSArray
|
||||||
extension __SwiftNativeNSArrayWithContiguousStorage: _NSArrayCore {
|
extension __SwiftNativeNSArrayWithContiguousStorage: _NSArrayCore {
|
||||||
@objc internal var count: Int {
|
@objc internal var count: Int {
|
||||||
return withUnsafeBufferOfObjects { $0.count }
|
return withUnsafeBufferOfObjects { $0.count }
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc(objectAtIndex:)
|
@inline(__always)
|
||||||
internal func objectAt(_ index: Int) -> AnyObject {
|
@nonobjc private func _objectAt(_ index: Int) -> AnyObject {
|
||||||
return withUnsafeBufferOfObjects {
|
return withUnsafeBufferOfObjects {
|
||||||
objects in
|
objects in
|
||||||
_precondition(
|
_precondition(
|
||||||
@@ -78,6 +80,16 @@ extension __SwiftNativeNSArrayWithContiguousStorage: _NSArrayCore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@objc(objectAtIndexedSubscript:)
|
||||||
|
dynamic internal func objectAtSubscript(_ index: Int) -> AnyObject {
|
||||||
|
return _objectAt(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc(objectAtIndex:)
|
||||||
|
dynamic internal func objectAt(_ index: Int) -> AnyObject {
|
||||||
|
return _objectAt(index)
|
||||||
|
}
|
||||||
|
|
||||||
@objc internal func getObjects(
|
@objc internal func getObjects(
|
||||||
_ aBuffer: UnsafeMutablePointer<AnyObject>, range: _SwiftNSRange
|
_ aBuffer: UnsafeMutablePointer<AnyObject>, range: _SwiftNSRange
|
||||||
) {
|
) {
|
||||||
@@ -131,6 +143,172 @@ extension __SwiftNativeNSArrayWithContiguousStorage: _NSArrayCore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@_fixed_layout
|
||||||
|
@usableFromInline
|
||||||
|
@objc internal final class _SwiftNSMutableArray :
|
||||||
|
_SwiftNativeNSMutableArray, _NSArrayCore
|
||||||
|
{
|
||||||
|
internal var contents: [AnyObject]
|
||||||
|
|
||||||
|
internal init(_ array: [AnyObject]) {
|
||||||
|
contents = array
|
||||||
|
super.init()
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc internal var count: Int {
|
||||||
|
return contents.count
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc(objectAtIndexedSubscript:)
|
||||||
|
dynamic internal func objectAtSubscript(_ index: Int) -> AnyObject {
|
||||||
|
//TODO: exception instead of precondition, once that's possible
|
||||||
|
return contents[index]
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc(objectAtIndex:)
|
||||||
|
dynamic internal func objectAt(_ index: Int) -> AnyObject {
|
||||||
|
//TODO: exception instead of precondition, once that's possible
|
||||||
|
return contents[index]
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc internal func getObjects(
|
||||||
|
_ aBuffer: UnsafeMutablePointer<AnyObject>, range: _SwiftNSRange
|
||||||
|
) {
|
||||||
|
return contents.withContiguousStorageIfAvailable { objects in
|
||||||
|
//TODO: exceptions instead of preconditions, once that's possible
|
||||||
|
|
||||||
|
_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).copyMemory(
|
||||||
|
from: objects.baseAddress! + range.location,
|
||||||
|
byteCount: range.length * MemoryLayout<AnyObject>.stride)
|
||||||
|
}!
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc(countByEnumeratingWithState:objects:count:)
|
||||||
|
internal func countByEnumerating(
|
||||||
|
with state: UnsafeMutablePointer<_SwiftNSFastEnumerationState>,
|
||||||
|
objects: UnsafeMutablePointer<AnyObject>?, count: Int
|
||||||
|
) -> Int {
|
||||||
|
var enumerationState = state.pointee
|
||||||
|
|
||||||
|
if enumerationState.state != 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return contents.withContiguousStorageIfAvailable {
|
||||||
|
objects in
|
||||||
|
enumerationState.mutationsPtr = _fastEnumerationStorageMutationsPtr
|
||||||
|
enumerationState.itemsPtr =
|
||||||
|
AutoreleasingUnsafeMutablePointer(objects.baseAddress)
|
||||||
|
enumerationState.state = 1
|
||||||
|
state.pointee = enumerationState
|
||||||
|
return objects.count
|
||||||
|
}!
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc(copyWithZone:)
|
||||||
|
dynamic internal func copy(with _: _SwiftNSZone?) -> AnyObject {
|
||||||
|
return contents._bridgeToObjectiveCImpl()
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc(insertObject:atIndex:)
|
||||||
|
dynamic internal func insert(_ anObject: AnyObject, at index: Int) {
|
||||||
|
contents.insert(anObject, at: index)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc(removeObjectAtIndex:)
|
||||||
|
dynamic internal func removeObject(at index: Int) {
|
||||||
|
contents.remove(at: index)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc(addObject:)
|
||||||
|
dynamic internal func add(_ anObject: AnyObject) {
|
||||||
|
contents.append(anObject)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc(removeLastObject)
|
||||||
|
dynamic internal func removeLastObject() {
|
||||||
|
contents.removeLast()
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc(replaceObjectAtIndex:withObject:)
|
||||||
|
dynamic internal func replaceObject(at index: Int, with anObject: AnyObject) {
|
||||||
|
//enforces bounds, unlike set equivalent, which can append
|
||||||
|
contents[index] = anObject
|
||||||
|
}
|
||||||
|
|
||||||
|
//Non-core methods overridden for performance
|
||||||
|
|
||||||
|
@objc(exchangeObjectAtIndex:withObjectAtIndex:)
|
||||||
|
dynamic internal func exchange(at index: Int, with index2: Int) {
|
||||||
|
swap(&contents[index], &contents[index2])
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc(replaceObjectsInRange:withObjects:count:)
|
||||||
|
dynamic internal func replaceObjects(in range: _SwiftNSRange,
|
||||||
|
with objects: UnsafePointer<AnyObject>,
|
||||||
|
count: Int) {
|
||||||
|
let range = range.location ..< range.location + range.length
|
||||||
|
let buf = UnsafeBufferPointer(start: objects, count: count)
|
||||||
|
contents.replaceSubrange(range, with: buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc(insertObjects:count:atIndex:)
|
||||||
|
dynamic internal func insertObjects(_ objects: UnsafePointer<AnyObject>,
|
||||||
|
count: Int,
|
||||||
|
at index: Int) {
|
||||||
|
let buf = UnsafeBufferPointer(start: objects, count: count)
|
||||||
|
contents.insert(contentsOf: buf, at: index)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc(indexOfObjectIdenticalTo:)
|
||||||
|
dynamic internal func index(ofObjectIdenticalTo object: AnyObject) -> Int {
|
||||||
|
return contents.firstIndex { $0 === object } ?? NSNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc(removeObjectsInRange:)
|
||||||
|
dynamic internal func removeObjects(in range: _SwiftNSRange) {
|
||||||
|
let range = range.location ..< range.location + range.length
|
||||||
|
contents.replaceSubrange(range, with: [])
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc(removeAllObjects)
|
||||||
|
dynamic internal func removeAllObjects() {
|
||||||
|
contents = []
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc(setObject:atIndex:)
|
||||||
|
dynamic internal func setObject(_ anObject: AnyObject, at index: Int) {
|
||||||
|
if index == contents.count {
|
||||||
|
contents.append(anObject)
|
||||||
|
} else {
|
||||||
|
contents[index] = anObject
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc(setObject:atIndexedSubscript:) dynamic
|
||||||
|
internal func setObjectSubscript(_ anObject: AnyObject, at index: Int) {
|
||||||
|
if index == contents.count {
|
||||||
|
contents.append(anObject)
|
||||||
|
} else {
|
||||||
|
contents[index] = anObject
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// An `NSArray` whose contiguous storage is created and filled, upon
|
/// An `NSArray` whose contiguous storage is created and filled, upon
|
||||||
/// first access, by bridging the elements of a Swift `Array`.
|
/// first access, by bridging the elements of a Swift `Array`.
|
||||||
///
|
///
|
||||||
@@ -292,6 +470,18 @@ internal class __ContiguousArrayStorageBase
|
|||||||
_internalInvariantFailure(
|
_internalInvariantFailure(
|
||||||
"Concrete subclasses must implement _getNonVerbatimBridgingBuffer")
|
"Concrete subclasses must implement _getNonVerbatimBridgingBuffer")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@objc(mutableCopyWithZone:)
|
||||||
|
dynamic internal func mutableCopy(with _: _SwiftNSZone?) -> AnyObject {
|
||||||
|
let arr = Array<AnyObject>(_ContiguousArrayBuffer(self))
|
||||||
|
return _SwiftNSMutableArray(arr)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc(indexOfObjectIdenticalTo:)
|
||||||
|
dynamic internal func index(ofObjectIdenticalTo object: AnyObject) -> Int {
|
||||||
|
let arr = Array<AnyObject>(_ContiguousArrayBuffer(self))
|
||||||
|
return arr.firstIndex { $0 === object } ?? NSNotFound
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@inlinable
|
@inlinable
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ using namespace swift;
|
|||||||
// NOTE: older runtimes called these _SwiftNativeNSXXXBase. The two must
|
// NOTE: older runtimes called these _SwiftNativeNSXXXBase. The two must
|
||||||
// coexist, so these were renamed. The old names must not be used in the new
|
// coexist, so these were renamed. The old names must not be used in the new
|
||||||
// runtime.
|
// runtime.
|
||||||
% for Class in ('Array', 'Dictionary', 'Set', 'String', 'Enumerator'):
|
% for Class in ('Array', 'MutableArray', 'Dictionary', 'Set', 'String', 'Enumerator'):
|
||||||
SWIFT_RUNTIME_STDLIB_API
|
SWIFT_RUNTIME_STDLIB_API
|
||||||
@interface __SwiftNativeNS${Class}Base : NSObject
|
@interface __SwiftNativeNS${Class}Base : NSObject
|
||||||
{
|
{
|
||||||
@@ -120,7 +120,7 @@ swift_stdlib_NSObject_isEqual(id lhs,
|
|||||||
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_SPI
|
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_SPI
|
||||||
bool
|
bool
|
||||||
swift_stdlib_connectNSBaseClasses() {
|
swift_stdlib_connectNSBaseClasses() {
|
||||||
% for Class in ('Array', 'Dictionary', 'Set', 'String', 'Enumerator'):
|
% for Class in ('Array', 'MutableArray', 'Dictionary', 'Set', 'String', 'Enumerator'):
|
||||||
Class NS${Class}Super = objc_lookUpClass("NS${Class}");
|
Class NS${Class}Super = objc_lookUpClass("NS${Class}");
|
||||||
if (!NS${Class}Super) return false;
|
if (!NS${Class}Super) return false;
|
||||||
Class NS${Class}OurClass = objc_lookUpClass("__SwiftNativeNS${Class}Base");
|
Class NS${Class}OurClass = objc_lookUpClass("__SwiftNativeNS${Class}Base");
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
Class _SwiftNSMutableArray is a new API without @available attribute
|
||||||
|
Class _SwiftNativeNSMutableArray is a new API without @available attribute
|
||||||
Func _collectReferencesInsideObject(_:) is a new API without @available attribute
|
Func _collectReferencesInsideObject(_:) is a new API without @available attribute
|
||||||
Func _loadDestroyTLSCounter() is a new API without @available attribute
|
Func _loadDestroyTLSCounter() is a new API without @available attribute
|
||||||
Protocol _RuntimeFunctionCountersStats is a new API without @available attribute
|
Protocol _RuntimeFunctionCountersStats is a new API without @available attribute
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ BOOL TestSwiftNativeNSBase_UnwantedCdtors()
|
|||||||
NSMutableSet *expectedClasses =
|
NSMutableSet *expectedClasses =
|
||||||
[NSMutableSet setWithObjects:
|
[NSMutableSet setWithObjects:
|
||||||
@"__SwiftNativeNSArrayBase",
|
@"__SwiftNativeNSArrayBase",
|
||||||
|
@"__SwiftNativeNSMutableArrayBase",
|
||||||
@"__SwiftNativeNSDictionaryBase",
|
@"__SwiftNativeNSDictionaryBase",
|
||||||
@"__SwiftNativeNSSetBase",
|
@"__SwiftNativeNSSetBase",
|
||||||
@"__SwiftNativeNSStringBase",
|
@"__SwiftNativeNSStringBase",
|
||||||
|
|||||||
Reference in New Issue
Block a user