diff --git a/stdlib/public/core/Bitset.swift b/stdlib/public/core/Bitset.swift index 3a0d97106c7a1..69045d88f4099 100644 --- a/stdlib/public/core/Bitset.swift +++ b/stdlib/public/core/Bitset.swift @@ -64,7 +64,7 @@ extension _UnsafeBitset { @inline(__always) internal static func join(word: Int, bit: Int) -> Int { _sanityCheck(bit >= 0 && bit < Word.capacity) - return word &* Word.capacity + bit + return word &* Word.capacity &+ bit } } @@ -72,7 +72,7 @@ extension _UnsafeBitset { @inlinable @inline(__always) internal static func wordCount(forCapacity capacity: Int) -> Int { - return word(for: capacity + Word.capacity - 1) + return word(for: capacity &+ Word.capacity &- 1) } @inlinable diff --git a/stdlib/public/core/BridgeStorage.swift b/stdlib/public/core/BridgeStorage.swift index df6bc83ef5358..b01d9d7434a60 100644 --- a/stdlib/public/core/BridgeStorage.swift +++ b/stdlib/public/core/BridgeStorage.swift @@ -60,7 +60,15 @@ struct _BridgeStorage< _sanityCheck(_usesNativeSwiftReferenceCounting(NativeClass.self)) rawValue = Builtin.reinterpretCast(native) } - + +#if !(arch(i386) || arch(arm)) + @inlinable + @inline(__always) + internal init(taggedPayload: UInt) { + rawValue = _bridgeObject(taggingPayload: taggedPayload) + } +#endif + @inlinable // FIXME(sil-serialize-all) public // @testable var spareBits: Int { diff --git a/stdlib/public/core/Dictionary.swift b/stdlib/public/core/Dictionary.swift index 843b616de7b4d..57c436c1bcdc2 100644 --- a/stdlib/public/core/Dictionary.swift +++ b/stdlib/public/core/Dictionary.swift @@ -396,13 +396,13 @@ public struct Dictionary { @inlinable internal init(_native: __owned _NativeDictionary) { - _variant = .native(_native) + _variant = _Variant(native: _native) } #if _runtime(_ObjC) @inlinable internal init(_cocoa: __owned _CocoaDictionary) { - _variant = .cocoa(_cocoa) + _variant = _Variant(cocoa: _cocoa) } /// Private initializer used for bridging. @@ -444,7 +444,7 @@ public struct Dictionary { /// reallocating its storage buffer. public // FIXME(reserveCapacity): Should be inlinable init(minimumCapacity: Int) { - _variant = .native(_NativeDictionary(capacity: minimumCapacity)) + _variant = _Variant(native: _NativeDictionary(capacity: minimumCapacity)) } /// Creates a new dictionary from the key-value pairs in the given sequence. @@ -1316,8 +1316,12 @@ extension Dictionary { return Values(_dictionary: self) } _modify { - var values = Values(_dictionary: self) - _variant = .native(_NativeDictionary()) + var values: Values + do { + var temp = _Variant(dummy: ()) + swap(&temp, &_variant) + values = Values(_variant: temp) + } yield &values self._variant = values._variant } @@ -1404,10 +1408,26 @@ extension Dictionary { @inlinable public static func ==(lhs: Keys, rhs: Keys) -> Bool { // Equal if the two dictionaries share storage. - if case (.native(let ln), .native(let rn)) = (lhs._variant, rhs._variant), - ln._storage === rn._storage { +#if _runtime(_ObjC) + if + lhs._variant.isNative, + rhs._variant.isNative, + lhs._variant.asNative._storage === rhs._variant.asNative._storage + { + return true + } + if + !lhs._variant.isNative, + !rhs._variant.isNative, + lhs._variant.asCocoa.object === rhs._variant.asCocoa.object + { + return true + } +#else + if lhs._variant.asNative._storage === rhs._variant.asNative._storage { return true } +#endif // Not equal if the dictionaries are different sizes. if lhs.count != rhs.count { @@ -1517,21 +1537,15 @@ 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 + if !_variant.isNative { + _variant = .init(native: _NativeDictionary(_variant.asCocoa)) } +#endif let isUnique = _variant.isUniquelyReferenced() + let native = _variant.asNative + let a = native.validatedBucket(for: i) + let b = native.validatedBucket(for: j) _variant.asNative.swapValuesAt(a, b, isUnique: isUnique) } } @@ -1606,51 +1620,20 @@ extension Dictionary.Values { extension Dictionary: Equatable where Value: Equatable { @inlinable public static func == (lhs: [Key: Value], rhs: [Key: Value]) -> Bool { - switch (lhs._variant, rhs._variant) { - case (.native(let lhsNative), .native(let rhsNative)): - - if lhsNative._storage === rhsNative._storage { - return true - } - - if lhsNative.count != rhsNative.count { - return false - } - - for (k, v) in lhs { - let (bucket, found) = rhsNative.find(k) - guard found, rhsNative.uncheckedValue(at: bucket) == v else { - return false - } - } - return true - - #if _runtime(_ObjC) - case (.cocoa(let lhsCocoa), .cocoa(let rhsCocoa)): - return lhsCocoa == rhsCocoa - - case (.native(let lhsNative), .cocoa(let rhsCocoa)): - if lhsNative.count != rhsCocoa.count { - return false - } - - defer { _fixLifetime(lhsNative) } - for bucket in lhsNative.hashTable { - let key = lhsNative.uncheckedKey(at: bucket) - let value = lhsNative.uncheckedValue(at: bucket) - guard - let rhsValue = rhsCocoa.lookup(_bridgeAnythingToObjectiveC(key)), - value == _forceBridgeFromObjectiveC(rhsValue, Value.self) - else { - return false - } - } - return true - - case (.cocoa, .native): - return rhs == lhs - #endif - } +#if _runtime(_ObjC) + switch (lhs._variant.isNative, rhs._variant.isNative) { + case (true, true): + return lhs._variant.asNative.isEqual(to: rhs._variant.asNative) + case (false, false): + return lhs._variant.asCocoa.isEqual(to: rhs._variant.asCocoa) + case (true, false): + return lhs._variant.asNative.isEqual(to: rhs._variant.asCocoa) + case (false, true): + return rhs._variant.asNative.isEqual(to: lhs._variant.asCocoa) + } +#else + return lhs._variant.asNative.isEqual(to: rhs._variant.asNative) +#endif } } @@ -1860,20 +1843,18 @@ extension Dictionary.Index { var handle = _asCocoa.handleBitPattern return handle == 0 || _isUnique_native(&handle) } -#endif @usableFromInline @_transparent internal var _isNative: Bool { switch _variant { case .native: return true -#if _runtime(_ObjC) case .cocoa: _cocoaPath() return false -#endif } } +#endif @usableFromInline @_transparent internal var _asNative: _HashTable.Index { @@ -1958,19 +1939,17 @@ 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) + 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 } } @@ -2034,6 +2013,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 @@ -2052,6 +2042,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 { @@ -2062,20 +2067,17 @@ 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() { + 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 1edaa80d46e48..1808ef97f8de6 100644 --- a/stdlib/public/core/DictionaryBridging.swift +++ b/stdlib/public/core/DictionaryBridging.swift @@ -434,13 +434,10 @@ internal struct _CocoaDictionary { } } -extension _CocoaDictionary: Equatable { +extension _CocoaDictionary { @usableFromInline - internal static func ==( - lhs: _CocoaDictionary, - rhs: _CocoaDictionary - ) -> Bool { - return _stdlib_NSObject_isEqual(lhs.object, rhs.object) + internal func isEqual(to other: _CocoaDictionary) -> Bool { + return _stdlib_NSObject_isEqual(self.object, other.object) } } @@ -805,12 +802,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/DictionaryBuilder.swift b/stdlib/public/core/DictionaryBuilder.swift index a6b1c65d46a9b..68ec578c66110 100644 --- a/stdlib/public/core/DictionaryBuilder.swift +++ b/stdlib/public/core/DictionaryBuilder.swift @@ -30,7 +30,9 @@ struct _DictionaryBuilder { @inlinable public mutating func add(key newKey: Key, value: Value) { - _target.insertNew(key: newKey, value: value) + _precondition(_target.count < _requestedCount, + "Can't add more members than promised") + _target._unsafeInsertNew(key: newKey, value: value) } @inlinable 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..4e218e8cd59fd 100644 --- a/stdlib/public/core/DictionaryVariant.swift +++ b/stdlib/public/core/DictionaryVariant.swift @@ -32,11 +32,38 @@ internal protocol _DictionaryBuffer { extension Dictionary { @usableFromInline - @_frozen - internal enum _Variant { - case native(_NativeDictionary) + @_fixed_layout + internal struct _Variant { #if _runtime(_ObjC) - case cocoa(_CocoaDictionary) + @usableFromInline + internal var object: _BridgeStorage<_RawDictionaryStorage, _NSDictionary> +#else + @usableFromInline + internal var object: _BridgeStorage<_RawDictionaryStorage, AnyObject> +#endif + + @inlinable + @inline(__always) + init(native: __owned _NativeDictionary) { + self.object = _BridgeStorage(native: native._storage) + } + + @inlinable + @inline(__always) + init(dummy: Void) { +#if arch(i386) || arch(arm) + self.init(native: _NativeDictionary()) +#else + self.object = _BridgeStorage(taggedPayload: 0) +#endif + } + +#if _runtime(_ObjC) + @inlinable + @inline(__always) + init(cocoa: __owned _CocoaDictionary) { + self.object = _BridgeStorage(objC: cocoa.object) + } #endif } } @@ -47,80 +74,58 @@ extension Dictionary._Variant { internal var guaranteedNative: Bool { return _canBeClass(Key.self) == 0 || _canBeClass(Value.self) == 0 } - - // Allow the optimizer to consider the surrounding code unreachable if Element - // is guaranteed to be native. - @usableFromInline @_transparent - internal func cocoaPath() { - if guaranteedNative { - _conditionallyUnreachable() - } - } #endif @inlinable internal mutating func isUniquelyReferenced() -> 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) + return object.isUniquelyReferenced_native_noSpareBits() + } + #if _runtime(_ObjC) - case .cocoa: - cocoaPath() - // Don't consider Cocoa buffer mutable, even if it is mutable and is - // uniquely referenced. - return false -#endif - } + @usableFromInline @_transparent + internal var isNative: Bool { + if guaranteedNative { return true } + return object.isNativeWithClearedSpareBits(0) } +#endif - @inlinable + @usableFromInline @_transparent internal var asNative: _NativeDictionary { - @inline(__always) get { - switch self { - case .native(let native): - return native -#if _runtime(_ObjC) - case .cocoa: - _sanityCheckFailure("internal error: not backed by native buffer") -#endif - } + return _NativeDictionary(object.nativeInstance_noSpareBits) } - @inline(__always) set { - self = .native(newValue) + self = .init(native: newValue) + } + _modify { + var native = _NativeDictionary( + object.nativeInstance_noSpareBits) + self = .init(dummy: ()) + yield &native + object = .init(native: native._storage) } } #if _runtime(_ObjC) @inlinable internal var asCocoa: _CocoaDictionary { - switch self { - case .native: - _sanityCheckFailure("internal error: not backed by NSDictionary") - case .cocoa(let cocoa): - return cocoa - } + return _CocoaDictionary(object.objCInstance) } #endif /// 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(_NativeDictionary(cocoa, capacity: capacity)) -#endif + self = .init(native: _NativeDictionary(cocoa, capacity: capacity)) + return } +#endif + let isUnique = isUniquelyReferenced() + asNative.reserveCapacity(capacity, isUnique: isUnique) } /// The number of elements that can be stored without expanding the current @@ -132,15 +137,12 @@ 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 + guard isNative else { + return asCocoa.count } +#endif + return asNative.capacity } } @@ -152,165 +154,133 @@ 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 + 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 + 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 + guard isNative else { + return Index(_cocoa: asCocoa.index(after: index._asCocoa)) } +#endif + return asNative.index(after: index) } @inlinable internal func formIndex(after index: inout Index) { - switch self { - case .native(let native): - index = native.index(after: index) #if _runtime(_ObjC) - case .cocoa(let cocoa): - cocoaPath() + guard isNative else { let isUnique = index._isUniquelyReferenced() - cocoa.formIndex(after: &index._asCocoa, isUnique: isUnique) -#endif + asCocoa.formIndex(after: &index._asCocoa, isUnique: isUnique) + return } +#endif + index = asNative.index(after: index) } @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() + 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 + 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() + 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() + 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) + 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) + 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) + guard isNative else { + let cocoaValue = asCocoa.value(at: index._asCocoa) return _forceBridgeFromObjectiveC(cocoaValue, Value.self) -#endif } +#endif + return asNative.value(at: index) } } @@ -325,30 +295,27 @@ 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() + guard isNative else { + let cocoa = asCocoa var native = _NativeDictionary( cocoa, capacity: cocoa.count + 1) let result = native.mutatingFind(key, isUnique: true) - self = .native(native) + self = .init(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 { - cocoaPath() - let native = _NativeDictionary(cocoa) - self = .native(native) + guard isNative else { + let native = _NativeDictionary(asCocoa) + self = .init(native: native) return native } #endif @@ -364,41 +331,35 @@ 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() + 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) + self = .init(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 = .init(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,45 +373,41 @@ 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() + 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) _precondition(found, "Bridging did not preserve equality") let old = native.uncheckedRemove(at: bucket, isUnique: true).value - self = .native(native) + self = .init(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 internal mutating func removeAll(keepingCapacity keepCapacity: Bool) { if !keepCapacity { - self = .native(_NativeDictionary()) + self = .init(native: _NativeDictionary()) return } 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 + guard isNative else { + self = .init(native: _NativeDictionary(capacity: asCocoa.count)) + return } +#endif + let isUnique = isUniquelyReferenced() + asNative.removeAll(isUnique: isUnique) } } @@ -461,15 +418,12 @@ 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 + guard isNative else { + return Dictionary.Iterator(_cocoa: asCocoa.makeIterator()) } +#endif + return Dictionary.Iterator(_native: asNative.makeIterator()) } } @@ -478,15 +432,12 @@ 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 + guard isNative else { + return try asCocoa.mapValues(transform) } +#endif + return try asNative.mapValues(transform) } @inlinable @@ -494,24 +445,22 @@ 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) + guard isNative else { + var native = _NativeDictionary(asCocoa) try native.merge( keysAndValues, isUnique: true, uniquingKeysWith: combine) - self = .native(native) -#endif + self = .init(native: native) + return } +#endif + let isUnique = isUniquelyReferenced() + try asNative.merge( + keysAndValues, + isUnique: isUnique, + uniquingKeysWith: combine) } } diff --git a/stdlib/public/core/HashTable.swift b/stdlib/public/core/HashTable.swift index 39ee521250826..8b09edcf75197 100644 --- a/stdlib/public/core/HashTable.swift +++ b/stdlib/public/core/HashTable.swift @@ -392,7 +392,7 @@ extension _HashTable { } var wrap = false while true { - word += 1 + word &+= 1 if word == wordCount { _precondition(!wrap, "Hash table has no holes") wrap = true diff --git a/stdlib/public/core/NativeDictionary.swift b/stdlib/public/core/NativeDictionary.swift index a44968030e8d0..da0cd449276a5 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) } } @@ -427,7 +426,7 @@ extension _NativeDictionary { // Insertions let bucket = hashTable.insertNew(hashValue: hashValue) uncheckedInitialize(at: bucket, toKey: key, value: value) } - _storage._count += 1 + _storage._count &+= 1 } /// Insert a new entry into uniquely held storage. @@ -527,6 +526,43 @@ extension _NativeDictionary { } } +extension _NativeDictionary where Value: Equatable { + @inlinable + @inline(__always) + func isEqual(to other: _NativeDictionary) -> Bool { + if self._storage === other._storage { return true } + if self.count != other.count { return false } + + for (key, value) in self { + let (bucket, found) = other.find(key) + guard found, other.uncheckedValue(at: bucket) == value else { + return false + } + } + return true + } + +#if _runtime(_ObjC) + @inlinable + func isEqual(to other: _CocoaDictionary) -> Bool { + if self.count != other.count { return false } + + defer { _fixLifetime(self) } + for bucket in self.hashTable { + let key = self.uncheckedKey(at: bucket) + let value = self.uncheckedValue(at: bucket) + guard + let cocoaValue = other.lookup(_bridgeAnythingToObjectiveC(key)), + value == _forceBridgeFromObjectiveC(cocoaValue, Value.self) + else { + return false + } + } + return true + } +#endif +} + extension _NativeDictionary: _HashTableDelegate { @inlinable @inline(__always) diff --git a/stdlib/public/core/NativeSet.swift b/stdlib/public/core/NativeSet.swift index 5ebeba3d7bd45..a45475dfbf574 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) } } @@ -361,7 +360,7 @@ extension _NativeSet { // Insertions let bucket = hashTable.insertNew(hashValue: hashValue) uncheckedInitialize(at: bucket, to: element) } - _storage._count += 1 + _storage._count &+= 1 } /// Insert a new element into uniquely held storage. @@ -425,6 +424,35 @@ extension _NativeSet { // Insertions } } +extension _NativeSet { + @inlinable + @inline(__always) + func isEqual(to other: _NativeSet) -> Bool { + if self._storage === other._storage { return true } + if self.count != other.count { return false } + + for member in self { + guard other.find(member).found else { return false } + } + return true + } + +#if _runtime(_ObjC) + @inlinable + func isEqual(to other: _CocoaSet) -> Bool { + if self.count != other.count { return false } + + defer { _fixLifetime(self) } + for bucket in self.hashTable { + let key = self.uncheckedElement(at: bucket) + let bridgedKey = _bridgeAnythingToObjectiveC(key) + guard other.contains(bridgedKey) else { return false } + } + return true + } +#endif +} + extension _NativeSet: _HashTableDelegate { @inlinable @inline(__always) diff --git a/stdlib/public/core/Set.swift b/stdlib/public/core/Set.swift index 6541ba75d28f0..cdb917e29052d 100644 --- a/stdlib/public/core/Set.swift +++ b/stdlib/public/core/Set.swift @@ -163,19 +163,19 @@ public struct Set { /// storage buffer. public // FIXME(reserveCapacity): Should be inlinable init(minimumCapacity: Int) { - _variant = .native(_NativeSet(capacity: minimumCapacity)) + _variant = _Variant(native: _NativeSet(capacity: minimumCapacity)) } /// Private initializer. @inlinable internal init(_native: __owned _NativeSet) { - _variant = .native(_native) + _variant = _Variant(native: _native) } #if _runtime(_ObjC) @inlinable internal init(_cocoa: __owned _CocoaSet) { - _variant = .cocoa(_cocoa) + _variant = _Variant(cocoa: _cocoa) } /// Private initializer used for bridging. @@ -421,48 +421,20 @@ extension Set: Equatable { /// `false`. @inlinable public static func == (lhs: Set, rhs: Set) -> Bool { - switch (lhs._variant, rhs._variant) { - case (.native(let lhsNative), .native(let rhsNative)): - - if lhsNative._storage === rhsNative._storage { - return true - } - - if lhsNative.count != rhsNative.count { - return false - } - - for member in lhsNative { - guard rhsNative.find(member).found else { - return false - } - } - return true - - #if _runtime(_ObjC) - case (.cocoa(let lhsCocoa), .cocoa(let rhsCocoa)): - return lhsCocoa == rhsCocoa - - case (.native(let lhsNative), .cocoa(let rhsCocoa)): - if lhsNative.count != rhsCocoa.count { - return false - } - - defer { _fixLifetime(lhsNative) } - for bucket in lhsNative.hashTable { - let key = lhsNative.uncheckedElement(at: bucket) - let bridgedKey = _bridgeAnythingToObjectiveC(key) - if rhsCocoa.contains(bridgedKey) { - continue - } - return false - } - return true - - case (.cocoa, .native): - return rhs == lhs - #endif +#if _runtime(_ObjC) + switch (lhs._variant.isNative, rhs._variant.isNative) { + case (true, true): + return lhs._variant.asNative.isEqual(to: rhs._variant.asNative) + case (false, false): + return lhs._variant.asCocoa.isEqual(to: rhs._variant.asCocoa) + case (true, false): + return lhs._variant.asNative.isEqual(to: rhs._variant.asCocoa) + case (false, true): + return rhs._variant.asNative.isEqual(to: lhs._variant.asCocoa) } +#else + return lhs._variant.asNative.isEqual(to: rhs._variant.asNative) +#endif } } @@ -1361,6 +1333,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 { @@ -1449,19 +1434,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 } } @@ -1526,6 +1509,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 { @@ -1542,6 +1538,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 { @@ -1553,19 +1563,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..8b9387a22d296 100644 --- a/stdlib/public/core/SetBridging.swift +++ b/stdlib/public/core/SetBridging.swift @@ -313,10 +313,10 @@ extension _CocoaSet { } } -extension _CocoaSet: Equatable { +extension _CocoaSet { @usableFromInline - internal static func ==(lhs: _CocoaSet, rhs: _CocoaSet) -> Bool { - return _stdlib_NSObject_isEqual(lhs.object, rhs.object) + internal func isEqual(to other: _CocoaSet) -> Bool { + return _stdlib_NSObject_isEqual(self.object, other.object) } } @@ -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/SetBuilder.swift b/stdlib/public/core/SetBuilder.swift index 7ad37896232c9..abf5b4a98dceb 100644 --- a/stdlib/public/core/SetBuilder.swift +++ b/stdlib/public/core/SetBuilder.swift @@ -29,10 +29,11 @@ struct _SetBuilder { } @inlinable + @inline(__always) public mutating func add(member: Element) { _precondition(_target.count < _requestedCount, "Can't add more members than promised") - _target.insertNew(member, isUnique: true) + _target._unsafeInsertNew(member) } @inlinable 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..746b9ca808b55 100644 --- a/stdlib/public/core/SetVariant.swift +++ b/stdlib/public/core/SetVariant.swift @@ -28,11 +28,38 @@ internal protocol _SetBuffer { extension Set { @usableFromInline - @_frozen - internal enum _Variant { - case native(_NativeSet) + @_fixed_layout + internal struct _Variant { #if _runtime(_ObjC) - case cocoa(_CocoaSet) + @usableFromInline + internal var object: _BridgeStorage<_RawSetStorage, _NSSet> +#else + @usableFromInline + internal var object: _BridgeStorage<_RawSetStorage, AnyObject> +#endif + + @inlinable + @inline(__always) + init(dummy: ()) { +#if arch(i386) || arch(arm) + self.init(native: _NativeSet()) +#else + self.object = _BridgeStorage(taggedPayload: 0) +#endif + } + + @inlinable + @inline(__always) + init(native: __owned _NativeSet) { + self.object = _BridgeStorage(native: native._storage) + } + +#if _runtime(_ObjC) + @inlinable + @inline(__always) + init(cocoa: __owned _CocoaSet) { + self.object = _BridgeStorage(objC: cocoa.object) + } #endif } } @@ -44,78 +71,57 @@ extension Set._Variant { internal var guaranteedNative: Bool { return _canBeClass(Element.self) == 0 } - - /// Allow the optimizer to consider the surrounding code unreachable if - /// Set is guaranteed to be native. - @usableFromInline - @_transparent - internal func cocoaPath() { - if guaranteedNative { - _conditionallyUnreachable() - } - } #endif @inlinable internal mutating func isUniquelyReferenced() -> Bool { - // Note that &self drills down through .native(_NativeSet) to the first - // property in _NativeSet, which is the reference to the storage. - switch self { - case .native: - return _isUnique_native(&self) + return object.isUniquelyReferenced_native_noSpareBits() + } + #if _runtime(_ObjC) - case .cocoa: - cocoaPath() - // Don't consider Cocoa buffer mutable, even if it is mutable and is - // uniquely referenced. - return false -#endif - } + @usableFromInline @_transparent + internal var isNative: Bool { + if guaranteedNative { return true } + return object.isNativeWithClearedSpareBits(0) } +#endif @usableFromInline @_transparent internal var asNative: _NativeSet { get { - switch self { - case .native(let nativeSet): - return nativeSet -#if _runtime(_ObjC) - case .cocoa: - _sanityCheckFailure("internal error: not backed by native buffer") -#endif - } + return _NativeSet(object.nativeInstance_noSpareBits) } set { - self = .native(newValue) + self = .init(native: newValue) + } + _modify { + var native = _NativeSet(object.nativeInstance_noSpareBits) + self = .init(dummy: ()) + yield &native + object = .init(native: native._storage) } } #if _runtime(_ObjC) @inlinable internal var asCocoa: _CocoaSet { - switch self { - case .native: - _sanityCheckFailure("internal error: not backed by NSSet") - case .cocoa(let cocoa): - return cocoa - } + return _CocoaSet(object.objCInstance) } #endif /// 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 + self = .init(native: _NativeSet(cocoa, capacity: capacity)) + return } +#endif + let isUnique = isUniquelyReferenced() + asNative.reserveCapacity(capacity, isUnique: isUnique) } /// The number of elements that can be stored without expanding the current @@ -127,15 +133,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,204 +148,172 @@ 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 internal func formIndex(after index: inout Index) { - switch self { - case .native(let native): - index = native.index(after: index) #if _runtime(_ObjC) - case .cocoa(let cocoa): - cocoaPath() + guard isNative else { let isUnique = index._isUniquelyReferenced() - cocoa.formIndex(after: &index._asCocoa, isUnique: isUnique) -#endif + asCocoa.formIndex(after: &index._asCocoa, isUnique: isUnique) + return } +#endif + index = asNative.index(after: index) } @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) + self = .init(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)) } var native = _NativeSet(cocoa, capacity: cocoa.count + 1) native.insertNew(element, isUnique: true) - self = .native(native) + self = .init(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) @@ -358,7 +329,7 @@ extension Set._Variant { _precondition(found, "Bridging did not preserve equality") let old = native.uncheckedRemove(at: bucket, isUnique: true) _precondition(member == old, "Bridging did not preserve equality") - self = .native(native) + self = .init(native: native) return old } #endif @@ -366,21 +337,19 @@ extension Set._Variant { @inlinable internal mutating func removeAll(keepingCapacity keepCapacity: Bool) { if !keepCapacity { - self = .native(_NativeSet()) + self = .init(native: _NativeSet()) return } 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 = .init(native: _NativeSet(capacity: asCocoa.count)) + return } +#endif + let isUnique = isUniquelyReferenced() + asNative.removeAll(isUnique: isUnique) } } @@ -391,15 +360,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()) } } diff --git a/test/api-digester/Outputs/stability-stdlib-abi.swift.expected b/test/api-digester/Outputs/stability-stdlib-abi.swift.expected index e548788af5466..4799a4bd1ec25 100644 --- a/test/api-digester/Outputs/stability-stdlib-abi.swift.expected +++ b/test/api-digester/Outputs/stability-stdlib-abi.swift.expected @@ -4,12 +4,32 @@ /* RawRepresentable Changes */ /* Removed Decls */ +EnumElement Dictionary._Variant.cocoa has been removed +EnumElement Set._Variant.cocoa has been removed +Func Dictionary._Variant.cocoaPath() has been removed +Func Set._Variant.cocoaPath() has been removed +Func _CocoaDictionary.==(_:_:) has been removed +Func _CocoaSet.==(_:_:) has been removed /* Moved Decls */ +Enum Dictionary._Variant has been changed to a Struct +Enum Set._Variant has been changed to a Struct /* Renamed Decls */ +EnumElement Dictionary._Variant.native has been renamed to Var Dictionary._Variant.isNative +EnumElement Set._Variant.native has been renamed to Var Set._Variant.isNative /* Type Changes */ +Enum Dictionary._Variant is now with @_fixed_layout +Enum Dictionary._Variant is now without @_frozen +Enum Set._Variant is now with @_fixed_layout +Enum Set._Variant is now without @_frozen +EnumElement Dictionary._Variant.native is no longer a stored property +EnumElement Set._Variant.native is no longer a stored property +Var Dictionary._Variant.object is added to a non-resilient type +Var Set._Variant.object is added to a non-resilient type +Struct _CocoaDictionary has removed conformance to Equatable +Struct _CocoaSet has removed conformance to Equatable /* Decl Attribute changes */ diff --git a/test/stdlib/Inputs/DictionaryKeyValueTypesObjC.swift b/test/stdlib/Inputs/DictionaryKeyValueTypesObjC.swift index 73bbff4f33a9b..a13fb2bb84938 100644 --- a/test/stdlib/Inputs/DictionaryKeyValueTypesObjC.swift +++ b/test/stdlib/Inputs/DictionaryKeyValueTypesObjC.swift @@ -20,12 +20,7 @@ public func convertNSDictionaryToDictionary< func isNativeDictionary( _ d: Dictionary) -> Bool { - switch d._variant { - case .native: - return true - case .cocoa: - return false - } + return d._variant.isNative } func isCocoaDictionary( diff --git a/validation-test/Reflection/reflect_Dictionary.swift b/validation-test/Reflection/reflect_Dictionary.swift index 769a9e1574557..aa6efd9e27496 100644 --- a/validation-test/Reflection/reflect_Dictionary.swift +++ b/validation-test/Reflection/reflect_Dictionary.swift @@ -28,7 +28,7 @@ reflect(object: obj) // CHECK-64: Type info: // CHECK-64: (class_instance size=24 alignment=8 stride=24 num_extra_inhabitants=0 // CHECK-64: (field name=t offset=16 -// CHECK-64: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 +// CHECK-64: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=1 // (unstable implementation details omitted) // CHECK-32: Reflecting an object. @@ -39,7 +39,7 @@ reflect(object: obj) // CHECK-32: Type info: // CHECK-32: (class_instance size=12 alignment=4 stride=12 num_extra_inhabitants=0 // CHECK-32: (field name=t offset=8 -// CHECK-32: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0 +// CHECK-32: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=1 // (unstable implementation details omitted) doneReflecting() diff --git a/validation-test/Reflection/reflect_Set.swift b/validation-test/Reflection/reflect_Set.swift index 97b71418efa43..5d0593422d9cb 100644 --- a/validation-test/Reflection/reflect_Set.swift +++ b/validation-test/Reflection/reflect_Set.swift @@ -28,7 +28,7 @@ reflect(object: obj) // CHECK-64: Type info: // CHECK-64: (class_instance size=24 alignment=8 stride=24 num_extra_inhabitants=0 // CHECK-64: (field name=t offset=16 -// CHECK-64: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 +// CHECK-64: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=1 // (unstable implementation details omitted) // CHECK-32: Reflecting an object. @@ -39,7 +39,7 @@ reflect(object: obj) // CHECK-32: Type info: // CHECK-32: (class_instance size=12 alignment=4 stride=12 num_extra_inhabitants=0 // CHECK-32: (field name=t offset=8 -// CHECK-32: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0 +// CHECK-32: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=1 // (unstable implementation details omitted) doneReflecting() diff --git a/validation-test/Reflection/reflect_multiple_types.swift b/validation-test/Reflection/reflect_multiple_types.swift index f8050c93d5716..9bc2f4ff603d9 100644 --- a/validation-test/Reflection/reflect_multiple_types.swift +++ b/validation-test/Reflection/reflect_multiple_types.swift @@ -132,7 +132,7 @@ reflect(object: obj) // CHECK-64-NEXT: (field name=large offset=0 // CHECK-64-NEXT: (reference kind=strong refcounting=native)))))) // CHECK-64-NEXT: (field name=t03 offset=40 -// CHECK-64-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 +// CHECK-64-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=1 // (unstable implementation details omitted) // CHECK-64: (field name=t04 offset=48 // CHECK-64-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 @@ -171,7 +171,7 @@ reflect(object: obj) // CHECK-64-NEXT: (field name=t14 offset=120 // CHECK-64-NEXT: (reference kind=strong refcounting=unknown)) // CHECK-64-NEXT: (field name=t15 offset=128 -// CHECK-64-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 +// CHECK-64-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=1 // (unstable implementation details omitted) // CHECK-64: (field name=t16 offset=136 // CHECK-64-NEXT: (struct size=16 alignment=8 stride=16 num_extra_inhabitants=1 @@ -220,7 +220,7 @@ reflect(object: obj) // CHECK-32-NEXT: (field name=large offset=0 // CHECK-32-NEXT: (reference kind=strong refcounting=native)))))) // CHECK-32-NEXT: (field name=t03 offset=24 -// CHECK-32-NEXT: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0 +// CHECK-32-NEXT: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=1 // (unstable implementation details omitted) // CHECK-32: (field name=t04 offset=32 // CHECK-32-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 @@ -259,7 +259,7 @@ reflect(object: obj) // CHECK-32-NEXT: (field name=t14 offset=80 // CHECK-32-NEXT: (reference kind=strong refcounting=unknown)) // CHECK-32-NEXT: (field name=t15 offset=84 -// CHECK-32-NEXT: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=0 +// CHECK-32-NEXT: (struct size=4 alignment=4 stride=4 num_extra_inhabitants=1 // (unstable implementation details omitted) // CHECK-32: (field name=t16 offset=88 // CHECK-32-NEXT: (struct size=12 alignment=4 stride=12 num_extra_inhabitants=4092 diff --git a/validation-test/stdlib/Set.swift b/validation-test/stdlib/Set.swift index 336370235ab01..115d5896e022b 100644 --- a/validation-test/stdlib/Set.swift +++ b/validation-test/stdlib/Set.swift @@ -110,14 +110,11 @@ func equalsUnordered(_ lhs: Set, _ rhs: Set) -> Bool { } func isNativeSet(_ s: Set) -> Bool { - switch s._variant { - case .native: - return true #if _runtime(_ObjC) - case .cocoa: - return false + return s._variant.isNative +#else + return true #endif - } } #if _runtime(_ObjC)