Files
swift-mirror/stdlib/public/core/Set.swift
Karoy Lorentey 8366edd93d [stdlib] Set, Dictionary: Simplify variant processing
Don’t duplicate native paths — make the cocoa case conditionally unreachable instead.
2018-09-22 02:04:09 +01:00

3404 lines
105 KiB
Swift

//===----------------------------------------------------------------------===//
//
// 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<Int>
/// print(primes.isSubset(of: 0..<10))
/// // Prints "true"
///
/// // Performs an intersection with an Array<Int>
/// 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<Int>
///
/// let laterPrimesSet = Set(morePrimes.filter { $0 > 10 })
/// // 'laterPrimesSet' is of type Set<Int>
///
/// 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<Element: Hashable> {
@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<Element>) {
_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<Element>(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<Element>, rhs: Set<Element>) -> 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: <rdar://problem/18915294> Cache Set<T> 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<Element: Hashable>: _AnyHashableBox {
internal let _value: Set<Element>
internal let _canonical: Set<AnyHashable>
internal init(_ value: Set<Element>) {
self._value = value
self._canonical = value as Set<AnyHashable>
}
internal var _base: Any {
return _value
}
internal var _canonicalBox: _AnyHashableBox {
return _SetAnyHashableBox<AnyHashable>(_canonical)
}
internal func _isEqual(to other: _AnyHashableBox) -> Bool? {
guard let other = other as? _SetAnyHashableBox<AnyHashable> 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: Hashable>() -> T? {
return _value as? T
}
internal func _downCastConditional<T>(
into result: UnsafeMutablePointer<T>
) -> 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<DayOfTheWeek> = [.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<DayOfTheWeek> = [.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<Int>()
/// print(emptySet.isEmpty)
/// // Prints "true"
///
/// emptySet = []
/// print(emptySet.isEmpty)
/// // Prints "true"
@inlinable
public init() {
self = Set<Element>(_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<Source: Sequence>(_ sequence: Source)
where Source.Element == Element {
self.init(minimumCapacity: sequence.underestimatedCount)
if let s = sequence as? Set<Element> {
// 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<S: Sequence>(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<S: Sequence>(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<S: Sequence>(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<S: Sequence>(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<S: Sequence>(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<S: Sequence>(_ other: S) -> Set<Element>
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<S: Sequence>(_ 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<S: Sequence>(_ other: S) -> Set<Element>
where S.Element == Element {
return self._subtracting(other)
}
@inlinable
internal func _subtracting<S: Sequence>(_ other: S) -> Set<Element>
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<S: Sequence>(_ other: S)
where S.Element == Element {
_subtract(other)
}
@inlinable
internal mutating func _subtract<S: Sequence>(_ 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<S: Sequence>(_ other: S) -> Set<Element>
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<S: Sequence>(_ 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<S: Sequence>(_ other: S) -> Set<Element>
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<S: Sequence>(_ 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<AnyObject>)
/// Equivalent to `NSSet.allObjects`, but does not leave objects on the
/// autorelease pool.
@inlinable
internal func _stdlib_NSSet_allObjects(
_ nss: _NSSet
) -> _HeapBuffer<Int, AnyObject> {
let count = nss.count
let storage = _HeapBuffer<Int, AnyObject>(
_HeapBufferStorage<Int, AnyObject>.self, count, count)
_stdlib_CFSetGetValues(nss, storage.baseAddress)
return storage
}
#endif
//===--- Compiler conversion/casting entry points for Set<Element> --------===//
/// 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<DerivedValue, BaseValue>(_ source: Set<DerivedValue>)
-> Set<BaseValue> {
var builder = _SetBuilder<BaseValue>(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<SourceValue, TargetValue>(
_ source: UnsafePointer<Set<SourceValue>>,
_ target: UnsafeMutablePointer<Set<TargetValue>>) {
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<BaseValue, DerivedValue>(_ source: Set<BaseValue>)
-> Set<DerivedValue> {
#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<SourceValue, TargetValue>(
_ source: UnsafePointer<Set<SourceValue>>,
_ target: UnsafeMutablePointer<Set<TargetValue>>
) -> Bool {
if let result: Set<TargetValue> = _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<BaseValue, DerivedValue>(
_ source: Set<BaseValue>
) -> Set<DerivedValue>? {
var result = Set<DerivedValue>(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<Element>) {
_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<Element>) -> 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<Element>) -> 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<Element>) -> 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<Element>) -> Set<Element> {
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<Element>) -> 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<Element>) -> 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<Element>) -> Set<Element> {
var newSet = Set<Element>()
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<Element>) {
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<AnyObject?>, 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<AnyObject>?, 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<Element: Hashable>
: _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<Element> {
@inline(__always)
get {
return self._rawElements.assumingMemoryBound(to: Element.self)
}
}
internal var asNative: _NativeSet<Element> {
return _NativeSet(self)
}
#if _runtime(_ObjC)
@objc
internal required init(objects: UnsafePointer<AnyObject?>, 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<Element>(asNative)
}
@objc(countByEnumeratingWithState:objects:count:)
internal func countByEnumerating(
with state: UnsafeMutablePointer<_SwiftNSFastEnumerationState>,
objects: UnsafeMutablePointer<AnyObject>?, 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..<count {
if index == endIndex { break }
let element = _elements[index.bucket]
unmanagedObjects[i] = _bridgeAnythingToObjectiveC(element)
stored += 1
index = asNative.index(after: index)
}
theState.extra.0 = CUnsignedLong(index.bucket)
state.pointee = theState
return stored
}
@objc(member:)
internal func member(_ object: AnyObject) -> 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<Element>.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<Element>.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<Element: Hashable> {
/// 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<Element>.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<Element> {
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<Element>.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<Element>.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<Element>.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<Element: Hashable>
: _SwiftNativeNSEnumerator, _NSEnumerator {
internal var base: _NativeSet<Element>
internal var bridgedElements: _BridgingHashBuffer?
internal var nextIndex: _NativeSet<Element>.Index
internal var endIndex: _NativeSet<Element>.Index
internal override required init() {
_sanityCheckFailure("don't call this designated initializer")
}
internal init(_ base: _NativeSet<Element>) {
_sanityCheck(_isBridgedVerbatimToObjectiveC(Element.self))
self.base = base
self.bridgedElements = nil
self.nextIndex = base.startIndex
self.endIndex = base.endIndex
}
internal init(_ deferred: _SwiftDeferredNSSet<Element>) {
_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<AnyObject>,
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<Element: Hashable>
: _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<Element>
internal init(_ native: _NativeSet<Element>) {
_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<AnyObject?> {
return _getUnsafePointerToStoredProperties(self)
.assumingMemoryBound(to: Optional<AnyObject>.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<AnyObject?>, 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<Element>(self)
}
@objc
internal var count: Int {
return native.count
}
@objc(countByEnumeratingWithState:objects:count:)
internal func countByEnumerating(
with state: UnsafeMutablePointer<_SwiftNSFastEnumerationState>,
objects: UnsafeMutablePointer<AnyObject>?,
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<Element>.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..<count {
if index == endIndex { break }
unmanagedObjects[i] = bridgedElements[index]
stored += 1
index = native.index(after: index)
}
theState.extra.0 = CUnsignedLong(index.bucket)
state.pointee = theState
return stored
}
}
#else
// FIXME: Remove this.
final internal class _SwiftDeferredNSSet<Element: Hashable> { }
#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..<allKeys.value {
if _stdlib_NSObject_isEqual(element, allKeys[i]) {
keyIndex = i
break
}
}
_sanityCheck(keyIndex >= 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<Element>)
#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<Element> 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<Element> {
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<Element>.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<Element>(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<Element>(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<Element>(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<Element>(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<Element>())
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<Element>.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<Int, AnyObject>
/// 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<Int, AnyObject>,
_ 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<Element>.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<Element>.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<Element> is guaranteed to be native.
@usableFromInline
@_transparent
internal func _cocoaPath() {
if _guaranteedNative {
_conditionallyUnreachable()
}
}
#endif
@usableFromInline @_transparent
internal var _asNative: _NativeSet<Element>.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<Element>.Index,
rhs: Set<Element>.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<Element>.Index,
rhs: Set<Element>.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<Element>`.
@_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<Element>.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<Element>.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<Element> is guaranteed to be native.
@usableFromInline @_transparent
internal func _cocoaPath() {
if _guaranteedNative {
_conditionallyUnreachable()
}
}
#endif
@usableFromInline @_transparent
internal var _asNative: _NativeSet<Element>.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<Element: Hashable> {
@usableFromInline
internal var _target: _NativeSet<Element>
@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<Element> {
_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<Element>()
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<Element>? {
// Try all three NSSet impls that we currently provide.
if let deferred = s as? _SwiftDeferredNSSet<Element> {
return Set(_native: deferred.native)
}
if let nativeStorage = s as? _SetStorage<Element> {
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<Element: Hashable> = Set<Element>.Index
public typealias SetIterator<Element: Hashable> = Set<Element>.Iterator