mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Piggybacks some resilience diagnostics onto the availability checking code. Public and versioned functions with inlineable bodies can only reference other public and internal entities, since the SIL code for the function body is serialized and stored as part of the module. This includes @_transparent functions, @_inlineable functions, accessors for @_inlineable storage, @inline(__always) functions, and in Swift 4 mode, default argument expressions. The new checks are a source-breaking change, however we don't guarantee source compatibility for underscored attributes. The new ABI and tests for the default argument model will come in subsequent commits.
5391 lines
176 KiB
Plaintext
5391 lines
176 KiB
Plaintext
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2017 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
|
|
|
|
// General Mutable, Value-Type Collections
|
|
// =================================================
|
|
//
|
|
// Implementation notes
|
|
// ====================
|
|
//
|
|
// `Dictionary` uses two storage schemes: native storage and Cocoa storage.
|
|
//
|
|
// Native storage is a hash table with open addressing and linear probing. The
|
|
// bucket array forms a logical ring (e.g., a chain can wrap around the end of
|
|
// buckets array to the beginning of it).
|
|
//
|
|
// The logical bucket array is implemented as three arrays: Key, Value, and a
|
|
// bitmap that marks valid entries. An invalid entry marks the end of a chain.
|
|
// There is always at least one invalid entry among the buckets. `Dictionary`
|
|
// does not use tombstones.
|
|
//
|
|
// In addition to the native storage, `Dictionary` can also wrap an
|
|
// `NSDictionary` in order to allow bridging `NSDictionary` to `Dictionary` in
|
|
// `O(1)`.
|
|
//
|
|
// Currently native storage uses a data structure like this::
|
|
//
|
|
// Dictionary<K,V> (a struct)
|
|
// +------------------------------------------------+
|
|
// | _VariantDictionaryBuffer<K,V> (an enum) |
|
|
// | +--------------------------------------------+ |
|
|
// | | [_NativeDictionaryBuffer<K,V> (a struct)] | |
|
|
// | +---|----------------------------------------+ |
|
|
// +----/-------------------------------------------+
|
|
// /
|
|
// |
|
|
// V _RawNativeDictionaryStorage (a class)
|
|
// +-----------------------------------------------------------+
|
|
// | capacity |
|
|
// | count |
|
|
// | ptrToBits |
|
|
// | ptrToKeys |
|
|
// | ptrToValues |
|
|
// | [inline array of bits indicating whether bucket is set ] |
|
|
// | [inline array of keys ] |
|
|
// | [inline array of values ] |
|
|
// +-----------------------------------------------------------+
|
|
//
|
|
//
|
|
// Cocoa storage uses a data structure like this::
|
|
//
|
|
// Dictionary<K,V> (a struct)
|
|
// +----------------------------------------------+
|
|
// | _VariantDictionaryBuffer<K,V> (an enum) |
|
|
// | +----------------------------------------+ |
|
|
// | | [ _CocoaDictionaryBuffer (a struct) ] | |
|
|
// | +---|------------------------------------+ |
|
|
// +-----|----------------------------------------+
|
|
// |
|
|
// +---+
|
|
// |
|
|
// V NSDictionary (a class)
|
|
// +--------------+
|
|
// | [refcount#1] |
|
|
// +--------------+
|
|
// ^
|
|
// +-+
|
|
// | Dictionary<K,V>.Index (an enum)
|
|
// +---|-----------------------------------+
|
|
// | | _CocoaDictionaryIndex (a struct) |
|
|
// | +-|-----------------------------+ |
|
|
// | | * [ all keys ] [ next index ] | |
|
|
// | +-------------------------------+ |
|
|
// +---------------------------------------+
|
|
//
|
|
//
|
|
// The Native Kinds of Storage
|
|
// ---------------------------
|
|
//
|
|
// There are three different classes that can provide a native backing storage:
|
|
// * `_RawNativeDictionaryStorage`
|
|
// * `_TypedNativeDictionaryStorage<K, V>` (extends Raw)
|
|
// * `_HashableTypedNativeDictionaryStorage<K: Hashable, V>` (extends Typed)
|
|
//
|
|
// (Hereafter RawStorage, TypedStorage, and HashableStorage, respectively)
|
|
//
|
|
// In a less optimized implementation, the parent classes could
|
|
// be eliminated, as they exist only to provide special-case behaviors.
|
|
// HashableStorage has everything a full implementation of a Dictionary
|
|
// requires, and is subsequently able to provide a full NSDictionary
|
|
// implementation. Note that HashableStorage must have the `K: Hashable`
|
|
// constraint because the NSDictionary implementation can't be provided in a
|
|
// constrained extension.
|
|
//
|
|
// In normal usage, you can expect the backing storage of a Dictionary to be a
|
|
// NativeStorage.
|
|
//
|
|
// TypedStorage is distinguished from HashableStorage to allow us to create a
|
|
// `_NativeDictionaryBuffer<AnyObject, AnyObject>`. Without the Hashable
|
|
// requirement, such a Buffer is restricted to operations which can be performed
|
|
// with only the structure of the Storage: indexing and iteration. This is used
|
|
// in _SwiftDeferredNSDictionary to construct twin "native" and "bridged"
|
|
// storage. Key-based lookups are performed on the native storage, with the
|
|
// resultant index then used on the bridged storage.
|
|
//
|
|
// The only thing that TypedStorage adds over RawStorage is an implementation of
|
|
// deinit, to clean up the AnyObjects it stores. Although it nominally
|
|
// inherits an NSDictionary implementation from RawStorage, this implementation
|
|
// isn't useful and is never used.
|
|
//
|
|
// RawStorage exists to allow a type-punned empty singleton Storage to be
|
|
// created. Any time an empty Dictionary is created, this Storage is used. If
|
|
// this type didn't exist, then NativeBuffer would have to store a Storage that
|
|
// declared its actual type parameters. Similarly, the empty singleton would
|
|
// have to declare its actual type parameters. If the singleton was, for
|
|
// instance, a `HashableStorage<(), ()>`, then it would be a violation of
|
|
// Swift's strict aliasing rules to pass it where a `HashableStorage<Int, Int>`
|
|
// was expected.
|
|
//
|
|
// It's therefore necessary for several types to store a RawStorage, rather than
|
|
// a TypedStorage, to allow for the possibility of the empty singleton.
|
|
// RawStorage also provides an implementation of an always-empty NSDictionary.
|
|
//
|
|
//
|
|
// Index Invalidation
|
|
// ------------------
|
|
//
|
|
// FIXME: decide if this guarantee is worth making, as it restricts
|
|
// collision resolution to first-come-first-serve. The most obvious alternative
|
|
// would be robin hood hashing. The Rust code base is the best
|
|
// resource on a *practical* implementation of robin hood hashing I know of:
|
|
// https://github.com/rust-lang/rust/blob/ac919fcd9d4a958baf99b2f2ed5c3d38a2ebf9d0/src/libstd/collections/hash/map.rs#L70-L178
|
|
//
|
|
// Indexing a container, `c[i]`, uses the integral offset stored in the index
|
|
// to access the elements referenced by the container. Generally, an index into
|
|
// one container has no meaning for another. However copy-on-write currently
|
|
// preserves indices under insertion, as long as reallocation doesn't occur:
|
|
//
|
|
// var (i, found) = d.find(k) // i is associated with d's storage
|
|
// if found {
|
|
// var e = d // now d is sharing its data with e
|
|
// e[newKey] = newValue // e now has a unique copy of the data
|
|
// return e[i] // use i to access e
|
|
// }
|
|
//
|
|
// The result should be a set of iterator invalidation rules familiar to anyone
|
|
// familiar with the C++ standard library. Note that because all accesses to a
|
|
// dictionary storage are bounds-checked, this scheme never compromises memory
|
|
// safety.
|
|
//
|
|
//
|
|
// Bridging
|
|
// ========
|
|
//
|
|
// Bridging `NSDictionary` to `Dictionary`
|
|
// ---------------------------------------
|
|
//
|
|
// FIXME(eager-bridging): rewrite this based on modern constraints.
|
|
//
|
|
// `NSDictionary` bridges to `Dictionary<NSObject, AnyObject>` in `O(1)`,
|
|
// without memory allocation.
|
|
//
|
|
// Bridging `Dictionary` to `NSDictionary`
|
|
// ---------------------------------------
|
|
//
|
|
// `Dictionary<K, V>` bridges to `NSDictionary` in O(1)
|
|
// but may incur an allocation depending on the following conditions:
|
|
//
|
|
// * If the Dictionary is freshly allocated without any elements, then it
|
|
// contains the empty singleton Storage which is returned as a toll-free
|
|
// implementation of `NSDictionary`.
|
|
//
|
|
// * If both `K` and `V` are bridged verbatim, then `Dictionary<K, V>` is
|
|
// still toll-free bridged to `NSDictionary` by returning its Storage.
|
|
//
|
|
// * If the Dictionary is actually a lazily bridged NSDictionary, then that
|
|
// NSDictionary is returned.
|
|
//
|
|
// * Otherwise, bridging the `Dictionary` is done by wrapping its buffer in a
|
|
// `_SwiftDeferredNSDictionary<K, V>`. This incurs an O(1)-sized allocation.
|
|
//
|
|
// Complete bridging of the native Storage's elements to another Storage
|
|
// is performed on first access. This is O(n) work, but is hopefully amortized
|
|
// by future accesses.
|
|
//
|
|
// This design ensures that:
|
|
// - Every time keys or values are accessed on the bridged `NSDictionary`,
|
|
// new objects are not created.
|
|
// - Accessing the same element (key or value) multiple times will return
|
|
// the same pointer.
|
|
//
|
|
// Bridging `NSSet` to `Set` and vice versa
|
|
// ----------------------------------------
|
|
//
|
|
// Bridging guarantees for `Set<Element>` are the same as for
|
|
// `Dictionary<Element, ()>`.
|
|
//
|
|
|
|
/// This protocol is only used for compile-time checks that
|
|
/// every buffer type implements all required operations.
|
|
internal protocol _HashBuffer {
|
|
associatedtype Key
|
|
associatedtype Value
|
|
associatedtype Index
|
|
associatedtype SequenceElement
|
|
associatedtype SequenceElementWithoutLabels
|
|
var startIndex: Index { get }
|
|
var endIndex: Index { get }
|
|
|
|
func index(after i: Index) -> Index
|
|
|
|
func formIndex(after i: inout Index)
|
|
|
|
func index(forKey key: Key) -> Index?
|
|
|
|
func assertingGet(_ i: Index) -> SequenceElement
|
|
|
|
func assertingGet(_ key: Key) -> Value
|
|
|
|
func maybeGet(_ key: Key) -> Value?
|
|
|
|
@discardableResult
|
|
mutating func updateValue(_ value: Value, forKey key: Key) -> Value?
|
|
|
|
@discardableResult
|
|
mutating func insert(
|
|
_ value: Value, forKey key: Key
|
|
) -> (inserted: Bool, memberAfterInsert: Value)
|
|
|
|
@discardableResult
|
|
mutating func remove(at index: Index) -> SequenceElement
|
|
|
|
@discardableResult
|
|
mutating func removeValue(forKey key: Key) -> Value?
|
|
|
|
@discardableResult
|
|
mutating func removeAll(keepingCapacity keepCapacity: Bool)
|
|
|
|
var count: Int { get }
|
|
|
|
static func fromArray(_ elements: [SequenceElementWithoutLabels]) -> Self
|
|
}
|
|
|
|
/// The inverse of the default hash table load factor. Factored out so that it
|
|
/// can be used in multiple places in the implementation and stay consistent.
|
|
/// Should not be used outside `Dictionary` implementation.
|
|
@_transparent
|
|
internal var _hashContainerDefaultMaxLoadFactorInverse: Double {
|
|
return 1.0 / 0.75
|
|
}
|
|
|
|
#if _runtime(_ObjC)
|
|
/// Call `[lhs isEqual: rhs]`.
|
|
///
|
|
/// This function is part of the runtime because `Bool` type is bridged to
|
|
/// `ObjCBool`, which is in Foundation overlay.
|
|
@_silgen_name("swift_stdlib_NSObject_isEqual")
|
|
internal func _stdlib_NSObject_isEqual(_ lhs: AnyObject, _ rhs: AnyObject) -> Bool
|
|
#endif
|
|
|
|
|
|
/// A temporary view of an array of AnyObject as an array of Unmanaged<AnyObject>
|
|
/// for fast iteration and transformation of the elements.
|
|
///
|
|
/// Accesses the underlying raw memory as Unmanaged<AnyObject> using untyped
|
|
/// memory accesses. The memory remains bound to managed AnyObjects.
|
|
internal struct _UnmanagedAnyObjectArray {
|
|
/// Underlying pointer.
|
|
internal var value: UnsafeMutableRawPointer
|
|
|
|
internal init(_ up: UnsafeMutablePointer<AnyObject>) {
|
|
self.value = UnsafeMutableRawPointer(up)
|
|
}
|
|
|
|
internal init?(_ up: UnsafeMutablePointer<AnyObject>?) {
|
|
guard let unwrapped = up else { return nil }
|
|
self.init(unwrapped)
|
|
}
|
|
|
|
internal subscript(i: Int) -> AnyObject {
|
|
get {
|
|
let unmanaged = value.load(
|
|
fromByteOffset: i * MemoryLayout<AnyObject>.stride,
|
|
as: Unmanaged<AnyObject>.self)
|
|
return unmanaged.takeUnretainedValue()
|
|
}
|
|
nonmutating set(newValue) {
|
|
let unmanaged = Unmanaged.passUnretained(newValue)
|
|
value.storeBytes(of: unmanaged,
|
|
toByteOffset: i * MemoryLayout<AnyObject>.stride,
|
|
as: Unmanaged<AnyObject>.self)
|
|
}
|
|
}
|
|
}
|
|
|
|
//===--- APIs unique to Set<Element> --------------------------------------===//
|
|
|
|
/// 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.
|
|
///
|
|
/// - SeeAlso: `Hashable`
|
|
@_fixed_layout
|
|
public struct Set<Element : Hashable> :
|
|
SetAlgebra, Hashable, Collection, ExpressibleByArrayLiteral {
|
|
|
|
internal typealias _Self = Set<Element>
|
|
internal typealias _VariantBuffer = _VariantSetBuffer<Element>
|
|
internal typealias _NativeBuffer = _NativeSetBuffer<Element>
|
|
|
|
@_versioned
|
|
internal var _variantBuffer: _VariantBuffer
|
|
|
|
/// Creates a new, empty set with at least the specified number of elements'
|
|
/// worth of buffer.
|
|
///
|
|
/// Use this initializer to avoid repeated reallocations of a set's buffer
|
|
/// if you know you'll be adding elements to the set after creation. The
|
|
/// actual capacity of the created set will be the smallest power of 2 that
|
|
/// is greater than or equal to `minimumCapacity`.
|
|
///
|
|
/// - Parameter minimumCapacity: The minimum number of elements that the
|
|
/// newly created set should be able to store without reallocating its
|
|
/// buffer.
|
|
public init(minimumCapacity: Int) {
|
|
_variantBuffer =
|
|
_VariantBuffer.native(
|
|
_NativeBuffer(minimumCapacity: minimumCapacity))
|
|
}
|
|
|
|
/// Private initializer.
|
|
internal init(_nativeBuffer: _NativeSetBuffer<Element>) {
|
|
_variantBuffer = _VariantBuffer.native(_nativeBuffer)
|
|
}
|
|
|
|
//
|
|
// All APIs below should dispatch to `_variantBuffer`, without doing any
|
|
// additional processing.
|
|
//
|
|
|
|
#if _runtime(_ObjC)
|
|
/// Private initializer used for bridging.
|
|
///
|
|
/// Only use this initializer when both conditions are true:
|
|
///
|
|
/// * it is statically known that the given `NSSet` is immutable;
|
|
/// * `Element` is bridged verbatim to Objective-C (i.e.,
|
|
/// is a reference type).
|
|
public init(_immutableCocoaSet: _NSSet) {
|
|
_sanityCheck(_isBridgedVerbatimToObjectiveC(Element.self),
|
|
"Set can be backed by NSSet _variantBuffer only when the member type can be bridged verbatim to Objective-C")
|
|
_variantBuffer = _VariantSetBuffer.cocoa(
|
|
_CocoaSetBuffer(cocoaSet: _immutableCocoaSet))
|
|
}
|
|
#endif
|
|
|
|
/// The starting position for iterating members of the set.
|
|
///
|
|
/// If the set is empty, `startIndex` is equal to `endIndex`.
|
|
public var startIndex: Index {
|
|
return _variantBuffer.startIndex
|
|
}
|
|
|
|
/// The "past the end" position for the set---that is, the position one
|
|
/// greater than the last valid subscript argument.
|
|
///
|
|
/// If the set is empty, `endIndex` is equal to `startIndex`.
|
|
public var endIndex: Index {
|
|
return _variantBuffer.endIndex
|
|
}
|
|
|
|
public func index(after i: Index) -> Index {
|
|
return _variantBuffer.index(after: i)
|
|
}
|
|
|
|
// APINAMING: complexity docs are broadly missing in this file.
|
|
|
|
/// 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`.
|
|
public func contains(_ member: Element) -> Bool {
|
|
return _variantBuffer.maybeGet(member) != nil
|
|
}
|
|
|
|
/// 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`.
|
|
public func index(of member: Element) -> Index? {
|
|
return _variantBuffer.index(forKey: member)
|
|
}
|
|
|
|
/// 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.
|
|
@discardableResult
|
|
public mutating func insert(
|
|
_ newMember: Element
|
|
) -> (inserted: Bool, memberAfterInsert: Element) {
|
|
return _variantBuffer.insert(newMember, forKey: newMember)
|
|
}
|
|
|
|
/// Inserts the given element into the set unconditionally.
|
|
///
|
|
/// If an element equal to `newMember` is already contained in the set,
|
|
/// `newMember` replaces the existing element. In this example, an existing
|
|
/// element is inserted into `classDays`, a set of days of the week.
|
|
///
|
|
/// enum DayOfTheWeek: Int {
|
|
/// case sunday, monday, tuesday, wednesday, thursday,
|
|
/// friday, saturday
|
|
/// }
|
|
///
|
|
/// var classDays: Set<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.
|
|
@discardableResult
|
|
public mutating func update(with newMember: Element) -> Element? {
|
|
return _variantBuffer.updateValue(newMember, forKey: newMember)
|
|
}
|
|
|
|
/// Removes the specified element from the set.
|
|
///
|
|
/// This example removes the element `"sugar"` from a set of ingredients.
|
|
///
|
|
/// var ingredients: Set = ["cocoa beans", "sugar", "cocoa butter", "salt"]
|
|
/// let toRemove = "sugar"
|
|
/// if let removed = ingredients.remove(toRemove) {
|
|
/// print("The recipe is now \(removed)-free.")
|
|
/// }
|
|
/// // Prints "The recipe is now sugar-free."
|
|
///
|
|
/// - Parameter member: The element to remove from the set.
|
|
/// - Returns: The value of the `member` parameter if it was a member of the
|
|
/// set; otherwise, `nil`.
|
|
@discardableResult
|
|
public mutating func remove(_ member: Element) -> Element? {
|
|
return _variantBuffer.removeValue(forKey: member)
|
|
}
|
|
|
|
/// Removes the element at the given index of the set.
|
|
///
|
|
/// - Parameter position: The index of the member to remove. `position` must
|
|
/// be a valid index of the set, and must not be equal to the set's end
|
|
/// index.
|
|
/// - Returns: The element that was removed from the set.
|
|
@discardableResult
|
|
public mutating func remove(at position: Index) -> Element {
|
|
return _variantBuffer.remove(at: position)
|
|
}
|
|
|
|
/// Removes all members from the set.
|
|
///
|
|
/// - Parameter keepingCapacity: If `true`, the set's buffer capacity is
|
|
/// preserved; if `false`, the underlying buffer is released. The
|
|
/// default is `false`.
|
|
public mutating func removeAll(keepingCapacity keepCapacity: Bool = false) {
|
|
_variantBuffer.removeAll(keepingCapacity: keepCapacity)
|
|
}
|
|
|
|
/// Removes the first element of the set.
|
|
///
|
|
/// Because a set is not an ordered collection, the "first" element may not
|
|
/// be the first element that was added to the set. The set must not be
|
|
/// empty.
|
|
///
|
|
/// - Complexity: Amortized O(1) if the set does not wrap a bridged `NSSet`.
|
|
/// If the set wraps a bridged `NSSet`, the performance is unspecified.
|
|
///
|
|
/// - Returns: A member of the set.
|
|
@discardableResult
|
|
public mutating func removeFirst() -> Element {
|
|
_precondition(!isEmpty, "can't removeFirst from an empty Set")
|
|
return remove(at: startIndex)
|
|
}
|
|
|
|
/// The number of elements in the set.
|
|
///
|
|
/// - Complexity: O(1).
|
|
public var count: Int {
|
|
return _variantBuffer.count
|
|
}
|
|
|
|
//
|
|
// `Sequence` conformance
|
|
//
|
|
|
|
/// Accesses the member at the given position.
|
|
public subscript(position: Index) -> Element {
|
|
return _variantBuffer.assertingGet(position)
|
|
}
|
|
|
|
/// Returns an iterator over the members of the set.
|
|
@inline(__always)
|
|
public func makeIterator() -> SetIterator<Element> {
|
|
return _variantBuffer.makeIterator()
|
|
}
|
|
|
|
//
|
|
// `ExpressibleByArrayLiteral` conformance
|
|
//
|
|
/// Creates a set containing the elements of the given array literal.
|
|
///
|
|
/// Do not call this initializer directly. It is used by the compiler when
|
|
/// you use an array literal. Instead, create a new set using an array
|
|
/// literal as its value by enclosing a comma-separated list of values in
|
|
/// square brackets. You can use an array literal anywhere a set is expected
|
|
/// by the type context.
|
|
///
|
|
/// Here, a set of strings is created from an array literal holding only
|
|
/// strings.
|
|
///
|
|
/// let ingredients: Set = ["cocoa beans", "sugar", "cocoa butter", "salt"]
|
|
/// if ingredients.isSuperset(of: ["sugar", "salt"]) {
|
|
/// print("Whatever it is, it's bound to be delicious!")
|
|
/// }
|
|
/// // Prints "Whatever it is, it's bound to be delicious!"
|
|
///
|
|
/// - Parameter elements: A variadic list of elements of the new set.
|
|
public init(arrayLiteral elements: Element...) {
|
|
self.init(_nativeBuffer: _NativeSetBuffer.fromArray(elements))
|
|
}
|
|
|
|
//
|
|
// APIs below this comment should be implemented strictly in terms of
|
|
// *public* APIs above. `_variantBuffer` should not be accessed directly.
|
|
//
|
|
// This separates concerns for testing. Tests for the following APIs need
|
|
// not to concern themselves with testing correctness of behavior of
|
|
// underlying buffer (and different variants of it), only correctness of the
|
|
// API itself.
|
|
//
|
|
|
|
/// Creates an empty set.
|
|
///
|
|
/// This is equivalent to initializing with an empty array literal. For
|
|
/// example:
|
|
///
|
|
/// var emptySet = Set<Int>()
|
|
/// print(emptySet.isEmpty)
|
|
/// // Prints "true"
|
|
///
|
|
/// emptySet = []
|
|
/// print(emptySet.isEmpty)
|
|
/// // Prints "true"
|
|
public init() {
|
|
self = Set<Element>(_nativeBuffer: _NativeBuffer())
|
|
}
|
|
|
|
/// Creates a new set from a finite sequence of items.
|
|
///
|
|
/// Use this initializer to create a new set from an existing sequence, for
|
|
/// example, an array or a range.
|
|
///
|
|
/// let validIndices = Set(0..<7).subtracting([2, 4, 5])
|
|
/// print(validIndices)
|
|
/// // Prints "[6, 0, 1, 3]"
|
|
///
|
|
/// This initializer can also be used to restore set methods after performing
|
|
/// sequence operations such as `filter(_:)` or `map(_:)` on a set. For
|
|
/// example, after filtering a set of prime numbers to remove any below 10,
|
|
/// you can create a new set by using this initializer.
|
|
///
|
|
/// let primes: Set = [2, 3, 5, 7, 11, 13, 17, 19, 23]
|
|
/// let laterPrimes = Set(primes.lazy.filter { $0 > 10 })
|
|
/// print(laterPrimes)
|
|
/// // Prints "[17, 19, 23, 11, 13]"
|
|
///
|
|
/// - Parameter sequence: The elements to use as members of the new set.
|
|
public init<Source : Sequence>(_ sequence: Source)
|
|
where Source.Iterator.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.
|
|
switch s._variantBuffer {
|
|
case .native(let buffer):
|
|
_variantBuffer = .native(buffer)
|
|
case .cocoa(let owner):
|
|
_variantBuffer = .cocoa(owner)
|
|
}
|
|
} 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`.
|
|
public func isSubset<S : Sequence>(of possibleSuperset: S) -> Bool
|
|
where S.Iterator.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`.
|
|
public func isStrictSubset<S : Sequence>(of possibleStrictSuperset: S) -> Bool
|
|
where S.Iterator.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`.
|
|
public func isSuperset<S : Sequence>(of possibleSubset: S) -> Bool
|
|
where S.Iterator.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`.
|
|
public func isStrictSuperset<S : Sequence>(of possibleStrictSubset: S) -> Bool
|
|
where S.Iterator.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`.
|
|
public func isDisjoint<S : Sequence>(with other: S) -> Bool
|
|
where S.Iterator.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`.
|
|
public func union<S : Sequence>(_ other: S) -> Set<Element>
|
|
where S.Iterator.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.
|
|
public mutating func formUnion<S : Sequence>(_ other: S)
|
|
where S.Iterator.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.
|
|
public func subtracting<S : Sequence>(_ other: S) -> Set<Element>
|
|
where S.Iterator.Element == Element {
|
|
return self._subtracting(other)
|
|
}
|
|
|
|
internal func _subtracting<S : Sequence>(_ other: S) -> Set<Element>
|
|
where S.Iterator.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.
|
|
public mutating func subtract<S : Sequence>(_ other: S)
|
|
where S.Iterator.Element == Element {
|
|
_subtract(other)
|
|
}
|
|
|
|
internal mutating func _subtract<S : Sequence>(_ other: S)
|
|
where S.Iterator.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.
|
|
public func intersection<S : Sequence>(_ other: S) -> Set<Element>
|
|
where S.Iterator.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.
|
|
public mutating func formIntersection<S : Sequence>(_ other: S)
|
|
where S.Iterator.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.
|
|
public func symmetricDifference<S : Sequence>(_ other: S) -> Set<Element>
|
|
where S.Iterator.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 `"Alicia"`, `"Chris"`, and
|
|
/// `"Diana"` 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.
|
|
public mutating func formSymmetricDifference<S : Sequence>(_ other: S)
|
|
where S.Iterator.Element == Element {
|
|
let otherSet = Set(other)
|
|
formSymmetricDifference(otherSet)
|
|
}
|
|
|
|
/// The hash value for the set.
|
|
///
|
|
/// Two sets that are equal will always have equal hash values.
|
|
///
|
|
/// Hash values are not guaranteed to be equal across different executions of
|
|
/// your program. Do not save hash values to use during a future execution.
|
|
public var hashValue: Int {
|
|
// FIXME(ABI)#177: <rdar://problem/18915294> Cache Set<T> hashValue
|
|
var result: Int = _mixInt(0)
|
|
for member in self {
|
|
result ^= _mixInt(member.hashValue)
|
|
}
|
|
return result
|
|
}
|
|
|
|
//
|
|
// `Sequence` conformance
|
|
//
|
|
|
|
public func _customContainsEquatableElement(_ member: Element) -> Bool? {
|
|
return contains(member)
|
|
}
|
|
|
|
public func _customIndexOfEquatableElement(
|
|
_ member: Element
|
|
) -> Index?? {
|
|
return Optional(index(of: member))
|
|
}
|
|
|
|
//
|
|
// Collection conformance
|
|
//
|
|
|
|
/// A Boolean value that indicates whether the set is empty.
|
|
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`.
|
|
public var first: Element? {
|
|
return count > 0 ? self[startIndex] : nil
|
|
}
|
|
}
|
|
|
|
/// Check for both subset and equality relationship between
|
|
/// a set and some sequence (which may itself be a `Set`).
|
|
///
|
|
/// (isSubset: lhs ⊂ rhs, isEqual: lhs ⊂ rhs and |lhs| = |rhs|)
|
|
internal func _compareSets<Element>(_ lhs: Set<Element>, _ rhs: Set<Element>)
|
|
-> (isSubset: Bool, isEqual: Bool) {
|
|
// FIXME(performance): performance could be better if we start by comparing
|
|
// counts.
|
|
for member in lhs {
|
|
if !rhs.contains(member) {
|
|
return (false, false)
|
|
}
|
|
}
|
|
return (true, lhs.count == rhs.count)
|
|
}
|
|
|
|
// FIXME: rdar://problem/23549059 (Optimize == for Set)
|
|
// Look into initially trying to compare the two sets by directly comparing the
|
|
// contents of both buffers in order. If they happen to have the exact same
|
|
// ordering we can get the `true` response without ever hashing. If the two
|
|
// buffers' contents differ at all then we have to fall back to hashing the
|
|
// rest of the elements (but we don't need to hash any prefix that did match).
|
|
extension Set {
|
|
/// 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`.
|
|
public static func == (lhs: Set<Element>, rhs: Set<Element>) -> Bool {
|
|
switch (lhs._variantBuffer, rhs._variantBuffer) {
|
|
case (.native(let lhsNative), .native(let rhsNative)):
|
|
|
|
if lhsNative._storage === rhsNative._storage {
|
|
return true
|
|
}
|
|
|
|
if lhsNative.count != rhsNative.count {
|
|
return false
|
|
}
|
|
|
|
for member in lhs {
|
|
let (_, found) =
|
|
rhsNative._find(member, startBucket: rhsNative._bucket(member))
|
|
if !found {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
|
|
case (_VariantSetBuffer.cocoa(let lhsCocoa),
|
|
_VariantSetBuffer.cocoa(let rhsCocoa)):
|
|
#if _runtime(_ObjC)
|
|
return _stdlib_NSObject_isEqual(lhsCocoa.cocoaSet, rhsCocoa.cocoaSet)
|
|
#else
|
|
_sanityCheckFailure("internal error: unexpected cocoa set")
|
|
#endif
|
|
|
|
case (_VariantSetBuffer.native(let lhsNative),
|
|
_VariantSetBuffer.cocoa(let rhsCocoa)):
|
|
#if _runtime(_ObjC)
|
|
|
|
if lhsNative.count != rhsCocoa.count {
|
|
return false
|
|
}
|
|
|
|
let endIndex = lhsNative.endIndex
|
|
var i = lhsNative.startIndex
|
|
while i != endIndex {
|
|
let key = lhsNative.assertingGet(i)
|
|
let bridgedKey: AnyObject = _bridgeAnythingToObjectiveC(key)
|
|
let optRhsValue: AnyObject? = rhsCocoa.maybeGet(bridgedKey)
|
|
if let rhsValue = optRhsValue {
|
|
if key == _forceBridgeFromObjectiveC(rhsValue, Element.self) {
|
|
i = lhsNative.index(after: i)
|
|
continue
|
|
}
|
|
}
|
|
i = lhsNative.index(after: i)
|
|
return false
|
|
}
|
|
return true
|
|
#else
|
|
_sanityCheckFailure("internal error: unexpected cocoa set")
|
|
#endif
|
|
|
|
case (_VariantSetBuffer.cocoa, _VariantSetBuffer.native):
|
|
#if _runtime(_ObjC)
|
|
return rhs == lhs
|
|
#else
|
|
_sanityCheckFailure("internal error: unexpected cocoa set")
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
extension Set : CustomStringConvertible, CustomDebugStringConvertible {
|
|
internal func makeDescription(isDebug: Bool) -> String {
|
|
var result = isDebug ? "Set([" : "["
|
|
var first = true
|
|
for member in self {
|
|
if first {
|
|
first = false
|
|
} else {
|
|
result += ", "
|
|
}
|
|
debugPrint(member, terminator: "", to: &result)
|
|
}
|
|
result += isDebug ? "])" : "]"
|
|
return result
|
|
}
|
|
|
|
/// A string that represents the contents of the set.
|
|
public var description: String {
|
|
return makeDescription(isDebug: false)
|
|
}
|
|
|
|
/// A string that represents the contents of the set, suitable for debugging.
|
|
public var debugDescription: String {
|
|
return makeDescription(isDebug: true)
|
|
}
|
|
}
|
|
|
|
#if _runtime(_ObjC)
|
|
@_silgen_name("swift_stdlib_CFSetGetValues")
|
|
func _stdlib_CFSetGetValues(_ nss: _NSSet, _: UnsafeMutablePointer<AnyObject>)
|
|
|
|
/// Equivalent to `NSSet.allObjects`, but does not leave objects on the
|
|
/// autorelease pool.
|
|
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`.
|
|
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()
|
|
}
|
|
|
|
#if _runtime(_ObjC)
|
|
|
|
/// Implements an unconditional upcast that involves bridging.
|
|
///
|
|
/// The cast can fail if bridging fails.
|
|
///
|
|
/// - Precondition: `SwiftValue` is bridged to Objective-C
|
|
/// and requires non-trivial bridging.
|
|
public func _setBridgeToObjectiveC<SwiftValue, ObjCValue>(
|
|
_ source: Set<SwiftValue>
|
|
) -> Set<ObjCValue> {
|
|
_sanityCheck(_isClassOrObjCExistential(ObjCValue.self))
|
|
_sanityCheck(!_isBridgedVerbatimToObjectiveC(SwiftValue.self))
|
|
|
|
var result = Set<ObjCValue>(minimumCapacity: source.count)
|
|
let valueBridgesDirectly =
|
|
_isBridgedVerbatimToObjectiveC(SwiftValue.self) ==
|
|
_isBridgedVerbatimToObjectiveC(ObjCValue.self)
|
|
|
|
for member in source {
|
|
var bridgedMember: ObjCValue
|
|
if valueBridgesDirectly {
|
|
bridgedMember = unsafeBitCast(member, to: ObjCValue.self)
|
|
} else {
|
|
let bridged: AnyObject = _bridgeAnythingToObjectiveC(member)
|
|
bridgedMember = unsafeBitCast(bridged, to: ObjCValue.self)
|
|
}
|
|
result.insert(bridgedMember)
|
|
}
|
|
return result
|
|
}
|
|
|
|
#endif
|
|
|
|
@_silgen_name("_swift_setDownCastIndirect")
|
|
public 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.
|
|
public func _setDownCast<BaseValue, DerivedValue>(_ source: Set<BaseValue>)
|
|
-> Set<DerivedValue> {
|
|
|
|
#if _runtime(_ObjC)
|
|
if _isClassOrObjCExistential(BaseValue.self)
|
|
&& _isClassOrObjCExistential(DerivedValue.self) {
|
|
switch source._variantBuffer {
|
|
case _VariantSetBuffer.native(let buffer):
|
|
return Set(_immutableCocoaSet: buffer.bridged())
|
|
case _VariantSetBuffer.cocoa(let cocoaBuffer):
|
|
return Set(_immutableCocoaSet: cocoaBuffer.cocoaSet)
|
|
}
|
|
}
|
|
#endif
|
|
return _setDownCastConditional(source)!
|
|
}
|
|
|
|
@_silgen_name("_swift_setDownCastConditionalIndirect")
|
|
public 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.
|
|
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
|
|
}
|
|
|
|
#if _runtime(_ObjC)
|
|
|
|
/// Implements an unconditional downcast that involves bridging.
|
|
///
|
|
/// - Precondition: At least one of `SwiftValue` is a bridged value
|
|
/// type, and the corresponding `ObjCValue` is a reference type.
|
|
public func _setBridgeFromObjectiveC<ObjCValue, SwiftValue>(
|
|
_ source: Set<ObjCValue>
|
|
) -> Set<SwiftValue> {
|
|
let result: Set<SwiftValue>? = _setBridgeFromObjectiveCConditional(source)
|
|
_precondition(result != nil, "This set cannot be bridged from Objective-C")
|
|
return result!
|
|
}
|
|
|
|
/// Implements a conditional downcast that involves bridging.
|
|
///
|
|
/// If the cast fails, the function returns `nil`. All checks should be
|
|
/// performed eagerly.
|
|
///
|
|
/// - Precondition: At least one of `SwiftValue` is a bridged value
|
|
/// type, and the corresponding `ObjCValue` is a reference type.
|
|
public func _setBridgeFromObjectiveCConditional<
|
|
ObjCValue, SwiftValue
|
|
>(
|
|
_ source: Set<ObjCValue>
|
|
) -> Set<SwiftValue>? {
|
|
_sanityCheck(_isClassOrObjCExistential(ObjCValue.self))
|
|
_sanityCheck(!_isBridgedVerbatimToObjectiveC(SwiftValue.self))
|
|
|
|
let valueBridgesDirectly =
|
|
_isBridgedVerbatimToObjectiveC(SwiftValue.self) ==
|
|
_isBridgedVerbatimToObjectiveC(ObjCValue.self)
|
|
|
|
var result = Set<SwiftValue>(minimumCapacity: source.count)
|
|
for value in source {
|
|
// Downcast the value.
|
|
var resultValue: SwiftValue
|
|
if valueBridgesDirectly {
|
|
if let bridgedValue = value as? SwiftValue {
|
|
resultValue = bridgedValue
|
|
} else {
|
|
return nil
|
|
}
|
|
} else {
|
|
if let bridgedValue = _conditionallyBridgeFromObjectiveC(
|
|
_reinterpretCastToAnyObject(value), SwiftValue.self) {
|
|
resultValue = bridgedValue
|
|
} else {
|
|
return nil
|
|
}
|
|
}
|
|
result.insert(resultValue)
|
|
}
|
|
return result
|
|
}
|
|
|
|
#endif
|
|
|
|
//===--- APIs unique to Dictionary<Key, Value> ----------------------------===//
|
|
|
|
/// A collection whose elements are key-value pairs.
|
|
///
|
|
/// A dictionary is a type of hash table, providing fast access to the entries
|
|
/// it contains. Each entry in the table is identified using its key, which is
|
|
/// a hashable type such as a string or number. You use that key to retrieve
|
|
/// the corresponding value, which can be any object. In other languages,
|
|
/// similar data types are known as hashes or associated arrays.
|
|
///
|
|
/// Create a new dictionary by using a dictionary literal. A dictionary literal
|
|
/// is a comma-separated list of key-value pairs, in which a colon separates
|
|
/// each key from its associated value, surrounded by square brackets. You can
|
|
/// assign a dictionary literal to a variable or constant or pass it to a
|
|
/// function that expects a dictionary.
|
|
///
|
|
/// Here's how you would create a dictionary of HTTP response codes and their
|
|
/// related messages:
|
|
///
|
|
/// var responseMessages = [200: "OK",
|
|
/// 403: "Access forbidden",
|
|
/// 404: "File not found",
|
|
/// 500: "Internal server error"]
|
|
///
|
|
/// The `responseMessages` variable is inferred to have type `[Int: String]`.
|
|
/// The `Key` type of the dictionary is `Int`, and the `Value` type of the
|
|
/// dictionary is `String`.
|
|
///
|
|
/// To create a dictionary with no key-value pairs, use an empty dictionary
|
|
/// literal (`[:]`).
|
|
///
|
|
/// var emptyDict: [String: String] = [:]
|
|
///
|
|
/// Any type that conforms to the `Hashable` protocol can be used as a
|
|
/// dictionary's `Key` type, including all of Swift's basic types. You can use
|
|
/// your own custom types as dictionary keys by making them conform to the
|
|
/// `Hashable` protocol.
|
|
///
|
|
/// Getting and Setting Dictionary Values
|
|
/// =====================================
|
|
///
|
|
/// The most common way to access values in a dictionary is to use a key as a
|
|
/// subscript. Subscripting with a key takes the following form:
|
|
///
|
|
/// print(responseMessages[200])
|
|
/// // Prints "Optional("OK")"
|
|
///
|
|
/// Subscripting a dictionary with a key returns an optional value, because a
|
|
/// dictionary might not hold a value for the key that you use in the
|
|
/// subscript.
|
|
///
|
|
/// The next example uses key-based subscripting of the `responseMessages`
|
|
/// dictionary with two keys that exist in the dictionary and one that does
|
|
/// not.
|
|
///
|
|
/// let httpResponseCodes = [200, 403, 301]
|
|
/// for code in httpResponseCodes {
|
|
/// if let message = responseMessages[code] {
|
|
/// print("Response \(code): \(message)")
|
|
/// } else {
|
|
/// print("Unknown response \(code)")
|
|
/// }
|
|
/// }
|
|
/// // Prints "Response 200: OK"
|
|
/// // Prints "Response 403: Access Forbidden"
|
|
/// // Prints "Unknown response 301"
|
|
///
|
|
/// You can also update, modify, or remove keys and values from a dictionary
|
|
/// using the key-based subscript. To add a new key-value pair, assign a value
|
|
/// to a key that isn't yet a part of the dictionary.
|
|
///
|
|
/// responseMessages[301] = "Moved permanently"
|
|
/// print(responseMessages[301])
|
|
/// // Prints "Optional("Moved permanently")"
|
|
///
|
|
/// Update an existing value by assigning a new value to a key that already
|
|
/// exists in the dictionary. If you assign `nil` to an existing key, the key
|
|
/// and its associated value are removed. The following example updates the
|
|
/// value for the `404` code to be simply "Not found" and removes the
|
|
/// key-value pair for the `500` code entirely.
|
|
///
|
|
/// responseMessages[404] = "Not found"
|
|
/// responseMessages[500] = nil
|
|
/// print(responseMessages)
|
|
/// // Prints "[301: "Moved permanently", 200: "OK", 403: "Access forbidden", 404: "Not found"]"
|
|
///
|
|
/// In a mutable `Dictionary` instance, you can modify in place a value that
|
|
/// you've accessed through a keyed subscript. The code sample below declares a
|
|
/// dictionary called `interestingNumbers` with string keys and values that
|
|
/// are integer arrays, then sorts each array in-place in descending order.
|
|
///
|
|
/// var interestingNumbers = ["primes": [2, 3, 5, 7, 11, 13, 15],
|
|
/// "triangular": [1, 3, 6, 10, 15, 21, 28],
|
|
/// "hexagonal": [1, 6, 15, 28, 45, 66, 91]]
|
|
/// for key in interestingNumbers.keys {
|
|
/// interestingNumbers[key]?.sort(by: >)
|
|
/// }
|
|
///
|
|
/// print(interestingNumbers["primes"]!)
|
|
/// // Prints "[15, 13, 11, 7, 5, 3, 2]"
|
|
///
|
|
/// Iterating Over the Contents of a Dictionary
|
|
/// ===========================================
|
|
///
|
|
/// Every dictionary is an unordered collection of key-value pairs. You can
|
|
/// iterate over a dictionary using a `for`-`in` loop, decomposing each
|
|
/// key-value pair into the elements of a tuple.
|
|
///
|
|
/// let imagePaths = ["star": "/glyphs/star.png",
|
|
/// "portrait": "/images/content/portrait.jpg",
|
|
/// "spacer": "/images/shared/spacer.gif"]
|
|
///
|
|
/// for (name, path) in imagePaths {
|
|
/// print("The path to '\(name)' is '\(path)'.")
|
|
/// }
|
|
/// // Prints "The path to 'star' is '/glyphs/star.png'."
|
|
/// // Prints "The path to 'portrait' is '/images/content/portrait.jpg'."
|
|
/// // Prints "The path to 'spacer' is '/images/shared/spacer.gif'."
|
|
///
|
|
/// The order of key-value pairs in a dictionary is stable between mutations
|
|
/// but is otherwise unpredictable. If you need an ordered collection of
|
|
/// key-value pairs and don't need the fast key lookup that `Dictionary`
|
|
/// provides, see the `DictionaryLiteral` type for an alternative.
|
|
///
|
|
/// You can search a dictionary's contents for a particular value using the
|
|
/// `contains(where:)` or `index(where:)` methods supplied by default
|
|
/// implementation. The following example checks to see if `imagePaths` contains
|
|
/// any paths in the `"/glyphs"` directory:
|
|
///
|
|
/// let glyphIndex = imagePaths.index { $0.value.hasPrefix("/glyphs") }
|
|
/// if let index = glyphIndex {
|
|
/// print("The '\(imagesPaths[index].key)' image is a glyph.")
|
|
/// } else {
|
|
/// print("No glyphs found!")
|
|
/// }
|
|
/// // Prints "The 'star' image is a glyph.")
|
|
///
|
|
/// Note that in this example, `imagePaths` is subscripted using a dictionary
|
|
/// index. Unlike the key-based subscript, the index-based subscript returns
|
|
/// the corresponding key-value pair as a non-optional tuple.
|
|
///
|
|
/// print(imagePaths[glyphIndex!])
|
|
/// // Prints "("star", "/glyphs/star.png")"
|
|
///
|
|
/// A dictionary's indices stay valid across additions to the dictionary as
|
|
/// long as the dictionary has enough capacity to store the added values
|
|
/// without allocating more buffer. When a dictionary outgrows its buffer,
|
|
/// existing indices may be invalidated without any notification.
|
|
///
|
|
/// When you know how many new values you're adding to a dictionary, use the
|
|
/// `init(minimumCapacity:)` initializer to allocate the correct amount of
|
|
/// buffer.
|
|
///
|
|
/// Bridging Between Dictionary and NSDictionary
|
|
/// ============================================
|
|
///
|
|
/// You can bridge between `Dictionary` and `NSDictionary` using the `as`
|
|
/// operator. For bridging to be possible, the `Key` and `Value` types of a
|
|
/// dictionary must be classes, `@objc` protocols, or types that bridge to
|
|
/// Foundation types.
|
|
///
|
|
/// Bridging from `Dictionary` to `NSDictionary` always takes O(1) time and
|
|
/// space. When the dictionary's `Key` and `Value` types are neither classes
|
|
/// nor `@objc` protocols, any required bridging of elements occurs at the
|
|
/// first access of each element. For this reason, the first operation that
|
|
/// uses the contents of the dictionary may take O(*n*).
|
|
///
|
|
/// Bridging from `NSDictionary` to `Dictionary` first calls the `copy(with:)`
|
|
/// method (`- copyWithZone:` in Objective-C) on the dictionary to get an
|
|
/// immutable copy and then performs additional Swift bookkeeping work that
|
|
/// takes O(1) time. For instances of `NSDictionary` that are already
|
|
/// immutable, `copy(with:)` usually returns the same dictionary in O(1) time;
|
|
/// otherwise, the copying performance is unspecified. The instances of
|
|
/// `NSDictionary` and `Dictionary` share buffer using the same copy-on-write
|
|
/// optimization that is used when two instances of `Dictionary` share
|
|
/// buffer.
|
|
///
|
|
/// - SeeAlso: `Hashable`
|
|
@_fixed_layout
|
|
public struct Dictionary<Key : Hashable, Value> :
|
|
Collection, ExpressibleByDictionaryLiteral {
|
|
|
|
internal typealias _Self = Dictionary<Key, Value>
|
|
internal typealias _VariantBuffer = _VariantDictionaryBuffer<Key, Value>
|
|
internal typealias _NativeBuffer = _NativeDictionaryBuffer<Key, Value>
|
|
|
|
/// The element type of a dictionary: a tuple containing an individual
|
|
/// key-value pair.
|
|
public typealias Element = (key: Key, value: Value)
|
|
|
|
@_versioned
|
|
internal var _variantBuffer: _VariantBuffer
|
|
|
|
/// Creates an empty dictionary.
|
|
public init() {
|
|
self = Dictionary<Key, Value>(_nativeBuffer: _NativeBuffer())
|
|
}
|
|
|
|
/// Creates a dictionary with at least the given number of elements worth of
|
|
/// buffer.
|
|
///
|
|
/// Use this initializer to avoid intermediate reallocations when you know
|
|
/// how many key-value pairs you are adding to a dictionary. The actual
|
|
/// capacity of the created dictionary is the smallest power of 2 that
|
|
/// is greater than or equal to `minimumCapacity`.
|
|
///
|
|
/// - Parameter minimumCapacity: The minimum number of key-value pairs to
|
|
/// allocate buffer for in the new dictionary.
|
|
public init(minimumCapacity: Int) {
|
|
_variantBuffer =
|
|
.native(_NativeBuffer(minimumCapacity: minimumCapacity))
|
|
}
|
|
|
|
internal init(_nativeBuffer: _NativeDictionaryBuffer<Key, Value>) {
|
|
_variantBuffer =
|
|
.native(_nativeBuffer)
|
|
}
|
|
|
|
#if _runtime(_ObjC)
|
|
/// Private initializer used for bridging.
|
|
///
|
|
/// Only use this initializer when both conditions are true:
|
|
///
|
|
/// * it is statically known that the given `NSDictionary` is immutable;
|
|
/// * `Key` and `Value` are bridged verbatim to Objective-C (i.e.,
|
|
/// are reference types).
|
|
public init(_immutableCocoaDictionary: _NSDictionary) {
|
|
_sanityCheck(
|
|
_isBridgedVerbatimToObjectiveC(Key.self) &&
|
|
_isBridgedVerbatimToObjectiveC(Value.self),
|
|
"Dictionary can be backed by NSDictionary buffer only when both key and value are bridged verbatim to Objective-C")
|
|
_variantBuffer = .cocoa(
|
|
_CocoaDictionaryBuffer(cocoaDictionary: _immutableCocoaDictionary))
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// All APIs below should dispatch to `_variantBuffer`, without doing any
|
|
// additional processing.
|
|
//
|
|
|
|
/// The position of the first element in a nonempty dictionary.
|
|
///
|
|
/// If the collection is empty, `startIndex` is equal to `endIndex`.
|
|
///
|
|
/// - Complexity: Amortized O(1) if the dictionary does not wrap a bridged
|
|
/// `NSDictionary`. If the dictionary wraps a bridged `NSDictionary`, the
|
|
/// performance is unspecified.
|
|
public var startIndex: Index {
|
|
return _variantBuffer.startIndex
|
|
}
|
|
|
|
/// The dictionary's "past the end" position---that is, the position one
|
|
/// greater than the last valid subscript argument.
|
|
///
|
|
/// If the collection is empty, `endIndex` is equal to `startIndex`.
|
|
///
|
|
/// - Complexity: Amortized O(1) if the dictionary does not wrap a bridged
|
|
/// `NSDictionary`; otherwise, the performance is unspecified.
|
|
public var endIndex: Index {
|
|
return _variantBuffer.endIndex
|
|
}
|
|
|
|
public func index(after i: Index) -> Index {
|
|
return _variantBuffer.index(after: i)
|
|
}
|
|
|
|
/// Returns the index for the given key.
|
|
///
|
|
/// If the given key is found in the dictionary, this method returns an index
|
|
/// into the dictionary that corresponds with the key-value pair.
|
|
///
|
|
/// let countryCodes = ["BR": "Brazil", "GH": "Ghana", "JP": "Japan"]
|
|
/// let index = countryCodes.index(forKey: "JP")
|
|
///
|
|
/// print("Country code for \(countryCodes[index!].value): '\(countryCodes[index!].key)'.")
|
|
/// // Prints "Country code for Japan: 'JP'."
|
|
///
|
|
/// - Parameter key: The key to find in the dictionary.
|
|
/// - Returns: The index for `key` and its associated value if `key` is in
|
|
/// the dictionary; otherwise, `nil`.
|
|
@inline(__always)
|
|
public func index(forKey key: Key) -> Index? {
|
|
// Complexity: amortized O(1) for native buffer, O(*n*) when wrapping an
|
|
// NSDictionary.
|
|
return _variantBuffer.index(forKey: key)
|
|
}
|
|
|
|
/// Accesses the key-value pair at the specified position.
|
|
///
|
|
/// This subscript takes an index into the dictionary, instead of a key, and
|
|
/// returns the corresponding key-value pair as a tuple. When performing
|
|
/// collection-based operations that return an index into a dictionary, use
|
|
/// this subscript with the resulting value.
|
|
///
|
|
/// For example, to find the key for a particular value in a dictionary, use
|
|
/// the `index(where:)` method.
|
|
///
|
|
/// let countryCodes = ["BR": "Brazil", "GH": "Ghana", "JP": "Japan"]
|
|
/// if let index = countryCodes.index(where: { $0.value == "Japan" }) {
|
|
/// print(countryCodes[index])
|
|
/// print("Japan's country code is '\(countryCodes[index].key)'.")
|
|
/// } else {
|
|
/// print("Didn't find 'Japan' as a value in the dictionary.")
|
|
/// }
|
|
/// // Prints "("JP", "Japan")"
|
|
/// // Prints "Japan's country code is 'JP'."
|
|
///
|
|
/// - Parameter position: The position of the key-value pair to access.
|
|
/// `position` must be a valid index of the dictionary and not equal to
|
|
/// `endIndex`.
|
|
/// - Returns: A two-element tuple with the key and value corresponding to
|
|
/// `position`.
|
|
public subscript(position: Index) -> Element {
|
|
return _variantBuffer.assertingGet(position)
|
|
}
|
|
|
|
/// Accesses the value associated with the given key for reading and writing.
|
|
///
|
|
/// This *key-based* subscript returns the value for the given key if the key
|
|
/// is found in the dictionary, or `nil` if the key is not found.
|
|
///
|
|
/// The following example creates a new dictionary and prints the value of a
|
|
/// key found in the dictionary (`"Coral"`) and a key not found in the
|
|
/// dictionary (`"Cerise"`).
|
|
///
|
|
/// var hues = ["Heliotrope": 296, "Coral": 16, "Aquamarine": 156]
|
|
/// print(hues["Coral"])
|
|
/// // Prints "Optional(16)"
|
|
/// print(hues["Cerise"])
|
|
/// // Prints "nil"
|
|
///
|
|
/// When you assign a value for a key and that key already exists, the
|
|
/// dictionary overwrites the existing value. If the dictionary doesn't
|
|
/// contain the key, the key and value are added as a new key-value pair.
|
|
///
|
|
/// Here, the value for the key `"Coral"` is updated from `16` to `18` and a
|
|
/// new key-value pair is added for the key `"Cerise"`.
|
|
///
|
|
/// hues["Coral"] = 18
|
|
/// print(hues["Coral"])
|
|
/// // Prints "Optional(18)"
|
|
///
|
|
/// hues["Cerise"] = 330
|
|
/// print(hues["Cerise"])
|
|
/// // Prints "Optional(330)"
|
|
///
|
|
/// If you assign `nil` as the value for the given key, the dictionary
|
|
/// removes that key and its associated value.
|
|
///
|
|
/// In the following example, the key-value pair for the key `"Aquamarine"`
|
|
/// is removed from the dictionary by assigning `nil` to the key-based
|
|
/// subscript.
|
|
///
|
|
/// hues["Aquamarine"] = nil
|
|
/// print(hues)
|
|
/// // Prints "["Coral": 18, "Heliotrope": 296, "Cerise": 330]"
|
|
///
|
|
/// - Parameter key: The key to find in the dictionary.
|
|
/// - Returns: The value associated with `key` if `key` is in the dictionary;
|
|
/// otherwise, `nil`.
|
|
public subscript(key: Key) -> Value? {
|
|
@inline(__always)
|
|
get {
|
|
return _variantBuffer.maybeGet(key)
|
|
}
|
|
set(newValue) {
|
|
if let x = newValue {
|
|
// FIXME(performance): this loads and discards the old value.
|
|
_variantBuffer.updateValue(x, forKey: key)
|
|
}
|
|
else {
|
|
// FIXME(performance): this loads and discards the old value.
|
|
removeValue(forKey: key)
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Updates the value stored in the dictionary for the given key, or adds a
|
|
/// new key-value pair if the key does not exist.
|
|
///
|
|
/// Use this method instead of key-based subscripting when you need to know
|
|
/// whether the new value supplants the value of an existing key. If the
|
|
/// value of an existing key is updated, `updateValue(_:forKey:)` returns
|
|
/// the original value.
|
|
///
|
|
/// var hues = ["Heliotrope": 296, "Coral": 16, "Aquamarine": 156]
|
|
///
|
|
/// if let oldValue = hues.updateValue(18, forKey: "Coral") {
|
|
/// print("The old value of \(oldValue) was replaced with a new one.")
|
|
/// }
|
|
/// // Prints "The old value of 16 was replaced with a new one."
|
|
///
|
|
/// If the given key is not present in the dictionary, this method adds the
|
|
/// key-value pair and returns `nil`.
|
|
///
|
|
/// if let oldValue = hues.updateValue(330, forKey: "Cerise") {
|
|
/// print("The old value of \(oldValue) was replaced with a new one.")
|
|
/// } else {
|
|
/// print("No value was found in the dictionary for that key.")
|
|
/// }
|
|
/// // Prints "No value was found in the dictionary for that key."
|
|
///
|
|
/// - Parameters:
|
|
/// - value: The new value to add to the dictionary.
|
|
/// - key: The key to associate with `value`. If `key` already exists in
|
|
/// the dictionary, `value` replaces the existing associated value. If
|
|
/// `key` isn't already a key of the dictionary, the `(key, value)` pair
|
|
/// is added.
|
|
/// - Returns: The value that was replaced, or `nil` if a new key-value pair
|
|
/// was added.
|
|
@discardableResult
|
|
public mutating func updateValue(
|
|
_ value: Value, forKey key: Key
|
|
) -> Value? {
|
|
return _variantBuffer.updateValue(value, forKey: key)
|
|
}
|
|
|
|
/// Removes and returns the key-value pair at the specified index.
|
|
///
|
|
/// Calling this method invalidates any existing indices for use with this
|
|
/// dictionary.
|
|
///
|
|
/// - Parameter index: The position of the key-value pair to remove. `index`
|
|
/// must be a valid index of the dictionary, and must not equal the
|
|
/// dictionary's end index.
|
|
/// - Returns: The key-value pair that correspond to `index`.
|
|
///
|
|
/// - Complexity: O(*n*), where *n* is the number of key-value pairs in the
|
|
/// dictionary.
|
|
@discardableResult
|
|
public mutating func remove(at index: Index) -> Element {
|
|
return _variantBuffer.remove(at: index)
|
|
}
|
|
|
|
/// Removes the given key and its associated value from the dictionary.
|
|
///
|
|
/// If the key is found in the dictionary, this method returns the key's
|
|
/// associated value. On removal, this method invalidates all indices with
|
|
/// respect to the dictionary.
|
|
///
|
|
/// var hues = ["Heliotrope": 296, "Coral": 16, "Aquamarine": 156]
|
|
/// if let value = hues.removeValue(forKey: "Coral") {
|
|
/// print("The value \(value) was removed.")
|
|
/// }
|
|
/// // Prints "The value 16 was removed."
|
|
///
|
|
/// If the key isn't found in the dictionary, `removeValue(forKey:)` returns
|
|
/// `nil`.
|
|
///
|
|
/// if let value = hues.removeValueForKey("Cerise") {
|
|
/// print("The value \(value) was removed.")
|
|
/// } else {
|
|
/// print("No value found for that key.")
|
|
/// }
|
|
/// // Prints "No value found for that key.""
|
|
///
|
|
/// - Parameter key: The key to remove along with its associated value.
|
|
/// - Returns: The value that was removed, or `nil` if the key was not
|
|
/// present in the dictionary.
|
|
///
|
|
/// - Complexity: O(*n*), where *n* is the number of key-value pairs in the
|
|
/// dictionary.
|
|
@discardableResult
|
|
public mutating func removeValue(forKey key: Key) -> Value? {
|
|
return _variantBuffer.removeValue(forKey: key)
|
|
}
|
|
|
|
/// Removes all key-value pairs from the dictionary.
|
|
///
|
|
/// Calling this method invalidates all indices with respect to the
|
|
/// dictionary.
|
|
///
|
|
/// - Parameter keepCapacity: Whether the dictionary should keep its
|
|
/// underlying buffer. If you pass `true`, the operation preserves the
|
|
/// buffer capacity that the collection has, otherwise the underlying
|
|
/// buffer is released. The default is `false`.
|
|
///
|
|
/// - Complexity: O(*n*), where *n* is the number of key-value pairs in the
|
|
/// dictionary.
|
|
public mutating func removeAll(keepingCapacity keepCapacity: Bool = false) {
|
|
// The 'will not decrease' part in the documentation comment is worded very
|
|
// carefully. The capacity can increase if we replace Cocoa buffer with
|
|
// native buffer.
|
|
_variantBuffer.removeAll(keepingCapacity: keepCapacity)
|
|
}
|
|
|
|
/// The number of key-value pairs in the dictionary.
|
|
///
|
|
/// - Complexity: O(1).
|
|
public var count: Int {
|
|
return _variantBuffer.count
|
|
}
|
|
|
|
//
|
|
// `Sequence` conformance
|
|
//
|
|
|
|
/// Returns an iterator over the dictionary's key-value pairs.
|
|
///
|
|
/// Iterating over a dictionary yields the key-value pairs as two-element
|
|
/// tuples. You can decompose the tuple in a `for`-`in` loop, which calls
|
|
/// `makeIterator()` behind the scenes, or when calling the iterator's
|
|
/// `next()` method directly.
|
|
///
|
|
/// let hues = ["Heliotrope": 296, "Coral": 16, "Aquamarine": 156]
|
|
/// for (name, hueValue) in hues {
|
|
/// print("The hue of \(name) is \(hueValue).")
|
|
/// }
|
|
/// // Prints "The hue of Heliotrope is 296."
|
|
/// // Prints "The hue of Coral is 16."
|
|
/// // Prints "The hue of Aquamarine is 156."
|
|
///
|
|
/// - Returns: An iterator over the dictionary with elements of type
|
|
/// `(key: Key, value: Value)`.
|
|
@inline(__always)
|
|
public func makeIterator() -> DictionaryIterator<Key, Value> {
|
|
return _variantBuffer.makeIterator()
|
|
}
|
|
|
|
//
|
|
// ExpressibleByDictionaryLiteral conformance
|
|
//
|
|
|
|
/// Creates a dictionary initialized with a dictionary literal.
|
|
///
|
|
/// Do not call this initializer directly. It is called by the compiler to
|
|
/// handle dictionary literals. To use a dictionary literal as the initial
|
|
/// value of a dictionary, enclose a comma-separated list of key-value pairs
|
|
/// in square brackets.
|
|
///
|
|
/// For example, the code sample below creates a dictionary with string keys
|
|
/// and values.
|
|
///
|
|
/// let countryCodes = ["BR": "Brazil", "GH": "Ghana", "JP": "Japan"]
|
|
/// print(countryCodes)
|
|
/// // Prints "["BR": "Brazil", "JP": "Japan", "GH": "Ghana"]"
|
|
///
|
|
/// - Parameter elements: The key-value pairs that will make up the new
|
|
/// dictionary. Each key in `elements` must be unique.
|
|
///
|
|
/// - SeeAlso: `ExpressibleByDictionaryLiteral`
|
|
@effects(readonly)
|
|
public init(dictionaryLiteral elements: (Key, Value)...) {
|
|
self.init(_nativeBuffer: _NativeDictionaryBuffer.fromArray(elements))
|
|
}
|
|
|
|
//
|
|
// APIs below this comment should be implemented strictly in terms of
|
|
// *public* APIs above. `_variantBuffer` should not be accessed directly.
|
|
//
|
|
// This separates concerns for testing. Tests for the following APIs need
|
|
// not to concern themselves with testing correctness of behavior of
|
|
// underlying buffer (and different variants of it), only correctness of the
|
|
// API itself.
|
|
//
|
|
|
|
/// A collection containing just the keys of the dictionary.
|
|
///
|
|
/// When iterated over, keys appear in this collection in the same order as they
|
|
/// occur in the dictionary's key-value pairs. Each key in the keys
|
|
/// collection has a unique value.
|
|
///
|
|
/// let countryCodes = ["BR": "Brazil", "GH": "Ghana", "JP": "Japan"]
|
|
/// for k in countryCodes.keys {
|
|
/// print(k)
|
|
/// }
|
|
/// // Prints "BR"
|
|
/// // Prints "JP"
|
|
/// // Prints "GH"
|
|
public var keys: LazyMapCollection<Dictionary, Key> {
|
|
return self.lazy.map { $0.key }
|
|
}
|
|
|
|
/// A collection containing just the values of the dictionary.
|
|
///
|
|
/// When iterated over, values appear in this collection in the same order as they
|
|
/// occur in the dictionary's key-value pairs.
|
|
///
|
|
/// let countryCodes = ["BR": "Brazil", "GH": "Ghana", "JP": "Japan"]
|
|
/// print(countryCodes)
|
|
/// // Prints "["BR": "Brazil", "JP": "Japan", "GH": "Ghana"]"
|
|
/// for v in countryCodes.values {
|
|
/// print(v)
|
|
/// }
|
|
/// // Prints "Brazil"
|
|
/// // Prints "Japan"
|
|
/// // Prints "Ghana"
|
|
public var values: LazyMapCollection<Dictionary, Value> {
|
|
return self.lazy.map { $0.value }
|
|
}
|
|
|
|
//
|
|
// Collection conformance
|
|
//
|
|
|
|
/// A Boolean value that indicates whether the dictionary is empty. (read
|
|
/// only)
|
|
///
|
|
/// Dictionaries are empty when created with an initializer or an empty
|
|
/// dictionary literal.
|
|
///
|
|
/// var frequencies: [String: Int] = [:]
|
|
/// print(frequencies.isEmpty)
|
|
/// // Prints "true"
|
|
public var isEmpty: Bool {
|
|
return count == 0
|
|
}
|
|
|
|
}
|
|
|
|
extension Dictionary where Key : Equatable, Value : Equatable {
|
|
public static func == (lhs: [Key : Value], rhs: [Key : Value]) -> Bool {
|
|
switch (lhs._variantBuffer, rhs._variantBuffer) {
|
|
case (.native(let lhsNative), .native(let rhsNative)):
|
|
|
|
if lhsNative._storage === rhsNative._storage {
|
|
return true
|
|
}
|
|
|
|
if lhsNative.count != rhsNative.count {
|
|
return false
|
|
}
|
|
|
|
for (k, v) in lhs {
|
|
let (pos, found) = rhsNative._find(k, startBucket: rhsNative._bucket(k))
|
|
// FIXME: Can't write the simple code pending
|
|
// <rdar://problem/15484639> Refcounting bug
|
|
/*
|
|
if !found || rhs[pos].value != lhsElement.value {
|
|
return false
|
|
}
|
|
*/
|
|
if !found {
|
|
return false
|
|
}
|
|
if rhsNative.value(at: pos.offset) != v {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
|
|
case (.cocoa(let lhsCocoa), .cocoa(let rhsCocoa)):
|
|
#if _runtime(_ObjC)
|
|
return _stdlib_NSObject_isEqual(
|
|
lhsCocoa.cocoaDictionary, rhsCocoa.cocoaDictionary)
|
|
#else
|
|
_sanityCheckFailure("internal error: unexpected cocoa dictionary")
|
|
#endif
|
|
|
|
case (.native(let lhsNative), .cocoa(let rhsCocoa)):
|
|
#if _runtime(_ObjC)
|
|
|
|
if lhsNative.count != rhsCocoa.count {
|
|
return false
|
|
}
|
|
|
|
let endIndex = lhsNative.endIndex
|
|
var index = lhsNative.startIndex
|
|
while index != endIndex {
|
|
let (key, value) = lhsNative.assertingGet(index)
|
|
let optRhsValue: AnyObject? =
|
|
rhsCocoa.maybeGet(_bridgeAnythingToObjectiveC(key))
|
|
|
|
guard let rhsValue = optRhsValue,
|
|
value == _forceBridgeFromObjectiveC(rhsValue, Value.self)
|
|
else {
|
|
return false
|
|
}
|
|
|
|
lhsNative.formIndex(after: &index)
|
|
continue
|
|
}
|
|
return true
|
|
#else
|
|
_sanityCheckFailure("internal error: unexpected cocoa dictionary")
|
|
#endif
|
|
|
|
case (.cocoa, .native):
|
|
#if _runtime(_ObjC)
|
|
return rhs == lhs
|
|
#else
|
|
_sanityCheckFailure("internal error: unexpected cocoa dictionary")
|
|
#endif
|
|
}
|
|
}
|
|
|
|
public static func != (lhs: [Key : Value], rhs: [Key : Value]) -> Bool {
|
|
return !(lhs == rhs)
|
|
}
|
|
}
|
|
|
|
extension Dictionary : CustomStringConvertible, CustomDebugStringConvertible {
|
|
internal func _makeDescription() -> String {
|
|
if count == 0 {
|
|
return "[:]"
|
|
}
|
|
|
|
var result = "["
|
|
var first = true
|
|
for (k, v) in self {
|
|
if first {
|
|
first = false
|
|
} else {
|
|
result += ", "
|
|
}
|
|
debugPrint(k, terminator: "", to: &result)
|
|
result += ": "
|
|
debugPrint(v, terminator: "", to: &result)
|
|
}
|
|
result += "]"
|
|
return result
|
|
}
|
|
|
|
/// A string that represents the contents of the dictionary.
|
|
public var description: String {
|
|
return _makeDescription()
|
|
}
|
|
|
|
/// A string that represents the contents of the dictionary, suitable for
|
|
/// debugging.
|
|
public var debugDescription: String {
|
|
return _makeDescription()
|
|
}
|
|
}
|
|
|
|
#if _runtime(_ObjC)
|
|
/// Equivalent to `NSDictionary.allKeys`, but does not leave objects on the
|
|
/// autorelease pool.
|
|
internal func _stdlib_NSDictionary_allKeys(_ nsd: _NSDictionary)
|
|
-> _HeapBuffer<Int, AnyObject> {
|
|
let count = nsd.count
|
|
let storage = _HeapBuffer<Int, AnyObject>(
|
|
_HeapBufferStorage<Int, AnyObject>.self, count, count)
|
|
|
|
nsd.getObjects(nil, andKeys: storage.baseAddress)
|
|
return storage
|
|
}
|
|
#endif
|
|
|
|
//===--- Compiler conversion/casting entry points for Dictionary<K, V> ----===//
|
|
|
|
/// Perform a non-bridged upcast that always succeeds.
|
|
///
|
|
/// - Precondition: `BaseKey` and `BaseValue` are base classes or base `@objc`
|
|
/// protocols (such as `AnyObject`) of `DerivedKey` and `DerivedValue`,
|
|
/// respectively.
|
|
public func _dictionaryUpCast<DerivedKey, DerivedValue, BaseKey, BaseValue>(
|
|
_ source: Dictionary<DerivedKey, DerivedValue>
|
|
) -> Dictionary<BaseKey, BaseValue> {
|
|
var result = Dictionary<BaseKey, BaseValue>(minimumCapacity: source.count)
|
|
|
|
for (k, v) in source {
|
|
result[k as! BaseKey] = (v as! BaseValue)
|
|
}
|
|
return result
|
|
}
|
|
|
|
#if _runtime(_ObjC)
|
|
|
|
/// Implements an unconditional upcast that involves bridging.
|
|
///
|
|
/// The cast can fail if bridging fails.
|
|
///
|
|
/// - Precondition: `SwiftKey` and `SwiftValue` are bridged to Objective-C,
|
|
/// and at least one of them requires non-trivial bridging.
|
|
@inline(never)
|
|
@_semantics("stdlib_binary_only")
|
|
public func _dictionaryBridgeToObjectiveC<
|
|
SwiftKey, SwiftValue, ObjCKey, ObjCValue
|
|
>(
|
|
_ source: Dictionary<SwiftKey, SwiftValue>
|
|
) -> Dictionary<ObjCKey, ObjCValue> {
|
|
|
|
// Note: We force this function to stay in the swift dylib because
|
|
// it is not performance sensitive and keeping it in the dylib saves
|
|
// a new kilobytes for each specialization for all users of dictionary.
|
|
|
|
_sanityCheck(
|
|
!_isBridgedVerbatimToObjectiveC(SwiftKey.self) ||
|
|
!_isBridgedVerbatimToObjectiveC(SwiftValue.self))
|
|
_sanityCheck(
|
|
_isClassOrObjCExistential(ObjCKey.self) ||
|
|
_isClassOrObjCExistential(ObjCValue.self))
|
|
|
|
var result = Dictionary<ObjCKey, ObjCValue>(minimumCapacity: source.count)
|
|
let keyBridgesDirectly =
|
|
_isBridgedVerbatimToObjectiveC(SwiftKey.self) ==
|
|
_isBridgedVerbatimToObjectiveC(ObjCKey.self)
|
|
let valueBridgesDirectly =
|
|
_isBridgedVerbatimToObjectiveC(SwiftValue.self) ==
|
|
_isBridgedVerbatimToObjectiveC(ObjCValue.self)
|
|
for (key, value) in source {
|
|
// Bridge the key
|
|
var bridgedKey: ObjCKey
|
|
if keyBridgesDirectly {
|
|
bridgedKey = unsafeBitCast(key, to: ObjCKey.self)
|
|
} else {
|
|
let bridged: AnyObject = _bridgeAnythingToObjectiveC(key)
|
|
bridgedKey = unsafeBitCast(bridged, to: ObjCKey.self)
|
|
}
|
|
|
|
// Bridge the value
|
|
var bridgedValue: ObjCValue
|
|
if valueBridgesDirectly {
|
|
bridgedValue = unsafeBitCast(value, to: ObjCValue.self)
|
|
} else {
|
|
let bridged: AnyObject? = _bridgeAnythingToObjectiveC(value)
|
|
bridgedValue = unsafeBitCast(bridged, to: ObjCValue.self)
|
|
}
|
|
|
|
result[bridgedKey] = bridgedValue
|
|
}
|
|
|
|
return result
|
|
}
|
|
#endif
|
|
|
|
@_silgen_name("_swift_dictionaryDownCastIndirect")
|
|
public func _dictionaryDownCastIndirect<SourceKey, SourceValue,
|
|
TargetKey, TargetValue>(
|
|
_ source: UnsafePointer<Dictionary<SourceKey, SourceValue>>,
|
|
_ target: UnsafeMutablePointer<Dictionary<TargetKey, TargetValue>>) {
|
|
target.initialize(to: _dictionaryDownCast(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: `DerivedKey` is a subtype of `BaseKey`, `DerivedValue` is
|
|
/// a subtype of `BaseValue`, and all of these types are reference types.
|
|
public func _dictionaryDownCast<BaseKey, BaseValue, DerivedKey, DerivedValue>(
|
|
_ source: Dictionary<BaseKey, BaseValue>
|
|
) -> Dictionary<DerivedKey, DerivedValue> {
|
|
|
|
#if _runtime(_ObjC)
|
|
if _isClassOrObjCExistential(BaseKey.self)
|
|
&& _isClassOrObjCExistential(BaseValue.self)
|
|
&& _isClassOrObjCExistential(DerivedKey.self)
|
|
&& _isClassOrObjCExistential(DerivedValue.self) {
|
|
|
|
switch source._variantBuffer {
|
|
case .native(let buffer):
|
|
// Note: it is safe to treat the buffer as immutable here because
|
|
// Dictionary will not mutate buffer with reference count greater than 1.
|
|
return Dictionary(_immutableCocoaDictionary: buffer.bridged())
|
|
case .cocoa(let cocoaBuffer):
|
|
return Dictionary(_immutableCocoaDictionary: cocoaBuffer.cocoaDictionary)
|
|
}
|
|
}
|
|
#endif
|
|
return _dictionaryDownCastConditional(source)!
|
|
}
|
|
|
|
@_silgen_name("_swift_dictionaryDownCastConditionalIndirect")
|
|
public func _dictionaryDownCastConditionalIndirect<SourceKey, SourceValue,
|
|
TargetKey, TargetValue>(
|
|
_ source: UnsafePointer<Dictionary<SourceKey, SourceValue>>,
|
|
_ target: UnsafeMutablePointer<Dictionary<TargetKey, TargetValue>>
|
|
) -> Bool {
|
|
if let result: Dictionary<TargetKey, TargetValue>
|
|
= _dictionaryDownCastConditional(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: `DerivedKey` is a subtype of `BaseKey`, `DerivedValue` is
|
|
/// a subtype of `BaseValue`, and all of these types are reference types.
|
|
public func _dictionaryDownCastConditional<
|
|
BaseKey, BaseValue, DerivedKey, DerivedValue
|
|
>(
|
|
_ source: Dictionary<BaseKey, BaseValue>
|
|
) -> Dictionary<DerivedKey, DerivedValue>? {
|
|
|
|
var result = Dictionary<DerivedKey, DerivedValue>()
|
|
for (k, v) in source {
|
|
guard let k1 = k as? DerivedKey, let v1 = v as? DerivedValue
|
|
else { return nil }
|
|
result[k1] = v1
|
|
}
|
|
return result
|
|
}
|
|
|
|
#if _runtime(_ObjC)
|
|
/// Implements an unconditional downcast that involves bridging.
|
|
///
|
|
/// - Precondition: At least one of `SwiftKey` or `SwiftValue` is a bridged value
|
|
/// type, and the corresponding `ObjCKey` or `ObjCValue` is a reference type.
|
|
public func _dictionaryBridgeFromObjectiveC<
|
|
ObjCKey, ObjCValue, SwiftKey, SwiftValue
|
|
>(
|
|
_ source: Dictionary<ObjCKey, ObjCValue>
|
|
) -> Dictionary<SwiftKey, SwiftValue> {
|
|
let result: Dictionary<SwiftKey, SwiftValue>? =
|
|
_dictionaryBridgeFromObjectiveCConditional(source)
|
|
_precondition(result != nil, "dictionary cannot be bridged from Objective-C")
|
|
return result!
|
|
}
|
|
|
|
/// Implements a conditional downcast that involves bridging.
|
|
///
|
|
/// If the cast fails, the function returns `nil`. All checks should be
|
|
/// performed eagerly.
|
|
///
|
|
/// - Precondition: At least one of `SwiftKey` or `SwiftValue` is a bridged value
|
|
/// type, and the corresponding `ObjCKey` or `ObjCValue` is a reference type.
|
|
public func _dictionaryBridgeFromObjectiveCConditional<
|
|
ObjCKey, ObjCValue, SwiftKey, SwiftValue
|
|
>(
|
|
_ source: Dictionary<ObjCKey, ObjCValue>
|
|
) -> Dictionary<SwiftKey, SwiftValue>? {
|
|
_sanityCheck(
|
|
_isClassOrObjCExistential(ObjCKey.self) ||
|
|
_isClassOrObjCExistential(ObjCValue.self))
|
|
_sanityCheck(
|
|
!_isBridgedVerbatimToObjectiveC(SwiftKey.self) ||
|
|
!_isBridgedVerbatimToObjectiveC(SwiftValue.self))
|
|
|
|
let keyBridgesDirectly =
|
|
_isBridgedVerbatimToObjectiveC(SwiftKey.self) ==
|
|
_isBridgedVerbatimToObjectiveC(ObjCKey.self)
|
|
let valueBridgesDirectly =
|
|
_isBridgedVerbatimToObjectiveC(SwiftValue.self) ==
|
|
_isBridgedVerbatimToObjectiveC(ObjCValue.self)
|
|
|
|
var result = Dictionary<SwiftKey, SwiftValue>(minimumCapacity: source.count)
|
|
for (key, value) in source {
|
|
// Downcast the key.
|
|
var resultKey: SwiftKey
|
|
if keyBridgesDirectly {
|
|
if let bridgedKey = key as? SwiftKey {
|
|
resultKey = bridgedKey
|
|
} else {
|
|
return nil
|
|
}
|
|
} else {
|
|
if let bridgedKey = _conditionallyBridgeFromObjectiveC(
|
|
_reinterpretCastToAnyObject(key), SwiftKey.self) {
|
|
resultKey = bridgedKey
|
|
} else {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// Downcast the value.
|
|
var resultValue: SwiftValue
|
|
if valueBridgesDirectly {
|
|
if let bridgedValue = value as? SwiftValue {
|
|
resultValue = bridgedValue
|
|
} else {
|
|
return nil
|
|
}
|
|
} else {
|
|
if let bridgedValue = _conditionallyBridgeFromObjectiveC(
|
|
_reinterpretCastToAnyObject(value), SwiftValue.self) {
|
|
resultValue = bridgedValue
|
|
} else {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
result[resultKey] = resultValue
|
|
}
|
|
return result
|
|
}
|
|
#endif
|
|
//===--- APIs templated for Dictionary and Set ----------------------------===//
|
|
|
|
%{
|
|
# Tuple items:
|
|
# Self: Class name
|
|
#
|
|
# a_self: Type name when using a generic noun
|
|
#
|
|
# TypeParametersDecl: Generic parameters appearing in top-level declarations
|
|
#
|
|
# TypeParameters: Generic parameters appearing in typealiases, etc.
|
|
#
|
|
# AnyTypeParameters: Generic parameters where all variables are AnyObject
|
|
#
|
|
# Sequence: The type of things appearing in the collection as a sequence
|
|
# e.g. dictionaries are a sequence of (Key, Value) pairs.
|
|
# AnySequenceType: The same as Sequence but everything is an AnyObject.
|
|
collections = [
|
|
('Set',
|
|
'set',
|
|
'Element : Hashable',
|
|
'Element',
|
|
'AnyObject',
|
|
'Element',
|
|
'AnyObject'),
|
|
|
|
('Dictionary',
|
|
'dictionary',
|
|
'Key : Hashable, Value',
|
|
'Key, Value',
|
|
'AnyObject, AnyObject',
|
|
'(key: Key, value: Value)',
|
|
'(AnyObject, AnyObject)'),
|
|
]
|
|
}%
|
|
|
|
% for (Self, a_self, TypeParametersDecl, TypeParameters, AnyTypeParameters, Sequence, AnySequenceType) in collections:
|
|
|
|
/// An instance of this class has all `${Self}` 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.
|
|
@objc_non_lazy_realization
|
|
internal class _RawNative${Self}Storage:
|
|
_SwiftNativeNS${Self}, _NS${Self}Core
|
|
{
|
|
internal typealias RawStorage = _RawNative${Self}Storage
|
|
|
|
internal final var capacity: Int
|
|
internal final var count: Int
|
|
|
|
internal final var initializedEntries: _UnsafeBitMap
|
|
internal final var keys: UnsafeMutableRawPointer
|
|
% if Self == 'Dictionary':
|
|
internal final var values: UnsafeMutableRawPointer
|
|
% end
|
|
|
|
// This API is unsafe and needs a `_fixLifetime` in the caller.
|
|
internal final
|
|
var _initializedHashtableEntriesBitMapBuffer: UnsafeMutablePointer<UInt> {
|
|
return UnsafeMutablePointer(Builtin.projectTailElems(self, UInt.self))
|
|
}
|
|
|
|
/// The empty singleton that is used for every single Dictionary that is
|
|
/// created without any elements. The contents of the storage should never
|
|
/// be mutated.
|
|
internal static var empty: RawStorage {
|
|
return Builtin.bridgeFromRawPointer(
|
|
Builtin.addressof(&_swiftEmpty${Self}Storage))
|
|
}
|
|
|
|
// This type is made with allocWithTailElems, so no init is ever called.
|
|
// But we still need to have an init to satisfy the compiler.
|
|
internal init(_doNotCallMe: ()) {
|
|
_sanityCheckFailure("Only create this by using the `empty` singleton")
|
|
}
|
|
|
|
#if _runtime(_ObjC)
|
|
//
|
|
// NS${Self} implementation, assuming Self is the empty singleton
|
|
//
|
|
|
|
/// Get the NSEnumerator implementation for self.
|
|
/// _HashableTypedNative${Self}Storage overloads this to give
|
|
/// _NativeSelfNSEnumerator proper type parameters.
|
|
func enumerator() -> _NSEnumerator {
|
|
return _Native${Self}NSEnumerator<${AnyTypeParameters}>(
|
|
_Native${Self}Buffer(_storage: self))
|
|
}
|
|
|
|
@objc(copyWithZone:)
|
|
func copy(with zone: _SwiftNSZone?) -> AnyObject {
|
|
return self
|
|
}
|
|
|
|
@objc(countByEnumeratingWithState:objects:count:)
|
|
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
|
|
}
|
|
|
|
%if Self == 'Set':
|
|
|
|
@objc
|
|
internal required init(objects: UnsafePointer<AnyObject?>, count: Int) {
|
|
_sanityCheckFailure("don't call this designated initializer")
|
|
}
|
|
|
|
@objc
|
|
internal func member(_ object: AnyObject) -> AnyObject? {
|
|
return nil
|
|
}
|
|
|
|
@objc
|
|
internal func objectEnumerator() -> _NSEnumerator {
|
|
return enumerator()
|
|
}
|
|
|
|
%elif Self == 'Dictionary':
|
|
|
|
@objc
|
|
internal required init(
|
|
objects: UnsafePointer<AnyObject?>,
|
|
forKeys: UnsafeRawPointer,
|
|
count: Int
|
|
) {
|
|
_sanityCheckFailure("don't call this designated initializer")
|
|
}
|
|
|
|
@objc(objectForKey:)
|
|
func objectFor(_ aKey: AnyObject) -> AnyObject? {
|
|
return nil
|
|
}
|
|
|
|
func keyEnumerator() -> _NSEnumerator {
|
|
return enumerator()
|
|
}
|
|
|
|
func getObjects(_ objects: UnsafeMutablePointer<AnyObject>?,
|
|
andKeys keys: UnsafeMutablePointer<AnyObject>?) {
|
|
// Do nothing, we're empty
|
|
}
|
|
|
|
%end
|
|
#endif
|
|
}
|
|
|
|
// See the docs at the top of this file for a description of this type
|
|
@_versioned
|
|
internal class _TypedNative${Self}Storage<${TypeParameters}> :
|
|
_RawNative${Self}Storage {
|
|
|
|
%if Self == 'Set': # Set needs these to keep signatures simple.
|
|
internal typealias Key = ${TypeParameters}
|
|
internal typealias Value = ${TypeParameters}
|
|
%end
|
|
|
|
deinit {
|
|
let keys = self.keys.assumingMemoryBound(to: Key.self)
|
|
%if Self == 'Dictionary':
|
|
let values = self.values.assumingMemoryBound(to: Value.self)
|
|
%end
|
|
|
|
if !_isPOD(Key.self) {
|
|
for i in 0 ..< capacity {
|
|
if initializedEntries[i] {
|
|
(keys+i).deinitialize()
|
|
}
|
|
}
|
|
}
|
|
|
|
%if Self == 'Dictionary':
|
|
if !_isPOD(Value.self) {
|
|
for i in 0 ..< capacity {
|
|
if initializedEntries[i] {
|
|
(values+i).deinitialize()
|
|
}
|
|
}
|
|
}
|
|
%end
|
|
_fixLifetime(self)
|
|
}
|
|
|
|
// This type is made with allocWithTailElems, so no init is ever called.
|
|
// But we still need to have an init to satisfy the compiler.
|
|
override internal init(_doNotCallMe: ()) {
|
|
_sanityCheckFailure("Only create this by calling Buffer's inits")
|
|
}
|
|
|
|
#if _runtime(_ObjC)
|
|
%if Self == 'Set':
|
|
@objc
|
|
internal required init(objects: UnsafePointer<AnyObject?>, count: Int) {
|
|
_sanityCheckFailure("don't call this designated initializer")
|
|
}
|
|
%elif Self == 'Dictionary':
|
|
@objc
|
|
internal required init(
|
|
objects: UnsafePointer<AnyObject?>,
|
|
forKeys: UnsafeRawPointer,
|
|
count: Int
|
|
) {
|
|
_sanityCheckFailure("don't call this designated initializer")
|
|
}
|
|
%end
|
|
#endif
|
|
}
|
|
|
|
|
|
// See the docs at the top of this file for a description of this type
|
|
@_versioned
|
|
final internal class _HashableTypedNative${Self}Storage<${TypeParametersDecl}> :
|
|
_TypedNative${Self}Storage<${TypeParameters}> {
|
|
|
|
internal typealias FullContainer = ${Self}<${TypeParameters}>
|
|
internal typealias Buffer = _Native${Self}Buffer<${TypeParameters}>
|
|
|
|
// This type is made with allocWithTailElems, so no init is ever called.
|
|
// But we still need to have an init to satisfy the compiler.
|
|
override internal init(_doNotCallMe: ()) {
|
|
_sanityCheckFailure("Only create this by calling Buffer's inits'")
|
|
}
|
|
|
|
|
|
#if _runtime(_ObjC)
|
|
// NS${Self} bridging:
|
|
|
|
// All actual functionality comes from buffer/full, which are
|
|
// just wrappers around a RawNative${Self}Storage.
|
|
|
|
var buffer: Buffer {
|
|
return Buffer(_storage: self)
|
|
}
|
|
|
|
var full: FullContainer {
|
|
return FullContainer(_nativeBuffer: buffer)
|
|
}
|
|
|
|
override func enumerator() -> _NSEnumerator {
|
|
return _Native${Self}NSEnumerator<${TypeParameters}>(
|
|
Buffer(_storage: self))
|
|
}
|
|
|
|
@objc(countByEnumeratingWithState:objects:count:)
|
|
override 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(full.startIndex._nativeIndex.offset)
|
|
}
|
|
|
|
// Test 'objects' rather than 'count' because (a) this is very rare anyway,
|
|
// and (b) the optimizer should then be able to optimize away the
|
|
// unwrapping check below.
|
|
if _slowPath(objects == nil) {
|
|
return 0
|
|
}
|
|
|
|
let unmanagedObjects = _UnmanagedAnyObjectArray(objects!)
|
|
var currIndex = _Native${Self}Index<${TypeParameters}>(
|
|
offset: Int(theState.extra.0))
|
|
let endIndex = buffer.endIndex
|
|
var stored = 0
|
|
for i in 0..<count {
|
|
if (currIndex == endIndex) {
|
|
break
|
|
}
|
|
|
|
unmanagedObjects[i] = buffer.bridgedKey(at: currIndex)
|
|
|
|
stored += 1
|
|
buffer.formIndex(after: &currIndex)
|
|
}
|
|
theState.extra.0 = CUnsignedLong(currIndex.offset)
|
|
state.pointee = theState
|
|
return stored
|
|
}
|
|
|
|
internal func getObjectFor(_ aKey: AnyObject) -> AnyObject? {
|
|
guard let nativeKey = _conditionallyBridgeFromObjectiveC(aKey, Key.self)
|
|
else { return nil }
|
|
|
|
let (i, found) = buffer._find(nativeKey,
|
|
startBucket: buffer._bucket(nativeKey))
|
|
|
|
if found {
|
|
return buffer.bridgedValue(at: i)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
%if Self == 'Set':
|
|
|
|
@objc
|
|
internal required init(objects: UnsafePointer<AnyObject?>, count: Int) {
|
|
_sanityCheckFailure("don't call this designated initializer")
|
|
}
|
|
|
|
@objc
|
|
override internal func member(_ object: AnyObject) -> AnyObject? {
|
|
return getObjectFor(object)
|
|
}
|
|
|
|
%elif Self == 'Dictionary':
|
|
|
|
@objc
|
|
internal required init(
|
|
objects: UnsafePointer<AnyObject?>,
|
|
forKeys: UnsafeRawPointer,
|
|
count: Int
|
|
) {
|
|
_sanityCheckFailure("don't call this designated initializer")
|
|
}
|
|
|
|
@objc(objectForKey:)
|
|
override func objectFor(_ aKey: AnyObject) -> AnyObject? {
|
|
return getObjectFor(aKey)
|
|
}
|
|
|
|
// We also override the following methods for efficiency.
|
|
@objc
|
|
override func getObjects(_ objects: UnsafeMutablePointer<AnyObject>?,
|
|
andKeys keys: UnsafeMutablePointer<AnyObject>?) {
|
|
// The user is expected to provide a storage of the correct size
|
|
if let unmanagedKeys = _UnmanagedAnyObjectArray(keys) {
|
|
if let unmanagedObjects = _UnmanagedAnyObjectArray(objects) {
|
|
// keys nonnull, objects nonnull
|
|
for (offset: i, element: (key: key, value: val)) in full.enumerated() {
|
|
unmanagedObjects[i] = _bridgeAnythingToObjectiveC(val)
|
|
unmanagedKeys[i] = _bridgeAnythingToObjectiveC(key)
|
|
}
|
|
} else {
|
|
// keys nonnull, objects null
|
|
for (offset: i, element: (key: key, value: _)) in full.enumerated() {
|
|
unmanagedKeys[i] = _bridgeAnythingToObjectiveC(key)
|
|
}
|
|
}
|
|
} else {
|
|
if let unmanagedObjects = _UnmanagedAnyObjectArray(objects) {
|
|
// keys null, objects nonnull
|
|
for (offset: i, element: (key: _, value: val)) in full.enumerated() {
|
|
unmanagedObjects[i] = _bridgeAnythingToObjectiveC(val)
|
|
}
|
|
} else {
|
|
// do nothing, both are null
|
|
}
|
|
}
|
|
}
|
|
%end
|
|
#endif
|
|
}
|
|
|
|
|
|
/// A wrapper around _RawNative${Self}Storage that provides most of the
|
|
/// implementation of ${Self}.
|
|
///
|
|
/// This type and most of its functionality doesn't require Hashable at all.
|
|
/// The reason for this is to support storing AnyObject for bridging
|
|
/// with _SwiftDeferredNS${Self}. What functionality actually relies on
|
|
/// Hashable can be found in an extension.
|
|
@_versioned
|
|
@_fixed_layout
|
|
internal struct _Native${Self}Buffer<${TypeParameters}> {
|
|
|
|
internal typealias RawStorage = _RawNative${Self}Storage
|
|
internal typealias TypedStorage = _TypedNative${Self}Storage<${TypeParameters}>
|
|
internal typealias Buffer = _Native${Self}Buffer<${TypeParameters}>
|
|
internal typealias Index = _Native${Self}Index<${TypeParameters}>
|
|
|
|
%if Self == 'Set': # Set needs these to keep signatures simple.
|
|
internal typealias Key = ${TypeParameters}
|
|
internal typealias Value = ${TypeParameters}
|
|
internal typealias SequenceElementWithoutLabels = Element
|
|
%else:
|
|
internal typealias SequenceElementWithoutLabels = (Key, Value)
|
|
%end
|
|
|
|
/// See this comments on _RawNative${Self}Storage and its subclasses to
|
|
/// understand why we store an untyped storage here.
|
|
internal var _storage: RawStorage
|
|
|
|
/// Creates a Buffer with a storage that is typed, but doesn't understand
|
|
/// Hashing. Mostly for bridging; prefer `init(capacity:)`.
|
|
internal init(capacity: Int, unhashable: ()) {
|
|
let numWordsForBitmap = _UnsafeBitMap.sizeInWords(forSizeInBits: capacity)
|
|
%if Self == 'Dictionary':
|
|
let storage = Builtin.allocWithTailElems_3(TypedStorage.self,
|
|
numWordsForBitmap._builtinWordValue, UInt.self,
|
|
capacity._builtinWordValue, Key.self,
|
|
capacity._builtinWordValue, Value.self)
|
|
%else:
|
|
let storage = Builtin.allocWithTailElems_2(TypedStorage.self,
|
|
numWordsForBitmap._builtinWordValue, UInt.self,
|
|
capacity._builtinWordValue, Key.self)
|
|
%end
|
|
self.init(capacity: capacity, storage: storage)
|
|
}
|
|
|
|
/// Given a capacity and uninitialized RawStorage, completes the
|
|
/// initialization and returns a Buffer.
|
|
internal init(capacity: Int, storage: RawStorage) {
|
|
storage.capacity = capacity
|
|
storage.count = 0
|
|
|
|
self.init(_storage: storage)
|
|
|
|
let initializedEntries = _UnsafeBitMap(
|
|
storage: _initializedHashtableEntriesBitMapBuffer,
|
|
bitCount: capacity)
|
|
initializedEntries.initializeToZero()
|
|
|
|
// Compute all the array offsets now, so we don't have to later
|
|
let bitmapAddr = Builtin.projectTailElems(_storage, UInt.self)
|
|
let numWordsForBitmap = _UnsafeBitMap.sizeInWords(forSizeInBits: capacity)
|
|
let keysAddr = Builtin.getTailAddr_Word(bitmapAddr,
|
|
numWordsForBitmap._builtinWordValue, UInt.self, Key.self)
|
|
|
|
// Initialize header
|
|
_storage.initializedEntries = initializedEntries
|
|
_storage.keys = UnsafeMutableRawPointer(keysAddr)
|
|
%if Self == 'Dictionary':
|
|
let valuesAddr = Builtin.getTailAddr_Word(keysAddr,
|
|
capacity._builtinWordValue, Key.self, Value.self)
|
|
_storage.values = UnsafeMutableRawPointer(valuesAddr)
|
|
%end
|
|
}
|
|
|
|
// Forwarding the individual fields of the storage in various forms
|
|
|
|
@_versioned
|
|
internal var capacity: Int {
|
|
return _assumeNonNegative(_storage.capacity)
|
|
}
|
|
|
|
@_versioned
|
|
internal var count: Int {
|
|
set {
|
|
_storage.count = newValue
|
|
}
|
|
get {
|
|
return _assumeNonNegative(_storage.count)
|
|
}
|
|
}
|
|
|
|
internal
|
|
var _initializedHashtableEntriesBitMapBuffer: UnsafeMutablePointer<UInt> {
|
|
return _storage._initializedHashtableEntriesBitMapBuffer
|
|
}
|
|
|
|
// This API is unsafe and needs a `_fixLifetime` in the caller.
|
|
@_versioned
|
|
internal var keys: UnsafeMutablePointer<Key> {
|
|
return _storage.keys.assumingMemoryBound(to: Key.self)
|
|
}
|
|
|
|
%if Self == 'Dictionary':
|
|
// This API is unsafe and needs a `_fixLifetime` in the caller.
|
|
@_versioned
|
|
internal var values: UnsafeMutablePointer<Value> {
|
|
return _storage.values.assumingMemoryBound(to: Value.self)
|
|
}
|
|
%end
|
|
|
|
/// Constructs a buffer adopting the given storage.
|
|
init(_storage: RawStorage) {
|
|
self._storage = _storage
|
|
}
|
|
|
|
/// Constructs an instance from the empty singleton.
|
|
init() {
|
|
self._storage = RawStorage.empty
|
|
}
|
|
|
|
|
|
|
|
// Most of the implementation of the _HashBuffer protocol,
|
|
// but only the parts that don't actually rely on hashing.
|
|
|
|
@_versioned
|
|
@inline(__always)
|
|
internal func key(at i: Int) -> Key {
|
|
_sanityCheck(i >= 0 && i < capacity)
|
|
_sanityCheck(isInitializedEntry(at: i))
|
|
defer { _fixLifetime(self) }
|
|
|
|
let res = (keys + i).pointee
|
|
return res
|
|
}
|
|
|
|
#if _runtime(_ObjC)
|
|
/// Returns the key at the given Index, bridged.
|
|
///
|
|
/// Intended for use with verbatim bridgeable keys.
|
|
internal func bridgedKey(at index: Index) -> AnyObject {
|
|
let k = key(at: index.offset)
|
|
return _bridgeAnythingToObjectiveC(k)
|
|
}
|
|
|
|
/// Returns the value at the given Index, bridged.
|
|
///
|
|
/// Intended for use with verbatim bridgeable keys.
|
|
internal func bridgedValue(at index: Index) -> AnyObject {
|
|
let v = value(at: index.offset)
|
|
return _bridgeAnythingToObjectiveC(v)
|
|
}
|
|
#endif
|
|
|
|
@_versioned
|
|
internal func isInitializedEntry(at i: Int) -> Bool {
|
|
_sanityCheck(i >= 0 && i < capacity)
|
|
defer { _fixLifetime(self) }
|
|
|
|
return _storage.initializedEntries[i]
|
|
}
|
|
|
|
@_transparent
|
|
internal func destroyEntry(at i: Int) {
|
|
_sanityCheck(isInitializedEntry(at: i))
|
|
defer { _fixLifetime(self) }
|
|
|
|
(keys + i).deinitialize()
|
|
%if Self == 'Dictionary':
|
|
(values + i).deinitialize()
|
|
%end
|
|
_storage.initializedEntries[i] = false
|
|
}
|
|
|
|
%if Self == 'Set':
|
|
@_transparent
|
|
internal func initializeKey(_ k: Key, at i: Int) {
|
|
_sanityCheck(!isInitializedEntry(at: i))
|
|
defer { _fixLifetime(self) }
|
|
|
|
(keys + i).initialize(to: k)
|
|
_storage.initializedEntries[i] = true
|
|
}
|
|
|
|
@_transparent
|
|
internal func moveInitializeEntry(from: Buffer, at: Int, toEntryAt: Int) {
|
|
_sanityCheck(!isInitializedEntry(at: toEntryAt))
|
|
|
|
defer { _fixLifetime(self) }
|
|
|
|
(keys + toEntryAt).initialize(to: (from.keys + at).move())
|
|
from._storage.initializedEntries[at] = false
|
|
_storage.initializedEntries[toEntryAt] = true
|
|
}
|
|
|
|
/// Alias for key(at:) in Sets for better code reuse
|
|
@_versioned
|
|
@_transparent
|
|
internal func value(at i: Int) -> Value {
|
|
return key(at: i)
|
|
}
|
|
|
|
internal func setKey(_ key: Key, at i: Int) {
|
|
_sanityCheck(i >= 0 && i < capacity)
|
|
_sanityCheck(isInitializedEntry(at: i))
|
|
defer { _fixLifetime(self) }
|
|
|
|
(keys + i).pointee = key
|
|
}
|
|
|
|
%elif Self == 'Dictionary':
|
|
@_transparent
|
|
internal func initializeKey(_ k: Key, value v: Value, at i: Int) {
|
|
_sanityCheck(!isInitializedEntry(at: i))
|
|
defer { _fixLifetime(self) }
|
|
|
|
(keys + i).initialize(to: k)
|
|
(values + i).initialize(to: v)
|
|
_storage.initializedEntries[i] = true
|
|
}
|
|
|
|
@_transparent
|
|
internal func moveInitializeEntry(from: Buffer, at: Int, toEntryAt: Int) {
|
|
_sanityCheck(!isInitializedEntry(at: toEntryAt))
|
|
defer { _fixLifetime(self) }
|
|
|
|
(keys + toEntryAt).initialize(to: (from.keys + at).move())
|
|
(values + toEntryAt).initialize(to: (from.values + at).move())
|
|
from._storage.initializedEntries[at] = false
|
|
_storage.initializedEntries[toEntryAt] = true
|
|
}
|
|
|
|
@_versioned
|
|
@_transparent
|
|
internal func value(at i: Int) -> Value {
|
|
_sanityCheck(isInitializedEntry(at: i))
|
|
defer { _fixLifetime(self) }
|
|
|
|
return (values + i).pointee
|
|
}
|
|
|
|
@_transparent
|
|
internal func setKey(_ key: Key, value: Value, at i: Int) {
|
|
_sanityCheck(isInitializedEntry(at: i))
|
|
defer { _fixLifetime(self) }
|
|
|
|
(keys + i).pointee = key
|
|
(values + i).pointee = value
|
|
}
|
|
|
|
%end
|
|
|
|
@_versioned
|
|
internal var startIndex: Index {
|
|
// We start at "index after -1" instead of "0" because we need to find the
|
|
// first occupied slot.
|
|
return index(after: Index(offset: -1))
|
|
}
|
|
|
|
@_versioned
|
|
internal var endIndex: Index {
|
|
return Index(offset: capacity)
|
|
}
|
|
|
|
@_versioned
|
|
internal func index(after i: Index) -> Index {
|
|
_precondition(i != endIndex)
|
|
var idx = i.offset + 1
|
|
while idx < capacity && !isInitializedEntry(at: idx) {
|
|
idx += 1
|
|
}
|
|
|
|
return Index(offset: idx)
|
|
}
|
|
|
|
@_versioned
|
|
internal func formIndex(after i: inout Index) {
|
|
i = index(after: i)
|
|
}
|
|
|
|
|
|
internal func assertingGet(_ i: Index) -> SequenceElement {
|
|
_precondition(i.offset >= 0 && i.offset < capacity)
|
|
_precondition(
|
|
isInitializedEntry(at: i.offset),
|
|
"attempting to access ${Self} elements using an invalid Index")
|
|
let key = self.key(at: i.offset)
|
|
%if Self == 'Set':
|
|
return key
|
|
%elif Self == 'Dictionary':
|
|
return (key, self.value(at: i.offset))
|
|
%end
|
|
|
|
}
|
|
}
|
|
|
|
extension _Native${Self}Buffer
|
|
where ${'Key' if Self == 'Dictionary' else 'Element'} : Hashable
|
|
{
|
|
internal typealias HashTypedStorage =
|
|
_HashableTypedNative${Self}Storage<${TypeParameters}>
|
|
internal typealias SequenceElement = ${Sequence}
|
|
|
|
@inline(__always)
|
|
internal init(minimumCapacity: Int) {
|
|
// Make sure there's a representable power of 2 >= minimumCapacity
|
|
_sanityCheck(minimumCapacity <= (Int.max >> 1) + 1)
|
|
var capacity = 2
|
|
while capacity < minimumCapacity {
|
|
capacity <<= 1
|
|
}
|
|
self.init(capacity: capacity)
|
|
}
|
|
|
|
/// Create a buffer instance with room for at least 'capacity'
|
|
/// entries and all entries marked invalid.
|
|
internal init(capacity: Int) {
|
|
let numWordsForBitmap = _UnsafeBitMap.sizeInWords(forSizeInBits: capacity)
|
|
%if Self == 'Dictionary':
|
|
let storage = Builtin.allocWithTailElems_3(HashTypedStorage.self,
|
|
numWordsForBitmap._builtinWordValue, UInt.self,
|
|
capacity._builtinWordValue, Key.self,
|
|
capacity._builtinWordValue, Value.self)
|
|
%else:
|
|
let storage = Builtin.allocWithTailElems_2(HashTypedStorage.self,
|
|
numWordsForBitmap._builtinWordValue, UInt.self,
|
|
capacity._builtinWordValue, Key.self)
|
|
%end
|
|
self.init(capacity: capacity, storage: storage)
|
|
}
|
|
|
|
#if _runtime(_ObjC)
|
|
func bridged() -> _NS${Self} {
|
|
// 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: _NS${Self}Core
|
|
|
|
if (_isBridgedVerbatimToObjectiveC(Key.self) &&
|
|
_isBridgedVerbatimToObjectiveC(Value.self)) ||
|
|
self._storage === RawStorage.empty {
|
|
nsSet = self._storage
|
|
} else {
|
|
nsSet = _SwiftDeferredNS${Self}(nativeBuffer: self)
|
|
}
|
|
|
|
// Cast from "minimal NS${Self}" to "NS${Self}"
|
|
// Note that if you actually ask Swift for this cast, it will fail.
|
|
// Never trust a shadow protocol!
|
|
return unsafeBitCast(nsSet, to: _NS${Self}.self)
|
|
}
|
|
#endif
|
|
|
|
/// A textual representation of `self`.
|
|
var description: String {
|
|
var result = ""
|
|
#if INTERNAL_CHECKS_ENABLED
|
|
for i in 0..<capacity {
|
|
if isInitializedEntry(at: i) {
|
|
let key = self.key(at: i)
|
|
result += "bucket \(i), ideal bucket = \(_bucket(key)), key = \(key)\n"
|
|
} else {
|
|
result += "bucket \(i), empty\n"
|
|
}
|
|
}
|
|
#endif
|
|
return result
|
|
}
|
|
|
|
internal var _bucketMask: Int {
|
|
// The capacity is not negative, therefore subtracting 1 will not overflow.
|
|
return capacity &- 1
|
|
}
|
|
|
|
@_versioned
|
|
@inline(__always) // For performance reasons.
|
|
internal func _bucket(_ k: Key) -> Int {
|
|
return _squeezeHashValue(k.hashValue, capacity)
|
|
}
|
|
|
|
@_versioned
|
|
internal func _index(after bucket: Int) -> Int {
|
|
// Bucket is within 0 and capacity. Therefore adding 1 does not overflow.
|
|
return (bucket &+ 1) & _bucketMask
|
|
}
|
|
|
|
internal func _prev(_ bucket: Int) -> Int {
|
|
// Bucket is not negative. Therefore subtracting 1 does not overflow.
|
|
return (bucket &- 1) & _bucketMask
|
|
}
|
|
|
|
/// Search for a given key starting from the specified bucket.
|
|
///
|
|
/// If the key is not present, returns the position where it could be
|
|
/// inserted.
|
|
@_versioned
|
|
@inline(__always)
|
|
internal func _find(_ key: Key, startBucket: Int)
|
|
-> (pos: Index, found: Bool) {
|
|
|
|
var bucket = startBucket
|
|
|
|
// The invariant guarantees there's always a hole, so we just loop
|
|
// until we find one
|
|
while true {
|
|
let isHole = !isInitializedEntry(at: bucket)
|
|
if isHole {
|
|
return (Index(offset: bucket), false)
|
|
}
|
|
if self.key(at: bucket) == key {
|
|
return (Index(offset: bucket), true)
|
|
}
|
|
bucket = _index(after: bucket)
|
|
}
|
|
}
|
|
|
|
@_transparent
|
|
internal static func minimumCapacity(
|
|
minimumCount: Int,
|
|
maxLoadFactorInverse: Double
|
|
) -> Int {
|
|
// `minimumCount + 1` below ensures that we don't fill in the last hole
|
|
return max(Int(Double(minimumCount) * maxLoadFactorInverse),
|
|
minimumCount + 1)
|
|
}
|
|
|
|
/// Buffer should be uniquely referenced.
|
|
/// The `key` should not be present in the ${Self}.
|
|
/// This function does *not* update `count`.
|
|
|
|
%if Self == 'Set':
|
|
|
|
internal func unsafeAddNew(key newKey: Element) {
|
|
let (i, found) = _find(newKey, startBucket: _bucket(newKey))
|
|
_sanityCheck(
|
|
!found, "unsafeAddNew was called, but the key is already present")
|
|
initializeKey(newKey, at: i.offset)
|
|
}
|
|
|
|
%elif Self == 'Dictionary':
|
|
|
|
internal func unsafeAddNew(key newKey: Key, value: Value) {
|
|
let (i, found) = _find(newKey, startBucket: _bucket(newKey))
|
|
_sanityCheck(
|
|
!found, "unsafeAddNew was called, but the key is already present")
|
|
initializeKey(newKey, value: value, at: i.offset)
|
|
}
|
|
|
|
%end
|
|
|
|
//
|
|
// _HashBuffer conformance
|
|
//
|
|
|
|
@_versioned
|
|
@inline(__always)
|
|
internal func index(forKey key: Key) -> Index? {
|
|
if count == 0 {
|
|
// Fast path that avoids computing the hash of the key.
|
|
return nil
|
|
}
|
|
let (i, found) = _find(key, startBucket: _bucket(key))
|
|
return found ? i : nil
|
|
}
|
|
|
|
|
|
internal func assertingGet(_ key: Key) -> Value {
|
|
let (i, found) = _find(key, startBucket: _bucket(key))
|
|
_precondition(found, "key not found")
|
|
%if Self == 'Set':
|
|
return self.key(at: i.offset)
|
|
%elif Self == 'Dictionary':
|
|
return self.value(at: i.offset)
|
|
%end
|
|
}
|
|
|
|
@_versioned
|
|
@inline(__always)
|
|
internal func maybeGet(_ key: Key) -> Value? {
|
|
if count == 0 {
|
|
// Fast path that avoids computing the hash of the key.
|
|
return nil
|
|
}
|
|
|
|
let (i, found) = _find(key, startBucket: _bucket(key))
|
|
if found {
|
|
%if Self == 'Set':
|
|
return self.key(at: i.offset)
|
|
%elif Self == 'Dictionary':
|
|
return self.value(at: i.offset)
|
|
%end
|
|
}
|
|
return nil
|
|
}
|
|
|
|
@discardableResult
|
|
internal func updateValue(_ value: Value, forKey key: Key) -> Value? {
|
|
_sanityCheckFailure(
|
|
"don't call mutating methods on _Native${Self}Buffer")
|
|
}
|
|
|
|
@discardableResult
|
|
internal func insert(
|
|
_ value: Value, forKey key: Key
|
|
) -> (inserted: Bool, memberAfterInsert: Value) {
|
|
_sanityCheckFailure(
|
|
"don't call mutating methods on _Native${Self}Buffer")
|
|
}
|
|
|
|
@discardableResult
|
|
internal func remove(at index: Index) -> SequenceElement {
|
|
_sanityCheckFailure(
|
|
"don't call mutating methods on _Native${Self}Buffer")
|
|
}
|
|
|
|
@discardableResult
|
|
internal func removeValue(forKey key: Key) -> Value? {
|
|
_sanityCheckFailure(
|
|
"don't call mutating methods on _Native${Self}Buffer")
|
|
}
|
|
|
|
internal func removeAll(keepingCapacity keepCapacity: Bool) {
|
|
_sanityCheckFailure(
|
|
"don't call mutating methods on _Native${Self}Buffer")
|
|
}
|
|
|
|
internal static func fromArray(_ elements: [SequenceElementWithoutLabels])
|
|
-> Buffer
|
|
{
|
|
if elements.isEmpty {
|
|
return Buffer()
|
|
}
|
|
|
|
let requiredCapacity =
|
|
Buffer.minimumCapacity(
|
|
minimumCount: elements.count,
|
|
maxLoadFactorInverse: _hashContainerDefaultMaxLoadFactorInverse)
|
|
var nativeBuffer = Buffer(minimumCapacity: requiredCapacity)
|
|
|
|
%if Self == 'Set':
|
|
|
|
var count = 0
|
|
for key in elements {
|
|
let (i, found) =
|
|
nativeBuffer._find(key, startBucket: nativeBuffer._bucket(key))
|
|
if found {
|
|
continue
|
|
}
|
|
nativeBuffer.initializeKey(key, at: i.offset)
|
|
count += 1
|
|
}
|
|
nativeBuffer.count = count
|
|
|
|
%elif Self == 'Dictionary':
|
|
|
|
for (key, value) in elements {
|
|
let (i, found) =
|
|
nativeBuffer._find(key, startBucket: nativeBuffer._bucket(key))
|
|
_precondition(!found, "${Self} literal contains duplicate keys")
|
|
nativeBuffer.initializeKey(key, value: value, at: i.offset)
|
|
}
|
|
nativeBuffer.count = elements.count
|
|
|
|
%end
|
|
|
|
return nativeBuffer
|
|
}
|
|
}
|
|
|
|
#if _runtime(_ObjC)
|
|
/// An NSEnumerator that works with any Native${Self}Buffer of
|
|
/// verbatim bridgeable elements. Used by the various NS${Self} impls.
|
|
final internal class _Native${Self}NSEnumerator<${TypeParameters}>
|
|
: _SwiftNativeNSEnumerator, _NSEnumerator {
|
|
|
|
internal typealias Buffer = _Native${Self}Buffer<${TypeParameters}>
|
|
internal typealias Index = _Native${Self}Index<${TypeParameters}>
|
|
|
|
internal override required init() {
|
|
_sanityCheckFailure("don't call this designated initializer")
|
|
}
|
|
|
|
internal init(_ buffer: Buffer) {
|
|
self.buffer = buffer
|
|
nextIndex = buffer.startIndex
|
|
endIndex = buffer.endIndex
|
|
}
|
|
|
|
internal var buffer: Buffer
|
|
internal var nextIndex: Index
|
|
internal var endIndex: 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 key = buffer.bridgedKey(at: nextIndex)
|
|
buffer.formIndex(after: &nextIndex)
|
|
return key
|
|
}
|
|
|
|
@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 key = buffer.bridgedKey(at: nextIndex)
|
|
buffer.formIndex(after: &nextIndex)
|
|
|
|
let unmanagedObjects = _UnmanagedAnyObjectArray(objects)
|
|
unmanagedObjects[0] = key
|
|
state.pointee = theState
|
|
return 1
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if _runtime(_ObjC)
|
|
/// This class exists for Objective-C bridging. It holds a reference to a
|
|
/// Native${Self}Buffer, 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 Native${Self}Buffer of AnyObject will be
|
|
/// constructed containing all the bridged elements.
|
|
final internal class _SwiftDeferredNS${Self}<${TypeParametersDecl}>
|
|
: _SwiftNativeNS${Self}, _NS${Self}Core {
|
|
|
|
internal typealias NativeBuffer = _Native${Self}Buffer<${TypeParameters}>
|
|
internal typealias BridgedBuffer = _Native${Self}Buffer<${AnyTypeParameters}>
|
|
internal typealias NativeIndex = _Native${Self}Index<${TypeParameters}>
|
|
internal typealias BridgedIndex = _Native${Self}Index<${AnyTypeParameters}>
|
|
|
|
%if Self == 'Set':
|
|
internal typealias Key = Element
|
|
internal typealias Value = Element
|
|
%end
|
|
|
|
internal init(minimumCapacity: Int = 2) {
|
|
nativeBuffer = NativeBuffer(minimumCapacity: minimumCapacity)
|
|
super.init()
|
|
}
|
|
|
|
internal init(nativeBuffer: NativeBuffer) {
|
|
self.nativeBuffer = nativeBuffer
|
|
super.init()
|
|
}
|
|
|
|
// This stored property should be stored at offset zero. We perform atomic
|
|
// operations on it.
|
|
//
|
|
// Do not access this property directly.
|
|
internal var _heapStorageBridged_DoNotUse: AnyObject?
|
|
|
|
/// The unbridged elements.
|
|
internal var nativeBuffer: NativeBuffer
|
|
|
|
@objc(copyWithZone:)
|
|
internal func copy(with zone: _SwiftNSZone?) -> AnyObject {
|
|
// Instances of this class should be visible outside of standard library as
|
|
// having `NS${Self}` type, which is immutable.
|
|
return self
|
|
}
|
|
|
|
%if Self == 'Set':
|
|
|
|
//
|
|
// NSSet implementation.
|
|
//
|
|
// Do not call any of these methods from the standard library! Use only
|
|
// `nativeBuffer`.
|
|
//
|
|
|
|
@objc
|
|
internal required init(objects: UnsafePointer<AnyObject?>, count: Int) {
|
|
_sanityCheckFailure("don't call this designated initializer")
|
|
}
|
|
|
|
@objc
|
|
internal func member(_ object: AnyObject) -> AnyObject? {
|
|
return bridgingObjectForKey(object)
|
|
}
|
|
|
|
@objc
|
|
internal func objectEnumerator() -> _NSEnumerator {
|
|
return enumerator()
|
|
}
|
|
|
|
%elif Self == 'Dictionary':
|
|
//
|
|
// NSDictionary implementation.
|
|
//
|
|
// Do not call any of these methods from the standard library! Use only
|
|
// `nativeBuffer`.
|
|
//
|
|
|
|
@objc
|
|
internal required init(
|
|
objects: UnsafePointer<AnyObject?>,
|
|
forKeys: UnsafeRawPointer,
|
|
count: Int
|
|
) {
|
|
_sanityCheckFailure("don't call this designated initializer")
|
|
}
|
|
|
|
@objc(objectForKey:)
|
|
internal func objectFor(_ aKey: AnyObject) -> AnyObject? {
|
|
return bridgingObjectForKey(aKey)
|
|
}
|
|
|
|
@objc
|
|
internal func keyEnumerator() -> _NSEnumerator {
|
|
return enumerator()
|
|
}
|
|
|
|
@objc
|
|
internal func getObjects(
|
|
_ objects: UnsafeMutablePointer<AnyObject>?,
|
|
andKeys keys: UnsafeMutablePointer<AnyObject>?
|
|
) {
|
|
bridgedAllKeysAndValues(objects, keys)
|
|
}
|
|
%end
|
|
|
|
/// Returns the pointer to the stored property, which contains bridged
|
|
/// ${Self} elements.
|
|
internal var _heapStorageBridgedPtr: UnsafeMutablePointer<AnyObject?> {
|
|
return _getUnsafePointerToStoredProperties(self).assumingMemoryBound(
|
|
to: Optional<AnyObject>.self)
|
|
}
|
|
|
|
/// The buffer for bridged ${Self} elements, if present.
|
|
internal var _bridgedStorage:
|
|
BridgedBuffer.RawStorage? {
|
|
get {
|
|
if let ref = _stdlib_atomicLoadARCRef(object: _heapStorageBridgedPtr) {
|
|
return unsafeDowncast(ref, to: BridgedBuffer.RawStorage.self)
|
|
}
|
|
return nil
|
|
}
|
|
}
|
|
|
|
/// Attach a buffer for bridged ${Self} elements.
|
|
internal func _initializeHeapStorageBridged(_ newStorage: AnyObject) {
|
|
_stdlib_atomicInitializeARCRef(
|
|
object: _heapStorageBridgedPtr, desired: newStorage)
|
|
}
|
|
|
|
/// Returns the bridged ${Self} values.
|
|
internal var bridgedBuffer: BridgedBuffer {
|
|
return BridgedBuffer(_storage: _bridgedStorage!)
|
|
}
|
|
|
|
internal func bridgeEverything() {
|
|
if _fastPath(_bridgedStorage != nil) {
|
|
return
|
|
}
|
|
|
|
// FIXME: rdar://problem/19486139 (split bridged buffers for keys and values)
|
|
// We bridge keys and values unconditionally here, even if one of them
|
|
// actually is verbatim bridgeable (e.g. Dictionary<Int, AnyObject>).
|
|
// Investigate only allocating the buffer for a Set in this case.
|
|
|
|
// Create buffer for bridged data.
|
|
let bridged = BridgedBuffer(capacity: nativeBuffer.capacity, unhashable: ())
|
|
|
|
// Bridge everything.
|
|
for i in 0..<nativeBuffer.capacity {
|
|
if nativeBuffer.isInitializedEntry(at: i) {
|
|
let key = _bridgeAnythingToObjectiveC(nativeBuffer.key(at: i))
|
|
%if Self == 'Set':
|
|
bridged.initializeKey(key, at: i)
|
|
%elif Self == 'Dictionary':
|
|
let val = _bridgeAnythingToObjectiveC(nativeBuffer.value(at: i))
|
|
bridged.initializeKey(key, value: val, at: i)
|
|
%end
|
|
}
|
|
}
|
|
|
|
// Atomically put the bridged elements in place.
|
|
_initializeHeapStorageBridged(bridged._storage)
|
|
}
|
|
|
|
%if Self == 'Dictionary':
|
|
|
|
internal func bridgedAllKeysAndValues(
|
|
_ objects: UnsafeMutablePointer<AnyObject>?,
|
|
_ keys: UnsafeMutablePointer<AnyObject>?
|
|
) {
|
|
bridgeEverything()
|
|
// The user is expected to provide a storage of the correct size
|
|
var i = 0 // Position in the input storage
|
|
let capacity = nativeBuffer.capacity
|
|
|
|
if let unmanagedKeys = _UnmanagedAnyObjectArray(keys) {
|
|
if let unmanagedObjects = _UnmanagedAnyObjectArray(objects) {
|
|
// keys nonnull, objects nonnull
|
|
for position in 0..<capacity {
|
|
if bridgedBuffer.isInitializedEntry(at: position) {
|
|
unmanagedObjects[i] = bridgedBuffer.value(at: position)
|
|
unmanagedKeys[i] = bridgedBuffer.key(at: position)
|
|
i += 1
|
|
}
|
|
}
|
|
} else {
|
|
// keys nonnull, objects null
|
|
for position in 0..<capacity {
|
|
if bridgedBuffer.isInitializedEntry(at: position) {
|
|
unmanagedKeys[i] = bridgedBuffer.key(at: position)
|
|
i += 1
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if let unmanagedObjects = _UnmanagedAnyObjectArray(objects) {
|
|
// keys null, objects nonnull
|
|
for position in 0..<capacity {
|
|
if bridgedBuffer.isInitializedEntry(at: position) {
|
|
unmanagedObjects[i] = bridgedBuffer.value(at: position)
|
|
i += 1
|
|
}
|
|
}
|
|
} else {
|
|
// do nothing, both are null
|
|
}
|
|
}
|
|
}
|
|
|
|
%end
|
|
|
|
@objc
|
|
internal var count: Int {
|
|
return nativeBuffer.count
|
|
}
|
|
|
|
internal func bridgingObjectForKey(_ aKey: AnyObject)
|
|
-> AnyObject? {
|
|
guard let nativeKey = _conditionallyBridgeFromObjectiveC(aKey, Key.self)
|
|
else { return nil }
|
|
|
|
let (i, found) = nativeBuffer._find(
|
|
nativeKey, startBucket: nativeBuffer._bucket(nativeKey))
|
|
if found {
|
|
bridgeEverything()
|
|
return bridgedBuffer.value(at: i.offset)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
internal func enumerator() -> _NSEnumerator {
|
|
bridgeEverything()
|
|
return _Native${Self}NSEnumerator<${AnyTypeParameters}>(bridgedBuffer)
|
|
}
|
|
|
|
@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(nativeBuffer.startIndex.offset)
|
|
}
|
|
|
|
// Test 'objects' rather than 'count' because (a) this is very rare anyway,
|
|
// and (b) the optimizer should then be able to optimize away the
|
|
// unwrapping check below.
|
|
if _slowPath(objects == nil) {
|
|
return 0
|
|
}
|
|
|
|
let unmanagedObjects = _UnmanagedAnyObjectArray(objects!)
|
|
var currIndex = _Native${Self}Index<${TypeParameters}>(
|
|
offset: Int(theState.extra.0))
|
|
let endIndex = nativeBuffer.endIndex
|
|
var stored = 0
|
|
|
|
// Only need to bridge once, so we can hoist it out of the loop.
|
|
if (currIndex != endIndex) {
|
|
bridgeEverything()
|
|
}
|
|
|
|
for i in 0..<count {
|
|
if (currIndex == endIndex) {
|
|
break
|
|
}
|
|
|
|
let bridgedKey = bridgedBuffer.key(at: currIndex.offset)
|
|
unmanagedObjects[i] = bridgedKey
|
|
stored += 1
|
|
nativeBuffer.formIndex(after: &currIndex)
|
|
}
|
|
theState.extra.0 = CUnsignedLong(currIndex.offset)
|
|
state.pointee = theState
|
|
return stored
|
|
}
|
|
}
|
|
#else
|
|
final internal class _SwiftDeferredNS${Self}<${TypeParametersDecl}> { }
|
|
#endif
|
|
|
|
#if _runtime(_ObjC)
|
|
@_versioned
|
|
@_fixed_layout
|
|
internal struct _Cocoa${Self}Buffer : _HashBuffer {
|
|
@_versioned
|
|
internal var cocoa${Self}: _NS${Self}
|
|
|
|
internal typealias Index = _Cocoa${Self}Index
|
|
internal typealias SequenceElement = ${AnySequenceType}
|
|
internal typealias SequenceElementWithoutLabels = ${AnySequenceType}
|
|
|
|
internal typealias Key = AnyObject
|
|
internal typealias Value = AnyObject
|
|
|
|
internal var startIndex: Index {
|
|
return Index(cocoa${Self}, startIndex: ())
|
|
}
|
|
|
|
internal var endIndex: Index {
|
|
return Index(cocoa${Self}, endIndex: ())
|
|
}
|
|
|
|
@_versioned
|
|
internal func index(after i: Index) -> Index {
|
|
return i.successor()
|
|
}
|
|
|
|
internal func formIndex(after i: inout Index) {
|
|
// FIXME: swift-3-indexing-model: optimize if possible.
|
|
i = i.successor()
|
|
}
|
|
|
|
@_versioned
|
|
internal func index(forKey key: Key) -> Index? {
|
|
// Fast path that does not involve creating an array of all keys. In case
|
|
// the key is present, this lookup is a penalty for the slow path, but the
|
|
// potential savings are significant: we could skip a memory allocation and
|
|
// a linear search.
|
|
if maybeGet(key) == nil {
|
|
return nil
|
|
}
|
|
|
|
%if Self == 'Set':
|
|
let allKeys = _stdlib_NSSet_allObjects(cocoaSet)
|
|
%elif Self == 'Dictionary':
|
|
let allKeys = _stdlib_NSDictionary_allKeys(cocoaDictionary)
|
|
%end
|
|
var keyIndex = -1
|
|
for i in 0..<allKeys.value {
|
|
if _stdlib_NSObject_isEqual(key, allKeys[i]) {
|
|
keyIndex = i
|
|
break
|
|
}
|
|
}
|
|
_sanityCheck(keyIndex >= 0,
|
|
"key was found in fast path, but not found later?")
|
|
return Index(cocoa${Self}, allKeys, keyIndex)
|
|
}
|
|
|
|
internal func assertingGet(_ i: Index) -> SequenceElement {
|
|
%if Self == 'Set':
|
|
let value: Value? = i.allKeys[i.currentKeyIndex]
|
|
_sanityCheck(value != nil, "item not found in underlying NS${Self}")
|
|
return value!
|
|
%elif Self == 'Dictionary':
|
|
let key: Key = i.allKeys[i.currentKeyIndex]
|
|
let value: Value = i.cocoaDictionary.objectFor(key)!
|
|
return (key, value)
|
|
%end
|
|
|
|
}
|
|
|
|
internal func assertingGet(_ key: Key) -> Value {
|
|
%if Self == 'Set':
|
|
let value: Value? = cocoa${Self}.member(key)
|
|
_precondition(value != nil, "member not found in underlying NS${Self}")
|
|
return value!
|
|
%elif Self == 'Dictionary':
|
|
let value: Value? = cocoa${Self}.objectFor(key)
|
|
_precondition(value != nil, "key not found in underlying NS${Self}")
|
|
return value!
|
|
%end
|
|
}
|
|
|
|
@inline(__always)
|
|
internal func maybeGet(_ key: Key) -> Value? {
|
|
|
|
%if Self == 'Set':
|
|
return cocoaSet.member(key)
|
|
%elif Self == 'Dictionary':
|
|
return cocoaDictionary.objectFor(key)
|
|
%end
|
|
|
|
}
|
|
|
|
@discardableResult
|
|
internal mutating func updateValue(_ value: Value, forKey key: Key) -> Value? {
|
|
_sanityCheckFailure("cannot mutate NS${Self}")
|
|
}
|
|
|
|
@discardableResult
|
|
internal mutating func insert(
|
|
_ value: Value, forKey key: Key
|
|
) -> (inserted: Bool, memberAfterInsert: Value) {
|
|
_sanityCheckFailure("cannot mutate NS${Self}")
|
|
}
|
|
|
|
@discardableResult
|
|
internal mutating func remove(at index: Index) -> SequenceElement {
|
|
_sanityCheckFailure("cannot mutate NS${Self}")
|
|
}
|
|
|
|
@discardableResult
|
|
internal mutating func removeValue(forKey key: Key) -> Value? {
|
|
_sanityCheckFailure("cannot mutate NS${Self}")
|
|
}
|
|
|
|
internal mutating func removeAll(keepingCapacity keepCapacity: Bool) {
|
|
_sanityCheckFailure("cannot mutate NS${Self}")
|
|
}
|
|
|
|
internal var count: Int {
|
|
return cocoa${Self}.count
|
|
}
|
|
|
|
internal static func fromArray(_ elements: [SequenceElementWithoutLabels])
|
|
-> _Cocoa${Self}Buffer {
|
|
|
|
_sanityCheckFailure("this function should never be called")
|
|
}
|
|
}
|
|
#else
|
|
@_versioned
|
|
@_fixed_layout
|
|
internal struct _Cocoa${Self}Buffer {}
|
|
#endif
|
|
|
|
@_versioned
|
|
@_fixed_layout
|
|
internal enum _Variant${Self}Buffer<${TypeParametersDecl}> : _HashBuffer {
|
|
|
|
internal typealias NativeBuffer = _Native${Self}Buffer<${TypeParameters}>
|
|
internal typealias NativeIndex = _Native${Self}Index<${TypeParameters}>
|
|
internal typealias CocoaBuffer = _Cocoa${Self}Buffer
|
|
internal typealias SequenceElement = ${Sequence}
|
|
internal typealias SequenceElementWithoutLabels = ${Sequence}
|
|
internal typealias SelfType = _Variant${Self}Buffer
|
|
|
|
%if Self == 'Set':
|
|
internal typealias Key = ${TypeParameters}
|
|
internal typealias Value = ${TypeParameters}
|
|
%end
|
|
|
|
case native(NativeBuffer)
|
|
case cocoa(CocoaBuffer)
|
|
|
|
@_versioned
|
|
@_transparent
|
|
internal var guaranteedNative: Bool {
|
|
return _canBeClass(Key.self) == 0 || _canBeClass(Value.self) == 0
|
|
}
|
|
|
|
internal mutating func isUniquelyReferenced() -> Bool {
|
|
// Note that &self drills down through .native(NativeBuffer) to the first
|
|
// property in NativeBuffer, which is the reference to the storage.
|
|
if _fastPath(guaranteedNative) {
|
|
return _isUnique_native(&self)
|
|
}
|
|
|
|
switch self {
|
|
case .native:
|
|
return _isUnique_native(&self)
|
|
case .cocoa:
|
|
// Don't consider Cocoa buffer mutable, even if it is mutable and is
|
|
// uniquely referenced.
|
|
return false
|
|
}
|
|
}
|
|
|
|
@_versioned
|
|
internal var asNative: NativeBuffer {
|
|
get {
|
|
switch self {
|
|
case .native(let buffer):
|
|
return buffer
|
|
case .cocoa:
|
|
_sanityCheckFailure("internal error: not backed by native buffer")
|
|
}
|
|
}
|
|
set {
|
|
self = .native(newValue)
|
|
}
|
|
}
|
|
|
|
#if _runtime(_ObjC)
|
|
internal var asCocoa: CocoaBuffer {
|
|
switch self {
|
|
case .native:
|
|
_sanityCheckFailure("internal error: not backed by NS${Self}")
|
|
case .cocoa(let cocoaBuffer):
|
|
return cocoaBuffer
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/// Ensure this we hold a unique reference to a native buffer
|
|
/// having at least `minimumCapacity` elements.
|
|
internal mutating func ensureUniqueNativeBuffer(_ minimumCapacity: Int)
|
|
-> (reallocated: Bool, capacityChanged: Bool) {
|
|
switch self {
|
|
case .native:
|
|
let oldCapacity = asNative.capacity
|
|
if isUniquelyReferenced() && oldCapacity >= minimumCapacity {
|
|
return (reallocated: false, capacityChanged: false)
|
|
}
|
|
|
|
let oldNativeBuffer = asNative
|
|
var newNativeBuffer = NativeBuffer(minimumCapacity: minimumCapacity)
|
|
let newCapacity = newNativeBuffer.capacity
|
|
for i in 0..<oldCapacity {
|
|
if oldNativeBuffer.isInitializedEntry(at: i) {
|
|
if oldCapacity == newCapacity {
|
|
let key = oldNativeBuffer.key(at: i)
|
|
%if Self == 'Set':
|
|
newNativeBuffer.initializeKey(key, at: i)
|
|
%elif Self == 'Dictionary':
|
|
let value = oldNativeBuffer.value(at: i)
|
|
newNativeBuffer.initializeKey(key, value: value , at: i)
|
|
%end
|
|
} else {
|
|
let key = oldNativeBuffer.key(at: i)
|
|
%if Self == 'Set':
|
|
newNativeBuffer.unsafeAddNew(key: key)
|
|
%elif Self == 'Dictionary':
|
|
newNativeBuffer.unsafeAddNew(
|
|
key: key,
|
|
value: oldNativeBuffer.value(at: i))
|
|
%end
|
|
}
|
|
}
|
|
}
|
|
newNativeBuffer.count = oldNativeBuffer.count
|
|
|
|
self = .native(newNativeBuffer)
|
|
return (reallocated: true,
|
|
capacityChanged: oldCapacity != newNativeBuffer.capacity)
|
|
|
|
case .cocoa(let cocoaBuffer):
|
|
#if _runtime(_ObjC)
|
|
let cocoa${Self} = cocoaBuffer.cocoa${Self}
|
|
var newNativeBuffer = NativeBuffer(minimumCapacity: minimumCapacity)
|
|
let oldCocoaIterator = _Cocoa${Self}Iterator(cocoa${Self})
|
|
%if Self == 'Set':
|
|
while let key = oldCocoaIterator.next() {
|
|
newNativeBuffer.unsafeAddNew(
|
|
key: _forceBridgeFromObjectiveC(key, Value.self))
|
|
}
|
|
|
|
%elif Self == 'Dictionary':
|
|
|
|
while let (key, value) = oldCocoaIterator.next() {
|
|
newNativeBuffer.unsafeAddNew(
|
|
key: _forceBridgeFromObjectiveC(key, Key.self),
|
|
value: _forceBridgeFromObjectiveC(value, Value.self))
|
|
}
|
|
|
|
%end
|
|
newNativeBuffer.count = cocoa${Self}.count
|
|
|
|
self = .native(newNativeBuffer)
|
|
return (reallocated: true, capacityChanged: true)
|
|
#else
|
|
_sanityCheckFailure("internal error: unexpected cocoa ${Self}")
|
|
#endif
|
|
}
|
|
}
|
|
|
|
#if _runtime(_ObjC)
|
|
@inline(never)
|
|
internal mutating func migrateDataToNativeBuffer(
|
|
_ cocoaBuffer: _Cocoa${Self}Buffer
|
|
) {
|
|
let minCapacity = NativeBuffer.minimumCapacity(
|
|
minimumCount: cocoaBuffer.count,
|
|
maxLoadFactorInverse: _hashContainerDefaultMaxLoadFactorInverse)
|
|
let allocated = ensureUniqueNativeBuffer(minCapacity).reallocated
|
|
_sanityCheck(allocated, "failed to allocate native ${Self} buffer")
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// _HashBuffer conformance
|
|
//
|
|
|
|
internal typealias Index = ${Self}Index<${TypeParameters}>
|
|
|
|
internal var startIndex: Index {
|
|
if _fastPath(guaranteedNative) {
|
|
return ._native(asNative.startIndex)
|
|
}
|
|
|
|
switch self {
|
|
case .native:
|
|
return ._native(asNative.startIndex)
|
|
case .cocoa(let cocoaBuffer):
|
|
#if _runtime(_ObjC)
|
|
return ._cocoa(cocoaBuffer.startIndex)
|
|
#else
|
|
_sanityCheckFailure("internal error: unexpected cocoa ${Self}")
|
|
#endif
|
|
}
|
|
}
|
|
|
|
internal var endIndex: Index {
|
|
if _fastPath(guaranteedNative) {
|
|
return ._native(asNative.endIndex)
|
|
}
|
|
|
|
switch self {
|
|
case .native:
|
|
return ._native(asNative.endIndex)
|
|
case .cocoa(let cocoaBuffer):
|
|
#if _runtime(_ObjC)
|
|
return ._cocoa(cocoaBuffer.endIndex)
|
|
#else
|
|
_sanityCheckFailure("internal error: unexpected cocoa ${Self}")
|
|
#endif
|
|
}
|
|
}
|
|
|
|
@_versioned
|
|
func index(after i: Index) -> Index {
|
|
if _fastPath(guaranteedNative) {
|
|
return ._native(asNative.index(after: i._nativeIndex))
|
|
}
|
|
|
|
switch self {
|
|
case .native:
|
|
return ._native(asNative.index(after: i._nativeIndex))
|
|
case .cocoa(let cocoaBuffer):
|
|
#if _runtime(_ObjC)
|
|
return ._cocoa(cocoaBuffer.index(after: i._cocoaIndex))
|
|
#else
|
|
_sanityCheckFailure("internal error: unexpected cocoa ${Self}")
|
|
#endif
|
|
}
|
|
}
|
|
|
|
internal func formIndex(after i: inout Index) {
|
|
// FIXME: swift-3-indexing-model: optimize if possible.
|
|
i = index(after: i)
|
|
}
|
|
|
|
@_versioned
|
|
@inline(__always)
|
|
internal func index(forKey key: Key) -> Index? {
|
|
if _fastPath(guaranteedNative) {
|
|
if let nativeIndex = asNative.index(forKey: key) {
|
|
return ._native(nativeIndex)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
switch self {
|
|
case .native:
|
|
if let nativeIndex = asNative.index(forKey: key) {
|
|
return ._native(nativeIndex)
|
|
}
|
|
return nil
|
|
case .cocoa(let cocoaBuffer):
|
|
#if _runtime(_ObjC)
|
|
let anyObjectKey: AnyObject = _bridgeAnythingToObjectiveC(key)
|
|
if let cocoaIndex = cocoaBuffer.index(forKey: anyObjectKey) {
|
|
return ._cocoa(cocoaIndex)
|
|
}
|
|
return nil
|
|
#else
|
|
_sanityCheckFailure("internal error: unexpected cocoa ${Self}")
|
|
#endif
|
|
}
|
|
}
|
|
|
|
internal func assertingGet(_ i: Index) -> SequenceElement {
|
|
if _fastPath(guaranteedNative) {
|
|
return asNative.assertingGet(i._nativeIndex)
|
|
}
|
|
|
|
switch self {
|
|
case .native:
|
|
return asNative.assertingGet(i._nativeIndex)
|
|
case .cocoa(let cocoaBuffer):
|
|
#if _runtime(_ObjC)
|
|
%if Self == 'Set':
|
|
let anyObjectValue: AnyObject = cocoaBuffer.assertingGet(i._cocoaIndex)
|
|
let nativeValue = _forceBridgeFromObjectiveC(anyObjectValue, Value.self)
|
|
return nativeValue
|
|
%elif Self == 'Dictionary':
|
|
let (anyObjectKey, anyObjectValue) =
|
|
cocoaBuffer.assertingGet(i._cocoaIndex)
|
|
let nativeKey = _forceBridgeFromObjectiveC(anyObjectKey, Key.self)
|
|
let nativeValue = _forceBridgeFromObjectiveC(anyObjectValue, Value.self)
|
|
return (nativeKey, nativeValue)
|
|
%end
|
|
#else
|
|
_sanityCheckFailure("internal error: unexpected cocoa ${Self}")
|
|
#endif
|
|
}
|
|
}
|
|
|
|
internal func assertingGet(_ key: Key) -> Value {
|
|
if _fastPath(guaranteedNative) {
|
|
return asNative.assertingGet(key)
|
|
}
|
|
|
|
switch self {
|
|
case .native:
|
|
return asNative.assertingGet(key)
|
|
case .cocoa(let cocoaBuffer):
|
|
#if _runtime(_ObjC)
|
|
// FIXME: This assumes that Key and Value are bridged verbatim.
|
|
let anyObjectKey: AnyObject = _bridgeAnythingToObjectiveC(key)
|
|
let anyObjectValue: AnyObject = cocoaBuffer.assertingGet(anyObjectKey)
|
|
return _forceBridgeFromObjectiveC(anyObjectValue, Value.self)
|
|
#else
|
|
_sanityCheckFailure("internal error: unexpected cocoa ${Self}")
|
|
#endif
|
|
}
|
|
}
|
|
|
|
#if _runtime(_ObjC)
|
|
@_versioned
|
|
@inline(never)
|
|
internal static func maybeGetFromCocoaBuffer(
|
|
_ cocoaBuffer : CocoaBuffer, forKey key: Key
|
|
) -> Value? {
|
|
let anyObjectKey: AnyObject = _bridgeAnythingToObjectiveC(key)
|
|
if let anyObjectValue = cocoaBuffer.maybeGet(anyObjectKey) {
|
|
return _forceBridgeFromObjectiveC(anyObjectValue, Value.self)
|
|
}
|
|
return nil
|
|
}
|
|
#endif
|
|
|
|
@_versioned
|
|
@inline(__always)
|
|
internal func maybeGet(_ key: Key) -> Value? {
|
|
if _fastPath(guaranteedNative) {
|
|
return asNative.maybeGet(key)
|
|
}
|
|
|
|
switch self {
|
|
case .native:
|
|
return asNative.maybeGet(key)
|
|
case .cocoa(let cocoaBuffer):
|
|
#if _runtime(_ObjC)
|
|
return SelfType.maybeGetFromCocoaBuffer(cocoaBuffer, forKey: key)
|
|
#else
|
|
_sanityCheckFailure("internal error: unexpected cocoa ${Self}")
|
|
#endif
|
|
}
|
|
}
|
|
|
|
internal mutating func nativeUpdateValue(
|
|
_ value: Value, forKey key: Key
|
|
) -> Value? {
|
|
var (i, found) = asNative._find(key, startBucket: asNative._bucket(key))
|
|
|
|
let minCapacity = found
|
|
? asNative.capacity
|
|
: NativeBuffer.minimumCapacity(
|
|
minimumCount: asNative.count + 1,
|
|
maxLoadFactorInverse: _hashContainerDefaultMaxLoadFactorInverse)
|
|
|
|
let (_, capacityChanged) = ensureUniqueNativeBuffer(minCapacity)
|
|
if capacityChanged {
|
|
i = asNative._find(key, startBucket: asNative._bucket(key)).pos
|
|
}
|
|
|
|
%if Self == 'Set':
|
|
let oldValue: Value? = found ? asNative.key(at: i.offset) : nil
|
|
if found {
|
|
asNative.setKey(key, at: i.offset)
|
|
} else {
|
|
asNative.initializeKey(key, at: i.offset)
|
|
asNative.count += 1
|
|
}
|
|
%elif Self == 'Dictionary':
|
|
let oldValue: Value? = found ? asNative.value(at: i.offset) : nil
|
|
if found {
|
|
asNative.setKey(key, value: value, at: i.offset)
|
|
} else {
|
|
asNative.initializeKey(key, value: value, at: i.offset)
|
|
asNative.count += 1
|
|
}
|
|
%end
|
|
|
|
return oldValue
|
|
}
|
|
|
|
@discardableResult
|
|
internal mutating func updateValue(
|
|
_ value: Value, forKey key: Key
|
|
) -> Value? {
|
|
|
|
if _fastPath(guaranteedNative) {
|
|
return nativeUpdateValue(value, forKey: key)
|
|
}
|
|
|
|
switch self {
|
|
case .native:
|
|
return nativeUpdateValue(value, forKey: key)
|
|
case .cocoa(let cocoaBuffer):
|
|
#if _runtime(_ObjC)
|
|
migrateDataToNativeBuffer(cocoaBuffer)
|
|
return nativeUpdateValue(value, forKey: key)
|
|
#else
|
|
_sanityCheckFailure("internal error: unexpected cocoa ${Self}")
|
|
#endif
|
|
}
|
|
}
|
|
|
|
internal mutating func nativeInsert(
|
|
_ value: Value, forKey key: Key
|
|
) -> (inserted: Bool, memberAfterInsert: Value) {
|
|
|
|
var (i, found) = asNative._find(key, startBucket: asNative._bucket(key))
|
|
if found {
|
|
%if Self == 'Set':
|
|
return (inserted: false, memberAfterInsert: asNative.key(at: i.offset))
|
|
%elif Self == 'Dictionary':
|
|
return (inserted: false, memberAfterInsert: asNative.value(at: i.offset))
|
|
%end
|
|
}
|
|
|
|
let minCapacity = NativeBuffer.minimumCapacity(
|
|
minimumCount: asNative.count + 1,
|
|
maxLoadFactorInverse: _hashContainerDefaultMaxLoadFactorInverse)
|
|
|
|
let (_, capacityChanged) = ensureUniqueNativeBuffer(minCapacity)
|
|
|
|
if capacityChanged {
|
|
i = asNative._find(key, startBucket: asNative._bucket(key)).pos
|
|
}
|
|
|
|
%if Self == 'Set':
|
|
asNative.initializeKey(key, at: i.offset)
|
|
asNative.count += 1
|
|
%elif Self == 'Dictionary':
|
|
asNative.initializeKey(key, value: value, at: i.offset)
|
|
asNative.count += 1
|
|
%end
|
|
|
|
return (inserted: true, memberAfterInsert: value)
|
|
}
|
|
|
|
@discardableResult
|
|
internal mutating func insert(
|
|
_ value: Value, forKey key: Key
|
|
) -> (inserted: Bool, memberAfterInsert: Value) {
|
|
|
|
if _fastPath(guaranteedNative) {
|
|
return nativeInsert(value, forKey: key)
|
|
}
|
|
|
|
switch self {
|
|
case .native:
|
|
return nativeInsert(value, forKey: key)
|
|
case .cocoa(let cocoaBuffer):
|
|
#if _runtime(_ObjC)
|
|
migrateDataToNativeBuffer(cocoaBuffer)
|
|
return nativeInsert(value, forKey: key)
|
|
#else
|
|
_sanityCheckFailure("internal error: unexpected cocoa ${Self}")
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/// - parameter idealBucket: The ideal bucket for the element being deleted.
|
|
/// - parameter offset: The offset of the element that will be deleted.
|
|
/// Precondition: there should be an initialized entry at offset.
|
|
internal mutating func nativeDelete(
|
|
_ nativeBuffer: NativeBuffer, idealBucket: Int, offset: Int
|
|
) {
|
|
_sanityCheck(
|
|
nativeBuffer.isInitializedEntry(at: offset), "expected initialized entry")
|
|
|
|
var nativeBuffer = nativeBuffer
|
|
|
|
// remove the element
|
|
nativeBuffer.destroyEntry(at: offset)
|
|
nativeBuffer.count -= 1
|
|
|
|
// If we've put a hole in a chain of contiguous elements, some
|
|
// element after the hole may belong where the new hole is.
|
|
var hole = offset
|
|
|
|
// Find the first bucket in the contiguous chain
|
|
var start = idealBucket
|
|
while nativeBuffer.isInitializedEntry(at: nativeBuffer._prev(start)) {
|
|
start = nativeBuffer._prev(start)
|
|
}
|
|
|
|
// Find the last bucket in the contiguous chain
|
|
var lastInChain = hole
|
|
var b = nativeBuffer._index(after: lastInChain)
|
|
while nativeBuffer.isInitializedEntry(at: b) {
|
|
lastInChain = b
|
|
b = nativeBuffer._index(after: b)
|
|
}
|
|
|
|
// Relocate out-of-place elements in the chain, repeating until
|
|
// none are found.
|
|
while hole != lastInChain {
|
|
// Walk backwards from the end of the chain looking for
|
|
// something out-of-place.
|
|
var b = lastInChain
|
|
while b != hole {
|
|
let idealBucket = nativeBuffer._bucket(nativeBuffer.key(at: b))
|
|
|
|
// Does this element belong between start and hole? We need
|
|
// two separate tests depending on whether [start, hole] wraps
|
|
// around the end of the storage
|
|
let c0 = idealBucket >= start
|
|
let c1 = idealBucket <= hole
|
|
if start <= hole ? (c0 && c1) : (c0 || c1) {
|
|
break // Found it
|
|
}
|
|
b = nativeBuffer._prev(b)
|
|
}
|
|
|
|
if b == hole { // No out-of-place elements found; we're done adjusting
|
|
break
|
|
}
|
|
|
|
// Move the found element into the hole
|
|
nativeBuffer.moveInitializeEntry(
|
|
from: nativeBuffer,
|
|
at: b,
|
|
toEntryAt: hole)
|
|
hole = b
|
|
}
|
|
}
|
|
|
|
internal mutating func nativeRemoveObject(forKey key: Key) -> Value? {
|
|
var idealBucket = asNative._bucket(key)
|
|
var (index, found) = asNative._find(key, startBucket: idealBucket)
|
|
|
|
// Fast path: if the key is not present, we will not mutate the set,
|
|
// so don't force unique buffer.
|
|
if !found {
|
|
return nil
|
|
}
|
|
|
|
let (_, capacityChanged) =
|
|
ensureUniqueNativeBuffer(asNative.capacity)
|
|
let nativeBuffer = asNative
|
|
if capacityChanged {
|
|
idealBucket = nativeBuffer._bucket(key)
|
|
(index, found) = nativeBuffer._find(key, startBucket: idealBucket)
|
|
_sanityCheck(found, "key was lost during buffer migration")
|
|
}
|
|
%if Self == 'Set':
|
|
let oldValue = nativeBuffer.key(at: index.offset)
|
|
%elif Self == 'Dictionary':
|
|
let oldValue = nativeBuffer.value(at: index.offset)
|
|
%end
|
|
nativeDelete(nativeBuffer, idealBucket: idealBucket,
|
|
offset: index.offset)
|
|
return oldValue
|
|
}
|
|
|
|
internal mutating func nativeRemove(
|
|
at nativeIndex: NativeIndex
|
|
) -> SequenceElement {
|
|
|
|
// The provided index should be valid, so we will always mutating the
|
|
// set buffer. Request unique buffer.
|
|
_ = ensureUniqueNativeBuffer(asNative.capacity)
|
|
let nativeBuffer = asNative
|
|
|
|
let result = nativeBuffer.assertingGet(nativeIndex)
|
|
%if Self == 'Set':
|
|
let key = result
|
|
%elif Self == 'Dictionary':
|
|
let key = result.0
|
|
%end
|
|
|
|
nativeDelete(nativeBuffer, idealBucket: nativeBuffer._bucket(key),
|
|
offset: nativeIndex.offset)
|
|
return result
|
|
}
|
|
|
|
@discardableResult
|
|
internal mutating func remove(at index: Index) -> SequenceElement {
|
|
if _fastPath(guaranteedNative) {
|
|
return nativeRemove(at: index._nativeIndex)
|
|
}
|
|
|
|
switch self {
|
|
case .native:
|
|
return nativeRemove(at: index._nativeIndex)
|
|
case .cocoa(let cocoaBuffer):
|
|
#if _runtime(_ObjC)
|
|
// We have to migrate the data first. But after we do so, the Cocoa
|
|
// index becomes useless, so get the key first.
|
|
//
|
|
// FIXME(performance): fuse data migration and element deletion into one
|
|
// operation.
|
|
let index = index._cocoaIndex
|
|
let anyObjectKey: AnyObject = index.allKeys[index.currentKeyIndex]
|
|
migrateDataToNativeBuffer(cocoaBuffer)
|
|
let key = _forceBridgeFromObjectiveC(anyObjectKey, Key.self)
|
|
let value = nativeRemoveObject(forKey: key)
|
|
|
|
%if Self == 'Set':
|
|
_sanityCheck(key == value, "bridging did not preserve equality")
|
|
return key
|
|
%elif Self == 'Dictionary':
|
|
return (key, value._unsafelyUnwrappedUnchecked)
|
|
%end
|
|
#else
|
|
_sanityCheckFailure("internal error: unexpected cocoa ${Self}")
|
|
#endif
|
|
}
|
|
}
|
|
|
|
@discardableResult
|
|
internal mutating func removeValue(forKey key: Key) -> Value? {
|
|
if _fastPath(guaranteedNative) {
|
|
return nativeRemoveObject(forKey: key)
|
|
}
|
|
|
|
switch self {
|
|
case .native:
|
|
return nativeRemoveObject(forKey: key)
|
|
case .cocoa(let cocoaBuffer):
|
|
#if _runtime(_ObjC)
|
|
let anyObjectKey: AnyObject = _bridgeAnythingToObjectiveC(key)
|
|
if cocoaBuffer.maybeGet(anyObjectKey) == nil {
|
|
return nil
|
|
}
|
|
migrateDataToNativeBuffer(cocoaBuffer)
|
|
return nativeRemoveObject(forKey: key)
|
|
#else
|
|
_sanityCheckFailure("internal error: unexpected cocoa ${Self}")
|
|
#endif
|
|
}
|
|
}
|
|
|
|
internal mutating func nativeRemoveAll() {
|
|
if !isUniquelyReferenced() {
|
|
asNative = NativeBuffer(minimumCapacity: asNative.capacity)
|
|
return
|
|
}
|
|
|
|
// We have already checked for the empty dictionary case and unique
|
|
// reference, so we will always mutate the dictionary buffer.
|
|
var nativeBuffer = asNative
|
|
|
|
for b in 0..<nativeBuffer.capacity {
|
|
if nativeBuffer.isInitializedEntry(at: b) {
|
|
nativeBuffer.destroyEntry(at: b)
|
|
}
|
|
}
|
|
nativeBuffer.count = 0
|
|
}
|
|
|
|
internal mutating func removeAll(keepingCapacity keepCapacity: Bool) {
|
|
if count == 0 {
|
|
return
|
|
}
|
|
|
|
if !keepCapacity {
|
|
self = .native(NativeBuffer(minimumCapacity: 2))
|
|
return
|
|
}
|
|
|
|
if _fastPath(guaranteedNative) {
|
|
nativeRemoveAll()
|
|
return
|
|
}
|
|
|
|
switch self {
|
|
case .native:
|
|
nativeRemoveAll()
|
|
case .cocoa(let cocoaBuffer):
|
|
#if _runtime(_ObjC)
|
|
self = .native(NativeBuffer(minimumCapacity: cocoaBuffer.count))
|
|
#else
|
|
_sanityCheckFailure("internal error: unexpected cocoa ${Self}")
|
|
#endif
|
|
}
|
|
}
|
|
|
|
internal var count: Int {
|
|
if _fastPath(guaranteedNative) {
|
|
return asNative.count
|
|
}
|
|
|
|
switch self {
|
|
case .native:
|
|
return asNative.count
|
|
case .cocoa(let cocoaBuffer):
|
|
#if _runtime(_ObjC)
|
|
return cocoaBuffer.count
|
|
#else
|
|
_sanityCheckFailure("internal error: unexpected cocoa ${Self}")
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/// Returns an iterator over the `(Key, Value)` pairs.
|
|
///
|
|
/// - Complexity: O(1).
|
|
@_versioned
|
|
@inline(__always)
|
|
internal func makeIterator() -> ${Self}Iterator<${TypeParameters}> {
|
|
switch self {
|
|
case .native(let buffer):
|
|
return ._native(
|
|
start: asNative.startIndex, end: asNative.endIndex, buffer: buffer)
|
|
case .cocoa(let cocoaBuffer):
|
|
#if _runtime(_ObjC)
|
|
return ._cocoa(_Cocoa${Self}Iterator(cocoaBuffer.cocoa${Self}))
|
|
#else
|
|
_sanityCheckFailure("internal error: unexpected cocoa ${Self}")
|
|
#endif
|
|
}
|
|
}
|
|
|
|
internal static func fromArray(_ elements: [SequenceElement])
|
|
-> _Variant${Self}Buffer<${TypeParameters}> {
|
|
|
|
_sanityCheckFailure("this function should never be called")
|
|
}
|
|
}
|
|
|
|
%{
|
|
compareOperators = ["<", "<=", ">", ">=", "=="]
|
|
}%
|
|
|
|
@_versioned
|
|
internal struct _Native${Self}Index<${TypeParameters}> : Comparable {
|
|
@_versioned
|
|
internal var offset: Int
|
|
|
|
@_versioned
|
|
internal init(offset: Int) {
|
|
self.offset = offset
|
|
}
|
|
}
|
|
|
|
extension _Native${Self}Index {
|
|
|
|
% for op in compareOperators:
|
|
internal static func ${op} (
|
|
lhs: _Native${Self}Index<${TypeParameters}>,
|
|
rhs: _Native${Self}Index<${TypeParameters}>
|
|
) -> Bool {
|
|
return lhs.offset ${op} rhs.offset
|
|
}
|
|
% end
|
|
|
|
}
|
|
|
|
|
|
#if _runtime(_ObjC)
|
|
@_versioned
|
|
internal struct _Cocoa${Self}Index : Comparable {
|
|
// Assumption: we rely on NSDictionary.getObjects when being
|
|
// repeatedly called on the same NSDictionary, returning items in the same
|
|
// order every time.
|
|
// Similarly, the same assumption holds for NSSet.allObjects.
|
|
|
|
/// A reference to the NS${Self}, which owns members in `allObjects`,
|
|
/// or `allKeys`, for NSSet and NSDictionary respectively.
|
|
internal let cocoa${Self}: _NS${Self}
|
|
// 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.
|
|
internal var allKeys: _HeapBuffer<Int, AnyObject>
|
|
|
|
/// Index into `allKeys`
|
|
internal var currentKeyIndex: Int
|
|
|
|
internal init(_ cocoa${Self}: _NS${Self}, startIndex: ()) {
|
|
self.cocoa${Self} = cocoa${Self}
|
|
%if Self == 'Set':
|
|
self.allKeys = _stdlib_NSSet_allObjects(cocoaSet)
|
|
%elif Self == 'Dictionary':
|
|
self.allKeys = _stdlib_NSDictionary_allKeys(cocoaDictionary)
|
|
%end
|
|
self.currentKeyIndex = 0
|
|
}
|
|
|
|
internal init(_ cocoa${Self}: _NS${Self}, endIndex: ()) {
|
|
self.cocoa${Self} = cocoa${Self}
|
|
%if Self == 'Set':
|
|
self.allKeys = _stdlib_NS${Self}_allObjects(cocoa${Self})
|
|
%elif Self == 'Dictionary':
|
|
self.allKeys = _stdlib_NS${Self}_allKeys(cocoa${Self})
|
|
%end
|
|
self.currentKeyIndex = allKeys.value
|
|
}
|
|
|
|
internal init(_ cocoa${Self}: _NS${Self},
|
|
_ allKeys: _HeapBuffer<Int, AnyObject>,
|
|
_ currentKeyIndex: Int
|
|
) {
|
|
self.cocoa${Self} = cocoa${Self}
|
|
self.allKeys = allKeys
|
|
self.currentKeyIndex = currentKeyIndex
|
|
}
|
|
|
|
/// Returns the next consecutive value after `self`.
|
|
///
|
|
/// - Precondition: The next value is representable.
|
|
internal func successor() -> _Cocoa${Self}Index {
|
|
// FIXME: swift-3-indexing-model: remove this method.
|
|
_precondition(
|
|
currentKeyIndex < allKeys.value, "cannot increment endIndex")
|
|
return _Cocoa${Self}Index(cocoa${Self}, allKeys, currentKeyIndex + 1)
|
|
}
|
|
}
|
|
|
|
extension _Cocoa${Self}Index {
|
|
|
|
% for op in compareOperators:
|
|
internal static func ${op} (
|
|
lhs: _Cocoa${Self}Index,
|
|
rhs: _Cocoa${Self}Index
|
|
) -> Bool {
|
|
return lhs.currentKeyIndex ${op} rhs.currentKeyIndex
|
|
}
|
|
% end
|
|
|
|
}
|
|
#else
|
|
internal struct _Cocoa${Self}Index {}
|
|
#endif
|
|
|
|
internal enum ${Self}IndexRepresentation<${TypeParametersDecl}> {
|
|
typealias _Index = ${Self}Index<${TypeParameters}>
|
|
typealias _NativeIndex = _Index._NativeIndex
|
|
typealias _CocoaIndex = _Index._CocoaIndex
|
|
|
|
case _native(_NativeIndex)
|
|
case _cocoa(_CocoaIndex)
|
|
}
|
|
|
|
extension ${Self} {
|
|
%{
|
|
if Self == 'Set':
|
|
SubscriptingWithIndexDoc = """\
|
|
/// Used to access the members in an instance of `Set<Element>`."""
|
|
elif Self == 'Dictionary':
|
|
SubscriptingWithIndexDoc = """\
|
|
/// Used to access the key-value pairs in an instance of
|
|
/// `Dictionary<Key, Value>`.
|
|
///
|
|
/// Dictionary has two subscripting interfaces:
|
|
///
|
|
/// 1. Subscripting with a key, yielding an optional value:
|
|
///
|
|
/// v = d[k]!
|
|
///
|
|
/// 2. Subscripting with an index, yielding a key-value pair:
|
|
///
|
|
/// (k, v) = d[i]"""
|
|
}%
|
|
|
|
${SubscriptingWithIndexDoc}
|
|
public struct Index : Comparable {
|
|
// Index for native buffer is efficient. Index for bridged NS${Self} 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 NS${Self} in terms of Cocoa enumeration facilities.
|
|
|
|
internal typealias _NativeIndex = _Native${Self}Index<${TypeParameters}>
|
|
internal typealias _CocoaIndex = _Cocoa${Self}Index
|
|
|
|
%if Self == 'Set':
|
|
internal typealias Key = ${TypeParameters}
|
|
internal typealias Value = ${TypeParameters}
|
|
%end
|
|
|
|
internal var _value: ${Self}IndexRepresentation<${TypeParameters}>
|
|
|
|
@_versioned
|
|
internal static func _native(_ index: _NativeIndex) -> Index {
|
|
return ${Self}Index(_value: ._native(index))
|
|
}
|
|
#if _runtime(_ObjC)
|
|
@_versioned
|
|
internal static func _cocoa(_ index: _CocoaIndex) -> Index {
|
|
return ${Self}Index(_value: ._cocoa(index))
|
|
}
|
|
#endif
|
|
|
|
@_versioned
|
|
@_transparent
|
|
internal var _guaranteedNative: Bool {
|
|
return _canBeClass(Key.self) == 0 && _canBeClass(Value.self) == 0
|
|
}
|
|
|
|
@_transparent
|
|
internal var _nativeIndex: _NativeIndex {
|
|
switch _value {
|
|
case ._native(let nativeIndex):
|
|
return nativeIndex
|
|
case ._cocoa:
|
|
_sanityCheckFailure("internal error: does not contain a native index")
|
|
}
|
|
}
|
|
|
|
#if _runtime(_ObjC)
|
|
@_transparent
|
|
internal var _cocoaIndex: _CocoaIndex {
|
|
switch _value {
|
|
case ._native:
|
|
_sanityCheckFailure("internal error: does not contain a Cocoa index")
|
|
case ._cocoa(let cocoaIndex):
|
|
return cocoaIndex
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
}
|
|
|
|
public typealias ${Self}Index<${TypeParametersDecl}> =
|
|
${Self}<${TypeParameters}>.Index
|
|
|
|
extension ${Self}.Index {
|
|
public static func == (
|
|
lhs: ${Self}<${TypeParameters}>.Index,
|
|
rhs: ${Self}<${TypeParameters}>.Index
|
|
) -> Bool {
|
|
if _fastPath(lhs._guaranteedNative) {
|
|
return lhs._nativeIndex == rhs._nativeIndex
|
|
}
|
|
|
|
switch (lhs._value, rhs._value) {
|
|
case (._native(let lhsNative), ._native(let rhsNative)):
|
|
return lhsNative == rhsNative
|
|
case (._cocoa(let lhsCocoa), ._cocoa(let rhsCocoa)):
|
|
#if _runtime(_ObjC)
|
|
return lhsCocoa == rhsCocoa
|
|
#else
|
|
_sanityCheckFailure("internal error: unexpected cocoa ${Self}")
|
|
#endif
|
|
default:
|
|
_preconditionFailure("comparing indexes from different sets")
|
|
}
|
|
}
|
|
|
|
public static func < (
|
|
lhs: ${Self}<${TypeParameters}>.Index,
|
|
rhs: ${Self}<${TypeParameters}>.Index
|
|
) -> Bool {
|
|
if _fastPath(lhs._guaranteedNative) {
|
|
return lhs._nativeIndex < rhs._nativeIndex
|
|
}
|
|
|
|
switch (lhs._value, rhs._value) {
|
|
case (._native(let lhsNative), ._native(let rhsNative)):
|
|
return lhsNative < rhsNative
|
|
case (._cocoa(let lhsCocoa), ._cocoa(let rhsCocoa)):
|
|
#if _runtime(_ObjC)
|
|
return lhsCocoa < rhsCocoa
|
|
#else
|
|
_sanityCheckFailure("internal error: unexpected cocoa ${Self}")
|
|
#endif
|
|
default:
|
|
_preconditionFailure("comparing indexes from different sets")
|
|
}
|
|
}
|
|
}
|
|
|
|
#if _runtime(_ObjC)
|
|
@_versioned
|
|
final internal class _Cocoa${Self}Iterator : IteratorProtocol {
|
|
internal typealias Element = ${AnySequenceType}
|
|
|
|
// Cocoa ${Self} 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 cocoa${Self}: _NS${Self}
|
|
|
|
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
|
|
|
|
@_versioned
|
|
internal init(_ cocoa${Self}: _NS${Self}) {
|
|
self.cocoa${Self} = cocoa${Self}
|
|
}
|
|
|
|
@_versioned
|
|
internal func next() -> Element? {
|
|
if itemIndex < 0 {
|
|
return nil
|
|
}
|
|
let cocoa${Self} = self.cocoa${Self}
|
|
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 = cocoa${Self}.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
|
|
%if Self == 'Set':
|
|
return key
|
|
%elif Self == 'Dictionary':
|
|
let value: AnyObject = cocoa${Self}.objectFor(key)!
|
|
return (key, value)
|
|
%end
|
|
}
|
|
}
|
|
#else
|
|
final internal class _Cocoa${Self}Iterator {}
|
|
#endif
|
|
|
|
@_versioned
|
|
internal enum ${Self}IteratorRepresentation<${TypeParametersDecl}> {
|
|
internal typealias _Iterator = ${Self}Iterator<${TypeParameters}>
|
|
internal typealias _NativeBuffer =
|
|
_Native${Self}Buffer<${TypeParameters}>
|
|
internal typealias _NativeIndex = _Iterator._NativeIndex
|
|
|
|
// For native buffer, we keep two indices to keep track of the iteration
|
|
// progress and the buffer owner to make the buffer non-uniquely
|
|
// referenced.
|
|
//
|
|
// Iterator is iterating over a frozen view of the collection
|
|
// state, so it should keep its own reference to the buffer.
|
|
case _native(
|
|
start: _NativeIndex, end: _NativeIndex, buffer: _NativeBuffer)
|
|
case _cocoa(_Cocoa${Self}Iterator)
|
|
}
|
|
|
|
/// An iterator over the members of a `${Self}<${TypeParameters}>`.
|
|
public struct ${Self}Iterator<${TypeParametersDecl}> : IteratorProtocol {
|
|
// ${Self} has a separate IteratorProtocol and Index because of efficiency
|
|
// and implementability reasons.
|
|
//
|
|
// Index for native buffer is efficient. Index for bridged NS${Self} is
|
|
// not.
|
|
//
|
|
// Even though fast enumeration is not suitable for implementing
|
|
// Index, which is multi-pass, it is suitable for implementing a
|
|
// IteratorProtocol, which is being consumed as iteration proceeds.
|
|
|
|
internal typealias _NativeBuffer =
|
|
_Native${Self}Buffer<${TypeParameters}>
|
|
internal typealias _NativeIndex = _Native${Self}Index<${TypeParameters}>
|
|
|
|
@_versioned
|
|
internal var _state: ${Self}IteratorRepresentation<${TypeParameters}>
|
|
|
|
@_versioned
|
|
internal static func _native(
|
|
start: _NativeIndex, end: _NativeIndex, buffer: _NativeBuffer
|
|
) -> ${Self}Iterator {
|
|
return ${Self}Iterator(
|
|
_state: ._native(start: start, end: end, buffer: buffer))
|
|
}
|
|
#if _runtime(_ObjC)
|
|
@_versioned
|
|
internal static func _cocoa(
|
|
_ iterator: _Cocoa${Self}Iterator
|
|
) -> ${Self}Iterator{
|
|
return ${Self}Iterator(_state: ._cocoa(iterator))
|
|
}
|
|
#endif
|
|
|
|
@_versioned
|
|
@_transparent
|
|
internal var _guaranteedNative: Bool {
|
|
%if Self == 'Set':
|
|
return _canBeClass(Element.self) == 0
|
|
%elif Self == 'Dictionary':
|
|
return _canBeClass(Key.self) == 0 || _canBeClass(Value.self) == 0
|
|
%end
|
|
}
|
|
|
|
@_versioned
|
|
internal mutating func _nativeNext() -> ${Sequence}? {
|
|
switch _state {
|
|
case ._native(let startIndex, let endIndex, let buffer):
|
|
if startIndex == endIndex {
|
|
return nil
|
|
}
|
|
let result = buffer.assertingGet(startIndex)
|
|
_state =
|
|
._native(start: buffer.index(after: startIndex), end: endIndex, buffer: buffer)
|
|
return result
|
|
case ._cocoa:
|
|
_sanityCheckFailure("internal error: not backed by NS${Self}")
|
|
}
|
|
}
|
|
|
|
/// 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`.
|
|
@inline(__always)
|
|
public mutating func next() -> ${Sequence}? {
|
|
if _fastPath(_guaranteedNative) {
|
|
return _nativeNext()
|
|
}
|
|
|
|
switch _state {
|
|
case ._native:
|
|
return _nativeNext()
|
|
case ._cocoa(let cocoaIterator):
|
|
#if _runtime(_ObjC)
|
|
%if Self == 'Set':
|
|
if let anyObjectElement = cocoaIterator.next() {
|
|
return _forceBridgeFromObjectiveC(anyObjectElement, Element.self)
|
|
}
|
|
%elif Self == 'Dictionary':
|
|
if let (anyObjectKey, anyObjectValue) = cocoaIterator.next() {
|
|
let nativeKey = _forceBridgeFromObjectiveC(anyObjectKey, Key.self)
|
|
let nativeValue = _forceBridgeFromObjectiveC(anyObjectValue, Value.self)
|
|
return (nativeKey, nativeValue)
|
|
}
|
|
%end
|
|
return nil
|
|
#else
|
|
_sanityCheckFailure("internal error: unexpected cocoa ${Self}")
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
extension ${Self}Iterator : CustomReflectable {
|
|
/// A mirror that reflects the iterator.
|
|
public var customMirror: Mirror {
|
|
return Mirror(
|
|
self,
|
|
children: EmptyCollection<(label: String?, value: Any)>())
|
|
}
|
|
}
|
|
|
|
extension ${Self} : CustomReflectable {
|
|
/// A mirror that reflects the ${a_self}.
|
|
public var customMirror: Mirror {
|
|
%if Self == 'Set':
|
|
let style = Mirror.DisplayStyle.`set`
|
|
%elif Self == 'Dictionary':
|
|
let style = Mirror.DisplayStyle.dictionary
|
|
%end
|
|
return Mirror(self, unlabeledChildren: self, displayStyle: style)
|
|
}
|
|
}
|
|
|
|
/// Initializes a `${Self}` from unique members.
|
|
///
|
|
/// Using a builder can be faster than inserting members into an empty
|
|
/// `${Self}`.
|
|
public struct _${Self}Builder<${TypeParametersDecl}> {
|
|
%if Self == 'Set':
|
|
public typealias Key = ${TypeParameters}
|
|
public typealias Value = ${TypeParameters}
|
|
%end
|
|
|
|
internal var _result: ${Self}<${TypeParameters}>
|
|
internal var _nativeBuffer: _Native${Self}Buffer<${TypeParameters}>
|
|
internal let _requestedCount: Int
|
|
internal var _actualCount: Int
|
|
|
|
public init(count: Int) {
|
|
let requiredCapacity =
|
|
_Native${Self}Buffer<${TypeParameters}>.minimumCapacity(
|
|
minimumCount: count,
|
|
maxLoadFactorInverse: _hashContainerDefaultMaxLoadFactorInverse)
|
|
_result = ${Self}<${TypeParameters}>(minimumCapacity: requiredCapacity)
|
|
_nativeBuffer = _result._variantBuffer.asNative
|
|
_requestedCount = count
|
|
_actualCount = 0
|
|
}
|
|
|
|
%if Self == 'Set':
|
|
public mutating func add(member newKey: Key) {
|
|
_nativeBuffer.unsafeAddNew(key: newKey)
|
|
_actualCount += 1
|
|
}
|
|
%elif Self == 'Dictionary':
|
|
public mutating func add(key newKey: Key, value: Value) {
|
|
_nativeBuffer.unsafeAddNew(key: newKey, value: value)
|
|
_actualCount += 1
|
|
}
|
|
%end
|
|
|
|
public mutating func take() -> ${Self}<${TypeParameters}> {
|
|
_precondition(_actualCount >= 0,
|
|
"cannot take the result twice")
|
|
_precondition(_actualCount == _requestedCount,
|
|
"the number of members added does not match the promised count")
|
|
|
|
// Finish building the `${Self}`.
|
|
_nativeBuffer.count = _requestedCount
|
|
|
|
// Prevent taking the result twice.
|
|
_actualCount = -1
|
|
return _result
|
|
}
|
|
}
|
|
|
|
extension ${Self} {
|
|
%if Self == '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`.
|
|
%elif Self == 'Dictionary':
|
|
/// Removes and returns the first key-value pair of the dictionary if the
|
|
/// dictionary isn't empty.
|
|
///
|
|
/// The first element of the dictionary is not necessarily the first element
|
|
/// added. Don't expect any particular ordering of key-value pairs.
|
|
///
|
|
/// - Returns: The first key-value pair of the dictionary if the dictionary
|
|
/// is not empty; otherwise, `nil`.
|
|
///
|
|
/// - Complexity: Averages to O(1) over many calls to `popFirst()`.
|
|
%end
|
|
public mutating func popFirst() -> Element? {
|
|
guard !isEmpty else { return nil }
|
|
return remove(at: startIndex)
|
|
}
|
|
}
|
|
|
|
//===--- Bridging ---------------------------------------------------------===//
|
|
|
|
#if _runtime(_ObjC)
|
|
extension ${Self} {
|
|
public func _bridgeToObjectiveCImpl() -> _NS${Self}Core {
|
|
switch _variantBuffer {
|
|
case _Variant${Self}Buffer.native(let buffer):
|
|
return buffer.bridged()
|
|
case _Variant${Self}Buffer.cocoa(let cocoaBuffer):
|
|
return cocoaBuffer.cocoa${Self}
|
|
}
|
|
}
|
|
|
|
/// Returns the native Dictionary hidden inside this NSDictionary;
|
|
/// returns nil otherwise.
|
|
public static func _bridgeFromObjectiveCAdoptingNativeStorageOf(
|
|
_ s: AnyObject
|
|
) -> ${Self}<${TypeParameters}>? {
|
|
|
|
// Try all three NS${Self} impls that we currently provide.
|
|
|
|
if let deferredBuffer = s as? _SwiftDeferredNS${Self}<${TypeParameters}> {
|
|
return ${Self}(_nativeBuffer: deferredBuffer.nativeBuffer)
|
|
}
|
|
|
|
if let nativeStorage = s as? _HashableTypedNative${Self}Storage<${TypeParameters}> {
|
|
return ${Self}(_nativeBuffer:
|
|
_Native${Self}Buffer(_storage: nativeStorage))
|
|
}
|
|
|
|
if s === _RawNative${Self}Storage.empty {
|
|
return ${Self}()
|
|
}
|
|
|
|
// FIXME: what if `s` is native storage, but for different key/value type?
|
|
return nil
|
|
}
|
|
}
|
|
#endif
|
|
|
|
%end
|
|
|
|
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.
|
|
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`.
|
|
public func isSubset(of other: Set<Element>) -> Bool {
|
|
let (isSubset, isEqual) = _compareSets(self, other)
|
|
return isSubset || isEqual
|
|
}
|
|
|
|
/// Returns a Boolean value that indicates whether this set is a superset of
|
|
/// the given set.
|
|
///
|
|
/// Set *A* is a superset of another set *B* if every member of *B* is also a
|
|
/// member of *A*.
|
|
///
|
|
/// let employees: Set = ["Alicia", "Bethany", "Chris", "Diana", "Eric"]
|
|
/// let attendees: Set = ["Alicia", "Bethany", "Diana"]
|
|
/// print(employees.isSuperset(of: attendees))
|
|
/// // Prints "true"
|
|
///
|
|
/// - Parameter other: Another set.
|
|
/// - Returns: `true` if the set is a superset of `other`; otherwise,
|
|
/// `false`.
|
|
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`.
|
|
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.
|
|
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`.
|
|
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`.
|
|
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.
|
|
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.
|
|
public mutating func formSymmetricDifference(_ other: Set<Element>) {
|
|
for member in other {
|
|
if contains(member) {
|
|
remove(member)
|
|
} else {
|
|
insert(member)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
extension Set {
|
|
@available(*, unavailable, renamed: "remove(at:)")
|
|
public mutating func removeAtIndex(_ index: Index) -> Element {
|
|
Builtin.unreachable()
|
|
}
|
|
|
|
@available(*, unavailable, renamed: "makeIterator()")
|
|
public func generate() -> SetIterator<Element> {
|
|
Builtin.unreachable()
|
|
}
|
|
|
|
@available(*, unavailable, renamed: "index(of:)")
|
|
public func indexOf(_ member: Element) -> Index? {
|
|
Builtin.unreachable()
|
|
}
|
|
}
|
|
|
|
extension Dictionary {
|
|
@available(*, unavailable, renamed: "remove(at:)")
|
|
public mutating func removeAtIndex(_ index: Index) -> Element {
|
|
Builtin.unreachable()
|
|
}
|
|
|
|
@available(*, unavailable, renamed: "index(forKey:)")
|
|
public func indexForKey(_ key: Key) -> Index? {
|
|
Builtin.unreachable()
|
|
}
|
|
|
|
@available(*, unavailable, renamed: "removeValue(forKey:)")
|
|
public mutating func removeValueForKey(_ key: Key) -> Value? {
|
|
Builtin.unreachable()
|
|
}
|
|
|
|
@available(*, unavailable, renamed: "makeIterator()")
|
|
public func generate() -> DictionaryIterator<Key, Value> {
|
|
Builtin.unreachable()
|
|
}
|
|
}
|