//===----------------------------------------------------------------------===// // // 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 /// 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 { @usableFromInline internal var _variant: _Variant /// 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 public init(minimumCapacity: Int) { _variant = .native(_NativeSet(capacity: minimumCapacity)) } /// Private initializer. @inlinable internal init(_native: _NativeSet) { _variant = .native(_native) } #if _runtime(_ObjC) @inlinable internal init(_cocoa: _CocoaSet) { _variant = .cocoa(_cocoa) } /// 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 public // SPI(Foundation) init(_immutableCocoaSet: _NSSet) { _sanityCheck(_isBridgedVerbatimToObjectiveC(Element.self), "Set can be backed by NSSet _variant only when the member type can be bridged verbatim to Objective-C") self.init(_cocoa: _CocoaSet(_immutableCocoaSet)) } #endif } extension Set: ExpressibleByArrayLiteral { /// 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 public init(arrayLiteral elements: Element...) { if elements.isEmpty { self.init() return } var native = _NativeSet(capacity: elements.count) for element in elements { let inserted = native._insert(element, isUnique: true).inserted if !inserted { // FIXME: Shouldn't this trap? } } self.init(_native: native) } } extension Set: Sequence { /// Returns an iterator over the members of the set. @inlinable @inline(__always) public __consuming func makeIterator() -> Iterator { return _variant.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 public func contains(_ member: Element) -> Bool { return _variant.contains(member) } @inlinable 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 __consuming func filter( _ isIncluded: (Element) throws -> Bool ) rethrows -> Set { // FIXME(performance): Eliminate rehashes by using a bitmap. 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 public var startIndex: Index { return _variant.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 public var endIndex: Index { return _variant.endIndex } /// Accesses the member at the given position. @inlinable public subscript(position: Index) -> Element { return _variant.element(at: position) } @inlinable public func index(after i: Index) -> Index { return _variant.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 public func firstIndex(of member: Element) -> Index? { return _variant.index(for: member) } @inlinable public func _customIndexOfEquatableElement( _ member: Element ) -> Index?? { return Optional(firstIndex(of: member)) } @inlinable public func _customLastIndexOfEquatableElement( _ member: Element ) -> Index?? { // The first and last elements are the same because each element is unique. return _customIndexOfEquatableElement(member) } /// The number of elements in the set. /// /// - Complexity: O(1). @inlinable public var count: Int { return _variant.count } /// A Boolean value that indicates whether the set is empty. @inlinable 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 public var first: Element? { var iterator = makeIterator() return iterator.next() } } // 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 public static func == (lhs: Set, rhs: Set) -> Bool { switch (lhs._variant, rhs._variant) { case (.native(let lhsNative), .native(let rhsNative)): if lhsNative._storage === rhsNative._storage { return true } if lhsNative.count != rhsNative.count { return false } for member in lhsNative { guard rhsNative.find(member).found else { return false } } return true #if _runtime(_ObjC) case (.cocoa(let lhsCocoa), .cocoa(let rhsCocoa)): return lhsCocoa == rhsCocoa case (.native(let lhsNative), .cocoa(let rhsCocoa)): if lhsNative.count != rhsCocoa.count { return false } defer { _fixLifetime(lhsNative) } for i in lhsNative.hashTable { let key = lhsNative.element(at: i) let bridgedKey = _bridgeAnythingToObjectiveC(key) if rhsCocoa.contains(bridgedKey) { continue } return false } return true case (.cocoa, .native): return rhs == lhs #endif } } } extension Set: Hashable { /// Hashes the essential components of this value by feeding them into the /// given hasher. /// /// - Parameter hasher: The hasher to use when combining the components /// of this instance. @inlinable public func hash(into hasher: inout Hasher) { // FIXME(ABI)#177: Cache Set hashValue var hash = 0 let seed = hasher._generateSeed() for member in self { hash ^= member._rawHashValue(seed: seed) } hasher.combine(hash) } } extension Set: _HasCustomAnyHashableRepresentation { public func _toCustomAnyHashable() -> AnyHashable? { return AnyHashable(_box: _SetAnyHashableBox(self)) } } internal struct _SetAnyHashableBox: _AnyHashableBox { internal let _value: Set internal let _canonical: Set internal init(_ value: Set) { self._value = value self._canonical = value as Set } internal var _base: Any { return _value } internal var _canonicalBox: _AnyHashableBox { return _SetAnyHashableBox(_canonical) } internal func _isEqual(to other: _AnyHashableBox) -> Bool? { guard let other = other as? _SetAnyHashableBox else { return nil } return _canonical == other._value } internal var _hashValue: Int { return _canonical.hashValue } internal func _hash(into hasher: inout Hasher) { _canonical.hash(into: &hasher) } internal func _rawHashValue(_seed: Hasher._Seed) -> Int { return _canonical._rawHashValue(seed: _seed) } internal func _unbox() -> T? { return _value as? T } internal func _downCastConditional( into result: UnsafeMutablePointer ) -> Bool { guard let value = _value as? T else { return false } result.initialize(to: value) return true } } 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 @discardableResult public mutating func insert( _ newMember: Element ) -> (inserted: Bool, memberAfterInsert: Element) { return _variant.insert(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 @discardableResult public mutating func update(with newMember: Element) -> Element? { return _variant.update(with: 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 @discardableResult public mutating func remove(_ member: Element) -> Element? { return _variant.remove(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 @discardableResult public mutating func remove(at position: Index) -> Element { return _variant.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 public mutating func removeAll(keepingCapacity keepCapacity: Bool = false) { _variant.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 @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. `_variant` 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 public init() { self = Set(_native: _NativeSet()) } /// 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 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. self._variant = s._variant } 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 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 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 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 public mutating func subtract(_ other: S) where S.Element == Element { _subtract(other) } @inlinable 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. public var description: String { return _makeCollectionDescription(for: self, withTypeName: nil) } /// A string that represents the contents of the set, suitable for debugging. public var debugDescription: String { return _makeCollectionDescription(for: self, withTypeName: "Set") } } #if _runtime(_ObjC) @_silgen_name("swift_stdlib_CFSetGetValues") @usableFromInline internal func _stdlib_CFSetGetValues(_ nss: _NSSet, _: UnsafeMutablePointer) /// Equivalent to `NSSet.allObjects`, but does not leave objects on the /// autorelease pool. @inlinable 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 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() } /// 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 public func _setDownCast(_ source: Set) -> Set { #if _runtime(_ObjC) if _isClassOrObjCExistential(BaseValue.self) && _isClassOrObjCExistential(DerivedValue.self) { switch source._variant { case .native(let nativeSet): return Set(_immutableCocoaSet: nativeSet.bridged()) case .cocoa(let cocoaSet): return Set(_immutableCocoaSet: cocoaSet.object) } } #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 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 } 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 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 { guard self.count <= other.count else { return false } for member in self { if !other.contains(member) { return false } } return true } /// 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) } } } } /// This protocol is only used for compile-time checks that /// every buffer type implements all required operations. internal protocol _SetBuffer { associatedtype Element associatedtype Index var startIndex: Index { get } var endIndex: Index { get } func index(after i: Index) -> Index func index(for element: Element) -> Index? var count: Int { get } func contains(_ member: Element) -> Bool func element(at i: Index) -> Element } /// 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 @_objc_non_lazy_realization internal class _RawSetStorage: _SwiftNativeNSSet { /// The current number of occupied entries in this set. @usableFromInline @nonobjc internal final var _count: Int /// The maximum number of elements that can be inserted into this set without /// exceeding the hash table's maximum load factor. @usableFromInline @nonobjc internal final var _capacity: Int /// The scale of this set. The number of buckets is 2 raised to the /// power of `scale`. @usableFromInline @nonobjc internal final var _scale: Int @usableFromInline internal final var _seed: Hasher._Seed @usableFromInline @nonobjc internal final var _rawElements: UnsafeMutableRawPointer // This type is made with allocWithTailElems, so no init is ever called. // But we still need to have an init to satisfy the compiler. @nonobjc internal init(_doNotCallMe: ()) { _sanityCheckFailure("This class cannot be directly initialized") } @inlinable @nonobjc internal final var _bucketCount: Int { @inline(__always) get { return 1 &<< _scale } } @inlinable @nonobjc internal final var _metadata: UnsafeMutablePointer<_HashTable.Word> { @inline(__always) get { let address = Builtin.projectTailElems(self, _HashTable.Word.self) return UnsafeMutablePointer(address) } } // The _HashTable struct contains pointers into tail-allocated storage, so // this is unsafe and needs `_fixLifetime` calls in the caller. @inlinable @nonobjc internal final var _hashTable: _HashTable { @inline(__always) get { return _HashTable(words: _metadata, bucketCount: _bucketCount) } } } /// The storage class for the singleton empty set. /// The single instance of this class is created by the runtime. @_fixed_layout @usableFromInline internal class _EmptySetSingleton: _RawSetStorage { @nonobjc override internal init(_doNotCallMe: ()) { _sanityCheckFailure("This class cannot be directly initialized") } #if _runtime(_ObjC) @objc internal required init(objects: UnsafePointer, count: Int) { _sanityCheckFailure("This class cannot be directly initialized") } #endif } extension _RawSetStorage { /// The empty singleton that is used for every single Set that is created /// without any elements. The contents of the storage must never be mutated. @inlinable @nonobjc internal static var empty: _EmptySetSingleton { return Builtin.bridgeFromRawPointer( Builtin.addressof(&_swiftEmptySetSingleton)) } } extension _EmptySetSingleton: _NSSetCore { #if _runtime(_ObjC) // // NSSet implementation, assuming Self is the empty singleton // @objc(copyWithZone:) internal func copy(with zone: _SwiftNSZone?) -> AnyObject { return self } @objc internal var count: Int { return 0 } @objc(member:) internal func member(_ object: AnyObject) -> AnyObject? { return nil } @objc internal func objectEnumerator() -> _NSEnumerator { return _SwiftEmptyNSEnumerator() } @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 } #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 _SetStorage : _RawSetStorage, _NSSetCore { // This type is made with allocWithTailElems, so no init is ever called. // But we still need to have an init to satisfy the compiler. @nonobjc override internal init(_doNotCallMe: ()) { _sanityCheckFailure("This class cannot be directly initialized") } deinit { guard _count > 0 else { return } if !_isPOD(Element.self) { let elements = _elements for index in _hashTable { (elements + index.bucket).deinitialize(count: 1) } } _fixLifetime(self) } @inlinable final internal var _elements: UnsafeMutablePointer { @inline(__always) get { return self._rawElements.assumingMemoryBound(to: Element.self) } } internal var asNative: _NativeSet { return _NativeSet(self) } #if _runtime(_ObjC) @objc internal required init(objects: UnsafePointer, count: Int) { _sanityCheckFailure("don't call this designated initializer") } @objc(copyWithZone:) internal func copy(with zone: _SwiftNSZone?) -> AnyObject { return self } @objc internal var count: Int { return _count } @objc internal func objectEnumerator() -> _NSEnumerator { return _SwiftSetNSEnumerator(asNative) } @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(asNative.startIndex.bucket) } // 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 index = _HashTable.Index(bucket: Int(theState.extra.0)) let endIndex = asNative.endIndex _precondition(index == endIndex || _hashTable.isValid(index)) var stored = 0 for i in 0.. AnyObject? { guard let native = _conditionallyBridgeFromObjectiveC(object, Element.self) else { return nil } let (index, found) = asNative.find(native) guard found else { return nil } return _bridgeAnythingToObjectiveC(_elements[index.bucket]) } #endif } extension _SetStorage { @usableFromInline @_effects(releasenone) internal static func reallocate( original: _RawSetStorage, capacity: Int ) -> (storage: _SetStorage, rehash: Bool) { _sanityCheck(capacity >= original._count) let scale = _HashTable.scale(forCapacity: capacity) let rehash = (scale != original._scale) let newStorage = _SetStorage.allocate(scale: scale) return (newStorage, rehash) } @usableFromInline @_effects(releasenone) static internal func allocate(scale: Int) -> _SetStorage { // The entry count must be representable by an Int value; hence the scale's // peculiar upper bound. _sanityCheck(scale >= 0 && scale < Int.bitWidth - 1) let bucketCount = 1 &<< scale let wordCount = _UnsafeBitset.wordCount(forCapacity: bucketCount) let storage = Builtin.allocWithTailElems_2( _SetStorage.self, wordCount._builtinWordValue, _HashTable.Word.self, bucketCount._builtinWordValue, Element.self) let metadataAddr = Builtin.projectTailElems(storage, _HashTable.Word.self) let elementsAddr = Builtin.getTailAddr_Word( metadataAddr, wordCount._builtinWordValue, _HashTable.Word.self, Element.self) storage._count = 0 storage._capacity = _HashTable.capacity(forScale: scale) storage._scale = scale storage._rawElements = UnsafeMutableRawPointer(elementsAddr) // We use a slightly different hash seed whenever we change the size of the // hash table, so that we avoid certain copy operations becoming quadratic, // without breaking value semantics. (For background details, see // https://bugs.swift.org/browse/SR-3268) // FIXME: Use true per-instance seeding instead. Per-capacity seeding still // leaves hash values the same in same-sized tables, which may affect // operations on two tables at once. (E.g., union.) storage._seed = ( Hasher._seed.0 ^ UInt64(truncatingIfNeeded: scale), Hasher._seed.1) // Initialize hash table metadata. storage._hashTable.clear() return storage } } /// A wrapper around _RawSetStorage that provides most of the /// implementation of Set. @usableFromInline @_fixed_layout internal struct _NativeSet { /// See the comments on _RawSetStorage and its subclasses to understand why we /// store an untyped storage here. @usableFromInline internal var _storage: _RawSetStorage /// Constructs an instance from the empty singleton. @inlinable @inline(__always) internal init() { self._storage = _RawSetStorage.empty } /// Constructs a native set adopting the given storage. @inlinable @inline(__always) internal init(_ storage: _RawSetStorage) { self._storage = storage } @usableFromInline @_effects(releasenone) internal init(capacity: Int) { let scale = _HashTable.scale(forCapacity: capacity) self._storage = _SetStorage.allocate(scale: scale) } #if _runtime(_ObjC) @inlinable internal init(_ cocoa: _CocoaSet) { self.init(cocoa, capacity: cocoa.count) } @inlinable internal init(_ cocoa: _CocoaSet, capacity: Int) { _sanityCheck(cocoa.count <= capacity) self.init(capacity: capacity) for element in cocoa { insertNew(_forceBridgeFromObjectiveC(element, Element.self)) } } #endif } extension _NativeSet { // Primitive fields @inlinable internal var capacity: Int { @inline(__always) get { return _assumeNonNegative(_storage._capacity) } } @inlinable internal var hashTable: _HashTable { @inline(__always) get { return _storage._hashTable } } // This API is unsafe and needs a `_fixLifetime` in the caller. @inlinable internal var _elements: UnsafeMutablePointer { return _storage._rawElements.assumingMemoryBound(to: Element.self) } } extension _NativeSet { // Low-level unchecked operations @inlinable @inline(__always) internal func uncheckedElement(at index: Index) -> Element { defer { _fixLifetime(self) } _sanityCheck(hashTable.isOccupied(index)) return _elements[index.bucket] } @inlinable @inline(__always) internal func uncheckedInitialize(at index: Index, to element: Element) { _sanityCheck(hashTable.isValid(index)) (_elements + index.bucket).initialize(to: element) } } extension _NativeSet { // Low-level lookup operations @inlinable @inline(__always) internal func hashValue(for element: Element) -> Int { return element._rawHashValue(seed: _storage._seed) } @inlinable @inline(__always) internal func find(_ element: Element) -> (index: Index, found: Bool) { return find(element, hashValue: self.hashValue(for: element)) } /// Search for a given element, assuming it has the specified hash value. /// /// If the element is not present in this set, return the position where it /// could be inserted. @inlinable @inline(__always) internal func find( _ element: Element, hashValue: Int ) -> (index: Index, found: Bool) { let hashTable = self.hashTable var index = hashTable.idealIndex(forHashValue: hashValue) while hashTable._isOccupied(index) { if uncheckedElement(at: index) == element { return (index, true) } index = hashTable.index(wrappedAfter: index) } return (index, false) } } extension _NativeSet { // ensureUnique @inlinable internal mutating func reallocate( movingElements move: Bool, capacity: Int ) -> Bool { _sanityCheck(capacity >= count) let (newStorage, rehash) = _SetStorage.reallocate( original: _storage, capacity: capacity) guard count > 0 else { _storage = newStorage return rehash } let result = _NativeSet(newStorage) switch (move, rehash) { case (true, _): // Move & rehash elements for index in hashTable { let element = (self._elements + index.bucket).move() result._unsafeInsertNew(element) } // Clear out old storage, ensuring that its deinit won't overrelease the // elements we've just moved out. _storage._hashTable.clear() _storage._count = 0 case (false, true): // Copy & rehash elements for index in hashTable { result._unsafeInsertNew(self.uncheckedElement(at: index)) } case (false, false): // Copy elements to same entries in new storage result.hashTable.copyContents(of: hashTable) result._storage._count = self.count for index in hashTable { let element = uncheckedElement(at: index) result.uncheckedInitialize(at: index, to: element) } } _storage = result._storage return rehash } /// Ensure storage of self is uniquely held and can hold at least `capacity` /// elements. Returns true iff contents were rehashed. @inlinable @inline(__always) internal mutating func ensureUnique(isUnique: Bool, capacity: Int) -> Bool { if capacity <= self.capacity { if isUnique { return false } return reallocate(movingElements: isUnique, capacity: self.capacity) } return reallocate(movingElements: isUnique, capacity: capacity) } @inlinable internal mutating func reserveCapacity(_ capacity: Int, isUnique: Bool) { _ = ensureUnique(isUnique: isUnique, capacity: capacity) } } extension _NativeSet: _SetBuffer { @usableFromInline internal typealias Index = _HashTable.Index @inlinable internal var startIndex: Index { return hashTable.startIndex } @inlinable internal var endIndex: Index { return hashTable.endIndex } @inlinable internal func index(after index: Index) -> Index { return hashTable.index(after: index) } @inlinable @inline(__always) internal func index(for element: Element) -> Index? { if count == 0 { // Fast path that avoids computing the hash of the key. return nil } let (index, found) = find(element) return found ? index : nil } @inlinable internal var count: Int { @inline(__always) get { return _assumeNonNegative(_storage._count) } } @inlinable @inline(__always) internal func contains(_ member: Element) -> Bool { // Fast path: Don't calculate the hash if the set has no elements. if count == 0 { return false } return find(member).found } @inlinable @inline(__always) internal func element(at index: Index) -> Element { hashTable.checkOccupied(index) return _elements[index.bucket] } } #if _runtime(_ObjC) extension _NativeSet { // Bridging @usableFromInline 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 _storage === _RawSetStorage.empty || count == 0 { nsSet = _RawSetStorage.empty } else if _isBridgedVerbatimToObjectiveC(Element.self) { nsSet = unsafeDowncast(_storage, to: _SetStorage.self) } else { nsSet = _SwiftDeferredNSSet(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 // This function has a highly visible name to make it stand out in stack traces. @usableFromInline @inline(never) internal func ELEMENT_TYPE_OF_SET_VIOLATES_HASHABLE_REQUIREMENTS( _ elementType: Any.Type ) -> Never { _assertionFailure( "Fatal error", """ Duplicate elements of type '\(elementType)' were found in a Set. This usually means either that the type violates Hashable's requirements, or that members of such a set were mutated after insertion. """, flags: _fatalErrorFlags()) } extension _NativeSet { // Insertions /// Insert a new element into uniquely held storage. /// Storage must be uniquely referenced with adequate capacity. /// The `element` must not be already present in the Set. @inlinable internal func _unsafeInsertNew(_ element: Element) { _sanityCheck(count + 1 <= capacity) let hashValue = self.hashValue(for: element) if _isDebugAssertConfiguration() { // In debug builds, perform a full lookup and trap if we detect duplicate // elements -- these imply that the Element type violates Hashable // requirements. This is generally more costly than a direct insertion, // because we'll need to compare elements in case of hash collisions. let (index, found) = find(element, hashValue: hashValue) guard !found else { ELEMENT_TYPE_OF_SET_VIOLATES_HASHABLE_REQUIREMENTS(Element.self) } hashTable.insert(index) uncheckedInitialize(at: index, to: element) } else { let index = hashTable.insertNew(hashValue: hashValue) uncheckedInitialize(at: index, to: element) } _storage._count += 1 } /// Insert a new element into uniquely held storage. /// Storage must be uniquely referenced. /// The `element` must not be already present in the Set. @inlinable internal mutating func insertNew(_ element: Element) { _ = ensureUnique(isUnique: true, capacity: count + 1) _unsafeInsertNew(element) } @inlinable internal mutating func update( with element: Element, isUnique: Bool ) -> Element? { var (index, found) = find(element) let rehashed = ensureUnique( isUnique: isUnique, capacity: count + (found ? 0 : 1)) if rehashed { let (i, f) = find(element) if f != found { ELEMENT_TYPE_OF_SET_VIOLATES_HASHABLE_REQUIREMENTS(Element.self) } index = i } if found { let old = (_elements + index.bucket).move() uncheckedInitialize(at: index, to: element) return old } hashTable.insert(index) uncheckedInitialize(at: index, to: element) _storage._count += 1 return nil } /// A variant of insert that returns the inserted index rather than the /// corresponding member. @inlinable @discardableResult internal mutating func _insert( _ element: Element, isUnique: Bool ) -> (inserted: Bool, index: Index) { var (index, found) = find(element) if found { return (false, index) } if ensureUnique(isUnique: isUnique, capacity: count + 1) { (index, found) = find(element) guard !found else { ELEMENT_TYPE_OF_SET_VIOLATES_HASHABLE_REQUIREMENTS(Element.self) } } hashTable.insert(index) uncheckedInitialize(at: index, to: element) _storage._count += 1 return (true, index) } @inlinable internal mutating func insert( _ element: Element, isUnique: Bool ) -> (inserted: Bool, memberAfterInsert: Element) { let (inserted, index) = _insert(element, isUnique: isUnique) if inserted { return (true, element) } return (false, uncheckedElement(at: index)) } } extension _NativeSet: _HashTableDelegate { @inlinable @inline(__always) internal func hashValue(at index: Index) -> Int { return hashValue(for: uncheckedElement(at: index)) } @inlinable @inline(__always) internal func moveEntry(from source: Index, to target: Index) { (_elements + target.bucket) .moveInitialize(from: _elements + source.bucket, count: 1) } } extension _NativeSet { // Deletion @inlinable internal mutating func _delete(at index: Index) { hashTable.delete(at: index, with: self) _storage._count -= 1 } @inlinable internal mutating func remove(_ member: Element, isUnique: Bool) -> Element? { var (index, found) = find(member) // Fast path: if the element is not present, we will not mutate the set, so // don't force unique buffer. if !found { return nil } if ensureUnique(isUnique: isUnique, capacity: capacity) { (index, found) = find(member) guard found else { ELEMENT_TYPE_OF_SET_VIOLATES_HASHABLE_REQUIREMENTS(Element.self) } } let old = (_elements + index.bucket).move() _delete(at: index) return old } @inlinable internal mutating func remove(at index: Index, isUnique: Bool) -> Element { _precondition(hashTable.isOccupied(index), "Invalid index") let rehashed = ensureUnique(isUnique: isUnique, capacity: capacity) _sanityCheck(!rehashed) let old = (_elements + index.bucket).move() _delete(at: index) return old } @usableFromInline internal mutating func removeAll(isUnique: Bool) { guard isUnique else { let scale = self._storage._scale _storage = _SetStorage.allocate(scale: scale) return } for index in hashTable { (_elements + index.bucket).deinitialize(count: 1) } hashTable.clear() _storage._count = 0 } } #if _runtime(_ObjC) /// An NSEnumerator that works with any _NativeSet of verbatim bridgeable /// elements. Used by the various NSSet impls. final internal class _SwiftSetNSEnumerator : _SwiftNativeNSEnumerator, _NSEnumerator { internal var base: _NativeSet internal var bridgedElements: _BridgingHashBuffer? internal var nextIndex: _NativeSet.Index internal var endIndex: _NativeSet.Index internal override required init() { _sanityCheckFailure("don't call this designated initializer") } internal init(_ base: _NativeSet) { _sanityCheck(_isBridgedVerbatimToObjectiveC(Element.self)) self.base = base self.bridgedElements = nil self.nextIndex = base.startIndex self.endIndex = base.endIndex } internal init(_ deferred: _SwiftDeferredNSSet) { _sanityCheck(!_isBridgedVerbatimToObjectiveC(Element.self)) self.base = deferred.native self.bridgedElements = deferred.bridgeElements() self.nextIndex = base.startIndex self.endIndex = base.endIndex } private func bridgedElement(at index: _HashTable.Index) -> AnyObject { if let bridgedElements = self.bridgedElements { return bridgedElements[index] } return _bridgeAnythingToObjectiveC(base.element(at: index)) } // // NSEnumerator implementation. // // Do not call any of these methods from the standard library! // @objc internal func nextObject() -> AnyObject? { if nextIndex == endIndex { return nil } let index = nextIndex nextIndex = base.index(after: nextIndex) return self.bridgedElement(at: index) } @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 unmanagedObjects = _UnmanagedAnyObjectArray(objects) unmanagedObjects[0] = self.bridgedElement(at: nextIndex) nextIndex = base.index(after: nextIndex) state.pointee = theState return 1 } } #endif #if _runtime(_ObjC) /// This class exists for Objective-C bridging. It holds a reference to a /// _NativeSet, 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 _NativeSet of AnyObject will be constructed /// containing all the bridged elements. final internal class _SwiftDeferredNSSet : _SwiftNativeNSSet, _NSSetCore { // This stored property must be stored at offset zero. We perform atomic // operations on it. // // Do not access this property directly. @nonobjc private var _bridgedElements_DoNotUse: AnyObject? /// The unbridged elements. internal var native: _NativeSet internal init(_ native: _NativeSet) { _sanityCheck(native.count > 0) _sanityCheck(!_isBridgedVerbatimToObjectiveC(Element.self)) self.native = native super.init() } deinit { _bridgedElements?.deinitialize(elementsFrom: native.hashTable) } /// Returns the pointer to the stored property, which contains bridged /// Set elements. @nonobjc private var _bridgedElementsPtr: UnsafeMutablePointer { return _getUnsafePointerToStoredProperties(self) .assumingMemoryBound(to: Optional.self) } /// The buffer for bridged Set elements, if present. @nonobjc private var _bridgedElements: _BridgingHashBuffer? { guard let ref = _stdlib_atomicLoadARCRef(object: _bridgedElementsPtr) else { return nil } return unsafeDowncast(ref, to: _BridgingHashBuffer.self) } /// Attach a buffer for bridged Set elements. @nonobjc private func _initializeBridgedElements( _ storage: _BridgingHashBuffer ) -> Bool { return _stdlib_atomicInitializeARCRef( object: _bridgedElementsPtr, desired: storage) } @nonobjc internal func bridgeElements() -> _BridgingHashBuffer { if let bridgedElements = _bridgedElements { return bridgedElements } // Allocate and initialize heap storage for bridged objects. let bridged = _BridgingHashBuffer.allocate( bucketCount: native._storage._bucketCount) for index in native.hashTable { let object = _bridgeAnythingToObjectiveC(native.element(at: index)) bridged.initialize(at: index, to: object) } // Atomically put the bridged elements in place. if !_initializeBridgedElements(bridged) { // Lost the race. bridged.deinitialize(elementsFrom: native.hashTable) return _bridgedElements! } return bridged } @objc internal required init(objects: UnsafePointer, count: Int) { _sanityCheckFailure("don't call this designated initializer") } @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 } @objc(member:) internal func member(_ object: AnyObject) -> AnyObject? { guard let element = _conditionallyBridgeFromObjectiveC(object, Element.self) else { return nil } let (index, found) = native.find(element) guard found else { return nil } let bridged = bridgeElements() return bridged[index] } @objc internal func objectEnumerator() -> _NSEnumerator { return _SwiftSetNSEnumerator(self) } @objc internal var count: Int { return native.count } @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(native.startIndex.bucket) } // 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 index = _NativeSet.Index(bucket: Int(theState.extra.0)) let endIndex = native.endIndex _precondition(index == endIndex || native.hashTable.isValid(index)) // Only need to bridge once, so we can hoist it out of the loop. let bridgedElements = bridgeElements() var stored = 0 for i in 0.. { } #endif #if _runtime(_ObjC) @usableFromInline @_fixed_layout internal struct _CocoaSet { @usableFromInline internal let object: _NSSet @inlinable internal init(_ object: _NSSet) { self.object = object } } extension _CocoaSet { @usableFromInline @_effects(releasenone) internal func member(for index: Index) -> AnyObject { return index.allKeys[index.currentKeyIndex] } } extension _CocoaSet: Equatable { @usableFromInline internal static func ==(lhs: _CocoaSet, rhs: _CocoaSet) -> Bool { return _stdlib_NSObject_isEqual(lhs.object, rhs.object) } } extension _CocoaSet: _SetBuffer { @usableFromInline internal typealias Element = AnyObject @inlinable internal var startIndex: Index { return Index(self, startIndex: ()) } @inlinable internal var endIndex: Index { return Index(self, endIndex: ()) } @inlinable internal func index(after i: Index) -> Index { var i = i formIndex(after: &i) return i } @usableFromInline @_effects(releasenone) internal func formIndex(after i: inout Index) { _precondition(i.base.object === self.object, "Invalid index") _precondition(i.currentKeyIndex < i.allKeys.value, "Cannot increment endIndex") i.currentKeyIndex += 1 } @usableFromInline internal func index(for element: AnyObject) -> 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 !contains(element) { return nil } let allKeys = _stdlib_NSSet_allObjects(object) var keyIndex = -1 for i in 0..= 0, "Key was found in fast path, but not found later?") return Index(self, allKeys, keyIndex) } @inlinable internal var count: Int { return object.count } @inlinable internal func contains(_ element: AnyObject) -> Bool { return object.member(element) != nil } @usableFromInline internal func element(at i: Index) -> AnyObject { let value: AnyObject? = i.allKeys[i.currentKeyIndex] _sanityCheck(value != nil, "Item not found in underlying NSSet") return value! } } #endif extension Set { @usableFromInline @_frozen internal enum _Variant { case native(_NativeSet) #if _runtime(_ObjC) case cocoa(_CocoaSet) #endif } } extension Set._Variant { #if _runtime(_ObjC) @usableFromInline @_transparent internal var guaranteedNative: Bool { return _canBeClass(Element.self) == 0 } /// Allow the optimizer to consider the surrounding code unreachable if /// Set is guaranteed to be native. @usableFromInline @_transparent internal func cocoaPath() { if guaranteedNative { _conditionallyUnreachable() } } #endif @inlinable internal mutating func isUniquelyReferenced() -> Bool { // Note that &self drills down through .native(_NativeSet) to the first // property in _NativeSet, which is the reference to the storage. switch self { case .native: return _isUnique_native(&self) #if _runtime(_ObjC) case .cocoa: cocoaPath() // Don't consider Cocoa buffer mutable, even if it is mutable and is // uniquely referenced. return false #endif } } @usableFromInline @_transparent internal var asNative: _NativeSet { get { switch self { case .native(let nativeSet): return nativeSet #if _runtime(_ObjC) case .cocoa: _sanityCheckFailure("internal error: not backed by native buffer") #endif } } set { self = .native(newValue) } } #if _runtime(_ObjC) @inlinable internal var asCocoa: _CocoaSet { switch self { case .native: _sanityCheckFailure("internal error: not backed by NSSet") case .cocoa(let cocoa): return cocoa } } #endif /// Reserves enough space for the specified number of elements to be stored /// without reallocating additional storage. @inlinable internal mutating func reserveCapacity(_ capacity: Int) { switch self { case .native: let isUnique = isUniquelyReferenced() asNative.reserveCapacity(capacity, isUnique: isUnique) #if _runtime(_ObjC) case .cocoa(let cocoa): let capacity = Swift.max(cocoa.count, capacity) self = .native(_NativeSet(cocoa, capacity: capacity)) #endif } } /// 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 internal var capacity: Int { switch self { case .native: return asNative.capacity #if _runtime(_ObjC) case .cocoa(let cocoa): return cocoa.count #endif } } } extension Set._Variant: _SetBuffer { @usableFromInline internal typealias Index = Set.Index @inlinable internal var startIndex: Index { switch self { case .native: return Index(_native: asNative.startIndex) #if _runtime(_ObjC) case .cocoa(let cocoaSet): cocoaPath() return Index(_cocoa: cocoaSet.startIndex) #endif } } @inlinable internal var endIndex: Index { switch self { case .native: return Index(_native: asNative.endIndex) #if _runtime(_ObjC) case .cocoa(let cocoaSet): cocoaPath() return Index(_cocoa: cocoaSet.endIndex) #endif } } @inlinable internal func index(after i: Index) -> Index { switch self { case .native: return Index(_native: asNative.index(after: i._asNative)) #if _runtime(_ObjC) case .cocoa(let cocoaSet): cocoaPath() return Index(_cocoa: cocoaSet.index(after: i._asCocoa)) #endif } } @inlinable @inline(__always) internal func index(for element: Element) -> Index? { switch self { case .native: guard let index = asNative.index(for: element) else { return nil } return Index(_native: index) #if _runtime(_ObjC) case .cocoa(let cocoa): cocoaPath() let cocoaElement = _bridgeAnythingToObjectiveC(element) guard let index = cocoa.index(for: cocoaElement) else { return nil } return Index(_cocoa: index) #endif } } @inlinable internal var count: Int { @inline(__always) get { switch self { case .native: return asNative.count #if _runtime(_ObjC) case .cocoa(let cocoa): cocoaPath() return cocoa.count #endif } } } @inlinable @inline(__always) internal func contains(_ member: Element) -> Bool { switch self { case .native: return asNative.contains(member) #if _runtime(_ObjC) case .cocoa(let cocoa): cocoaPath() return cocoa.contains(_bridgeAnythingToObjectiveC(member)) #endif } } @inlinable @inline(__always) internal func element(at i: Index) -> Element { switch self { case .native: return asNative.element(at: i._asNative) #if _runtime(_ObjC) case .cocoa(let cocoa): cocoaPath() let cocoaMember = cocoa.element(at: i._asCocoa) return _forceBridgeFromObjectiveC(cocoaMember, Element.self) #endif } } } extension Set._Variant { @inlinable internal mutating func update(with value: Element) -> Element? { switch self { case .native: let isUnique = self.isUniquelyReferenced() return asNative.update(with: value, isUnique: isUnique) #if _runtime(_ObjC) case .cocoa(let cocoa): cocoaPath() // Make sure we have space for an extra element. var native = _NativeSet(cocoa, capacity: cocoa.count + 1) let old = native.update(with: value, isUnique: true) self = .native(native) return old #endif } } @inlinable internal mutating func insert( _ element: Element ) -> (inserted: Bool, memberAfterInsert: Element) { switch self { case .native: let isUnique = self.isUniquelyReferenced() return asNative.insert(element, isUnique: isUnique) #if _runtime(_ObjC) case .cocoa(let cocoa): // Make sure we have space for an extra element. var native = _NativeSet(cocoa, capacity: cocoa.count + 1) let result = native.insert(element, isUnique: true) self = .native(native) return result #endif } } @inlinable @discardableResult internal mutating func remove(at index: Index) -> Element { switch self { case .native: let isUnique = isUniquelyReferenced() return asNative.remove(at: index._asNative, isUnique: isUnique) #if _runtime(_ObjC) case .cocoa(let cocoa): cocoaPath() // 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 cocoaMember = cocoa.member(for: index._asCocoa) var native = _NativeSet(cocoa) let nativeMember = _forceBridgeFromObjectiveC(cocoaMember, Element.self) let old = native.remove(nativeMember, isUnique: true) _sanityCheck(nativeMember == old, "Bridging did not preserve equality") self = .native(native) return nativeMember #endif } } @inlinable @discardableResult internal mutating func remove(_ member: Element) -> Element? { switch self { case .native: let isUnique = isUniquelyReferenced() return asNative.remove(member, isUnique: isUnique) #if _runtime(_ObjC) case .cocoa(let cocoa): cocoaPath() let cocoaMember = _bridgeAnythingToObjectiveC(member) if !cocoa.contains(cocoaMember) { return nil } var native = _NativeSet(cocoa) let old = native.remove(member, isUnique: true) self = .native(native) _sanityCheck(old != nil, "Bridging did not preserve equality") return old #endif } } @inlinable internal mutating func removeAll(keepingCapacity keepCapacity: Bool) { if !keepCapacity { self = .native(_NativeSet()) return } guard count > 0 else { return } switch self { case .native: let isUnique = isUniquelyReferenced() asNative.removeAll(isUnique: isUnique) #if _runtime(_ObjC) case .cocoa(let cocoa): self = .native(_NativeSet(capacity: cocoa.count)) #endif } } } extension Set._Variant { /// Returns an iterator over the elements. /// /// - Complexity: O(1). @inlinable @inline(__always) __consuming internal func makeIterator() -> Set.Iterator { switch self { case .native(let native): return Set.Iterator(_native: native.makeIterator()) #if _runtime(_ObjC) case .cocoa(let cocoa): return Set.Iterator(_cocoa: cocoa.makeIterator()) #endif } } } #if _runtime(_ObjC) extension _CocoaSet { @_fixed_layout // FIXME(sil-serialize-all) @usableFromInline internal struct Index { // 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 base: _CocoaSet // 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(_ base: _CocoaSet, startIndex: ()) { self.base = base self.allKeys = _stdlib_NSSet_allObjects(base.object) self.currentKeyIndex = 0 } @inlinable // FIXME(sil-serialize-all) internal init(_ base: _CocoaSet, endIndex: ()) { self.base = base self.allKeys = _stdlib_NSSet_allObjects(base.object) self.currentKeyIndex = allKeys.value } @inlinable // FIXME(sil-serialize-all) internal init( _ base: _CocoaSet, _ allKeys: _HeapBuffer, _ currentKeyIndex: Int ) { self.base = base self.allKeys = allKeys self.currentKeyIndex = currentKeyIndex } } } extension _CocoaSet.Index: Equatable { @inlinable internal static func == (lhs: _CocoaSet.Index, rhs: _CocoaSet.Index) -> Bool { _precondition(lhs.base.object === rhs.base.object, "Comparing indexes from different sets") return lhs.currentKeyIndex == rhs.currentKeyIndex } } extension _CocoaSet.Index: Comparable { @inlinable internal static func < (lhs: _CocoaSet.Index, rhs: _CocoaSet.Index) -> Bool { _precondition(lhs.base.object === rhs.base.object, "Comparing indexes from different sets") return lhs.currentKeyIndex < rhs.currentKeyIndex } } #endif extension Set { /// The position of an element in a set. @_fixed_layout public struct Index { // 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. @_frozen @usableFromInline internal enum _Variant { case native(_NativeSet.Index) #if _runtime(_ObjC) case cocoa(_CocoaSet.Index) #endif } @usableFromInline internal var _variant: _Variant @inlinable @inline(__always) internal init(_variant: _Variant) { self._variant = _variant } @inlinable @inline(__always) internal init(_native index: _NativeSet.Index) { self.init(_variant: .native(index)) } #if _runtime(_ObjC) @inlinable @inline(__always) internal init(_cocoa index: _CocoaSet.Index) { self.init(_variant: .cocoa(index)) } #endif } } extension Set.Index { #if _runtime(_ObjC) @usableFromInline @_transparent internal var _guaranteedNative: Bool { return _canBeClass(Element.self) == 0 } /// Allow the optimizer to consider the surrounding code unreachable if /// Set is guaranteed to be native. @usableFromInline @_transparent internal func _cocoaPath() { if _guaranteedNative { _conditionallyUnreachable() } } #endif @usableFromInline @_transparent internal var _asNative: _NativeSet.Index { switch _variant { case .native(let nativeIndex): return nativeIndex #if _runtime(_ObjC) case .cocoa: _sanityCheckFailure("internal error: does not contain a native index") #endif } } #if _runtime(_ObjC) @usableFromInline @_transparent internal var _asCocoa: _CocoaSet.Index { switch _variant { case .native: _sanityCheckFailure("internal error: does not contain a Cocoa index") case .cocoa(let cocoaIndex): return cocoaIndex } } #endif } extension Set.Index: Equatable { @inlinable public static func == ( lhs: Set.Index, rhs: Set.Index ) -> Bool { switch (lhs._variant, rhs._variant) { case (.native(let lhsNative), .native(let rhsNative)): return lhsNative == rhsNative #if _runtime(_ObjC) case (.cocoa(let lhsCocoa), .cocoa(let rhsCocoa)): lhs._cocoaPath() return lhsCocoa == rhsCocoa default: _preconditionFailure("Comparing indexes from different sets") #endif } } } extension Set.Index: Comparable { @inlinable public static func < ( lhs: Set.Index, rhs: Set.Index ) -> Bool { switch (lhs._variant, rhs._variant) { case (.native(let lhsNative), .native(let rhsNative)): return lhsNative < rhsNative #if _runtime(_ObjC) case (.cocoa(let lhsCocoa), .cocoa(let rhsCocoa)): lhs._cocoaPath() return lhsCocoa < rhsCocoa default: _preconditionFailure("Comparing indexes from different sets") #endif } } } extension Set.Index: Hashable { /// Hashes the essential components of this value by feeding them into the /// given hasher. /// /// - Parameter hasher: The hasher to use when combining the components /// of this instance. @inlinable public func hash(into hasher: inout Hasher) { #if _runtime(_ObjC) switch _variant { case .native(let nativeIndex): hasher.combine(0 as UInt8) hasher.combine(nativeIndex.bucket) case .cocoa(let cocoaIndex): _cocoaPath() hasher.combine(1 as UInt8) hasher.combine(cocoaIndex.currentKeyIndex) } #else hasher.combine(_asNative.bucket) #endif } } extension _NativeSet: Sequence { @usableFromInline @_fixed_layout internal struct Iterator { // The iterator is iterating over a frozen view of the collection state, so // it keeps its own reference to the set. @usableFromInline internal let base: _NativeSet @usableFromInline internal var iterator: _HashTable.Iterator @inlinable init(_ base: _NativeSet) { self.base = base self.iterator = base.hashTable.makeIterator() } } @inlinable __consuming internal func makeIterator() -> Iterator { return Iterator(self) } } extension _NativeSet.Iterator: IteratorProtocol { @inlinable internal mutating func next() -> Element? { guard let index = iterator.next() else { return nil } return base.uncheckedElement(at: index) } } #if _runtime(_ObjC) extension _CocoaSet: Sequence { @usableFromInline final internal class Iterator { // 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. internal var _fastEnumerationState: _SwiftNSFastEnumerationState = _makeSwiftNSFastEnumerationState() // This stored property should be stored right after // `_fastEnumerationState`. There's code below relying on this. internal var _fastEnumerationStackBuf = _CocoaFastEnumerationStackBuf() internal let base: _CocoaSet internal var _fastEnumerationStatePtr: UnsafeMutablePointer<_SwiftNSFastEnumerationState> { return _getUnsafePointerToStoredProperties(self).assumingMemoryBound( to: _SwiftNSFastEnumerationState.self) } 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. internal var itemIndex: Int = 0 internal var itemCount: Int = 0 internal init(_ base: _CocoaSet) { self.base = base } } @usableFromInline __consuming internal func makeIterator() -> Iterator { return Iterator(self) } } extension _CocoaSet.Iterator: IteratorProtocol { @usableFromInline internal typealias Element = AnyObject @usableFromInline internal func next() -> Element? { if itemIndex < 0 { return nil } let base = self.base 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 = base.object.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 extension Set { /// An iterator over the members of a `Set`. @_fixed_layout public struct Iterator { // Set has a separate IteratorProtocol and Index because of efficiency // and implementability reasons. // // Native sets have efficient indices. Bridged NSSet instances don't. // // 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. @usableFromInline @_frozen internal enum _Variant { case native(_NativeSet.Iterator) #if _runtime(_ObjC) case cocoa(_CocoaSet.Iterator) #endif } @usableFromInline internal var _variant: _Variant @inlinable internal init(_variant: _Variant) { self._variant = _variant } @inlinable internal init(_native: _NativeSet.Iterator) { self.init(_variant: .native(_native)) } #if _runtime(_ObjC) @usableFromInline internal init(_cocoa: _CocoaSet.Iterator) { self.init(_variant: .cocoa(_cocoa)) } #endif } } extension Set.Iterator { #if _runtime(_ObjC) @usableFromInline @_transparent internal var _guaranteedNative: Bool { return _canBeClass(Element.self) == 0 } /// Allow the optimizer to consider the surrounding code unreachable if /// Set is guaranteed to be native. @usableFromInline @_transparent internal func _cocoaPath() { if _guaranteedNative { _conditionallyUnreachable() } } #endif @usableFromInline @_transparent internal var _asNative: _NativeSet.Iterator { get { switch _variant { case .native(let nativeIterator): return nativeIterator #if _runtime(_ObjC) case .cocoa: _sanityCheckFailure("internal error: does not contain a native index") #endif } } set { self._variant = .native(newValue) } } } extension Set.Iterator: IteratorProtocol { /// 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 @inline(__always) public mutating func next() -> Element? { switch _variant { case .native: return _asNative.next() #if _runtime(_ObjC) case .cocoa(let cocoaIterator): _cocoaPath() if let cocoaElement = cocoaIterator.next() { return _forceBridgeFromObjectiveC(cocoaElement, Element.self) } return nil #endif } } } extension Set.Iterator: CustomReflectable { /// A mirror that reflects the iterator. public var customMirror: Mirror { return Mirror( self, children: EmptyCollection<(label: String?, value: Any)>()) } } extension Set: CustomReflectable { /// A mirror that reflects the set. 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 public // SPI(Foundation) struct _SetBuilder { @usableFromInline internal var _target: _NativeSet @usableFromInline internal let _requestedCount: Int @inlinable public init(count: Int) { _target = _NativeSet(capacity: count) _requestedCount = count } @inlinable public mutating func add(member: Element) { _precondition(_target.count < _requestedCount, "Can't add more members than promised") _target.insertNew(member) } @inlinable public mutating func take() -> Set { _precondition(_target.capacity > 0 || _requestedCount == 0, "Cannot take the result twice") _precondition(_target.count == _requestedCount, "The number of members added does not match the promised count") // Prevent taking the result twice. var result = _NativeSet() swap(&result, &_target) return Set(_native: 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) } /// The total number of elements that the set can contain without /// allocating new storage. @inlinable public var capacity: Int { return _variant.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 public mutating func reserveCapacity(_ minimumCapacity: Int) { _variant.reserveCapacity(minimumCapacity) _sanityCheck(self.capacity >= minimumCapacity) } } //===--- Bridging ---------------------------------------------------------===// #if _runtime(_ObjC) extension Set { @inlinable public func _bridgeToObjectiveCImpl() -> _NSSetCore { switch _variant { case .native(let nativeSet): return nativeSet.bridged() case .cocoa(let cocoaSet): return cocoaSet.object } } /// Returns the native Dictionary hidden inside this NSDictionary; /// returns nil otherwise. public static func _bridgeFromObjectiveCAdoptingNativeStorageOf( _ s: AnyObject ) -> Set? { // Try all three NSSet impls that we currently provide. if let deferred = s as? _SwiftDeferredNSSet { return Set(_native: deferred.native) } if let nativeStorage = s as? _SetStorage { return Set(_native: _NativeSet(nativeStorage)) } if s === _RawSetStorage.empty { return Set() } // FIXME: what if `s` is native storage, but for different key/value type? return nil } } #endif public typealias SetIndex = Set.Index public typealias SetIterator = Set.Iterator