Merge pull request #5680 from Gankro/revert-indices
revert _CocoaDictionaryBuffer indexing design
diff --git a/stdlib/public/core/HashedCollections.swift.gyb b/stdlib/public/core/HashedCollections.swift.gyb
index 7b22bac..89af066 100644
--- a/stdlib/public/core/HashedCollections.swift.gyb
+++ b/stdlib/public/core/HashedCollections.swift.gyb
@@ -3749,12 +3749,9 @@
#endif
#if _runtime(_ObjC)
-
-// FIXME: this should really be a struct but can't because of the lazy allKeys.
-// (but it might be removed with eager bridging, so this is "fine" for now)
@_versioned
@_fixed_layout
-internal final class _Cocoa${Self}Buffer : _HashBuffer {
+internal struct _Cocoa${Self}Buffer : _HashBuffer {
@_versioned
internal var cocoa${Self}: _NS${Self}
@@ -3765,31 +3762,22 @@
internal typealias Key = AnyObject
internal typealias Value = AnyObject
- internal lazy var allKeys : _Box<_HeapBuffer<Int, AnyObject>> = {
- return _Box(_stdlib_NS${Self}_all${'Objects' if Self == 'Set' else 'Keys'}(self.cocoa${Self}))
- }()
-
internal var startIndex: Index {
- return Index(value: 0)
+ return Index(cocoa${Self}, startIndex: ())
}
internal var endIndex: Index {
- return Index(value: allKeys._value.value)
+ return Index(cocoa${Self}, endIndex: ())
}
- // Assumption: we rely on NS${Self}.getObjects when being
- // repeatedly called on the same NS${Self}, returning items in the same
- // order every time.
@_versioned
internal func index(after i: Index) -> Index {
- _precondition(
- i.currentKeyIndex < allKeys._value.value, "cannot increment endIndex")
- return _Cocoa${Self}Index(value: i.currentKeyIndex + 1)
+ return i.successor()
}
- @_versioned
internal func formIndex(after i: inout Index) {
- i = index(after: i)
+ // FIXME: swift-3-indexing-model: optimize if possible.
+ i = i.successor()
}
@_versioned
@@ -3802,26 +3790,31 @@
return nil
}
+%if Self == 'Set':
+ let allKeys = _stdlib_NSSet_allObjects(cocoaSet)
+%elif Self == 'Dictionary':
+ let allKeys = _stdlib_NSDictionary_allKeys(cocoaDictionary)
+%end
var keyIndex = -1
- for i in 0..<allKeys._value.value {
- if _stdlib_NSObject_isEqual(key, allKeys._value[i]) {
+ for i in 0..<allKeys.value {
+ if _stdlib_NSObject_isEqual(key, allKeys[i]) {
keyIndex = i
break
}
}
_sanityCheck(keyIndex >= 0,
"key was found in fast path, but not found later?")
- return Index(value: keyIndex)
+ return Index(cocoa${Self}, allKeys, keyIndex)
}
internal func assertingGet(_ i: Index) -> SequenceElement {
%if Self == 'Set':
- let value: Value? = allKeys._value[i.currentKeyIndex]
+ let value: Value? = i.allKeys[i.currentKeyIndex]
_sanityCheck(value != nil, "item not found in underlying NS${Self}")
return value!
%elif Self == 'Dictionary':
- let key: Key = allKeys._value[i.currentKeyIndex]
- let value: Value = cocoaDictionary.objectFor(key)!
+ let key: Key = i.allKeys[i.currentKeyIndex]
+ let value: Value = i.cocoaDictionary.objectFor(key)!
return (key, value)
%end
@@ -3850,33 +3843,29 @@
}
- internal init(cocoa${Self}: _NS${Self}) {
- self.cocoa${Self} = cocoa${Self}
- }
-
@discardableResult
- internal func updateValue(_ value: Value, forKey key: Key) -> Value? {
+ internal mutating func updateValue(_ value: Value, forKey key: Key) -> Value? {
_sanityCheckFailure("cannot mutate NS${Self}")
}
@discardableResult
- internal func insert(
+ internal mutating func insert(
_ value: Value, forKey key: Key
) -> (inserted: Bool, memberAfterInsert: Value) {
_sanityCheckFailure("cannot mutate NS${Self}")
}
@discardableResult
- internal func remove(at index: Index) -> SequenceElement {
+ internal mutating func remove(at index: Index) -> SequenceElement {
_sanityCheckFailure("cannot mutate NS${Self}")
}
@discardableResult
- internal func removeValue(forKey key: Key) -> Value? {
+ internal mutating func removeValue(forKey key: Key) -> Value? {
_sanityCheckFailure("cannot mutate NS${Self}")
}
- internal func removeAll(keepingCapacity keepCapacity: Bool) {
+ internal mutating func removeAll(keepingCapacity keepCapacity: Bool) {
_sanityCheckFailure("cannot mutate NS${Self}")
}
@@ -4465,9 +4454,8 @@
//
// FIXME(performance): fuse data migration and element deletion into one
// operation.
- let cocoaIndex = index._cocoaIndex
- let anyObjectKey: AnyObject =
- cocoaBuffer.allKeys._value[cocoaIndex.currentKeyIndex]
+ let index = index._cocoaIndex
+ let anyObjectKey: AnyObject = index.allKeys[index.currentKeyIndex]
migrateDataToNativeBuffer(cocoaBuffer)
let key = _forceBridgeFromObjectiveC(anyObjectKey, Key.self)
let value = nativeRemoveObject(forKey: key)
@@ -4628,11 +4616,61 @@
#if _runtime(_ObjC)
@_versioned
internal struct _Cocoa${Self}Index : Comparable {
- /// Index into `allKeys` on the CocoaSelfBuffer
+ // Assumption: we rely on NSDictionary.getObjects when being
+ // repeatedly called on the same NSDictionary, returning items in the same
+ // order every time.
+ // Similarly, the same assumption holds for NSSet.allObjects.
+
+ /// A reference to the NS${Self}, which owns members in `allObjects`,
+ /// or `allKeys`, for NSSet and NSDictionary respectively.
+ internal let cocoa${Self}: _NS${Self}
+ // FIXME: swift-3-indexing-model: try to remove the cocoa reference, but make
+ // sure that we have a safety check for accessing `allKeys`. Maybe move both
+ // into the dictionary/set itself.
+
+ /// An unowned array of keys.
+ internal var allKeys: _HeapBuffer<Int, AnyObject>
+
+ /// Index into `allKeys`
internal var currentKeyIndex: Int
- internal init(value: Int) {
- currentKeyIndex = value
+ internal init(_ cocoa${Self}: _NS${Self}, startIndex: ()) {
+ self.cocoa${Self} = cocoa${Self}
+%if Self == 'Set':
+ self.allKeys = _stdlib_NSSet_allObjects(cocoaSet)
+%elif Self == 'Dictionary':
+ self.allKeys = _stdlib_NSDictionary_allKeys(cocoaDictionary)
+%end
+ self.currentKeyIndex = 0
+ }
+
+ internal init(_ cocoa${Self}: _NS${Self}, endIndex: ()) {
+ self.cocoa${Self} = cocoa${Self}
+%if Self == 'Set':
+ self.allKeys = _stdlib_NS${Self}_allObjects(cocoa${Self})
+%elif Self == 'Dictionary':
+ self.allKeys = _stdlib_NS${Self}_allKeys(cocoa${Self})
+%end
+ self.currentKeyIndex = allKeys.value
+ }
+
+ internal init(_ cocoa${Self}: _NS${Self},
+ _ allKeys: _HeapBuffer<Int, AnyObject>,
+ _ currentKeyIndex: Int
+ ) {
+ self.cocoa${Self} = cocoa${Self}
+ self.allKeys = allKeys
+ self.currentKeyIndex = currentKeyIndex
+ }
+
+ /// Returns the next consecutive value after `self`.
+ ///
+ /// - Precondition: The next value is representable.
+ internal func successor() -> _Cocoa${Self}Index {
+ // FIXME: swift-3-indexing-model: remove this method.
+ _precondition(
+ currentKeyIndex < allKeys.value, "cannot increment endIndex")
+ return _Cocoa${Self}Index(cocoa${Self}, allKeys, currentKeyIndex + 1)
}
}