//===----------------------------------------------------------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// import SwiftShims //===--- APIs unique to Set --------------------------------------===// /// An unordered collection of unique elements. /// /// You use a set instead of an array when you need to test efficiently for /// membership and you aren't concerned with the order of the elements in the /// collection, or when you need to ensure that each element appears only once /// in a collection. /// /// You can create a set with any element type that conforms to the `Hashable` /// protocol. By default, most types in the standard library are hashable, /// including strings, numeric and Boolean types, enumeration cases without /// associated values, and even sets themselves. /// /// Swift makes it as easy to create a new set as to create a new array. Simply /// assign an array literal to a variable or constant with the `Set` type /// specified. /// /// let ingredients: Set = ["cocoa beans", "sugar", "cocoa butter", "salt"] /// if ingredients.contains("sugar") { /// print("No thanks, too sweet.") /// } /// // Prints "No thanks, too sweet." /// /// Set Operations /// ============== /// /// Sets provide a suite of mathematical set operations. For example, you can /// efficiently test a set for membership of an element or check its /// intersection with another set: /// /// - Use the `contains(_:)` method to test whether a set contains a specific /// element. /// - Use the "equal to" operator (`==`) to test whether two sets contain the /// same elements. /// - Use the `isSubset(of:)` method to test whether a set contains all the /// elements of another set or sequence. /// - Use the `isSuperset(of:)` method to test whether all elements of a set /// are contained in another set or sequence. /// - Use the `isStrictSubset(of:)` and `isStrictSuperset(of:)` methods to test /// whether a set is a subset or superset of, but not equal to, another set. /// - Use the `isDisjoint(with:)` method to test whether a set has any elements /// in common with another set. /// /// You can also combine, exclude, or subtract the elements of two sets: /// /// - Use the `union(_:)` method to create a new set with the elements of a set /// and another set or sequence. /// - Use the `intersection(_:)` method to create a new set with only the /// elements common to a set and another set or sequence. /// - Use the `symmetricDifference(_:)` method to create a new set with the /// elements that are in either a set or another set or sequence, but not in /// both. /// - Use the `subtracting(_:)` method to create a new set with the elements of /// a set that are not also in another set or sequence. /// /// You can modify a set in place by using these methods' mutating /// counterparts: `formUnion(_:)`, `formIntersection(_:)`, /// `formSymmetricDifference(_:)`, and `subtract(_:)`. /// /// Set operations are not limited to use with other sets. Instead, you can /// perform set operations with another set, an array, or any other sequence /// type. /// /// var primes: Set = [2, 3, 5, 7] /// /// // Tests whether primes is a subset of a Range /// print(primes.isSubset(of: 0..<10)) /// // Prints "true" /// /// // Performs an intersection with an Array /// let favoriteNumbers = [5, 7, 15, 21] /// print(primes.intersection(favoriteNumbers)) /// // Prints "[5, 7]" /// /// Sequence and Collection Operations /// ================================== /// /// In addition to the `Set` type's set operations, you can use any nonmutating /// sequence or collection methods with a set. /// /// if primes.isEmpty { /// print("No primes!") /// } else { /// print("We have \(primes.count) primes.") /// } /// // Prints "We have 4 primes." /// /// let primesSum = primes.reduce(0, +) /// // 'primesSum' == 17 /// /// let primeStrings = primes.sorted().map(String.init) /// // 'primeStrings' == ["2", "3", "5", "7"] /// /// You can iterate through a set's unordered elements with a `for`-`in` loop. /// /// for number in primes { /// print(number) /// } /// // Prints "5" /// // Prints "7" /// // Prints "2" /// // Prints "3" /// /// Many sequence and collection operations return an array or a type-erasing /// collection wrapper instead of a set. To restore efficient set operations, /// create a new set from the result. /// /// let morePrimes = primes.union([11, 13, 17, 19]) /// /// let laterPrimes = morePrimes.filter { $0 > 10 } /// // 'laterPrimes' is of type Array /// /// let laterPrimesSet = Set(morePrimes.filter { $0 > 10 }) /// // 'laterPrimesSet' is of type Set /// /// Bridging Between Set and NSSet /// ============================== /// /// You can bridge between `Set` and `NSSet` using the `as` operator. For /// bridging to be possible, the `Element` type of a set must be a class, an /// `@objc` protocol (a protocol imported from Objective-C or marked with the /// `@objc` attribute), or a type that bridges to a Foundation type. /// /// Bridging from `Set` to `NSSet` always takes O(1) time and space. When the /// set's `Element` type is neither a class nor an `@objc` protocol, any /// required bridging of elements occurs at the first access of each element, /// so the first operation that uses the contents of the set (for example, a /// membership test) can take O(*n*). /// /// Bridging from `NSSet` to `Set` first calls the `copy(with:)` method /// (`- copyWithZone:` in Objective-C) on the set to get an immutable copy and /// then performs additional Swift bookkeeping work that takes O(1) time. For /// instances of `NSSet` that are already immutable, `copy(with:)` returns the /// same set in constant time; otherwise, the copying performance is /// unspecified. The instances of `NSSet` and `Set` share buffer using the /// same copy-on-write optimization that is used when two instances of `Set` /// share buffer. @_fixed_layout public struct Set { internal typealias _VariantBuffer = _VariantSetBuffer internal typealias _NativeBuffer = _NativeSetBuffer @usableFromInline internal var _variantBuffer: _VariantBuffer } extension Set { /// Creates an empty set with preallocated space for at least the specified /// number of elements. /// /// Use this initializer to avoid intermediate reallocations of a set's /// storage buffer when you know how many elements you'll insert into the set /// after creation. /// /// - Parameter minimumCapacity: The minimum number of elements that the /// newly created set should be able to store without reallocating its /// storage buffer. @inlinable // FIXME(sil-serialize-all) public init(minimumCapacity: Int) { _variantBuffer = _VariantBuffer.native( _NativeBuffer(minimumCapacity: minimumCapacity)) } /// Private initializer. @inlinable // FIXME(sil-serialize-all) internal init(_nativeBuffer: _NativeSetBuffer) { _variantBuffer = _VariantBuffer.native(_nativeBuffer) } // // All APIs below should dispatch to `_variantBuffer`, without doing any // additional processing. // #if _runtime(_ObjC) /// Private initializer used for bridging. /// /// Only use this initializer when both conditions are true: /// /// * it is statically known that the given `NSSet` is immutable; /// * `Element` is bridged verbatim to Objective-C (i.e., /// is a reference type). @inlinable // FIXME(sil-serialize-all) public init(_immutableCocoaSet: _NSSet) { _sanityCheck(_isBridgedVerbatimToObjectiveC(Element.self), "Set can be backed by NSSet _variantBuffer only when the member type can be bridged verbatim to Objective-C") _variantBuffer = _VariantSetBuffer.cocoa( _CocoaSetBuffer(cocoaSet: _immutableCocoaSet)) } #endif } extension Set: ExpressibleByArrayLiteral { // // `ExpressibleByArrayLiteral` conformance // /// Creates a set containing the elements of the given array literal. /// /// Do not call this initializer directly. It is used by the compiler when /// you use an array literal. Instead, create a new set using an array /// literal as its value by enclosing a comma-separated list of values in /// square brackets. You can use an array literal anywhere a set is expected /// by the type context. /// /// Here, a set of strings is created from an array literal holding only /// strings. /// /// let ingredients: Set = ["cocoa beans", "sugar", "cocoa butter", "salt"] /// if ingredients.isSuperset(of: ["sugar", "salt"]) { /// print("Whatever it is, it's bound to be delicious!") /// } /// // Prints "Whatever it is, it's bound to be delicious!" /// /// - Parameter elements: A variadic list of elements of the new set. @inlinable // FIXME(sil-serialize-all) public init(arrayLiteral elements: Element...) { self.init(_nativeBuffer: _NativeSetBuffer.fromArray(elements)) } } extension Set: Sequence { /// Returns an iterator over the members of the set. @inlinable // FIXME(sil-serialize-all) @inline(__always) public func makeIterator() -> SetIterator { return _variantBuffer.makeIterator() } /// Returns a Boolean value that indicates whether the given element exists /// in the set. /// /// This example uses the `contains(_:)` method to test whether an integer is /// a member of a set of prime numbers. /// /// let primes: Set = [2, 3, 5, 7] /// let x = 5 /// if primes.contains(x) { /// print("\(x) is prime!") /// } else { /// print("\(x). Not prime.") /// } /// // Prints "5 is prime!" /// /// - Parameter member: An element to look for in the set. /// - Returns: `true` if `member` exists in the set; otherwise, `false`. /// /// - Complexity: O(1) @inlinable // FIXME(sil-serialize-all) public func contains(_ member: Element) -> Bool { return _variantBuffer.maybeGet(member) != nil } @inlinable // FIXME(sil-serialize-all) public func _customContainsEquatableElement(_ member: Element) -> Bool? { return contains(member) } } // This is not quite Sequence.filter, because that returns [Element], not Self // (RangeReplaceableCollection.filter returns Self, but Set isn't an RRC) extension Set { /// Returns a new set containing the elements of the set that satisfy the /// given predicate. /// /// In this example, `filter(_:)` is used to include only names shorter than /// five characters. /// /// let cast: Set = ["Vivien", "Marlon", "Kim", "Karl"] /// let shortNames = cast.filter { $0.count < 5 } /// /// shortNames.isSubset(of: cast) /// // true /// shortNames.contains("Vivien") /// // false /// /// - Parameter isIncluded: A closure that takes an element as its argument /// and returns a Boolean value indicating whether the element should be /// included in the returned set. /// - Returns: A set of the elements that `isIncluded` allows. @inlinable @available(swift, introduced: 4.0) public func filter( _ isIncluded: (Element) throws -> Bool ) rethrows -> Set { var result = Set() for element in self { if try isIncluded(element) { result.insert(element) } } return result } } extension Set: Collection { /// The starting position for iterating members of the set. /// /// If the set is empty, `startIndex` is equal to `endIndex`. @inlinable // FIXME(sil-serialize-all) public var startIndex: Index { return _variantBuffer.startIndex } /// The "past the end" position for the set---that is, the position one /// greater than the last valid subscript argument. /// /// If the set is empty, `endIndex` is equal to `startIndex`. @inlinable // FIXME(sil-serialize-all) public var endIndex: Index { return _variantBuffer.endIndex } /// Accesses the member at the given position. @inlinable // FIXME(sil-serialize-all) public subscript(position: Index) -> Element { return _variantBuffer.assertingGet(position) } @inlinable // FIXME(sil-serialize-all) public func index(after i: Index) -> Index { return _variantBuffer.index(after: i) } // APINAMING: complexity docs are broadly missing in this file. /// Returns the index of the given element in the set, or `nil` if the /// element is not a member of the set. /// /// - Parameter member: An element to search for in the set. /// - Returns: The index of `member` if it exists in the set; otherwise, /// `nil`. /// /// - Complexity: O(1) @inlinable // FIXME(sil-serialize-all) public func firstIndex(of member: Element) -> Index? { return _variantBuffer.index(forKey: member) } @inlinable // FIXME(sil-serialize-all) public func _customIndexOfEquatableElement( _ member: Element ) -> Index?? { return Optional(firstIndex(of: member)) } /// The number of elements in the set. /// /// - Complexity: O(1). @inlinable // FIXME(sil-serialize-all) public var count: Int { return _variantBuffer.count } /// A Boolean value that indicates whether the set is empty. @inlinable // FIXME(sil-serialize-all) public var isEmpty: Bool { return count == 0 } /// The first element of the set. /// /// The first element of the set is not necessarily the first element added /// to the set. Don't expect any particular ordering of set elements. /// /// If the set is empty, the value of this property is `nil`. @inlinable // FIXME(sil-serialize-all) public var first: Element? { return count > 0 ? self[startIndex] : nil } } /// Check for both subset and equality relationship between /// a set and some sequence (which may itself be a `Set`). /// /// (isSubset: lhs ⊂ rhs, isEqual: lhs ⊂ rhs and |lhs| = |rhs|) @inlinable internal func _compareSets(_ lhs: Set, _ rhs: Set) -> (isSubset: Bool, isEqual: Bool) { // FIXME(performance): performance could be better if we start by comparing // counts. for member in lhs { if !rhs.contains(member) { return (false, false) } } return (true, lhs.count == rhs.count) } // FIXME: rdar://problem/23549059 (Optimize == for Set) // Look into initially trying to compare the two sets by directly comparing the // contents of both buffers in order. If they happen to have the exact same // ordering we can get the `true` response without ever hashing. If the two // buffers' contents differ at all then we have to fall back to hashing the // rest of the elements (but we don't need to hash any prefix that did match). extension Set: Equatable { /// Returns a Boolean value indicating whether two sets have equal elements. /// /// - Parameters: /// - lhs: A set. /// - rhs: Another set. /// - Returns: `true` if the `lhs` and `rhs` have the same elements; otherwise, /// `false`. @inlinable // FIXME(sil-serialize-all) public static func == (lhs: Set, rhs: Set) -> Bool { switch (lhs._variantBuffer, rhs._variantBuffer) { case (.native(let lhsNative), .native(let rhsNative)): if lhsNative._storage === rhsNative._storage { return true } if lhsNative.count != rhsNative.count { return false } for member in lhs { let (_, found) = rhsNative._find(member, startBucket: rhsNative._bucket(member)) if !found { return false } } return true #if _runtime(_ObjC) case (_VariantSetBuffer.cocoa(let lhsCocoa), _VariantSetBuffer.cocoa(let rhsCocoa)): return _stdlib_NSObject_isEqual(lhsCocoa.cocoaSet, rhsCocoa.cocoaSet) case (_VariantSetBuffer.native(let lhsNative), _VariantSetBuffer.cocoa(let rhsCocoa)): if lhsNative.count != rhsCocoa.count { return false } let endIndex = lhsNative.endIndex var i = lhsNative.startIndex while i != endIndex { let key = lhsNative.assertingGet(i) let bridgedKey: AnyObject = _bridgeAnythingToObjectiveC(key) let optRhsValue: AnyObject? = rhsCocoa.maybeGet(bridgedKey) if let rhsValue = optRhsValue { if key == _forceBridgeFromObjectiveC(rhsValue, Element.self) { i = lhsNative.index(after: i) continue } } i = lhsNative.index(after: i) return false } return true case (_VariantSetBuffer.cocoa, _VariantSetBuffer.native): return rhs == lhs #endif } } } extension Set: Hashable { /// The hash value for the set. /// /// Two sets that are equal will always have equal hash values. /// /// Hash values are not guaranteed to be equal across different executions of /// your program. Do not save hash values to use during a future execution. @inlinable // FIXME(sil-serialize-all) public var hashValue: Int { // FIXME(ABI)#177: Cache Set hashValue return _hashValue(for: self) } @inlinable // FIXME(sil-serialize-all) public func _hash(into hasher: inout _Hasher) { var hash = 0 for member in self { hash ^= _hashValue(for: member) } hasher.combine(hash) } } extension Set: SetAlgebra { /// Inserts the given element in the set if it is not already present. /// /// If an element equal to `newMember` is already contained in the set, this /// method has no effect. In the following example, a new element is /// inserted into `classDays`, a set of days of the week. When an existing /// element is inserted, the `classDays` set does not change. /// /// enum DayOfTheWeek: Int { /// case sunday, monday, tuesday, wednesday, thursday, /// friday, saturday /// } /// /// var classDays: Set = [.wednesday, .friday] /// print(classDays.insert(.monday)) /// // Prints "(true, .monday)" /// print(classDays) /// // Prints "[.friday, .wednesday, .monday]" /// /// print(classDays.insert(.friday)) /// // Prints "(false, .friday)" /// print(classDays) /// // Prints "[.friday, .wednesday, .monday]" /// /// - Parameter newMember: An element to insert into the set. /// - Returns: `(true, newMember)` if `newMember` was not contained in the /// set. If an element equal to `newMember` was already contained in the /// set, the method returns `(false, oldMember)`, where `oldMember` is the /// element that was equal to `newMember`. In some cases, `oldMember` may /// be distinguishable from `newMember` by identity comparison or some /// other means. @inlinable // FIXME(sil-serialize-all) @discardableResult public mutating func insert( _ newMember: Element ) -> (inserted: Bool, memberAfterInsert: Element) { return _variantBuffer.insert(newMember, forKey: newMember) } /// Inserts the given element into the set unconditionally. /// /// If an element equal to `newMember` is already contained in the set, /// `newMember` replaces the existing element. In this example, an existing /// element is inserted into `classDays`, a set of days of the week. /// /// enum DayOfTheWeek: Int { /// case sunday, monday, tuesday, wednesday, thursday, /// friday, saturday /// } /// /// var classDays: Set = [.monday, .wednesday, .friday] /// print(classDays.update(with: .monday)) /// // Prints "Optional(.monday)" /// /// - Parameter newMember: An element to insert into the set. /// - Returns: An element equal to `newMember` if the set already contained /// such a member; otherwise, `nil`. In some cases, the returned element /// may be distinguishable from `newMember` by identity comparison or some /// other means. @inlinable // FIXME(sil-serialize-all) @discardableResult public mutating func update(with newMember: Element) -> Element? { return _variantBuffer.updateValue(newMember, forKey: newMember) } /// Removes the specified element from the set. /// /// This example removes the element `"sugar"` from a set of ingredients. /// /// var ingredients: Set = ["cocoa beans", "sugar", "cocoa butter", "salt"] /// let toRemove = "sugar" /// if let removed = ingredients.remove(toRemove) { /// print("The recipe is now \(removed)-free.") /// } /// // Prints "The recipe is now sugar-free." /// /// - Parameter member: The element to remove from the set. /// - Returns: The value of the `member` parameter if it was a member of the /// set; otherwise, `nil`. @inlinable // FIXME(sil-serialize-all) @discardableResult public mutating func remove(_ member: Element) -> Element? { return _variantBuffer.removeValue(forKey: member) } /// Removes the element at the given index of the set. /// /// - Parameter position: The index of the member to remove. `position` must /// be a valid index of the set, and must not be equal to the set's end /// index. /// - Returns: The element that was removed from the set. @inlinable // FIXME(sil-serialize-all) @discardableResult public mutating func remove(at position: Index) -> Element { return _variantBuffer.remove(at: position) } /// Removes all members from the set. /// /// - Parameter keepingCapacity: If `true`, the set's buffer capacity is /// preserved; if `false`, the underlying buffer is released. The /// default is `false`. @inlinable // FIXME(sil-serialize-all) public mutating func removeAll(keepingCapacity keepCapacity: Bool = false) { _variantBuffer.removeAll(keepingCapacity: keepCapacity) } /// Removes the first element of the set. /// /// Because a set is not an ordered collection, the "first" element may not /// be the first element that was added to the set. The set must not be /// empty. /// /// - Complexity: Amortized O(1) if the set does not wrap a bridged `NSSet`. /// If the set wraps a bridged `NSSet`, the performance is unspecified. /// /// - Returns: A member of the set. @inlinable // FIXME(sil-serialize-all) @discardableResult public mutating func removeFirst() -> Element { _precondition(!isEmpty, "Can't removeFirst from an empty Set") return remove(at: startIndex) } // // APIs below this comment should be implemented strictly in terms of // *public* APIs above. `_variantBuffer` should not be accessed directly. // // This separates concerns for testing. Tests for the following APIs need // not to concern themselves with testing correctness of behavior of // underlying buffer (and different variants of it), only correctness of the // API itself. // /// Creates an empty set. /// /// This is equivalent to initializing with an empty array literal. For /// example: /// /// var emptySet = Set() /// print(emptySet.isEmpty) /// // Prints "true" /// /// emptySet = [] /// print(emptySet.isEmpty) /// // Prints "true" @inlinable // FIXME(sil-serialize-all) public init() { self = Set(_nativeBuffer: _NativeBuffer()) } /// Creates a new set from a finite sequence of items. /// /// Use this initializer to create a new set from an existing sequence, for /// example, an array or a range. /// /// let validIndices = Set(0..<7).subtracting([2, 4, 5]) /// print(validIndices) /// // Prints "[6, 0, 1, 3]" /// /// This initializer can also be used to restore set methods after performing /// sequence operations such as `filter(_:)` or `map(_:)` on a set. For /// example, after filtering a set of prime numbers to remove any below 10, /// you can create a new set by using this initializer. /// /// let primes: Set = [2, 3, 5, 7, 11, 13, 17, 19, 23] /// let laterPrimes = Set(primes.lazy.filter { $0 > 10 }) /// print(laterPrimes) /// // Prints "[17, 19, 23, 11, 13]" /// /// - Parameter sequence: The elements to use as members of the new set. @inlinable // FIXME(sil-serialize-all) public init(_ sequence: Source) where Source.Element == Element { self.init(minimumCapacity: sequence.underestimatedCount) if let s = sequence as? Set { // If this sequence is actually a native `Set`, then we can quickly // adopt its native buffer and let COW handle uniquing only // if necessary. switch s._variantBuffer { case .native(let buffer): _variantBuffer = .native(buffer) #if _runtime(_ObjC) case .cocoa(let owner): _variantBuffer = .cocoa(owner) #endif } } else { for item in sequence { insert(item) } } } /// Returns a Boolean value that indicates whether the set is a subset of the /// given sequence. /// /// Set *A* is a subset of another set *B* if every member of *A* is also a /// member of *B*. /// /// let employees = ["Alicia", "Bethany", "Chris", "Diana", "Eric"] /// let attendees: Set = ["Alicia", "Bethany", "Diana"] /// print(attendees.isSubset(of: employees)) /// // Prints "true" /// /// - Parameter possibleSuperset: A sequence of elements. `possibleSuperset` /// must be finite. /// - Returns: `true` if the set is a subset of `possibleSuperset`; /// otherwise, `false`. @inlinable public func isSubset(of possibleSuperset: S) -> Bool where S.Element == Element { // FIXME(performance): isEmpty fast path, here and elsewhere. let other = Set(possibleSuperset) return isSubset(of: other) } /// Returns a Boolean value that indicates whether the set is a strict subset /// of the given sequence. /// /// Set *A* is a strict subset of another set *B* if every member of *A* is /// also a member of *B* and *B* contains at least one element that is not a /// member of *A*. /// /// let employees = ["Alicia", "Bethany", "Chris", "Diana", "Eric"] /// let attendees: Set = ["Alicia", "Bethany", "Diana"] /// print(attendees.isStrictSubset(of: employees)) /// // Prints "true" /// /// // A set is never a strict subset of itself: /// print(attendees.isStrictSubset(of: attendees)) /// // Prints "false" /// /// - Parameter possibleStrictSuperset: A sequence of elements. /// `possibleStrictSuperset` must be finite. /// - Returns: `true` is the set is strict subset of /// `possibleStrictSuperset`; otherwise, `false`. @inlinable public func isStrictSubset(of possibleStrictSuperset: S) -> Bool where S.Element == Element { // FIXME: code duplication. let other = Set(possibleStrictSuperset) return isStrictSubset(of: other) } /// Returns a Boolean value that indicates whether the set is a superset of /// the given sequence. /// /// Set *A* is a superset of another set *B* if every member of *B* is also a /// member of *A*. /// /// let employees: Set = ["Alicia", "Bethany", "Chris", "Diana", "Eric"] /// let attendees = ["Alicia", "Bethany", "Diana"] /// print(employees.isSuperset(of: attendees)) /// // Prints "true" /// /// - Parameter possibleSubset: A sequence of elements. `possibleSubset` must /// be finite. /// - Returns: `true` if the set is a superset of `possibleSubset`; /// otherwise, `false`. @inlinable public func isSuperset(of possibleSubset: S) -> Bool where S.Element == Element { // FIXME(performance): Don't build a set; just ask if every element is in // `self`. let other = Set(possibleSubset) return other.isSubset(of: self) } /// Returns a Boolean value that indicates whether the set is a strict /// superset of the given sequence. /// /// Set *A* is a strict superset of another set *B* if every member of *B* is /// also a member of *A* and *A* contains at least one element that is *not* /// a member of *B*. /// /// let employees: Set = ["Alicia", "Bethany", "Chris", "Diana", "Eric"] /// let attendees = ["Alicia", "Bethany", "Diana"] /// print(employees.isStrictSuperset(of: attendees)) /// // Prints "true" /// print(employees.isStrictSuperset(of: employees)) /// // Prints "false" /// /// - Parameter possibleStrictSubset: A sequence of elements. /// `possibleStrictSubset` must be finite. /// - Returns: `true` if the set is a strict superset of /// `possibleStrictSubset`; otherwise, `false`. @inlinable // FIXME(sil-serialize-all) public func isStrictSuperset(of possibleStrictSubset: S) -> Bool where S.Element == Element { let other = Set(possibleStrictSubset) return other.isStrictSubset(of: self) } /// Returns a Boolean value that indicates whether the set has no members in /// common with the given sequence. /// /// In the following example, the `employees` set is disjoint with the /// elements of the `visitors` array because no name appears in both. /// /// let employees: Set = ["Alicia", "Bethany", "Chris", "Diana", "Eric"] /// let visitors = ["Marcia", "Nathaniel", "Olivia"] /// print(employees.isDisjoint(with: visitors)) /// // Prints "true" /// /// - Parameter other: A sequence of elements. `other` must be finite. /// - Returns: `true` if the set has no elements in common with `other`; /// otherwise, `false`. @inlinable // FIXME(sil-serialize-all) public func isDisjoint(with other: S) -> Bool where S.Element == Element { // FIXME(performance): Don't need to build a set. let otherSet = Set(other) return isDisjoint(with: otherSet) } /// Returns a new set with the elements of both this set and the given /// sequence. /// /// In the following example, the `attendeesAndVisitors` set is made up /// of the elements of the `attendees` set and the `visitors` array: /// /// let attendees: Set = ["Alicia", "Bethany", "Diana"] /// let visitors = ["Marcia", "Nathaniel"] /// let attendeesAndVisitors = attendees.union(visitors) /// print(attendeesAndVisitors) /// // Prints "["Diana", "Nathaniel", "Bethany", "Alicia", "Marcia"]" /// /// If the set already contains one or more elements that are also in /// `other`, the existing members are kept. If `other` contains multiple /// instances of equivalent elements, only the first instance is kept. /// /// let initialIndices = Set(0..<5) /// let expandedIndices = initialIndices.union([2, 3, 6, 6, 7, 7]) /// print(expandedIndices) /// // Prints "[2, 4, 6, 7, 0, 1, 3]" /// /// - Parameter other: A sequence of elements. `other` must be finite. /// - Returns: A new set with the unique elements of this set and `other`. @inlinable public func union(_ other: S) -> Set where S.Element == Element { var newSet = self newSet.formUnion(other) return newSet } /// Inserts the elements of the given sequence into the set. /// /// If the set already contains one or more elements that are also in /// `other`, the existing members are kept. If `other` contains multiple /// instances of equivalent elements, only the first instance is kept. /// /// var attendees: Set = ["Alicia", "Bethany", "Diana"] /// let visitors = ["Diana", "Marcia", "Nathaniel"] /// attendees.formUnion(visitors) /// print(attendees) /// // Prints "["Diana", "Nathaniel", "Bethany", "Alicia", "Marcia"]" /// /// - Parameter other: A sequence of elements. `other` must be finite. @inlinable public mutating func formUnion(_ other: S) where S.Element == Element { for item in other { insert(item) } } /// Returns a new set containing the elements of this set that do not occur /// in the given sequence. /// /// In the following example, the `nonNeighbors` set is made up of the /// elements of the `employees` set that are not elements of `neighbors`: /// /// let employees: Set = ["Alicia", "Bethany", "Chris", "Diana", "Eric"] /// let neighbors = ["Bethany", "Eric", "Forlani", "Greta"] /// let nonNeighbors = employees.subtracting(neighbors) /// print(nonNeighbors) /// // Prints "["Chris", "Diana", "Alicia"]" /// /// - Parameter other: A sequence of elements. `other` must be finite. /// - Returns: A new set. @inlinable public func subtracting(_ other: S) -> Set where S.Element == Element { return self._subtracting(other) } @inlinable // FIXME(sil-serialize-all) internal func _subtracting(_ other: S) -> Set where S.Element == Element { var newSet = self newSet.subtract(other) return newSet } /// Removes the elements of the given sequence from the set. /// /// In the following example, the elements of the `employees` set that are /// also elements of the `neighbors` array are removed. In particular, the /// names `"Bethany"` and `"Eric"` are removed from `employees`. /// /// var employees: Set = ["Alicia", "Bethany", "Chris", "Diana", "Eric"] /// let neighbors = ["Bethany", "Eric", "Forlani", "Greta"] /// employees.subtract(neighbors) /// print(employees) /// // Prints "["Chris", "Diana", "Alicia"]" /// /// - Parameter other: A sequence of elements. `other` must be finite. @inlinable // FIXME(sil-serialize-all) public mutating func subtract(_ other: S) where S.Element == Element { _subtract(other) } @inlinable // FIXME(sil-serialize-all) internal mutating func _subtract(_ other: S) where S.Element == Element { for item in other { remove(item) } } /// Returns a new set with the elements that are common to both this set and /// the given sequence. /// /// In the following example, the `bothNeighborsAndEmployees` set is made up /// of the elements that are in *both* the `employees` and `neighbors` sets. /// Elements that are in only one or the other are left out of the result of /// the intersection. /// /// let employees: Set = ["Alicia", "Bethany", "Chris", "Diana", "Eric"] /// let neighbors = ["Bethany", "Eric", "Forlani", "Greta"] /// let bothNeighborsAndEmployees = employees.intersection(neighbors) /// print(bothNeighborsAndEmployees) /// // Prints "["Bethany", "Eric"]" /// /// - Parameter other: A sequence of elements. `other` must be finite. /// - Returns: A new set. @inlinable public func intersection(_ other: S) -> Set where S.Element == Element { let otherSet = Set(other) return intersection(otherSet) } /// Removes the elements of the set that aren't also in the given sequence. /// /// In the following example, the elements of the `employees` set that are /// not also members of the `neighbors` set are removed. In particular, the /// names `"Alicia"`, `"Chris"`, and `"Diana"` are removed. /// /// var employees: Set = ["Alicia", "Bethany", "Chris", "Diana", "Eric"] /// let neighbors = ["Bethany", "Eric", "Forlani", "Greta"] /// employees.formIntersection(neighbors) /// print(employees) /// // Prints "["Bethany", "Eric"]" /// /// - Parameter other: A sequence of elements. `other` must be finite. @inlinable public mutating func formIntersection(_ other: S) where S.Element == Element { // Because `intersect` needs to both modify and iterate over // the left-hand side, the index may become invalidated during // traversal so an intermediate set must be created. // // FIXME(performance): perform this operation at a lower level // to avoid invalidating the index and avoiding a copy. let result = self.intersection(other) // The result can only have fewer or the same number of elements. // If no elements were removed, don't perform a reassignment // as this may cause an unnecessary uniquing COW. if result.count != count { self = result } } /// Returns a new set with the elements that are either in this set or in the /// given sequence, but not in both. /// /// In the following example, the `eitherNeighborsOrEmployees` set is made up /// of the elements of the `employees` and `neighbors` sets that are not in /// both `employees` *and* `neighbors`. In particular, the names `"Bethany"` /// and `"Eric"` do not appear in `eitherNeighborsOrEmployees`. /// /// let employees: Set = ["Alicia", "Bethany", "Diana", "Eric"] /// let neighbors = ["Bethany", "Eric", "Forlani"] /// let eitherNeighborsOrEmployees = employees.symmetricDifference(neighbors) /// print(eitherNeighborsOrEmployees) /// // Prints "["Diana", "Forlani", "Alicia"]" /// /// - Parameter other: A sequence of elements. `other` must be finite. /// - Returns: A new set. @inlinable public func symmetricDifference(_ other: S) -> Set where S.Element == Element { var newSet = self newSet.formSymmetricDifference(other) return newSet } /// Replace this set with the elements contained in this set or the given /// set, but not both. /// /// In the following example, the elements of the `employees` set that are /// also members of `neighbors` are removed from `employees`, while the /// elements of `neighbors` that are not members of `employees` are added to /// `employees`. In particular, the names `"Bethany"` and `"Eric"` are /// removed from `employees` while the name `"Forlani"` is added. /// /// var employees: Set = ["Alicia", "Bethany", "Diana", "Eric"] /// let neighbors = ["Bethany", "Eric", "Forlani"] /// employees.formSymmetricDifference(neighbors) /// print(employees) /// // Prints "["Diana", "Forlani", "Alicia"]" /// /// - Parameter other: A sequence of elements. `other` must be finite. @inlinable public mutating func formSymmetricDifference(_ other: S) where S.Element == Element { let otherSet = Set(other) formSymmetricDifference(otherSet) } } extension Set: CustomStringConvertible, CustomDebugStringConvertible { /// A string that represents the contents of the set. @inlinable // FIXME(sil-serialize-all) public var description: String { return _makeCollectionDescription(for: self, withTypeName: nil) } /// A string that represents the contents of the set, suitable for debugging. @inlinable // FIXME(sil-serialize-all) public var debugDescription: String { return _makeCollectionDescription(for: self, withTypeName: "Set") } } #if _runtime(_ObjC) @_silgen_name("swift_stdlib_CFSetGetValues") @usableFromInline // FIXME(sil-serialize-all) internal func _stdlib_CFSetGetValues(_ nss: _NSSet, _: UnsafeMutablePointer) /// Equivalent to `NSSet.allObjects`, but does not leave objects on the /// autorelease pool. @inlinable // FIXME(sil-serialize-all) internal func _stdlib_NSSet_allObjects(_ nss: _NSSet) -> _HeapBuffer { let count = nss.count let storage = _HeapBuffer( _HeapBufferStorage.self, count, count) _stdlib_CFSetGetValues(nss, storage.baseAddress) return storage } #endif //===--- Compiler conversion/casting entry points for Set --------===// /// Perform a non-bridged upcast that always succeeds. /// /// - Precondition: `BaseValue` is a base class or base `@objc` /// protocol (such as `AnyObject`) of `DerivedValue`. @inlinable // FIXME(sil-serialize-all) public func _setUpCast(_ source: Set) -> Set { var builder = _SetBuilder(count: source.count) for x in source { builder.add(member: x as! BaseValue) } return builder.take() } #if _runtime(_ObjC) /// Implements an unconditional upcast that involves bridging. /// /// The cast can fail if bridging fails. /// /// - Precondition: `SwiftValue` is bridged to Objective-C /// and requires non-trivial bridging. @inlinable // FIXME(sil-serialize-all) public func _setBridgeToObjectiveC( _ source: Set ) -> Set { _sanityCheck(_isClassOrObjCExistential(ObjCValue.self)) _sanityCheck(!_isBridgedVerbatimToObjectiveC(SwiftValue.self)) var result = Set(minimumCapacity: source.count) let valueBridgesDirectly = _isBridgedVerbatimToObjectiveC(SwiftValue.self) == _isBridgedVerbatimToObjectiveC(ObjCValue.self) for member in source { var bridgedMember: ObjCValue if valueBridgesDirectly { bridgedMember = unsafeBitCast(member, to: ObjCValue.self) } else { let bridged: AnyObject = _bridgeAnythingToObjectiveC(member) bridgedMember = unsafeBitCast(bridged, to: ObjCValue.self) } result.insert(bridgedMember) } return result } #endif /// Called by the casting machinery. @_silgen_name("_swift_setDownCastIndirect") internal func _setDownCastIndirect( _ source: UnsafePointer>, _ target: UnsafeMutablePointer>) { target.initialize(to: _setDownCast(source.pointee)) } /// Implements a forced downcast. This operation should have O(1) complexity. /// /// The cast can fail if bridging fails. The actual checks and bridging can be /// deferred. /// /// - Precondition: `DerivedValue` is a subtype of `BaseValue` and both /// are reference types. @inlinable // FIXME(sil-serialize-all) public func _setDownCast(_ source: Set) -> Set { #if _runtime(_ObjC) if _isClassOrObjCExistential(BaseValue.self) && _isClassOrObjCExistential(DerivedValue.self) { switch source._variantBuffer { case _VariantSetBuffer.native(let buffer): return Set(_immutableCocoaSet: buffer.bridged()) case _VariantSetBuffer.cocoa(let cocoaBuffer): return Set(_immutableCocoaSet: cocoaBuffer.cocoaSet) } } #endif return _setDownCastConditional(source)! } /// Called by the casting machinery. @_silgen_name("_swift_setDownCastConditionalIndirect") internal func _setDownCastConditionalIndirect( _ source: UnsafePointer>, _ target: UnsafeMutablePointer> ) -> Bool { if let result: Set = _setDownCastConditional(source.pointee) { target.initialize(to: result) return true } return false } /// Implements a conditional downcast. /// /// If the cast fails, the function returns `nil`. All checks should be /// performed eagerly. /// /// - Precondition: `DerivedValue` is a subtype of `BaseValue` and both /// are reference types. @inlinable // FIXME(sil-serialize-all) public func _setDownCastConditional( _ source: Set ) -> Set? { var result = Set(minimumCapacity: source.count) for member in source { if let derivedMember = member as? DerivedValue { result.insert(derivedMember) continue } return nil } return result } #if _runtime(_ObjC) /// Implements an unconditional downcast that involves bridging. /// /// - Precondition: At least one of `SwiftValue` is a bridged value /// type, and the corresponding `ObjCValue` is a reference type. @inlinable // FIXME(sil-serialize-all) public func _setBridgeFromObjectiveC( _ source: Set ) -> Set { let result: Set? = _setBridgeFromObjectiveCConditional(source) _precondition(result != nil, "This set cannot be bridged from Objective-C") return result! } /// Implements a conditional downcast that involves bridging. /// /// If the cast fails, the function returns `nil`. All checks should be /// performed eagerly. /// /// - Precondition: At least one of `SwiftValue` is a bridged value /// type, and the corresponding `ObjCValue` is a reference type. @inlinable // FIXME(sil-serialize-all) public func _setBridgeFromObjectiveCConditional< ObjCValue, SwiftValue >( _ source: Set ) -> Set? { _sanityCheck(_isClassOrObjCExistential(ObjCValue.self)) _sanityCheck(!_isBridgedVerbatimToObjectiveC(SwiftValue.self)) let valueBridgesDirectly = _isBridgedVerbatimToObjectiveC(SwiftValue.self) == _isBridgedVerbatimToObjectiveC(ObjCValue.self) var result = Set(minimumCapacity: source.count) for value in source { // Downcast the value. var resultValue: SwiftValue if valueBridgesDirectly { if let bridgedValue = value as? SwiftValue { resultValue = bridgedValue } else { return nil } } else { if let bridgedValue = _conditionallyBridgeFromObjectiveC( _reinterpretCastToAnyObject(value), SwiftValue.self) { resultValue = bridgedValue } else { return nil } } result.insert(resultValue) } return result } #endif extension Set { /// Removes the elements of the given set from this set. /// /// In the following example, the elements of the `employees` set that are /// also members of the `neighbors` set are removed. In particular, the /// names `"Bethany"` and `"Eric"` are removed from `employees`. /// /// var employees: Set = ["Alicia", "Bethany", "Chris", "Diana", "Eric"] /// let neighbors: Set = ["Bethany", "Eric", "Forlani", "Greta"] /// employees.subtract(neighbors) /// print(employees) /// // Prints "["Diana", "Chris", "Alicia"]" /// /// - Parameter other: Another set. @inlinable // FIXME(sil-serialize-all) public mutating func subtract(_ other: Set) { _subtract(other) } /// Returns a Boolean value that indicates whether this set is a subset of /// the given set. /// /// Set *A* is a subset of another set *B* if every member of *A* is also a /// member of *B*. /// /// let employees: Set = ["Alicia", "Bethany", "Chris", "Diana", "Eric"] /// let attendees: Set = ["Alicia", "Bethany", "Diana"] /// print(attendees.isSubset(of: employees)) /// // Prints "true" /// /// - Parameter other: Another set. /// - Returns: `true` if the set is a subset of `other`; otherwise, `false`. @inlinable public func isSubset(of other: Set) -> Bool { let (isSubset, isEqual) = _compareSets(self, other) return isSubset || isEqual } /// Returns a Boolean value that indicates whether this set is a superset of /// the given set. /// /// Set *A* is a superset of another set *B* if every member of *B* is also a /// member of *A*. /// /// let employees: Set = ["Alicia", "Bethany", "Chris", "Diana", "Eric"] /// let attendees: Set = ["Alicia", "Bethany", "Diana"] /// print(employees.isSuperset(of: attendees)) /// // Prints "true" /// /// - Parameter other: Another set. /// - Returns: `true` if the set is a superset of `other`; otherwise, /// `false`. @inlinable public func isSuperset(of other: Set) -> Bool { return other.isSubset(of: self) } /// Returns a Boolean value that indicates whether this set has no members in /// common with the given set. /// /// In the following example, the `employees` set is disjoint with the /// `visitors` set because no name appears in both sets. /// /// let employees: Set = ["Alicia", "Bethany", "Chris", "Diana", "Eric"] /// let visitors: Set = ["Marcia", "Nathaniel", "Olivia"] /// print(employees.isDisjoint(with: visitors)) /// // Prints "true" /// /// - Parameter other: Another set. /// - Returns: `true` if the set has no elements in common with `other`; /// otherwise, `false`. @inlinable public func isDisjoint(with other: Set) -> Bool { for member in self { if other.contains(member) { return false } } return true } /// Returns a new set containing the elements of this set that do not occur /// in the given set. /// /// In the following example, the `nonNeighbors` set is made up of the /// elements of the `employees` set that are not elements of `neighbors`: /// /// let employees: Set = ["Alicia", "Bethany", "Chris", "Diana", "Eric"] /// let neighbors: Set = ["Bethany", "Eric", "Forlani", "Greta"] /// let nonNeighbors = employees.subtracting(neighbors) /// print(nonNeighbors) /// // Prints "["Diana", "Chris", "Alicia"]" /// /// - Parameter other: Another set. /// - Returns: A new set. @inlinable public func subtracting(_ other: Set) -> Set { return self._subtracting(other) } /// Returns a Boolean value that indicates whether the set is a strict /// superset of the given sequence. /// /// Set *A* is a strict superset of another set *B* if every member of *B* is /// also a member of *A* and *A* contains at least one element that is *not* /// a member of *B*. /// /// let employees: Set = ["Alicia", "Bethany", "Chris", "Diana", "Eric"] /// let attendees: Set = ["Alicia", "Bethany", "Diana"] /// print(employees.isStrictSuperset(of: attendees)) /// // Prints "true" /// print(employees.isStrictSuperset(of: employees)) /// // Prints "false" /// /// - Parameter other: Another set. /// - Returns: `true` if the set is a strict superset of /// `other`; otherwise, `false`. @inlinable public func isStrictSuperset(of other: Set) -> Bool { return self.isSuperset(of: other) && self != other } /// Returns a Boolean value that indicates whether the set is a strict subset /// of the given sequence. /// /// Set *A* is a strict subset of another set *B* if every member of *A* is /// also a member of *B* and *B* contains at least one element that is not a /// member of *A*. /// /// let employees: Set = ["Alicia", "Bethany", "Chris", "Diana", "Eric"] /// let attendees: Set = ["Alicia", "Bethany", "Diana"] /// print(attendees.isStrictSubset(of: employees)) /// // Prints "true" /// /// // A set is never a strict subset of itself: /// print(attendees.isStrictSubset(of: attendees)) /// // Prints "false" /// /// - Parameter other: Another set. /// - Returns: `true` if the set is a strict subset of /// `other`; otherwise, `false`. @inlinable public func isStrictSubset(of other: Set) -> Bool { return other.isStrictSuperset(of: self) } /// Returns a new set with the elements that are common to both this set and /// the given sequence. /// /// In the following example, the `bothNeighborsAndEmployees` set is made up /// of the elements that are in *both* the `employees` and `neighbors` sets. /// Elements that are in only one or the other are left out of the result of /// the intersection. /// /// let employees: Set = ["Alicia", "Bethany", "Chris", "Diana", "Eric"] /// let neighbors: Set = ["Bethany", "Eric", "Forlani", "Greta"] /// let bothNeighborsAndEmployees = employees.intersection(neighbors) /// print(bothNeighborsAndEmployees) /// // Prints "["Bethany", "Eric"]" /// /// - Parameter other: Another set. /// - Returns: A new set. @inlinable public func intersection(_ other: Set) -> Set { var newSet = Set() for member in self { if other.contains(member) { newSet.insert(member) } } return newSet } /// Removes the elements of the set that are also in the given sequence and /// adds the members of the sequence that are not already in the set. /// /// In the following example, the elements of the `employees` set that are /// also members of `neighbors` are removed from `employees`, while the /// elements of `neighbors` that are not members of `employees` are added to /// `employees`. In particular, the names `"Alicia"`, `"Chris"`, and /// `"Diana"` are removed from `employees` while the names `"Forlani"` and /// `"Greta"` are added. /// /// var employees: Set = ["Alicia", "Bethany", "Chris", "Diana", "Eric"] /// let neighbors: Set = ["Bethany", "Eric", "Forlani", "Greta"] /// employees.formSymmetricDifference(neighbors) /// print(employees) /// // Prints "["Diana", "Chris", "Forlani", "Alicia", "Greta"]" /// /// - Parameter other: Another set. @inlinable public mutating func formSymmetricDifference(_ other: Set) { for member in other { if contains(member) { remove(member) } else { insert(member) } } } } //===--- APIs templated for Dictionary and Set ----------------------------===// /// An instance of this class has all `Set` data tail-allocated. /// Enough bytes are allocated to hold the bitmap for marking valid entries, /// keys, and values. The data layout starts with the bitmap, followed by the /// keys, followed by the values. // // See the docs at the top of the file for more details on this type // // NOTE: The precise layout of this type is relied on in the runtime // to provide a statically allocated empty singleton. // See stdlib/public/stubs/GlobalObjects.cpp for details. @_fixed_layout // FIXME(sil-serialize-all) @usableFromInline // FIXME(sil-serialize-all) @_objc_non_lazy_realization internal class _RawNativeSetStorage: _SwiftNativeNSSet, _NSSetCore { internal typealias RawStorage = _RawNativeSetStorage @usableFromInline // FIXME(sil-serialize-all) @nonobjc internal final var bucketCount: Int @usableFromInline // FIXME(sil-serialize-all) internal final var count: Int @usableFromInline // FIXME(sil-serialize-all) internal final var initializedEntries: _UnsafeBitMap @usableFromInline // FIXME(sil-serialize-all) @nonobjc internal final var keys: UnsafeMutableRawPointer @usableFromInline // FIXME(sil-serialize-all) internal final var seed: (UInt64, UInt64) // This API is unsafe and needs a `_fixLifetime` in the caller. @inlinable // FIXME(sil-serialize-all) @nonobjc internal final var _initializedHashtableEntriesBitMapBuffer: UnsafeMutablePointer { return UnsafeMutablePointer(Builtin.projectTailElems(self, UInt.self)) } /// The empty singleton that is used for every single Dictionary that is /// created without any elements. The contents of the storage should never /// be mutated. @inlinable // FIXME(sil-serialize-all) @nonobjc internal static var empty: RawStorage { return Builtin.bridgeFromRawPointer( Builtin.addressof(&_swiftEmptySetStorage)) } // This type is made with allocWithTailElems, so no init is ever called. // But we still need to have an init to satisfy the compiler. @inlinable // FIXME(sil-serialize-all) @nonobjc internal init(_doNotCallMe: ()) { _sanityCheckFailure("Only create this by using the `empty` singleton") } #if _runtime(_ObjC) // // NSSet implementation, assuming Self is the empty singleton // /// Get the NSEnumerator implementation for self. /// _HashableTypedNativeSetStorage overloads this to give /// _NativeSelfNSEnumerator proper type parameters. @inlinable // FIXME(sil-serialize-all) @objc internal func enumerator() -> _NSEnumerator { return _NativeSetNSEnumerator( _NativeSetBuffer(_storage: self)) } @inlinable // FIXME(sil-serialize-all) @objc(copyWithZone:) internal func copy(with zone: _SwiftNSZone?) -> AnyObject { return self } @inlinable // FIXME(sil-serialize-all) @objc(countByEnumeratingWithState:objects:count:) internal func countByEnumerating( with state: UnsafeMutablePointer<_SwiftNSFastEnumerationState>, objects: UnsafeMutablePointer?, count: Int ) -> Int { // Even though we never do anything in here, we need to update the // state so that callers know we actually ran. var theState = state.pointee if theState.state == 0 { theState.state = 1 // Arbitrary non-zero value. theState.itemsPtr = AutoreleasingUnsafeMutablePointer(objects) theState.mutationsPtr = _fastEnumerationStorageMutationsPtr } state.pointee = theState return 0 } @inlinable // FIXME(sil-serialize-all) @objc internal required init(objects: UnsafePointer, count: Int) { _sanityCheckFailure("don't call this designated initializer") } @inlinable // FIXME(sil-serialize-all) @objc internal func member(_ object: AnyObject) -> AnyObject? { return nil } @inlinable // FIXME(sil-serialize-all) @objc internal func objectEnumerator() -> _NSEnumerator { return enumerator() } #endif } // See the docs at the top of this file for a description of this type @_fixed_layout // FIXME(sil-serialize-all) @usableFromInline internal class _TypedNativeSetStorage: _RawNativeSetStorage { internal typealias Key = Element internal typealias Value = Element deinit { let keys = self.keys.assumingMemoryBound(to: Key.self) if !_isPOD(Key.self) { for i in 0 ..< bucketCount { if initializedEntries[i] { (keys+i).deinitialize(count: 1) } } } _fixLifetime(self) } // This type is made with allocWithTailElems, so no init is ever called. // But we still need to have an init to satisfy the compiler. @inlinable // FIXME(sil-serialize-all) @nonobjc override internal init(_doNotCallMe: ()) { _sanityCheckFailure("Only create this by calling Buffer's inits") } #if _runtime(_ObjC) @inlinable // FIXME(sil-serialize-all) @objc internal required init(objects: UnsafePointer, count: Int) { _sanityCheckFailure("don't call this designated initializer") } #endif } // See the docs at the top of this file for a description of this type @_fixed_layout // FIXME(sil-serialize-all) @usableFromInline final internal class _HashableTypedNativeSetStorage : _TypedNativeSetStorage { internal typealias FullContainer = Set internal typealias Buffer = _NativeSetBuffer // This type is made with allocWithTailElems, so no init is ever called. // But we still need to have an init to satisfy the compiler. @inlinable // FIXME(sil-serialize-all) @nonobjc override internal init(_doNotCallMe: ()) { _sanityCheckFailure("Only create this by calling Buffer's inits'") } #if _runtime(_ObjC) // NSSet bridging: // All actual functionality comes from buffer/full, which are // just wrappers around a RawNativeSetStorage. @inlinable // FIXME(sil-serialize-all) internal var buffer: Buffer { return Buffer(_storage: self) } @inlinable // FIXME(sil-serialize-all) internal var full: FullContainer { return FullContainer(_nativeBuffer: buffer) } @inlinable // FIXME(sil-serialize-all) internal override func enumerator() -> _NSEnumerator { return _NativeSetNSEnumerator( Buffer(_storage: self)) } @inlinable // FIXME(sil-serialize-all) @objc(countByEnumeratingWithState:objects:count:) internal override func countByEnumerating( with state: UnsafeMutablePointer<_SwiftNSFastEnumerationState>, objects: UnsafeMutablePointer?, count: Int ) -> Int { var theState = state.pointee if theState.state == 0 { theState.state = 1 // Arbitrary non-zero value. theState.itemsPtr = AutoreleasingUnsafeMutablePointer(objects) theState.mutationsPtr = _fastEnumerationStorageMutationsPtr theState.extra.0 = CUnsignedLong(full.startIndex._nativeIndex.offset) } // Test 'objects' rather than 'count' because (a) this is very rare anyway, // and (b) the optimizer should then be able to optimize away the // unwrapping check below. if _slowPath(objects == nil) { return 0 } let unmanagedObjects = _UnmanagedAnyObjectArray(objects!) var currIndex = _NativeSetIndex( offset: Int(theState.extra.0)) let endIndex = buffer.endIndex var stored = 0 for i in 0.. AnyObject? { guard let nativeKey = _conditionallyBridgeFromObjectiveC(aKey, Key.self) else { return nil } let (i, found) = buffer._find(nativeKey, startBucket: buffer._bucket(nativeKey)) if found { return buffer.bridgedValue(at: i) } return nil } @inlinable // FIXME(sil-serialize-all) @objc internal required init(objects: UnsafePointer, count: Int) { _sanityCheckFailure("don't call this designated initializer") } @inlinable // FIXME(sil-serialize-all) @objc override internal func member(_ object: AnyObject) -> AnyObject? { return getObjectFor(object) } #endif } /// A wrapper around _RawNativeSetStorage that provides most of the /// implementation of Set. /// /// This type and most of its functionality doesn't require Hashable at all. /// The reason for this is to support storing AnyObject for bridging /// with _SwiftDeferredNSSet. What functionality actually relies on /// Hashable can be found in an extension. @usableFromInline @_fixed_layout internal struct _NativeSetBuffer { internal typealias RawStorage = _RawNativeSetStorage internal typealias TypedStorage = _TypedNativeSetStorage internal typealias Buffer = _NativeSetBuffer internal typealias Index = _NativeSetIndex internal typealias Key = Element internal typealias Value = Element internal typealias SequenceElementWithoutLabels = Element /// See this comments on _RawNativeSetStorage and its subclasses to /// understand why we store an untyped storage here. @usableFromInline // FIXME(sil-serialize-all) internal var _storage: RawStorage /// Creates a Buffer with a storage that is typed, but doesn't understand /// Hashing. Mostly for bridging; prefer `init(minimumCapacity:)`. @inlinable // FIXME(sil-serialize-all) internal init(_exactBucketCount bucketCount: Int, unhashable: ()) { let bitmapWordCount = _UnsafeBitMap.sizeInWords(forSizeInBits: bucketCount) let storage = Builtin.allocWithTailElems_2(TypedStorage.self, bitmapWordCount._builtinWordValue, UInt.self, bucketCount._builtinWordValue, Key.self) self.init(_exactBucketCount: bucketCount, storage: storage) } /// Given a bucket count and uninitialized RawStorage, completes the /// initialization and returns a Buffer. @inlinable // FIXME(sil-serialize-all) internal init(_exactBucketCount bucketCount: Int, storage: RawStorage) { storage.bucketCount = bucketCount storage.count = 0 self.init(_storage: storage) let initializedEntries = _UnsafeBitMap( storage: _initializedHashtableEntriesBitMapBuffer, bitCount: bucketCount) initializedEntries.initializeToZero() // Compute all the array offsets now, so we don't have to later let bitmapAddr = Builtin.projectTailElems(_storage, UInt.self) let bitmapWordCount = _UnsafeBitMap.sizeInWords(forSizeInBits: bucketCount) let keysAddr = Builtin.getTailAddr_Word(bitmapAddr, bitmapWordCount._builtinWordValue, UInt.self, Key.self) // Initialize header _storage.initializedEntries = initializedEntries _storage.keys = UnsafeMutableRawPointer(keysAddr) // We assign a unique hash seed to each distinct hash table size, so that we // avoid certain copy operations becoming quadratic, without breaking value // semantics. (See https://bugs.swift.org/browse/SR-3268) // // We don't need to generate a brand new seed for each table size: it's // enough to change a single bit in the global seed by XORing the bucket // count to it. (The bucket count is always a power of two.) // // FIXME: Use an approximation of true per-instance seeding. We can't just // use the base address, because COW copies need to share the same seed. let seed = _Hasher._seed let perturbation = bucketCount _storage.seed = (seed.0 ^ UInt64(truncatingIfNeeded: perturbation), seed.1) } // Forwarding the individual fields of the storage in various forms @inlinable // FIXME(sil-serialize-all) internal var bucketCount: Int { return _assumeNonNegative(_storage.bucketCount) } @inlinable // FIXME(sil-serialize-all) internal var count: Int { set { _storage.count = newValue } get { return _assumeNonNegative(_storage.count) } } @inlinable // FIXME(sil-serialize-all) internal var _initializedHashtableEntriesBitMapBuffer: UnsafeMutablePointer { return _storage._initializedHashtableEntriesBitMapBuffer } // This API is unsafe and needs a `_fixLifetime` in the caller. @inlinable // FIXME(sil-serialize-all) internal var keys: UnsafeMutablePointer { return _storage.keys.assumingMemoryBound(to: Key.self) } /// Constructs a buffer adopting the given storage. @inlinable // FIXME(sil-serialize-all) internal init(_storage: RawStorage) { self._storage = _storage } /// Constructs an instance from the empty singleton. @inlinable // FIXME(sil-serialize-all) internal init() { self._storage = RawStorage.empty } // Most of the implementation of the _HashBuffer protocol, // but only the parts that don't actually rely on hashing. @inlinable // FIXME(sil-serialize-all) @inline(__always) internal func key(at i: Int) -> Key { _sanityCheck(i >= 0 && i < bucketCount) _sanityCheck(isInitializedEntry(at: i)) defer { _fixLifetime(self) } let res = (keys + i).pointee return res } #if _runtime(_ObjC) /// Returns the key at the given Index, bridged. /// /// Intended for use with verbatim bridgeable keys. @inlinable // FIXME(sil-serialize-all) internal func bridgedKey(at index: Index) -> AnyObject { let k = key(at: index.offset) return _bridgeAnythingToObjectiveC(k) } /// Returns the value at the given Index, bridged. /// /// Intended for use with verbatim bridgeable keys. @inlinable // FIXME(sil-serialize-all) internal func bridgedValue(at index: Index) -> AnyObject { let v = value(at: index.offset) return _bridgeAnythingToObjectiveC(v) } #endif @inlinable // FIXME(sil-serialize-all) internal func isInitializedEntry(at i: Int) -> Bool { _sanityCheck(i >= 0 && i < bucketCount) defer { _fixLifetime(self) } return _storage.initializedEntries[i] } @inlinable // FIXME(sil-serialize-all) @_transparent internal func destroyEntry(at i: Int) { _sanityCheck(isInitializedEntry(at: i)) defer { _fixLifetime(self) } (keys + i).deinitialize(count: 1) _storage.initializedEntries[i] = false } @inlinable // FIXME(sil-serialize-all) @_transparent internal func initializeKey(_ k: Key, at i: Int) { _sanityCheck(!isInitializedEntry(at: i)) defer { _fixLifetime(self) } (keys + i).initialize(to: k) _storage.initializedEntries[i] = true } @inlinable // FIXME(sil-serialize-all) @_transparent internal func moveInitializeEntry(from: Buffer, at: Int, toEntryAt: Int) { _sanityCheck(!isInitializedEntry(at: toEntryAt)) defer { _fixLifetime(self) } (keys + toEntryAt).initialize(to: (from.keys + at).move()) from._storage.initializedEntries[at] = false _storage.initializedEntries[toEntryAt] = true } /// Alias for key(at:) in Sets for better code reuse @inlinable // FIXME(sil-serialize-all) @_transparent internal func value(at i: Int) -> Value { return key(at: i) } @inlinable // FIXME(sil-serialize-all) internal func setKey(_ key: Key, at i: Int) { _sanityCheck(i >= 0 && i < bucketCount) _sanityCheck(isInitializedEntry(at: i)) defer { _fixLifetime(self) } (keys + i).pointee = key } @inlinable // FIXME(sil-serialize-all) internal var startIndex: Index { // We start at "index after -1" instead of "0" because we need to find the // first occupied slot. return index(after: Index(offset: -1)) } @inlinable // FIXME(sil-serialize-all) internal var endIndex: Index { return Index(offset: bucketCount) } @inlinable // FIXME(sil-serialize-all) internal func index(after i: Index) -> Index { _precondition(i != endIndex) var idx = i.offset + 1 while idx < bucketCount && !isInitializedEntry(at: idx) { idx += 1 } return Index(offset: idx) } @inlinable // FIXME(sil-serialize-all) internal func formIndex(after i: inout Index) { i = index(after: i) } @inlinable // FIXME(sil-serialize-all) internal func assertingGet(_ i: Index) -> SequenceElement { _precondition(i.offset >= 0 && i.offset < bucketCount) _precondition( isInitializedEntry(at: i.offset), "Attempting to access Set elements using an invalid Index") let key = self.key(at: i.offset) return key } } extension _NativeSetBuffer where Element: Hashable { internal typealias HashTypedStorage = _HashableTypedNativeSetStorage internal typealias SequenceElement = Element @inlinable // FIXME(sil-serialize-all) @inline(__always) internal init(minimumCapacity: Int) { let bucketCount = _NativeSetBuffer.bucketCount( forCapacity: minimumCapacity, maxLoadFactorInverse: _hashContainerDefaultMaxLoadFactorInverse) self.init(bucketCount: bucketCount) } @inlinable // FIXME(sil-serialize-all) @inline(__always) internal init(bucketCount: Int) { // Actual bucket count is the next power of 2 greater than or equal to // bucketCount. Make sure that is representable. _sanityCheck(bucketCount <= (Int.max >> 1) + 1) let buckets = 1 &<< ((Swift.max(bucketCount, 2) - 1)._binaryLogarithm() + 1) self.init(_exactBucketCount: buckets) } /// Create a buffer instance with room for at least 'bucketCount' entries, /// marking all entries invalid. @inlinable // FIXME(sil-serialize-all) internal init(_exactBucketCount bucketCount: Int) { let bitmapWordCount = _UnsafeBitMap.sizeInWords(forSizeInBits: bucketCount) let storage = Builtin.allocWithTailElems_2(HashTypedStorage.self, bitmapWordCount._builtinWordValue, UInt.self, bucketCount._builtinWordValue, Key.self) self.init(_exactBucketCount: bucketCount, storage: storage) } #if _runtime(_ObjC) @inlinable // FIXME(sil-serialize-all) internal func bridged() -> _NSSet { // We can zero-cost bridge if our keys are verbatim // or if we're the empty singleton. // Temporary var for SOME type safety before a cast. let nsSet: _NSSetCore if (_isBridgedVerbatimToObjectiveC(Key.self) && _isBridgedVerbatimToObjectiveC(Value.self)) || self._storage === RawStorage.empty { nsSet = self._storage } else { nsSet = _SwiftDeferredNSSet(nativeBuffer: self) } // Cast from "minimal NSSet" to "NSSet" // Note that if you actually ask Swift for this cast, it will fail. // Never trust a shadow protocol! return unsafeBitCast(nsSet, to: _NSSet.self) } #endif /// A textual representation of `self`. @inlinable // FIXME(sil-serialize-all) internal var description: String { var result = "" #if INTERNAL_CHECKS_ENABLED for i in 0.. Int { var hasher = _Hasher(_seed: _storage.seed) hasher.combine(k) return hasher.finalize() & _bucketMask } @inlinable // FIXME(sil-serialize-all) internal func _index(after bucket: Int) -> Int { // Bucket is within 0 and bucketCount. Therefore adding 1 does not overflow. return (bucket &+ 1) & _bucketMask } @inlinable // FIXME(sil-serialize-all) internal func _prev(_ bucket: Int) -> Int { // Bucket is not negative. Therefore subtracting 1 does not overflow. return (bucket &- 1) & _bucketMask } /// Search for a given key starting from the specified bucket. /// /// If the key is not present, returns the position where it could be /// inserted. @inlinable // FIXME(sil-serialize-all) @inline(__always) internal func _find(_ key: Key, startBucket: Int) -> (pos: Index, found: Bool) { var bucket = startBucket // The invariant guarantees there's always a hole, so we just loop // until we find one while true { let isHole = !isInitializedEntry(at: bucket) if isHole { return (Index(offset: bucket), false) } if self.key(at: bucket) == key { return (Index(offset: bucket), true) } bucket = _index(after: bucket) } } @inlinable // FIXME(sil-serialize-all) @_transparent internal static func bucketCount( forCapacity capacity: Int, maxLoadFactorInverse: Double ) -> Int { // `capacity + 1` below ensures that we don't fill in the last hole return max(Int((Double(capacity) * maxLoadFactorInverse).rounded(.up)), capacity + 1) } /// Buffer should be uniquely referenced. /// The `key` should not be present in the Set. /// This function does *not* update `count`. @inlinable // FIXME(sil-serialize-all) internal func unsafeAddNew(key newKey: Element) { let (i, found) = _find(newKey, startBucket: _bucket(newKey)) _precondition( !found, "Duplicate element found in Set. Elements may have been mutated after insertion") initializeKey(newKey, at: i.offset) } // // _HashBuffer conformance // @inlinable // FIXME(sil-serialize-all) @inline(__always) internal func index(forKey key: Key) -> Index? { if count == 0 { // Fast path that avoids computing the hash of the key. return nil } let (i, found) = _find(key, startBucket: _bucket(key)) return found ? i : nil } @inlinable // FIXME(sil-serialize-all) internal func assertingGet(_ key: Key) -> Value { let (i, found) = _find(key, startBucket: _bucket(key)) _precondition(found, "Key not found") return self.key(at: i.offset) } @inlinable // FIXME(sil-serialize-all) @inline(__always) internal func maybeGet(_ key: Key) -> Value? { if count == 0 { // Fast path that avoids computing the hash of the key. return nil } let (i, found) = _find(key, startBucket: _bucket(key)) if found { return self.key(at: i.offset) } return nil } @inlinable // FIXME(sil-serialize-all) @discardableResult internal func updateValue(_ value: Value, forKey key: Key) -> Value? { _sanityCheckFailure( "don't call mutating methods on _NativeSetBuffer") } @inlinable // FIXME(sil-serialize-all) @discardableResult internal func insert( _ value: Value, forKey key: Key ) -> (inserted: Bool, memberAfterInsert: Value) { _sanityCheckFailure( "don't call mutating methods on _NativeSetBuffer") } @inlinable // FIXME(sil-serialize-all) @discardableResult internal func remove(at index: Index) -> SequenceElement { _sanityCheckFailure( "don't call mutating methods on _NativeSetBuffer") } @inlinable // FIXME(sil-serialize-all) @discardableResult internal func removeValue(forKey key: Key) -> Value? { _sanityCheckFailure( "don't call mutating methods on _NativeSetBuffer") } @inlinable // FIXME(sil-serialize-all) internal func removeAll(keepingCapacity keepCapacity: Bool) { _sanityCheckFailure( "don't call mutating methods on _NativeSetBuffer") } @inlinable // FIXME(sil-serialize-all) internal static func fromArray(_ elements: [SequenceElementWithoutLabels]) -> Buffer { if elements.isEmpty { return Buffer() } var nativeBuffer = Buffer(minimumCapacity: elements.count) var count = 0 for key in elements { let (i, found) = nativeBuffer._find(key, startBucket: nativeBuffer._bucket(key)) if found { continue } nativeBuffer.initializeKey(key, at: i.offset) count += 1 } nativeBuffer.count = count return nativeBuffer } } #if _runtime(_ObjC) /// An NSEnumerator that works with any NativeSetBuffer of /// verbatim bridgeable elements. Used by the various NSSet impls. @_fixed_layout // FIXME(sil-serialize-all) @usableFromInline // FIXME(sil-serialize-all) final internal class _NativeSetNSEnumerator : _SwiftNativeNSEnumerator, _NSEnumerator { internal typealias Buffer = _NativeSetBuffer internal typealias Index = _NativeSetIndex @inlinable // FIXME(sil-serialize-all) internal override required init() { _sanityCheckFailure("don't call this designated initializer") } @inlinable // FIXME(sil-serialize-all) internal init(_ buffer: Buffer) { self.buffer = buffer nextIndex = buffer.startIndex endIndex = buffer.endIndex } @usableFromInline // FIXME(sil-serialize-all) internal var buffer: Buffer @usableFromInline // FIXME(sil-serialize-all) internal var nextIndex: Index @usableFromInline // FIXME(sil-serialize-all) internal var endIndex: Index // // NSEnumerator implementation. // // Do not call any of these methods from the standard library! // @inlinable // FIXME(sil-serialize-all) @objc internal func nextObject() -> AnyObject? { if nextIndex == endIndex { return nil } let key = buffer.bridgedKey(at: nextIndex) buffer.formIndex(after: &nextIndex) return key } @inlinable // FIXME(sil-serialize-all) @objc(countByEnumeratingWithState:objects:count:) internal func countByEnumerating( with state: UnsafeMutablePointer<_SwiftNSFastEnumerationState>, objects: UnsafeMutablePointer, count: Int ) -> Int { var theState = state.pointee if theState.state == 0 { theState.state = 1 // Arbitrary non-zero value. theState.itemsPtr = AutoreleasingUnsafeMutablePointer(objects) theState.mutationsPtr = _fastEnumerationStorageMutationsPtr } if nextIndex == endIndex { state.pointee = theState return 0 } // Return only a single element so that code can start iterating via fast // enumeration, terminate it, and continue via NSEnumerator. let key = buffer.bridgedKey(at: nextIndex) buffer.formIndex(after: &nextIndex) let unmanagedObjects = _UnmanagedAnyObjectArray(objects) unmanagedObjects[0] = key state.pointee = theState return 1 } } #endif #if _runtime(_ObjC) /// This class exists for Objective-C bridging. It holds a reference to a /// NativeSetBuffer, and can be upcast to NSSelf when bridging is necessary. /// This is the fallback implementation for situations where toll-free bridging /// isn't possible. On first access, a NativeSetBuffer of AnyObject will be /// constructed containing all the bridged elements. @_fixed_layout // FIXME(sil-serialize-all) @usableFromInline // FIXME(sil-serialize-all) final internal class _SwiftDeferredNSSet : _SwiftNativeNSSet, _NSSetCore { internal typealias NativeBuffer = _NativeSetBuffer internal typealias BridgedBuffer = _NativeSetBuffer internal typealias NativeIndex = _NativeSetIndex internal typealias BridgedIndex = _NativeSetIndex internal typealias Key = Element internal typealias Value = Element @inlinable // FIXME(sil-serialize-all) @nonobjc internal init(bucketCount: Int = 2) { nativeBuffer = NativeBuffer(bucketCount: bucketCount) super.init() } @inlinable // FIXME(sil-serialize-all) internal init(nativeBuffer: NativeBuffer) { self.nativeBuffer = nativeBuffer super.init() } // This stored property should be stored at offset zero. We perform atomic // operations on it. // // Do not access this property directly. @usableFromInline // FIXME(sil-serialize-all) @nonobjc internal var _heapStorageBridged_DoNotUse: AnyObject? /// The unbridged elements. @usableFromInline // FIXME(sil-serialize-all) internal var nativeBuffer: NativeBuffer @inlinable // FIXME(sil-serialize-all) @objc(copyWithZone:) internal func copy(with zone: _SwiftNSZone?) -> AnyObject { // Instances of this class should be visible outside of standard library as // having `NSSet` type, which is immutable. return self } // // NSSet implementation. // // Do not call any of these methods from the standard library! Use only // `nativeBuffer`. // @inlinable // FIXME(sil-serialize-all) @objc internal required init(objects: UnsafePointer, count: Int) { _sanityCheckFailure("don't call this designated initializer") } @inlinable // FIXME(sil-serialize-all) @objc internal func member(_ object: AnyObject) -> AnyObject? { return bridgingObjectForKey(object) } @inlinable // FIXME(sil-serialize-all) @objc internal func objectEnumerator() -> _NSEnumerator { return enumerator() } /// Returns the pointer to the stored property, which contains bridged /// Set elements. @inlinable // FIXME(sil-serialize-all) @nonobjc internal var _heapStorageBridgedPtr: UnsafeMutablePointer { return _getUnsafePointerToStoredProperties(self).assumingMemoryBound( to: Optional.self) } /// The buffer for bridged Set elements, if present. @inlinable // FIXME(sil-serialize-all) @nonobjc internal var _bridgedStorage: BridgedBuffer.RawStorage? { get { if let ref = _stdlib_atomicLoadARCRef(object: _heapStorageBridgedPtr) { return unsafeDowncast(ref, to: BridgedBuffer.RawStorage.self) } return nil } } /// Attach a buffer for bridged Set elements. @inlinable // FIXME(sil-serialize-all) @nonobjc internal func _initializeHeapStorageBridged(_ newStorage: AnyObject) { _stdlib_atomicInitializeARCRef( object: _heapStorageBridgedPtr, desired: newStorage) } /// Returns the bridged Set values. @inlinable // FIXME(sil-serialize-all) internal var bridgedBuffer: BridgedBuffer { return BridgedBuffer(_storage: _bridgedStorage!) } @inlinable // FIXME(sil-serialize-all) @nonobjc internal func bridgeEverything() { if _fastPath(_bridgedStorage != nil) { return } // FIXME: rdar://problem/19486139 (split bridged buffers for keys and values) // We bridge keys and values unconditionally here, even if one of them // actually is verbatim bridgeable (e.g. Dictionary). // Investigate only allocating the buffer for a Set in this case. // Create buffer for bridged data. let bridged = BridgedBuffer( _exactBucketCount: nativeBuffer.bucketCount, unhashable: ()) // Bridge everything. for i in 0.. AnyObject? { guard let nativeKey = _conditionallyBridgeFromObjectiveC(aKey, Key.self) else { return nil } let (i, found) = nativeBuffer._find( nativeKey, startBucket: nativeBuffer._bucket(nativeKey)) if found { bridgeEverything() return bridgedBuffer.value(at: i.offset) } return nil } @inlinable // FIXME(sil-serialize-all) @objc internal func enumerator() -> _NSEnumerator { bridgeEverything() return _NativeSetNSEnumerator(bridgedBuffer) } @inlinable // FIXME(sil-serialize-all) @objc(countByEnumeratingWithState:objects:count:) internal func countByEnumerating( with state: UnsafeMutablePointer<_SwiftNSFastEnumerationState>, objects: UnsafeMutablePointer?, count: Int ) -> Int { var theState = state.pointee if theState.state == 0 { theState.state = 1 // Arbitrary non-zero value. theState.itemsPtr = AutoreleasingUnsafeMutablePointer(objects) theState.mutationsPtr = _fastEnumerationStorageMutationsPtr theState.extra.0 = CUnsignedLong(nativeBuffer.startIndex.offset) } // Test 'objects' rather than 'count' because (a) this is very rare anyway, // and (b) the optimizer should then be able to optimize away the // unwrapping check below. if _slowPath(objects == nil) { return 0 } let unmanagedObjects = _UnmanagedAnyObjectArray(objects!) var currIndex = _NativeSetIndex( offset: Int(theState.extra.0)) let endIndex = nativeBuffer.endIndex var stored = 0 // Only need to bridge once, so we can hoist it out of the loop. if (currIndex != endIndex) { bridgeEverything() } for i in 0.. { } #endif #if _runtime(_ObjC) @usableFromInline @_fixed_layout internal struct _CocoaSetBuffer: _HashBuffer { @usableFromInline internal var cocoaSet: _NSSet @inlinable // FIXME(sil-serialize-all) internal init(cocoaSet: _NSSet) { self.cocoaSet = cocoaSet } internal typealias Index = _CocoaSetIndex internal typealias SequenceElement = AnyObject internal typealias SequenceElementWithoutLabels = AnyObject internal typealias Key = AnyObject internal typealias Value = AnyObject @inlinable // FIXME(sil-serialize-all) internal var startIndex: Index { return Index(cocoaSet, startIndex: ()) } @inlinable // FIXME(sil-serialize-all) internal var endIndex: Index { return Index(cocoaSet, endIndex: ()) } @inlinable // FIXME(sil-serialize-all) internal func index(after i: Index) -> Index { return i.successor() } @inlinable // FIXME(sil-serialize-all) internal func formIndex(after i: inout Index) { // FIXME: swift-3-indexing-model: optimize if possible. i = i.successor() } @inlinable // FIXME(sil-serialize-all) internal func index(forKey key: Key) -> Index? { // Fast path that does not involve creating an array of all keys. In case // the key is present, this lookup is a penalty for the slow path, but the // potential savings are significant: we could skip a memory allocation and // a linear search. if maybeGet(key) == nil { return nil } let allKeys = _stdlib_NSSet_allObjects(cocoaSet) var keyIndex = -1 for i in 0..= 0, "Key was found in fast path, but not found later?") return Index(cocoaSet, allKeys, keyIndex) } @inlinable // FIXME(sil-serialize-all) internal func assertingGet(_ i: Index) -> SequenceElement { let value: Value? = i.allKeys[i.currentKeyIndex] _sanityCheck(value != nil, "Item not found in underlying NSSet") return value! } @inlinable // FIXME(sil-serialize-all) internal func assertingGet(_ key: Key) -> Value { let value: Value? = cocoaSet.member(key) _precondition(value != nil, "Member not found in underlying NSSet") return value! } @inlinable // FIXME(sil-serialize-all) @inline(__always) internal func maybeGet(_ key: Key) -> Value? { return cocoaSet.member(key) } @inlinable // FIXME(sil-serialize-all) @discardableResult internal mutating func updateValue(_ value: Value, forKey key: Key) -> Value? { _sanityCheckFailure("cannot mutate NSSet") } @inlinable // FIXME(sil-serialize-all) @discardableResult internal mutating func insert( _ value: Value, forKey key: Key ) -> (inserted: Bool, memberAfterInsert: Value) { _sanityCheckFailure("cannot mutate NSSet") } @inlinable // FIXME(sil-serialize-all) @discardableResult internal mutating func remove(at index: Index) -> SequenceElement { _sanityCheckFailure("cannot mutate NSSet") } @inlinable // FIXME(sil-serialize-all) @discardableResult internal mutating func removeValue(forKey key: Key) -> Value? { _sanityCheckFailure("cannot mutate NSSet") } @inlinable // FIXME(sil-serialize-all) internal mutating func removeAll(keepingCapacity keepCapacity: Bool) { _sanityCheckFailure("cannot mutate NSSet") } @inlinable // FIXME(sil-serialize-all) internal var count: Int { return cocoaSet.count } @inlinable // FIXME(sil-serialize-all) internal static func fromArray(_ elements: [SequenceElementWithoutLabels]) -> _CocoaSetBuffer { _sanityCheckFailure("this function should never be called") } } #endif @usableFromInline @_frozen internal enum _VariantSetBuffer: _HashBuffer { internal typealias NativeBuffer = _NativeSetBuffer internal typealias NativeIndex = _NativeSetIndex #if _runtime(_ObjC) internal typealias CocoaBuffer = _CocoaSetBuffer #endif internal typealias SequenceElement = Element internal typealias SequenceElementWithoutLabels = Element internal typealias SelfType = _VariantSetBuffer internal typealias Key = Element internal typealias Value = Element case native(NativeBuffer) #if _runtime(_ObjC) case cocoa(CocoaBuffer) #endif @inlinable // FIXME(sil-serialize-all) @_transparent internal var guaranteedNative: Bool { return _canBeClass(Key.self) == 0 || _canBeClass(Value.self) == 0 } @inlinable // FIXME(sil-serialize-all) internal mutating func isUniquelyReferenced() -> Bool { // Note that &self drills down through .native(NativeBuffer) to the first // property in NativeBuffer, which is the reference to the storage. if _fastPath(guaranteedNative) { return _isUnique_native(&self) } switch self { case .native: return _isUnique_native(&self) #if _runtime(_ObjC) case .cocoa: // Don't consider Cocoa buffer mutable, even if it is mutable and is // uniquely referenced. return false #endif } } @inlinable // FIXME(sil-serialize-all) internal var asNative: NativeBuffer { get { switch self { case .native(let buffer): return buffer #if _runtime(_ObjC) case .cocoa: _sanityCheckFailure("internal error: not backed by native buffer") #endif } } set { self = .native(newValue) } } @inlinable // FIXME(sil-serialize-all) internal mutating func ensureNativeBuffer() { #if _runtime(_ObjC) if _fastPath(guaranteedNative) { return } if case .cocoa(let cocoaBuffer) = self { migrateDataToNativeBuffer(cocoaBuffer) } #endif } #if _runtime(_ObjC) @inlinable // FIXME(sil-serialize-all) internal var asCocoa: CocoaBuffer { switch self { case .native: _sanityCheckFailure("internal error: not backed by NSSet") case .cocoa(let cocoaBuffer): return cocoaBuffer } } #endif /// Return true if self is native. @inlinable // FIXME(sil-serialize-all) internal var _isNative: Bool { #if _runtime(_ObjC) switch self { case .native: return true case .cocoa: return false } #else return true #endif } @inline(__always) @inlinable // FIXME(sil-serialize-all) internal mutating func ensureUniqueNativeBufferNative( withBucketCount desiredBucketCount: Int ) -> (reallocated: Bool, capacityChanged: Bool) { let oldBucketCount = asNative.bucketCount if oldBucketCount >= desiredBucketCount && isUniquelyReferenced() { return (reallocated: false, capacityChanged: false) } let oldNativeBuffer = asNative var newNativeBuffer = NativeBuffer(bucketCount: desiredBucketCount) let newBucketCount = newNativeBuffer.bucketCount for i in 0.. (reallocated: Bool, capacityChanged: Bool) { let bucketCount = NativeBuffer.bucketCount( forCapacity: minimumCapacity, maxLoadFactorInverse: _hashContainerDefaultMaxLoadFactorInverse) return ensureUniqueNativeBuffer(withBucketCount: bucketCount) } /// Ensure this we hold a unique reference to a native buffer /// having at least `minimumCapacity` elements. @inlinable // FIXME(sil-serialize-all) internal mutating func ensureUniqueNativeBuffer( withBucketCount desiredBucketCount: Int ) -> (reallocated: Bool, capacityChanged: Bool) { #if _runtime(_ObjC) // This is a performance optimization that was put in to ensure that we did // not make a copy of self to call _isNative over the entire if region // causing at -Onone the uniqueness check to fail. This code used to be: // // if _isNative { // return ensureUniqueNativeBufferNative( // withBucketCount: desiredBucketCount) // } // // SR-6437 let n = _isNative if n { return ensureUniqueNativeBufferNative(withBucketCount: desiredBucketCount) } switch self { case .native: fatalError("This should have been handled earlier") case .cocoa(let cocoaBuffer): let cocoaSet = cocoaBuffer.cocoaSet var newNativeBuffer = NativeBuffer(bucketCount: desiredBucketCount) let oldCocoaIterator = _CocoaSetIterator(cocoaSet) while let key = oldCocoaIterator.next() { newNativeBuffer.unsafeAddNew( key: _forceBridgeFromObjectiveC(key, Value.self)) } newNativeBuffer.count = cocoaSet.count self = .native(newNativeBuffer) return (reallocated: true, capacityChanged: true) } #else return ensureUniqueNativeBufferNative(withBucketCount: desiredBucketCount) #endif } #if _runtime(_ObjC) @inlinable // FIXME(sil-serialize-all) @inline(never) internal mutating func migrateDataToNativeBuffer( _ cocoaBuffer: _CocoaSetBuffer ) { let allocated = ensureUniqueNativeBuffer( withCapacity: cocoaBuffer.count).reallocated _sanityCheck(allocated, "failed to allocate native Set buffer") } #endif /// Reserves enough space for the specified number of elements to be stored /// without reallocating additional storage. @inlinable // FIXME(sil-serialize-all) internal mutating func reserveCapacity(_ capacity: Int) { _ = ensureUniqueNativeBuffer(withCapacity: capacity) } /// The number of elements that can be stored without expanding the current /// storage. /// /// For bridged storage, this is equal to the current count of the /// collection, since any addition will trigger a copy of the elements into /// newly allocated storage. For native storage, this is the element count /// at which adding any more elements will exceed the load factor. @inlinable // FIXME(sil-serialize-all) internal var capacity: Int { switch self { case .native: return Int(Double(asNative.bucketCount) / _hashContainerDefaultMaxLoadFactorInverse) #if _runtime(_ObjC) case .cocoa(let cocoaBuffer): return cocoaBuffer.count #endif } } // // _HashBuffer conformance // internal typealias Index = SetIndex @inlinable // FIXME(sil-serialize-all) internal var startIndex: Index { if _fastPath(guaranteedNative) { return ._native(asNative.startIndex) } switch self { case .native: return ._native(asNative.startIndex) #if _runtime(_ObjC) case .cocoa(let cocoaBuffer): return ._cocoa(cocoaBuffer.startIndex) #endif } } @inlinable // FIXME(sil-serialize-all) internal var endIndex: Index { if _fastPath(guaranteedNative) { return ._native(asNative.endIndex) } switch self { case .native: return ._native(asNative.endIndex) #if _runtime(_ObjC) case .cocoa(let cocoaBuffer): return ._cocoa(cocoaBuffer.endIndex) #endif } } @inlinable // FIXME(sil-serialize-all) internal func index(after i: Index) -> Index { if _fastPath(guaranteedNative) { return ._native(asNative.index(after: i._nativeIndex)) } switch self { case .native: return ._native(asNative.index(after: i._nativeIndex)) #if _runtime(_ObjC) case .cocoa(let cocoaBuffer): return ._cocoa(cocoaBuffer.index(after: i._cocoaIndex)) #endif } } @inlinable // FIXME(sil-serialize-all) internal func formIndex(after i: inout Index) { // FIXME: swift-3-indexing-model: optimize if possible. i = index(after: i) } @inlinable // FIXME(sil-serialize-all) @inline(__always) internal func index(forKey key: Key) -> Index? { if _fastPath(guaranteedNative) { if let nativeIndex = asNative.index(forKey: key) { return ._native(nativeIndex) } return nil } switch self { case .native: if let nativeIndex = asNative.index(forKey: key) { return ._native(nativeIndex) } return nil #if _runtime(_ObjC) case .cocoa(let cocoaBuffer): let anyObjectKey: AnyObject = _bridgeAnythingToObjectiveC(key) if let cocoaIndex = cocoaBuffer.index(forKey: anyObjectKey) { return ._cocoa(cocoaIndex) } return nil #endif } } @inlinable // FIXME(sil-serialize-all) internal func assertingGet(_ i: Index) -> SequenceElement { if _fastPath(guaranteedNative) { return asNative.assertingGet(i._nativeIndex) } switch self { case .native: return asNative.assertingGet(i._nativeIndex) #if _runtime(_ObjC) case .cocoa(let cocoaBuffer): let anyObjectValue: AnyObject = cocoaBuffer.assertingGet(i._cocoaIndex) let nativeValue = _forceBridgeFromObjectiveC(anyObjectValue, Value.self) return nativeValue #endif } } @inlinable // FIXME(sil-serialize-all) internal func assertingGet(_ key: Key) -> Value { if _fastPath(guaranteedNative) { return asNative.assertingGet(key) } switch self { case .native: return asNative.assertingGet(key) #if _runtime(_ObjC) case .cocoa(let cocoaBuffer): // FIXME: This assumes that Key and Value are bridged verbatim. let anyObjectKey: AnyObject = _bridgeAnythingToObjectiveC(key) let anyObjectValue: AnyObject = cocoaBuffer.assertingGet(anyObjectKey) return _forceBridgeFromObjectiveC(anyObjectValue, Value.self) #endif } } #if _runtime(_ObjC) @inlinable // FIXME(sil-serialize-all) @inline(never) internal static func maybeGetFromCocoaBuffer( _ cocoaBuffer: CocoaBuffer, forKey key: Key ) -> Value? { let anyObjectKey: AnyObject = _bridgeAnythingToObjectiveC(key) if let anyObjectValue = cocoaBuffer.maybeGet(anyObjectKey) { return _forceBridgeFromObjectiveC(anyObjectValue, Value.self) } return nil } #endif @inlinable // FIXME(sil-serialize-all) @inline(__always) internal func maybeGet(_ key: Key) -> Value? { if _fastPath(guaranteedNative) { return asNative.maybeGet(key) } switch self { case .native: return asNative.maybeGet(key) #if _runtime(_ObjC) case .cocoa(let cocoaBuffer): return SelfType.maybeGetFromCocoaBuffer(cocoaBuffer, forKey: key) #endif } } @inlinable // FIXME(sil-serialize-all) internal mutating func nativeUpdateValue( _ value: Value, forKey key: Key ) -> Value? { var (i, found) = asNative._find(key, startBucket: asNative._bucket(key)) let minBuckets = found ? asNative.bucketCount : NativeBuffer.bucketCount( forCapacity: asNative.count + 1, maxLoadFactorInverse: _hashContainerDefaultMaxLoadFactorInverse) let (_, capacityChanged) = ensureUniqueNativeBuffer( withBucketCount: minBuckets) if capacityChanged { i = asNative._find(key, startBucket: asNative._bucket(key)).pos } let oldValue: Value? = found ? asNative.key(at: i.offset) : nil if found { asNative.setKey(key, at: i.offset) } else { asNative.initializeKey(key, at: i.offset) asNative.count += 1 } return oldValue } @inlinable // FIXME(sil-serialize-all) @discardableResult internal mutating func updateValue( _ value: Value, forKey key: Key ) -> Value? { if _fastPath(guaranteedNative) { return nativeUpdateValue(value, forKey: key) } switch self { case .native: return nativeUpdateValue(value, forKey: key) #if _runtime(_ObjC) case .cocoa(let cocoaBuffer): migrateDataToNativeBuffer(cocoaBuffer) return nativeUpdateValue(value, forKey: key) #endif } } @inlinable // FIXME(sil-serialize-all) internal mutating func nativeInsert( _ value: Value, forKey key: Key ) -> (inserted: Bool, memberAfterInsert: Value) { var (i, found) = asNative._find(key, startBucket: asNative._bucket(key)) if found { return (inserted: false, memberAfterInsert: asNative.key(at: i.offset)) } let minCapacity = asNative.count + 1 let (_, capacityChanged) = ensureUniqueNativeBuffer( withCapacity: minCapacity) if capacityChanged { i = asNative._find(key, startBucket: asNative._bucket(key)).pos } asNative.initializeKey(key, at: i.offset) asNative.count += 1 return (inserted: true, memberAfterInsert: value) } @inlinable // FIXME(sil-serialize-all) @discardableResult internal mutating func insert( _ value: Value, forKey key: Key ) -> (inserted: Bool, memberAfterInsert: Value) { ensureNativeBuffer() return nativeInsert(value, forKey: key) } /// - parameter idealBucket: The ideal bucket for the element being deleted. /// - parameter offset: The offset of the element that will be deleted. /// Precondition: there should be an initialized entry at offset. @inlinable // FIXME(sil-serialize-all) internal mutating func nativeDelete( _ nativeBuffer: NativeBuffer, idealBucket: Int, offset: Int ) { _sanityCheck( nativeBuffer.isInitializedEntry(at: offset), "expected initialized entry") var nativeBuffer = nativeBuffer // remove the element nativeBuffer.destroyEntry(at: offset) nativeBuffer.count -= 1 // If we've put a hole in a chain of contiguous elements, some // element after the hole may belong where the new hole is. var hole = offset // Find the first bucket in the contiguous chain var start = idealBucket while nativeBuffer.isInitializedEntry(at: nativeBuffer._prev(start)) { start = nativeBuffer._prev(start) } // Find the last bucket in the contiguous chain var lastInChain = hole var b = nativeBuffer._index(after: lastInChain) while nativeBuffer.isInitializedEntry(at: b) { lastInChain = b b = nativeBuffer._index(after: b) } // Relocate out-of-place elements in the chain, repeating until // none are found. while hole != lastInChain { // Walk backwards from the end of the chain looking for // something out-of-place. var b = lastInChain while b != hole { let idealBucket = nativeBuffer._bucket(nativeBuffer.key(at: b)) // Does this element belong between start and hole? We need // two separate tests depending on whether [start, hole] wraps // around the end of the storage let c0 = idealBucket >= start let c1 = idealBucket <= hole if start <= hole ? (c0 && c1) : (c0 || c1) { break // Found it } b = nativeBuffer._prev(b) } if b == hole { // No out-of-place elements found; we're done adjusting break } // Move the found element into the hole nativeBuffer.moveInitializeEntry( from: nativeBuffer, at: b, toEntryAt: hole) hole = b } } @inlinable // FIXME(sil-serialize-all) internal mutating func nativeRemoveObject(forKey key: Key) -> Value? { var idealBucket = asNative._bucket(key) var (index, found) = asNative._find(key, startBucket: idealBucket) // Fast path: if the key is not present, we will not mutate the set, // so don't force unique buffer. if !found { return nil } // This is a performance optimization that was put in to ensure that we // did not make a copy of self to call asNative.bucketCount over // ensureUniqueNativeBefore causing at -Onone the uniqueness check to // fail. This code used to be: // // ... = ensureUniqueNativeBuffer(withBucketCount: asNative.bucketCount) // // SR-6437 let bucketCount = asNative.bucketCount let (_, capacityChanged) = ensureUniqueNativeBuffer( withBucketCount: bucketCount) let nativeBuffer = asNative if capacityChanged { idealBucket = nativeBuffer._bucket(key) (index, found) = nativeBuffer._find(key, startBucket: idealBucket) _sanityCheck(found, "key was lost during buffer migration") } let oldValue = nativeBuffer.key(at: index.offset) nativeDelete(nativeBuffer, idealBucket: idealBucket, offset: index.offset) return oldValue } @inlinable // FIXME(sil-serialize-all) internal mutating func nativeRemove( at nativeIndex: NativeIndex ) -> SequenceElement { // This is a performance optimization that was put in to ensure that we did // not make a copy of self to call asNative.bucketCount over // ensureUniqueNativeBefore causing at -Onone the uniqueness check to // fail. This code used to be: // // _ = ensureUniqueNativeBuffer(withBucketCount: asNative.bucketCount) // // SR-6437 let bucketCount = asNative.bucketCount // The provided index should be valid, so we will always mutating the // set buffer. Request unique buffer. _ = ensureUniqueNativeBuffer(withBucketCount: bucketCount) let nativeBuffer = asNative let result = nativeBuffer.assertingGet(nativeIndex) let key = result nativeDelete(nativeBuffer, idealBucket: nativeBuffer._bucket(key), offset: nativeIndex.offset) return result } @inlinable // FIXME(sil-serialize-all) @discardableResult internal mutating func remove(at index: Index) -> SequenceElement { if _fastPath(guaranteedNative) { return nativeRemove(at: index._nativeIndex) } switch self { case .native: return nativeRemove(at: index._nativeIndex) #if _runtime(_ObjC) case .cocoa(let cocoaBuffer): // We have to migrate the data first. But after we do so, the Cocoa // index becomes useless, so get the key first. // // FIXME(performance): fuse data migration and element deletion into one // operation. let index = index._cocoaIndex let anyObjectKey: AnyObject = index.allKeys[index.currentKeyIndex] migrateDataToNativeBuffer(cocoaBuffer) let key = _forceBridgeFromObjectiveC(anyObjectKey, Key.self) let value = nativeRemoveObject(forKey: key) _sanityCheck(key == value, "bridging did not preserve equality") return key #endif } } @inlinable // FIXME(sil-serialize-all) @discardableResult internal mutating func removeValue(forKey key: Key) -> Value? { if _fastPath(guaranteedNative) { return nativeRemoveObject(forKey: key) } switch self { case .native: return nativeRemoveObject(forKey: key) #if _runtime(_ObjC) case .cocoa(let cocoaBuffer): let anyObjectKey: AnyObject = _bridgeAnythingToObjectiveC(key) if cocoaBuffer.maybeGet(anyObjectKey) == nil { return nil } migrateDataToNativeBuffer(cocoaBuffer) return nativeRemoveObject(forKey: key) #endif } } @inlinable // FIXME(sil-serialize-all) internal mutating func nativeRemoveAll() { if !isUniquelyReferenced() { asNative = NativeBuffer(_exactBucketCount: asNative.bucketCount) return } // We have already checked for the empty dictionary case and unique // reference, so we will always mutate the dictionary buffer. var nativeBuffer = asNative for b in 0.. SetIterator { switch self { case .native(let buffer): return ._native( start: asNative.startIndex, end: asNative.endIndex, buffer: buffer) #if _runtime(_ObjC) case .cocoa(let cocoaBuffer): return ._cocoa(_CocoaSetIterator(cocoaBuffer.cocoaSet)) #endif } } @inlinable // FIXME(sil-serialize-all) internal static func fromArray(_ elements: [SequenceElement]) -> _VariantSetBuffer { _sanityCheckFailure("this function should never be called") } } @_fixed_layout // FIXME(sil-serialize-all) @usableFromInline internal struct _NativeSetIndex: Comparable { @usableFromInline internal var offset: Int @inlinable // FIXME(sil-serialize-all) internal init(offset: Int) { self.offset = offset } } extension _NativeSetIndex { @inlinable // FIXME(sil-serialize-all) internal static func < ( lhs: _NativeSetIndex, rhs: _NativeSetIndex ) -> Bool { return lhs.offset < rhs.offset } @inlinable // FIXME(sil-serialize-all) internal static func <= ( lhs: _NativeSetIndex, rhs: _NativeSetIndex ) -> Bool { return lhs.offset <= rhs.offset } @inlinable // FIXME(sil-serialize-all) internal static func > ( lhs: _NativeSetIndex, rhs: _NativeSetIndex ) -> Bool { return lhs.offset > rhs.offset } @inlinable // FIXME(sil-serialize-all) internal static func >= ( lhs: _NativeSetIndex, rhs: _NativeSetIndex ) -> Bool { return lhs.offset >= rhs.offset } @inlinable // FIXME(sil-serialize-all) internal static func == ( lhs: _NativeSetIndex, rhs: _NativeSetIndex ) -> Bool { return lhs.offset == rhs.offset } } #if _runtime(_ObjC) @_fixed_layout // FIXME(sil-serialize-all) @usableFromInline internal struct _CocoaSetIndex: Comparable { // Assumption: we rely on NSDictionary.getObjects when being // repeatedly called on the same NSDictionary, returning items in the same // order every time. // Similarly, the same assumption holds for NSSet.allObjects. /// A reference to the NSSet, which owns members in `allObjects`, /// or `allKeys`, for NSSet and NSDictionary respectively. @usableFromInline // FIXME(sil-serialize-all) internal let cocoaSet: _NSSet // FIXME: swift-3-indexing-model: try to remove the cocoa reference, but make // sure that we have a safety check for accessing `allKeys`. Maybe move both // into the dictionary/set itself. /// An unowned array of keys. @usableFromInline // FIXME(sil-serialize-all) internal var allKeys: _HeapBuffer /// Index into `allKeys` @usableFromInline // FIXME(sil-serialize-all) internal var currentKeyIndex: Int @inlinable // FIXME(sil-serialize-all) internal init(_ cocoaSet: _NSSet, startIndex: ()) { self.cocoaSet = cocoaSet self.allKeys = _stdlib_NSSet_allObjects(cocoaSet) self.currentKeyIndex = 0 } @inlinable // FIXME(sil-serialize-all) internal init(_ cocoaSet: _NSSet, endIndex: ()) { self.cocoaSet = cocoaSet self.allKeys = _stdlib_NSSet_allObjects(cocoaSet) self.currentKeyIndex = allKeys.value } @inlinable // FIXME(sil-serialize-all) internal init(_ cocoaSet: _NSSet, _ allKeys: _HeapBuffer, _ currentKeyIndex: Int ) { self.cocoaSet = cocoaSet self.allKeys = allKeys self.currentKeyIndex = currentKeyIndex } /// Returns the next consecutive value after `self`. /// /// - Precondition: The next value is representable. @inlinable // FIXME(sil-serialize-all) internal func successor() -> _CocoaSetIndex { // FIXME: swift-3-indexing-model: remove this method. _precondition( currentKeyIndex < allKeys.value, "Cannot increment endIndex") return _CocoaSetIndex(cocoaSet, allKeys, currentKeyIndex + 1) } } extension _CocoaSetIndex { @inlinable // FIXME(sil-serialize-all) internal static func < ( lhs: _CocoaSetIndex, rhs: _CocoaSetIndex ) -> Bool { return lhs.currentKeyIndex < rhs.currentKeyIndex } @inlinable // FIXME(sil-serialize-all) internal static func <= ( lhs: _CocoaSetIndex, rhs: _CocoaSetIndex ) -> Bool { return lhs.currentKeyIndex <= rhs.currentKeyIndex } @inlinable // FIXME(sil-serialize-all) internal static func > ( lhs: _CocoaSetIndex, rhs: _CocoaSetIndex ) -> Bool { return lhs.currentKeyIndex > rhs.currentKeyIndex } @inlinable // FIXME(sil-serialize-all) internal static func >= ( lhs: _CocoaSetIndex, rhs: _CocoaSetIndex ) -> Bool { return lhs.currentKeyIndex >= rhs.currentKeyIndex } @inlinable // FIXME(sil-serialize-all) internal static func == ( lhs: _CocoaSetIndex, rhs: _CocoaSetIndex ) -> Bool { return lhs.currentKeyIndex == rhs.currentKeyIndex } } #endif @_frozen // FIXME(sil-serialize-all) @usableFromInline // FIXME(sil-serialize-all) internal enum SetIndexRepresentation { typealias _Index = SetIndex typealias _NativeIndex = _Index._NativeIndex #if _runtime(_ObjC) typealias _CocoaIndex = _Index._CocoaIndex #endif case _native(_NativeIndex) #if _runtime(_ObjC) case _cocoa(_CocoaIndex) #endif } extension Set { /// The position of an element in a set. @_fixed_layout // FIXME(sil-serialize-all) public struct Index: Comparable, Hashable { // Index for native buffer is efficient. Index for bridged NSSet is // not, because neither NSEnumerator nor fast enumeration support moving // backwards. Even if they did, there is another issue: NSEnumerator does // not support NSCopying, and fast enumeration does not document that it is // safe to copy the state. So, we cannot implement Index that is a value // type for bridged NSSet in terms of Cocoa enumeration facilities. internal typealias _NativeIndex = _NativeSetIndex #if _runtime(_ObjC) internal typealias _CocoaIndex = _CocoaSetIndex #endif internal typealias Key = Element internal typealias Value = Element @inlinable // FIXME(sil-serialize-all) internal init(_value: SetIndexRepresentation) { self._value = _value } @usableFromInline // FIXME(sil-serialize-all) internal var _value: SetIndexRepresentation @inlinable // FIXME(sil-serialize-all) internal static func _native(_ index: _NativeIndex) -> Index { return SetIndex(_value: ._native(index)) } #if _runtime(_ObjC) @inlinable // FIXME(sil-serialize-all) internal static func _cocoa(_ index: _CocoaIndex) -> Index { return SetIndex(_value: ._cocoa(index)) } #endif @inlinable // FIXME(sil-serialize-all) @_transparent internal var _guaranteedNative: Bool { return _canBeClass(Key.self) == 0 && _canBeClass(Value.self) == 0 } @inlinable // FIXME(sil-serialize-all) @_transparent internal var _nativeIndex: _NativeIndex { switch _value { case ._native(let nativeIndex): return nativeIndex #if _runtime(_ObjC) case ._cocoa: _sanityCheckFailure("internal error: does not contain a native index") #endif } } #if _runtime(_ObjC) @inlinable // FIXME(sil-serialize-all) @_transparent internal var _cocoaIndex: _CocoaIndex { switch _value { case ._native: _sanityCheckFailure("internal error: does not contain a Cocoa index") case ._cocoa(let cocoaIndex): return cocoaIndex } } #endif } } public typealias SetIndex = Set.Index extension Set.Index { @inlinable // FIXME(sil-serialize-all) public static func == ( lhs: Set.Index, rhs: Set.Index ) -> Bool { if _fastPath(lhs._guaranteedNative) { return lhs._nativeIndex == rhs._nativeIndex } switch (lhs._value, rhs._value) { case (._native(let lhsNative), ._native(let rhsNative)): return lhsNative == rhsNative #if _runtime(_ObjC) case (._cocoa(let lhsCocoa), ._cocoa(let rhsCocoa)): return lhsCocoa == rhsCocoa default: _preconditionFailure("Comparing indexes from different sets") #endif } } @inlinable // FIXME(sil-serialize-all) public static func < ( lhs: Set.Index, rhs: Set.Index ) -> Bool { if _fastPath(lhs._guaranteedNative) { return lhs._nativeIndex < rhs._nativeIndex } switch (lhs._value, rhs._value) { case (._native(let lhsNative), ._native(let rhsNative)): return lhsNative < rhsNative #if _runtime(_ObjC) case (._cocoa(let lhsCocoa), ._cocoa(let rhsCocoa)): return lhsCocoa < rhsCocoa default: _preconditionFailure("Comparing indexes from different sets") #endif } } @inlinable // FIXME(sil-serialize-all) public var hashValue: Int { if _fastPath(_guaranteedNative) { return _nativeIndex.offset } switch _value { case ._native(let nativeIndex): return nativeIndex.offset #if _runtime(_ObjC) case ._cocoa(let cocoaIndex): return cocoaIndex.currentKeyIndex #endif } } } #if _runtime(_ObjC) @_fixed_layout // FIXME(sil-serialize-all) @usableFromInline final internal class _CocoaSetIterator: IteratorProtocol { internal typealias Element = AnyObject // Cocoa Set iterator has to be a class, otherwise we cannot // guarantee that the fast enumeration struct is pinned to a certain memory // location. // This stored property should be stored at offset zero. There's code below // relying on this. @usableFromInline // FIXME(sil-serialize-all) internal var _fastEnumerationState: _SwiftNSFastEnumerationState = _makeSwiftNSFastEnumerationState() // This stored property should be stored right after `_fastEnumerationState`. // There's code below relying on this. @usableFromInline // FIXME(sil-serialize-all) internal var _fastEnumerationStackBuf = _CocoaFastEnumerationStackBuf() @usableFromInline // FIXME(sil-serialize-all) internal let cocoaSet: _NSSet @inlinable // FIXME(sil-serialize-all) internal var _fastEnumerationStatePtr: UnsafeMutablePointer<_SwiftNSFastEnumerationState> { return _getUnsafePointerToStoredProperties(self).assumingMemoryBound( to: _SwiftNSFastEnumerationState.self) } @inlinable // FIXME(sil-serialize-all) internal var _fastEnumerationStackBufPtr: UnsafeMutablePointer<_CocoaFastEnumerationStackBuf> { return UnsafeMutableRawPointer(_fastEnumerationStatePtr + 1) .assumingMemoryBound(to: _CocoaFastEnumerationStackBuf.self) } // These members have to be word-sized integers, they cannot be limited to // Int8 just because our storage holds 16 elements: fast enumeration is // allowed to return inner pointers to the container, which can be much // larger. @usableFromInline // FIXME(sil-serialize-all) internal var itemIndex: Int = 0 @usableFromInline // FIXME(sil-serialize-all) internal var itemCount: Int = 0 @inlinable // FIXME(sil-serialize-all) internal init(_ cocoaSet: _NSSet) { self.cocoaSet = cocoaSet } @inlinable // FIXME(sil-serialize-all) internal func next() -> Element? { if itemIndex < 0 { return nil } let cocoaSet = self.cocoaSet if itemIndex == itemCount { let stackBufCount = _fastEnumerationStackBuf.count // We can't use `withUnsafeMutablePointer` here to get pointers to // properties, because doing so might introduce a writeback storage, but // fast enumeration relies on the pointer identity of the enumeration // state struct. itemCount = cocoaSet.countByEnumerating( with: _fastEnumerationStatePtr, objects: UnsafeMutableRawPointer(_fastEnumerationStackBufPtr) .assumingMemoryBound(to: AnyObject.self), count: stackBufCount) if itemCount == 0 { itemIndex = -1 return nil } itemIndex = 0 } let itemsPtrUP = UnsafeMutableRawPointer(_fastEnumerationState.itemsPtr!) .assumingMemoryBound(to: AnyObject.self) let itemsPtr = _UnmanagedAnyObjectArray(itemsPtrUP) let key: AnyObject = itemsPtr[itemIndex] itemIndex += 1 return key } } #endif @usableFromInline @_frozen // FIXME(sil-serialize-all) internal enum SetIteratorRepresentation { internal typealias _Iterator = SetIterator internal typealias _NativeBuffer = _NativeSetBuffer internal typealias _NativeIndex = _Iterator._NativeIndex // For native buffer, we keep two indices to keep track of the iteration // progress and the buffer owner to make the buffer non-uniquely // referenced. // // Iterator is iterating over a frozen view of the collection // state, so it should keep its own reference to the buffer. case _native( start: _NativeIndex, end: _NativeIndex, buffer: _NativeBuffer) #if _runtime(_ObjC) case _cocoa(_CocoaSetIterator) #endif } /// An iterator over the members of a `Set`. @_fixed_layout // FIXME(sil-serialize-all) public struct SetIterator: IteratorProtocol { // Set has a separate IteratorProtocol and Index because of efficiency // and implementability reasons. // // Index for native buffer is efficient. Index for bridged NSSet is // not. // // Even though fast enumeration is not suitable for implementing // Index, which is multi-pass, it is suitable for implementing a // IteratorProtocol, which is being consumed as iteration proceeds. internal typealias _NativeBuffer = _NativeSetBuffer internal typealias _NativeIndex = _NativeSetIndex @usableFromInline internal var _state: SetIteratorRepresentation @inlinable // FIXME(sil-serialize-all) internal init(_state: SetIteratorRepresentation) { self._state = _state } @inlinable // FIXME(sil-serialize-all) internal static func _native( start: _NativeIndex, end: _NativeIndex, buffer: _NativeBuffer ) -> SetIterator { return SetIterator( _state: ._native(start: start, end: end, buffer: buffer)) } #if _runtime(_ObjC) @inlinable // FIXME(sil-serialize-all) internal static func _cocoa( _ iterator: _CocoaSetIterator ) -> SetIterator{ return SetIterator(_state: ._cocoa(iterator)) } #endif @inlinable // FIXME(sil-serialize-all) @_transparent internal var _guaranteedNative: Bool { return _canBeClass(Element.self) == 0 } @inlinable // FIXME(sil-serialize-all) internal mutating func _nativeNext() -> Element? { switch _state { case ._native(let startIndex, let endIndex, let buffer): if startIndex == endIndex { return nil } let result = buffer.assertingGet(startIndex) _state = ._native(start: buffer.index(after: startIndex), end: endIndex, buffer: buffer) return result #if _runtime(_ObjC) case ._cocoa: _sanityCheckFailure("internal error: not backed by NSSet") #endif } } /// Advances to the next element and returns it, or `nil` if no next element /// exists. /// /// Once `nil` has been returned, all subsequent calls return `nil`. @inlinable // FIXME(sil-serialize-all) @inline(__always) public mutating func next() -> Element? { if _fastPath(_guaranteedNative) { return _nativeNext() } switch _state { case ._native: return _nativeNext() #if _runtime(_ObjC) case ._cocoa(let cocoaIterator): if let anyObjectElement = cocoaIterator.next() { return _forceBridgeFromObjectiveC(anyObjectElement, Element.self) } return nil #endif } } } extension SetIterator: CustomReflectable { /// A mirror that reflects the iterator. @inlinable // FIXME(sil-serialize-all) public var customMirror: Mirror { return Mirror( self, children: EmptyCollection<(label: String?, value: Any)>()) } } extension Set: CustomReflectable { /// A mirror that reflects the set. @inlinable // FIXME(sil-serialize-all) public var customMirror: Mirror { let style = Mirror.DisplayStyle.`set` return Mirror(self, unlabeledChildren: self, displayStyle: style) } } /// Initializes a `Set` from unique members. /// /// Using a builder can be faster than inserting members into an empty /// `Set`. @_fixed_layout // FIXME(sil-serialize-all) public struct _SetBuilder { public typealias Key = Element public typealias Value = Element @usableFromInline // FIXME(sil-serialize-all) internal var _result: Set @usableFromInline // FIXME(sil-serialize-all) internal var _nativeBuffer: _NativeSetBuffer @usableFromInline // FIXME(sil-serialize-all) internal let _requestedCount: Int @usableFromInline // FIXME(sil-serialize-all) internal var _actualCount: Int @inlinable // FIXME(sil-serialize-all) public init(count: Int) { _result = Set(minimumCapacity: count) _nativeBuffer = _result._variantBuffer.asNative _requestedCount = count _actualCount = 0 } @inlinable // FIXME(sil-serialize-all) public mutating func add(member newKey: Key) { _nativeBuffer.unsafeAddNew(key: newKey) _actualCount += 1 } @inlinable // FIXME(sil-serialize-all) public mutating func take() -> Set { _precondition(_actualCount >= 0, "Cannot take the result twice") _precondition(_actualCount == _requestedCount, "The number of members added does not match the promised count") // Finish building the `Set`. _nativeBuffer.count = _requestedCount // Prevent taking the result twice. _actualCount = -1 return _result } } extension Set { /// Removes and returns the first element of the set. /// /// Because a set is not an ordered collection, the "first" element may not /// be the first element that was added to the set. /// /// - Returns: A member of the set. If the set is empty, returns `nil`. @inlinable public mutating func popFirst() -> Element? { guard !isEmpty else { return nil } return remove(at: startIndex) } @inlinable @available(swift, obsoleted: 4.0) public func filter( _ isIncluded: (Element) throws -> Bool, obsoletedInSwift4: () = () ) rethrows -> [Element] { var result: [Element] = [] for x in self { if try isIncluded(x) { result.append(x) } } return result } /// The total number of elements that the set can contain without /// allocating new storage. @inlinable // FIXME(sil-serialize-all) public var capacity: Int { return _variantBuffer.capacity } /// Reserves enough space to store the specified number of elements. /// /// If you are adding a known number of elements to a set, use this /// method to avoid multiple reallocations. This method ensures that the /// set has unique, mutable, contiguous storage, with space allocated /// for at least the requested number of elements. /// /// Calling the `reserveCapacity(_:)` method on a set with bridged /// storage triggers a copy to contiguous storage even if the existing /// storage has room to store `minimumCapacity` elements. /// /// - Parameter minimumCapacity: The requested number of elements to /// store. @inlinable // FIXME(sil-serialize-all) public mutating func reserveCapacity(_ minimumCapacity: Int) { _variantBuffer.reserveCapacity(minimumCapacity) _sanityCheck(self.capacity >= minimumCapacity) } } //===--- Bridging ---------------------------------------------------------===// #if _runtime(_ObjC) extension Set { @inlinable // FIXME(sil-serialize-all) public func _bridgeToObjectiveCImpl() -> _NSSetCore { switch _variantBuffer { case _VariantSetBuffer.native(let buffer): return buffer.bridged() case _VariantSetBuffer.cocoa(let cocoaBuffer): return cocoaBuffer.cocoaSet } } /// Returns the native Dictionary hidden inside this NSDictionary; /// returns nil otherwise. @inlinable // FIXME(sil-serialize-all) public static func _bridgeFromObjectiveCAdoptingNativeStorageOf( _ s: AnyObject ) -> Set? { // Try all three NSSet impls that we currently provide. if let deferredBuffer = s as? _SwiftDeferredNSSet { return Set(_nativeBuffer: deferredBuffer.nativeBuffer) } if let nativeStorage = s as? _HashableTypedNativeSetStorage { return Set(_nativeBuffer: _NativeSetBuffer(_storage: nativeStorage)) } if s === _RawNativeSetStorage.empty { return Set() } // FIXME: what if `s` is native storage, but for different key/value type? return nil } } #endif