diff --git a/stdlib/public/core/Dictionary.swift b/stdlib/public/core/Dictionary.swift index cc15df4bf11ba..600768baf4fef 100644 --- a/stdlib/public/core/Dictionary.swift +++ b/stdlib/public/core/Dictionary.swift @@ -1513,21 +1513,16 @@ extension Dictionary { @inlinable public mutating func swapAt(_ i: Index, _ j: Index) { guard i != j else { return } - let (a, b): (_HashTable.Bucket, _HashTable.Bucket) - switch _variant { - case .native(let native): - a = native.validatedBucket(for: i) - b = native.validatedBucket(for: j) #if _runtime(_ObjC) - case .cocoa(let cocoa): - _variant.cocoaPath() - let native = _NativeDictionary(cocoa) - a = native.validatedBucket(for: i) - b = native.validatedBucket(for: j) - _variant = .native(native) -#endif + let isNative: Bool + do { isNative = _variant.isNative } + if !isNative { + _variant = .native(_NativeDictionary(_variant.asCocoa)) } +#endif let isUnique = _variant.isUniquelyReferenced() + let a = _variant.asNative.validatedBucket(for: i) + let b = _variant.asNative.validatedBucket(for: j) _variant.asNative.swapValuesAt(a, b, isUnique: isUnique) } } @@ -1850,6 +1845,17 @@ extension Dictionary.Index { var handle = _asCocoa.handleBitPattern return handle == 0 || _isUnique_native(&handle) } + + @usableFromInline @_transparent + internal var _isNative: Bool { + switch _variant { + case .native: + return true + case .cocoa: + _cocoaPath() + return false + } + } #endif @usableFromInline @_transparent @@ -1935,19 +1941,19 @@ extension Dictionary.Index: Comparable { extension Dictionary.Index: Hashable { public // FIXME(cocoa-index): Make inlinable func hash(into hasher: inout Hasher) { - #if _runtime(_ObjC) - switch _variant { - case .native(let nativeIndex): - hasher.combine(0 as UInt8) - hasher.combine(nativeIndex.bucket.offset) - case .cocoa(let cocoaIndex): - _cocoaPath() +#if _runtime(_ObjC) + let isNative: Bool + do { isNative = _isNative } + guard isNative else { hasher.combine(1 as UInt8) - hasher.combine(cocoaIndex.storage.currentKeyIndex) + hasher.combine(_asCocoa.storage.currentKeyIndex) + return } - #else + hasher.combine(0 as UInt8) hasher.combine(_asNative.bucket.offset) - #endif +#else + hasher.combine(_asNative.bucket.offset) +#endif } } @@ -2011,6 +2017,17 @@ extension Dictionary.Iterator { _conditionallyUnreachable() } } + + @usableFromInline @_transparent + internal var _isNative: Bool { + switch _variant { + case .native: + return true + case .cocoa: + _cocoaPath() + return false + } + } #endif @usableFromInline @_transparent @@ -2029,6 +2046,21 @@ extension Dictionary.Iterator { self._variant = .native(newValue) } } + +#if _runtime(_ObjC) + @usableFromInline @_transparent + internal var _asCocoa: _CocoaDictionary.Iterator { + get { + switch _variant { + case .native: + _sanityCheckFailure("internal error: does not contain a Cocoa index") + case .cocoa(let cocoa): + return cocoa + } + } + } +#endif + } extension Dictionary.Iterator: IteratorProtocol { @@ -2039,20 +2071,19 @@ extension Dictionary.Iterator: IteratorProtocol { @inlinable @inline(__always) public mutating func next() -> (key: Key, value: Value)? { - switch _variant { - case .native: - return _asNative.next() #if _runtime(_ObjC) - case .cocoa(let cocoaIterator): - _cocoaPath() - if let (cocoaKey, cocoaValue) = cocoaIterator.next() { + let isNative: Bool + do { isNative = _isNative } + guard isNative else { + if let (cocoaKey, cocoaValue) = _asCocoa.next() { let nativeKey = _forceBridgeFromObjectiveC(cocoaKey, Key.self) let nativeValue = _forceBridgeFromObjectiveC(cocoaValue, Value.self) return (nativeKey, nativeValue) } return nil -#endif } +#endif + return _asNative.next() } } diff --git a/stdlib/public/core/DictionaryBridging.swift b/stdlib/public/core/DictionaryBridging.swift index a434aaf7db9c0..cf67d5887a18f 100644 --- a/stdlib/public/core/DictionaryBridging.swift +++ b/stdlib/public/core/DictionaryBridging.swift @@ -797,12 +797,10 @@ extension _CocoaDictionary.Iterator: IteratorProtocol { extension Dictionary { @inlinable public __consuming func _bridgeToObjectiveCImpl() -> _NSDictionaryCore { - switch _variant { - case .native(let nativeDictionary): - return nativeDictionary.bridged() - case .cocoa(let cocoaDictionary): - return cocoaDictionary.object + guard _variant.isNative else { + return _variant.asCocoa.object } + return _variant.asNative.bridged() } /// Returns the native Dictionary hidden inside this NSDictionary; diff --git a/stdlib/public/core/DictionaryCasting.swift b/stdlib/public/core/DictionaryCasting.swift index 50403ee41c7e9..38f83b940772f 100644 --- a/stdlib/public/core/DictionaryCasting.swift +++ b/stdlib/public/core/DictionaryCasting.swift @@ -56,14 +56,14 @@ public func _dictionaryDownCast( && _isClassOrObjCExistential(DerivedKey.self) && _isClassOrObjCExistential(DerivedValue.self) { - switch source._variant { - case .native(let native): - // Note: it is safe to treat the buffer as immutable here because - // Dictionary will not mutate buffer with reference count greater than 1. - return Dictionary(_immutableCocoaDictionary: native.bridged()) - case .cocoa(let cocoa): - return Dictionary(_immutableCocoaDictionary: cocoa.object) + guard source._variant.isNative else { + return Dictionary( + _immutableCocoaDictionary: source._variant.asCocoa.object) } + // Note: it is safe to treat the buffer as immutable here because + // Dictionary will not mutate buffer with reference count greater than 1. + return Dictionary( + _immutableCocoaDictionary: source._variant.asNative.bridged()) } #endif return _dictionaryDownCastConditional(source)! diff --git a/stdlib/public/core/DictionaryVariant.swift b/stdlib/public/core/DictionaryVariant.swift index ee5ea7d82123a..08338ac3141e6 100644 --- a/stdlib/public/core/DictionaryVariant.swift +++ b/stdlib/public/core/DictionaryVariant.swift @@ -56,24 +56,34 @@ extension Dictionary._Variant { _conditionallyUnreachable() } } -#endif - @inlinable - internal mutating func isUniquelyReferenced() -> Bool { + @usableFromInline @_transparent + internal var isNative: Bool { switch self { case .native: - // Note that &self drills down through .native(_NativeDictionary) to the - // first property in _NativeDictionary, which is the reference to the - // storage. - return _isUnique_native(&self) -#if _runtime(_ObjC) + return true case .cocoa: cocoaPath() - // Don't consider Cocoa buffer mutable, even if it is mutable and is - // uniquely referenced. return false + } + } #endif + + @inlinable + internal mutating func isUniquelyReferenced() -> Bool { +#if _runtime(_ObjC) + let isNative: Bool + do { isNative = self.isNative } + guard isNative else { + // Don't consider Cocoa a buffer mutable, even if it is mutable and it is + // uniquely referenced. + return false } +#endif + // Note that &self drills down through .native(_NativeDictionary) to the + // first property in _NativeDictionary, which is the reference to the + // storage. + return _isUnique_native(&self) } @inlinable @@ -110,17 +120,18 @@ extension Dictionary._Variant { /// Reserves enough space for the specified number of elements to be stored /// without reallocating additional storage. internal mutating func reserveCapacity(_ capacity: Int) { - switch self { - case .native: - let isUnique = isUniquelyReferenced() - asNative.reserveCapacity(capacity, isUnique: isUnique) #if _runtime(_ObjC) - case .cocoa(let cocoa): - cocoaPath() + let isNative: Bool + do { isNative = self.isNative } + guard isNative else { + let cocoa = asCocoa let capacity = Swift.max(cocoa.count, capacity) self = .native(_NativeDictionary(cocoa, capacity: capacity)) -#endif + return } +#endif + let isUnique = isUniquelyReferenced() + asNative.reserveCapacity(capacity, isUnique: isUnique) } /// The number of elements that can be stored without expanding the current @@ -132,15 +143,14 @@ extension Dictionary._Variant { /// at which adding any more elements will exceed the load factor. @inlinable internal var capacity: Int { - switch self { - case .native: - return asNative.capacity #if _runtime(_ObjC) - case .cocoa(let cocoa): - cocoaPath() - return cocoa.count -#endif + let isNative: Bool + do { isNative = self.isNative } + guard isNative else { + return asCocoa.count } +#endif + return asNative.capacity } } @@ -152,41 +162,38 @@ extension Dictionary._Variant: _DictionaryBuffer { @inlinable internal var startIndex: Index { - switch self { - case .native(let native): - return native.startIndex #if _runtime(_ObjC) - case .cocoa(let cocoa): - cocoaPath() - return Index(_cocoa: cocoa.startIndex) -#endif + let isNative: Bool + do { isNative = self.isNative } + guard isNative else { + return Index(_cocoa: asCocoa.startIndex) } +#endif + return asNative.startIndex } @inlinable internal var endIndex: Index { - switch self { - case .native(let native): - return native.endIndex #if _runtime(_ObjC) - case .cocoa(let cocoa): - cocoaPath() - return Index(_cocoa: cocoa.endIndex) -#endif + let isNative: Bool + do { isNative = self.isNative } + guard isNative else { + return Index(_cocoa: asCocoa.endIndex) } +#endif + return asNative.endIndex } @inlinable internal func index(after index: Index) -> Index { - switch self { - case .native(let native): - return native.index(after: index) #if _runtime(_ObjC) - case .cocoa(let cocoa): - cocoaPath() - return Index(_cocoa: cocoa.index(after: index._asCocoa)) -#endif + let isNative: Bool + do { isNative = self.isNative } + guard isNative else { + return Index(_cocoa: asCocoa.index(after: index._asCocoa)) } +#endif + return asNative.index(after: index) } @inlinable @@ -206,111 +213,104 @@ extension Dictionary._Variant: _DictionaryBuffer { @inlinable @inline(__always) internal func index(forKey key: Key) -> Index? { - switch self { - case .native(let native): - return native.index(forKey: key) #if _runtime(_ObjC) - case .cocoa(let cocoa): - cocoaPath() + let isNative: Bool + do { isNative = self.isNative } + guard isNative else { let cocoaKey = _bridgeAnythingToObjectiveC(key) - guard let index = cocoa.index(forKey: cocoaKey) else { return nil } + guard let index = asCocoa.index(forKey: cocoaKey) else { return nil } return Index(_cocoa: index) -#endif } +#endif + return asNative.index(forKey: key) } @inlinable internal var count: Int { @inline(__always) get { - switch self { - case .native(let native): - return native.count #if _runtime(_ObjC) - case .cocoa(let cocoa): - cocoaPath() - return cocoa.count -#endif + let isNative: Bool + do { isNative = self.isNative } + guard isNative else { + return asCocoa.count } +#endif + return asNative.count } } @inlinable @inline(__always) func contains(_ key: Key) -> Bool { - switch self { - case .native(let native): - return native.contains(key) #if _runtime(_ObjC) - case .cocoa(let cocoa): - cocoaPath() + let isNative: Bool + do { isNative = self.isNative } + guard isNative else { let cocoaKey = _bridgeAnythingToObjectiveC(key) - return cocoa.contains(cocoaKey) -#endif + return asCocoa.contains(cocoaKey) } +#endif + return asNative.contains(key) } @inlinable @inline(__always) func lookup(_ key: Key) -> Value? { - switch self { - case .native(let native): - return native.lookup(key) #if _runtime(_ObjC) - case .cocoa(let cocoa): - cocoaPath() + let isNative: Bool + do { isNative = self.isNative } + guard isNative else { let cocoaKey = _bridgeAnythingToObjectiveC(key) - guard let cocoaValue = cocoa.lookup(cocoaKey) else { return nil } + guard let cocoaValue = asCocoa.lookup(cocoaKey) else { return nil } return _forceBridgeFromObjectiveC(cocoaValue, Value.self) -#endif } +#endif + return asNative.lookup(key) } @inlinable @inline(__always) func lookup(_ index: Index) -> (key: Key, value: Value) { - switch self { - case .native(let native): - return native.lookup(index) #if _runtime(_ObjC) - case .cocoa(let cocoa): - cocoaPath() - let (cocoaKey, cocoaValue) = cocoa.lookup(index._asCocoa) + let isNative: Bool + do { isNative = self.isNative } + guard isNative else { + let (cocoaKey, cocoaValue) = asCocoa.lookup(index._asCocoa) let nativeKey = _forceBridgeFromObjectiveC(cocoaKey, Key.self) let nativeValue = _forceBridgeFromObjectiveC(cocoaValue, Value.self) return (nativeKey, nativeValue) -#endif } +#endif + return asNative.lookup(index) } @inlinable @inline(__always) func key(at index: Index) -> Key { - switch self { - case .native(let native): - return native.key(at: index) #if _runtime(_ObjC) - case .cocoa(let cocoa): - cocoaPath() - let cocoaKey = cocoa.key(at: index._asCocoa) + let isNative: Bool + do { isNative = self.isNative } + guard isNative else { + let cocoaKey = asCocoa.key(at: index._asCocoa) return _forceBridgeFromObjectiveC(cocoaKey, Key.self) -#endif } +#endif + return asNative.key(at: index) } @inlinable @inline(__always) func value(at index: Index) -> Value { - switch self { - case .native(let native): - return native.value(at: index) #if _runtime(_ObjC) - case .cocoa(let cocoa): - cocoaPath() - let cocoaValue = cocoa.value(at: index._asCocoa) + let isNative: Bool + do { isNative = self.isNative } + guard isNative else { + let cocoaValue = asCocoa.value(at: index._asCocoa) return _forceBridgeFromObjectiveC(cocoaValue, Value.self) -#endif } +#endif + return asNative.value(at: index) } } @@ -325,29 +325,31 @@ extension Dictionary._Variant { internal mutating func mutatingFind( _ key: Key ) -> (bucket: _NativeDictionary.Bucket, found: Bool) { - switch self { - case .native: - let isUnique = isUniquelyReferenced() - return asNative.mutatingFind(key, isUnique: isUnique) #if _runtime(_ObjC) - case .cocoa(let cocoa): - cocoaPath() + let isNative: Bool + do { isNative = self.isNative } + guard isNative else { + let cocoa = asCocoa var native = _NativeDictionary( cocoa, capacity: cocoa.count + 1) let result = native.mutatingFind(key, isUnique: true) self = .native(native) return result -#endif } +#endif + let isUnique = isUniquelyReferenced() + return asNative.mutatingFind(key, isUnique: isUnique) } @inlinable @inline(__always) internal mutating func ensureUniqueNative() -> _NativeDictionary { #if _runtime(_ObjC) - if case .cocoa(let cocoa) = self { + let isNative: Bool + do { isNative = self.isNative } + guard isNative else { cocoaPath() - let native = _NativeDictionary(cocoa) + let native = _NativeDictionary(asCocoa) self = .native(native) return native } @@ -364,41 +366,37 @@ extension Dictionary._Variant { _ value: __owned Value, forKey key: Key ) -> Value? { - switch self { - case .native: - let isUnique = self.isUniquelyReferenced() - return asNative.updateValue(value, forKey: key, isUnique: isUnique) #if _runtime(_ObjC) - case .cocoa(let cocoa): - cocoaPath() + let isNative: Bool + do { isNative = self.isNative } + guard isNative else { // Make sure we have space for an extra element. + let cocoa = asCocoa var native = _NativeDictionary( cocoa, capacity: cocoa.count + 1) let result = native.updateValue(value, forKey: key, isUnique: true) self = .native(native) return result -#endif } +#endif + let isUnique = self.isUniquelyReferenced() + return asNative.updateValue(value, forKey: key, isUnique: isUnique) } @inlinable internal mutating func setValue(_ value: __owned Value, forKey key: Key) { - switch self { - case .native: - let isUnique = self.isUniquelyReferenced() - asNative.setValue(value, forKey: key, isUnique: isUnique) #if _runtime(_ObjC) - case .cocoa(let cocoa): - cocoaPath() + if !isNative { // Make sure we have space for an extra element. - var native = _NativeDictionary( + let cocoa = asCocoa + self = .native(_NativeDictionary( cocoa, - capacity: cocoa.count + 1) - native.setValue(value, forKey: key, isUnique: true) - self = .native(native) -#endif + capacity: cocoa.count + 1)) } +#endif + let isUnique = self.isUniquelyReferenced() + asNative.setValue(value, forKey: key, isUnique: isUnique) } @inlinable @@ -412,16 +410,12 @@ extension Dictionary._Variant { @inlinable internal mutating func removeValue(forKey key: Key) -> Value? { - switch self { - case .native: - let (bucket, found) = asNative.find(key) - guard found else { return nil } - let isUnique = isUniquelyReferenced() - return asNative.uncheckedRemove(at: bucket, isUnique: isUnique).value #if _runtime(_ObjC) - case .cocoa(let cocoa): - cocoaPath() + let isNative: Bool + do { isNative = self.isNative } + guard isNative else { let cocoaKey = _bridgeAnythingToObjectiveC(key) + let cocoa = asCocoa guard cocoa.lookup(cocoaKey) != nil else { return nil } var native = _NativeDictionary(cocoa) let (bucket, found) = native.find(key) @@ -429,8 +423,12 @@ extension Dictionary._Variant { let old = native.uncheckedRemove(at: bucket, isUnique: true).value self = .native(native) return old -#endif } +#endif + let (bucket, found) = asNative.find(key) + guard found else { return nil } + let isUnique = isUniquelyReferenced() + return asNative.uncheckedRemove(at: bucket, isUnique: isUnique).value } @inlinable @@ -441,16 +439,16 @@ extension Dictionary._Variant { } guard count > 0 else { return } - switch self { - case .native: - let isUnique = isUniquelyReferenced() - asNative.removeAll(isUnique: isUnique) #if _runtime(_ObjC) - case .cocoa(let cocoa): - cocoaPath() - self = .native(_NativeDictionary(capacity: cocoa.count)) -#endif + let isNative: Bool + do { isNative = self.isNative } + guard isNative else { + self = .native(_NativeDictionary(capacity: asCocoa.count)) + return } +#endif + let isUnique = isUniquelyReferenced() + asNative.removeAll(isUnique: isUnique) } } @@ -461,15 +459,14 @@ extension Dictionary._Variant { @inlinable @inline(__always) __consuming internal func makeIterator() -> Dictionary.Iterator { - switch self { - case .native(let native): - return Dictionary.Iterator(_native: native.makeIterator()) #if _runtime(_ObjC) - case .cocoa(let cocoa): - cocoaPath() - return Dictionary.Iterator(_cocoa: cocoa.makeIterator()) -#endif + let isNative: Bool + do { isNative = self.isNative } + guard isNative else { + return Dictionary.Iterator(_cocoa: asCocoa.makeIterator()) } +#endif + return Dictionary.Iterator(_native: asNative.makeIterator()) } } @@ -478,15 +475,14 @@ extension Dictionary._Variant { internal func mapValues( _ transform: (Value) throws -> T ) rethrows -> _NativeDictionary { - switch self { - case .native(let native): - return try native.mapValues(transform) #if _runtime(_ObjC) - case .cocoa(let cocoa): - cocoaPath() - return try cocoa.mapValues(transform) -#endif + let isNative: Bool + do { isNative = self.isNative } + guard isNative else { + return try asCocoa.mapValues(transform) } +#endif + return try asNative.mapValues(transform) } @inlinable @@ -494,24 +490,24 @@ extension Dictionary._Variant { _ keysAndValues: __owned S, uniquingKeysWith combine: (Value, Value) throws -> Value ) rethrows where S.Element == (Key, Value) { - switch self { - case .native: - let isUnique = isUniquelyReferenced() - try asNative.merge( - keysAndValues, - isUnique: isUnique, - uniquingKeysWith: combine) #if _runtime(_ObjC) - case .cocoa(let cocoa): - cocoaPath() - var native = _NativeDictionary(cocoa) + let isNative: Bool + do { isNative = self.isNative } + guard isNative else { + var native = _NativeDictionary(asCocoa) try native.merge( keysAndValues, isUnique: true, uniquingKeysWith: combine) self = .native(native) -#endif + return } +#endif + let isUnique = isUniquelyReferenced() + try asNative.merge( + keysAndValues, + isUnique: isUnique, + uniquingKeysWith: combine) } } diff --git a/stdlib/public/core/NativeDictionary.swift b/stdlib/public/core/NativeDictionary.swift index 5dd30798392ee..1119c4db0994f 100644 --- a/stdlib/public/core/NativeDictionary.swift +++ b/stdlib/public/core/NativeDictionary.swift @@ -275,15 +275,13 @@ extension _NativeDictionary { @inlinable @inline(__always) func validatedBucket(for index: Dictionary.Index) -> Bucket { - switch index._variant { - case .native(let native): - return validatedBucket(for: native) #if _runtime(_ObjC) - case .cocoa(let cocoa): + guard index._isNative else { index._cocoaPath() // Accept Cocoa indices as long as they contain a key that exists in this // dictionary, and the address of their Cocoa object generates the same // age. + let cocoa = index._asCocoa if cocoa.age == self.age { let key = _forceBridgeFromObjectiveC(cocoa.key, Key.self) let (bucket, found) = find(key) @@ -293,8 +291,9 @@ extension _NativeDictionary { } _preconditionFailure( "Attempting to access Dictionary elements using an invalid index") -#endif } +#endif + return validatedBucket(for: index._asNative) } } diff --git a/stdlib/public/core/NativeSet.swift b/stdlib/public/core/NativeSet.swift index 38aa7b19b19e6..6b261216637ea 100644 --- a/stdlib/public/core/NativeSet.swift +++ b/stdlib/public/core/NativeSet.swift @@ -241,12 +241,10 @@ extension _NativeSet { @inlinable @inline(__always) func validatedBucket(for index: Set.Index) -> Bucket { - switch index._variant { - case .native(let native): - return validatedBucket(for: native) #if _runtime(_ObjC) - case .cocoa(let cocoa): + guard index._isNative else { index._cocoaPath() + let cocoa = index._asCocoa // Accept Cocoa indices as long as they contain an element that exists in // this set, and the address of their Cocoa object generates the same age. if cocoa.age == self.age { @@ -258,8 +256,9 @@ extension _NativeSet { } _preconditionFailure( "Attempting to access Set elements using an invalid index") -#endif } +#endif + return validatedBucket(for: index._asNative) } } diff --git a/stdlib/public/core/Set.swift b/stdlib/public/core/Set.swift index 2dadaabf386a7..dba65a482cd7f 100644 --- a/stdlib/public/core/Set.swift +++ b/stdlib/public/core/Set.swift @@ -1358,6 +1358,19 @@ extension Set.Index { } #endif +#if _runtime(_ObjC) + @usableFromInline @_transparent + internal var _isNative: Bool { + switch _variant { + case .native: + return true + case .cocoa: + _cocoaPath() + return false + } + } +#endif + @usableFromInline @_transparent internal var _asNative: _HashTable.Index { switch _variant { @@ -1446,19 +1459,17 @@ extension Set.Index: Hashable { /// of this instance. public // FIXME(cocoa-index): Make inlinable func hash(into hasher: inout Hasher) { - #if _runtime(_ObjC) - switch _variant { - case .native(let nativeIndex): - hasher.combine(0 as UInt8) - hasher.combine(nativeIndex.bucket.offset) - case .cocoa(let cocoaIndex): - _cocoaPath() +#if _runtime(_ObjC) + guard _isNative else { hasher.combine(1 as UInt8) - hasher.combine(cocoaIndex.storage.currentKeyIndex) + hasher.combine(_asCocoa.storage.currentKeyIndex) + return } - #else + hasher.combine(0 as UInt8) hasher.combine(_asNative.bucket.offset) - #endif +#else + hasher.combine(_asNative.bucket.offset) +#endif } } @@ -1523,6 +1534,19 @@ extension Set.Iterator { } #endif +#if _runtime(_ObjC) + @usableFromInline @_transparent + internal var _isNative: Bool { + switch _variant { + case .native: + return true + case .cocoa: + _cocoaPath() + return false + } + } +#endif + @usableFromInline @_transparent internal var _asNative: _NativeSet.Iterator { get { @@ -1539,6 +1563,20 @@ extension Set.Iterator { self._variant = .native(newValue) } } + +#if _runtime(_ObjC) + @usableFromInline @_transparent + internal var _asCocoa: _CocoaSet.Iterator { + get { + switch _variant { + case .native: + _sanityCheckFailure("internal error: does not contain a Cocoa index") + case .cocoa(let cocoa): + return cocoa + } + } + } +#endif } extension Set.Iterator: IteratorProtocol { @@ -1550,19 +1588,12 @@ extension Set.Iterator: IteratorProtocol { @inline(__always) public mutating func next() -> Element? { #if _runtime(_ObjC) - switch _variant { - case .native: - return _asNative.next() - case .cocoa(let cocoaIterator): - _cocoaPath() - if let cocoaElement = cocoaIterator.next() { - return _forceBridgeFromObjectiveC(cocoaElement, Element.self) - } - return nil + guard _isNative else { + guard let cocoaElement = _asCocoa.next() else { return nil } + return _forceBridgeFromObjectiveC(cocoaElement, Element.self) } -#else - return _asNative.next() #endif + return _asNative.next() } } diff --git a/stdlib/public/core/SetBridging.swift b/stdlib/public/core/SetBridging.swift index 06cdef01d569b..d793b971abdba 100644 --- a/stdlib/public/core/SetBridging.swift +++ b/stdlib/public/core/SetBridging.swift @@ -619,12 +619,10 @@ extension _CocoaSet.Iterator: IteratorProtocol { extension Set { @inlinable public __consuming func _bridgeToObjectiveCImpl() -> _NSSetCore { - switch _variant { - case .native(let nativeSet): - return nativeSet.bridged() - case .cocoa(let cocoaSet): - return cocoaSet.object + guard _variant.isNative else { + return _variant.asCocoa.object } + return _variant.asNative.bridged() } /// Returns the native Dictionary hidden inside this NSDictionary; diff --git a/stdlib/public/core/SetCasting.swift b/stdlib/public/core/SetCasting.swift index 787c51a420717..6562738c228b0 100644 --- a/stdlib/public/core/SetCasting.swift +++ b/stdlib/public/core/SetCasting.swift @@ -48,12 +48,10 @@ public func _setDownCast(_ source: Set) #if _runtime(_ObjC) if _isClassOrObjCExistential(BaseValue.self) && _isClassOrObjCExistential(DerivedValue.self) { - switch source._variant { - case .native(let nativeSet): - return Set(_immutableCocoaSet: nativeSet.bridged()) - case .cocoa(let cocoaSet): - return Set(_immutableCocoaSet: cocoaSet.object) + guard source._variant.isNative else { + return Set(_immutableCocoaSet: source._variant.asCocoa.object) } + return Set(_immutableCocoaSet: source._variant.asNative.bridged()) } #endif return _setDownCastConditional(source)! diff --git a/stdlib/public/core/SetVariant.swift b/stdlib/public/core/SetVariant.swift index 33ce0d85cd88b..2ee712554c9f7 100644 --- a/stdlib/public/core/SetVariant.swift +++ b/stdlib/public/core/SetVariant.swift @@ -58,20 +58,30 @@ extension Set._Variant { @inlinable internal mutating func isUniquelyReferenced() -> Bool { +#if _runtime(_ObjC) + guard isNative else { + // Don't consider Cocoa buffer mutable, even if it is mutable and is + // uniquely referenced. + return false + } +#endif // Note that &self drills down through .native(_NativeSet) to the first // property in _NativeSet, which is the reference to the storage. + return _isUnique_native(&self) + } + +#if _runtime(_ObjC) + @usableFromInline @_transparent + internal var isNative: Bool { switch self { case .native: - return _isUnique_native(&self) -#if _runtime(_ObjC) + return true case .cocoa: cocoaPath() - // Don't consider Cocoa buffer mutable, even if it is mutable and is - // uniquely referenced. return false -#endif } } +#endif @usableFromInline @_transparent internal var asNative: _NativeSet { @@ -105,17 +115,16 @@ extension Set._Variant { /// Reserves enough space for the specified number of elements to be stored /// without reallocating additional storage. internal mutating func reserveCapacity(_ capacity: Int) { - switch self { - case .native: - let isUnique = isUniquelyReferenced() - asNative.reserveCapacity(capacity, isUnique: isUnique) #if _runtime(_ObjC) - case .cocoa(let cocoa): - cocoaPath() + guard isNative else { + let cocoa = asCocoa let capacity = Swift.max(cocoa.count, capacity) self = .native(_NativeSet(cocoa, capacity: capacity)) -#endif + return } +#endif + let isUnique = isUniquelyReferenced() + asNative.reserveCapacity(capacity, isUnique: isUnique) } /// The number of elements that can be stored without expanding the current @@ -127,15 +136,12 @@ extension Set._Variant { /// at which adding any more elements will exceed the load factor. @inlinable internal var capacity: Int { - switch self { - case .native: - return asNative.capacity #if _runtime(_ObjC) - case .cocoa(let cocoa): - cocoaPath() - return cocoa.count -#endif + guard isNative else { + return asCocoa.count } +#endif + return asNative.capacity } } @@ -145,41 +151,32 @@ extension Set._Variant: _SetBuffer { @inlinable internal var startIndex: Index { - switch self { - case .native(let native): - return native.startIndex #if _runtime(_ObjC) - case .cocoa(let cocoaSet): - cocoaPath() - return Index(_cocoa: cocoaSet.startIndex) -#endif + guard isNative else { + return Index(_cocoa: asCocoa.startIndex) } +#endif + return asNative.startIndex } @inlinable internal var endIndex: Index { - switch self { - case .native(let native): - return native.endIndex #if _runtime(_ObjC) - case .cocoa(let cocoaSet): - cocoaPath() - return Index(_cocoa: cocoaSet.endIndex) -#endif + guard isNative else { + return Index(_cocoa: asCocoa.endIndex) } +#endif + return asNative.endIndex } @inlinable internal func index(after index: Index) -> Index { - switch self { - case .native(let native): - return native.index(after: index) #if _runtime(_ObjC) - case .cocoa(let cocoaSet): - cocoaPath() - return Index(_cocoa: cocoaSet.index(after: index._asCocoa)) -#endif + guard isNative else { + return Index(_cocoa: asCocoa.index(after: index._asCocoa)) } +#endif + return asNative.index(after: index) } @inlinable @@ -199,102 +196,78 @@ extension Set._Variant: _SetBuffer { @inlinable @inline(__always) internal func index(for element: Element) -> Index? { - switch self { - case .native(let native): - return native.index(for: element) #if _runtime(_ObjC) - case .cocoa(let cocoa): - cocoaPath() + guard isNative else { let cocoaElement = _bridgeAnythingToObjectiveC(element) - guard let index = cocoa.index(for: cocoaElement) else { return nil } + guard let index = asCocoa.index(for: cocoaElement) else { return nil } return Index(_cocoa: index) -#endif } +#endif + return asNative.index(for: element) } @inlinable internal var count: Int { @inline(__always) get { - switch self { - case .native(let native): - return native.count #if _runtime(_ObjC) - case .cocoa(let cocoa): - cocoaPath() - return cocoa.count -#endif + guard isNative else { + return asCocoa.count } +#endif + return asNative.count } } @inlinable @inline(__always) internal func contains(_ member: Element) -> Bool { - switch self { - case .native(let native): - return native.contains(member) #if _runtime(_ObjC) - case .cocoa(let cocoa): - cocoaPath() - return cocoa.contains(_bridgeAnythingToObjectiveC(member)) -#endif + guard isNative else { + return asCocoa.contains(_bridgeAnythingToObjectiveC(member)) } +#endif + return asNative.contains(member) } @inlinable @inline(__always) internal func element(at index: Index) -> Element { - switch self { - case .native(let native): - return native.element(at: index) #if _runtime(_ObjC) - case .cocoa(let cocoa): - cocoaPath() - let cocoaMember = cocoa.element(at: index._asCocoa) + guard isNative else { + let cocoaMember = asCocoa.element(at: index._asCocoa) return _forceBridgeFromObjectiveC(cocoaMember, Element.self) -#endif } +#endif + return asNative.element(at: index) } } extension Set._Variant { @inlinable internal mutating func update(with value: __owned Element) -> Element? { - switch self { - case .native: - let isUnique = self.isUniquelyReferenced() - return asNative.update(with: value, isUnique: isUnique) #if _runtime(_ObjC) - case .cocoa(let cocoa): - cocoaPath() + guard isNative else { // Make sure we have space for an extra element. - var native = _NativeSet(cocoa, capacity: cocoa.count + 1) + var native = _NativeSet(asCocoa, capacity: asCocoa.count + 1) let old = native.update(with: value, isUnique: true) self = .native(native) return old -#endif } +#endif + let isUnique = self.isUniquelyReferenced() + return asNative.update(with: value, isUnique: isUnique) } @inlinable internal mutating func insert( _ element: __owned Element ) -> (inserted: Bool, memberAfterInsert: Element) { - switch self { - case .native: - let (bucket, found) = asNative.find(element) - if found { - return (false, asNative.uncheckedElement(at: bucket)) - } - let isUnique = self.isUniquelyReferenced() - asNative.insertNew(element, at: bucket, isUnique: isUnique) - return (true, element) #if _runtime(_ObjC) - case .cocoa(let cocoa): - cocoaPath() + guard isNative else { // Make sure we have space for an extra element. let cocoaMember = _bridgeAnythingToObjectiveC(element) + let cocoa = asCocoa if let m = cocoa.member(for: cocoaMember) { return (false, _forceBridgeFromObjectiveC(m, Element.self)) } @@ -302,47 +275,50 @@ extension Set._Variant { native.insertNew(element, isUnique: true) self = .native(native) return (true, element) + } #endif + let (bucket, found) = asNative.find(element) + if found { + return (false, asNative.uncheckedElement(at: bucket)) } + let isUnique = self.isUniquelyReferenced() + asNative.insertNew(element, at: bucket, isUnique: isUnique) + return (true, element) } @inlinable @discardableResult internal mutating func remove(at index: Index) -> Element { - switch self { - case .native: - let isUnique = isUniquelyReferenced() - let bucket = asNative.validatedBucket(for: index) - return asNative.uncheckedRemove(at: bucket, isUnique: isUnique) #if _runtime(_ObjC) - case .cocoa(let cocoa): - cocoaPath() + guard isNative else { // We have to migrate the data first. But after we do so, the Cocoa // index becomes useless, so get the element first. + let cocoa = asCocoa let cocoaMember = cocoa.member(for: index._asCocoa) let nativeMember = _forceBridgeFromObjectiveC(cocoaMember, Element.self) return _migrateToNative(cocoa, removing: nativeMember) -#endif } +#endif + let isUnique = isUniquelyReferenced() + let bucket = asNative.validatedBucket(for: index) + return asNative.uncheckedRemove(at: bucket, isUnique: isUnique) } @inlinable @discardableResult internal mutating func remove(_ member: Element) -> Element? { - switch self { - case .native: - let (bucket, found) = asNative.find(member) - guard found else { return nil } - let isUnique = isUniquelyReferenced() - return asNative.uncheckedRemove(at: bucket, isUnique: isUnique) #if _runtime(_ObjC) - case .cocoa(let cocoa): - cocoaPath() + guard isNative else { + let cocoa = asCocoa let cocoaMember = _bridgeAnythingToObjectiveC(member) guard cocoa.contains(cocoaMember) else { return nil } return _migrateToNative(cocoa, removing: member) -#endif } +#endif + let (bucket, found) = asNative.find(member) + guard found else { return nil } + let isUnique = isUniquelyReferenced() + return asNative.uncheckedRemove(at: bucket, isUnique: isUnique) } #if _runtime(_ObjC) @@ -371,16 +347,14 @@ extension Set._Variant { } guard count > 0 else { return } - switch self { - case .native: - let isUnique = isUniquelyReferenced() - asNative.removeAll(isUnique: isUnique) #if _runtime(_ObjC) - case .cocoa(let cocoa): - cocoaPath() - self = .native(_NativeSet(capacity: cocoa.count)) -#endif + guard isNative else { + self = .native(_NativeSet(capacity: asCocoa.count)) + return } +#endif + let isUnique = isUniquelyReferenced() + asNative.removeAll(isUnique: isUnique) } } @@ -391,15 +365,12 @@ extension Set._Variant { @inlinable @inline(__always) internal __consuming func makeIterator() -> Set.Iterator { - switch self { - case .native(let native): - return Set.Iterator(_native: native.makeIterator()) #if _runtime(_ObjC) - case .cocoa(let cocoa): - cocoaPath() - return Set.Iterator(_cocoa: cocoa.makeIterator()) -#endif + guard isNative else { + return Set.Iterator(_cocoa: asCocoa.makeIterator()) } +#endif + return Set.Iterator(_native: asNative.makeIterator()) } }