//===----------------------------------------------------------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // 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 unoccupied entry marks the end of a // chain. There is always at least one unoccupied 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)`. // // Native dictionary storage uses a data structure like this:: // // struct Dictionary // +------------------------------------------------+ // | enum Dictionary._Variant | // | +--------------------------------------------+ | // | | [struct _NativeDictionary | | // | +---|----------------------------------------+ | // +----/-------------------------------------------+ // / // | // V // class __RawDictionaryStorage // +-----------------------------------------------------------+ // | | // | | // | _count | // | _capacity | // | _scale | // | _age | // | _seed | // | _rawKeys | // | _rawValue | // | [inline bitset of occupied entries] | // | [inline array of keys] | // | [inline array of values] | // +-----------------------------------------------------------+ // // Cocoa storage uses a data structure like this: // // struct Dictionary // +----------------------------------------------+ // | enum Dictionary._Variant | // | +----------------------------------------+ | // | | [ struct __CocoaDictionary | | // | +---|------------------------------------+ | // +----/-----------------------------------------+ // / // | // V // class NSDictionary // +--------------+ // | [refcount#1] | // | etc. | // +--------------+ // ^ // | // \ struct __CocoaDictionary.Index // +--|------------------------------------+ // | * base: __CocoaDictionary | // | allKeys: array of all keys | // | currentKeyIndex: index into allKeys | // +---------------------------------------+ // // // The Native Kinds of Storage // --------------------------- // // The native backing store is represented by three different classes: // * `__RawDictionaryStorage` // * `__EmptyDictionarySingleton` (extends Raw) // * `_DictionaryStorage` (extends Raw) // // (Hereafter `Raw`, `Empty`, and `Storage`, respectively) // // In a less optimized implementation, `Raw` and `Empty` could be eliminated, as // they exist only to provide special-case behaviors. // // `Empty` is the a type-punned empty singleton storage. Its single instance is // created by the runtime during process startup. Because we use the same // instance for all empty dictionaries, it cannot declare type parameters. // // `Storage` provides backing storage for regular native dictionaries. All // non-empty native dictionaries use an instance of `Storage` to store their // elements. `Storage` is a generic class with a nontrivial deinit. // // `Raw` is the base class for both `Empty` and `Storage`. It defines a full set // of ivars to access dictionary contents. Like `Empty`, `Raw` is also // non-generic; the base addresses it stores are represented by untyped raw // pointers. The only reason `Raw` exists is to allow `_NativeDictionary` to // treat `Empty` and `Storage` in a unified way. // // Storage classes don't contain much logic; `Raw` in particular is just a // collection of ivars. `Storage` provides allocation/deinitialization logic, // while `Empty`/`Storage` implement NSDictionary methods. All other operations // are actually implemented by the `_NativeDictionary` and `_HashTable` structs. // // The `_HashTable` struct provides low-level hash table metadata operations. // (Lookups, iteration, insertion, removal.) It owns and maintains the // tail-allocated bitmap. // // `_NativeDictionary` implements the actual Dictionary operations. It // consists of a reference to a `Raw` instance, to allow for the possibility of // the empty singleton. // // // 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. // // As a safeguard against using invalid indices, Set and Dictionary maintain a // mutation counter in their storage header (`_age`). This counter gets bumped // every time an element is removed and whenever the contents are // rehashed. Native indices include a copy of this counter so that index // validation can verify it matches with current storage. This can't catch all // misuse, because counters may match by accident; but it does make indexing a // lot more reliable. // // Bridging // ======== // // Bridging `NSDictionary` to `Dictionary` // --------------------------------------- // // FIXME(eager-bridging): rewrite this based on modern constraints. // // `NSDictionary` bridges to `Dictionary` in `O(1)`, // without memory allocation. // // Bridging to `Dictionary` takes `O(n)` time, as the // keys need to be fully rehashed after conversion to `AnyHashable`. // // Bridging `NSDictionary` to `Dictionary` is O(1) if both Key and // Value are bridged verbatim. // // Bridging `Dictionary` to `NSDictionary` // --------------------------------------- // // `Dictionary` 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` 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 it in a // `_SwiftDeferredNSDictionary`. 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` are the same as for // `Dictionary`. // /// 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, 17], /// "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 "[17, 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 `KeyValuePairs` type for an alternative. /// /// You can search a dictionary's contents for a particular value using the /// `contains(where:)` or `firstIndex(where:)` methods supplied by default /// implementation. The following example checks to see if `imagePaths` contains /// any paths in the `"/glyphs"` directory: /// /// let glyphIndex = imagePaths.firstIndex(where: { $0.value.hasPrefix("/glyphs") }) /// if let index = glyphIndex { /// print("The '\(imagePaths[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 "(key: "star", value: "/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. @frozen @_eagerMove public struct Dictionary { /// The element type of a dictionary: a tuple containing an individual /// key-value pair. public typealias Element = (key: Key, value: Value) @usableFromInline internal var _variant: _Variant @inlinable internal init(_native: __owned _NativeDictionary) { _variant = _Variant(native: _native) } #if _runtime(_ObjC) @inlinable internal init(_cocoa: __owned __CocoaDictionary) { _variant = _Variant(cocoa: _cocoa) } /// 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). @inlinable public // SPI(Foundation) init(_immutableCocoaDictionary: __owned AnyObject) { _internalInvariant( _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 """) self.init(_cocoa: __CocoaDictionary(_immutableCocoaDictionary)) } #endif /// Creates an empty dictionary. @inlinable public init() { self.init(_native: _NativeDictionary()) } /// Creates an empty dictionary with preallocated space for at least the /// specified number of elements. /// /// Use this initializer to avoid intermediate reallocations of a dictionary's /// storage buffer when you know how many key-value pairs you are adding to a /// dictionary after creation. /// /// - Parameter minimumCapacity: The minimum number of key-value pairs that /// the newly created dictionary should be able to store without /// reallocating its storage buffer. public // FIXME(reserveCapacity): Should be inlinable init(minimumCapacity: Int) { _variant = _Variant(native: _NativeDictionary(capacity: minimumCapacity)) } /// Creates a new dictionary from the key-value pairs in the given sequence. /// /// You use this initializer to create a dictionary when you have a sequence /// of key-value tuples with unique keys. Passing a sequence with duplicate /// keys to this initializer results in a runtime error. If your /// sequence might have duplicate keys, use the /// `Dictionary(_:uniquingKeysWith:)` initializer instead. /// /// The following example creates a new dictionary using an array of strings /// as the keys and the integers in a countable range as the values: /// /// let digitWords = ["one", "two", "three", "four", "five"] /// let wordToValue = Dictionary(uniqueKeysWithValues: zip(digitWords, 1...5)) /// print(wordToValue["three"]!) /// // Prints "3" /// print(wordToValue) /// // Prints "["three": 3, "four": 4, "five": 5, "one": 1, "two": 2]" /// /// - Parameter keysAndValues: A sequence of key-value pairs to use for /// the new dictionary. Every key in `keysAndValues` must be unique. /// - Returns: A new dictionary initialized with the elements of /// `keysAndValues`. /// - Precondition: The sequence must not have duplicate keys. @inlinable public init( uniqueKeysWithValues keysAndValues: __owned S ) where S.Element == (Key, Value) { if let d = keysAndValues as? Dictionary { self = d return } var native = _NativeDictionary( capacity: keysAndValues.underestimatedCount) // '_MergeError.keyCollision' is caught and handled with an appropriate // error message one level down, inside native.merge(_:...). We throw an // error instead of calling fatalError() directly because we want the // message to include the duplicate key, and the closure only has access to // the conflicting values. #if !$Embedded try! native.merge( keysAndValues, isUnique: true, uniquingKeysWith: { _, _ in throw _MergeError.keyCollision }) #else native.merge( keysAndValues, isUnique: true, uniquingKeysWith: { _, _ throws(_MergeError) in throw _MergeError.keyCollision } ) #endif self.init(_native: native) } /// Creates a new dictionary from the key-value pairs in the given sequence, /// using a combining closure to determine the value for any duplicate keys. /// /// You use this initializer to create a dictionary when you have a sequence /// of key-value tuples that might have duplicate keys. As the dictionary is /// built, the initializer calls the `combine` closure with the current and /// new values for any duplicate keys. Pass a closure as `combine` that /// returns the value to use in the resulting dictionary: The closure can /// choose between the two values, combine them to produce a new value, or /// even throw an error. /// /// The following example shows how to choose the first and last values for /// any duplicate keys: /// /// let pairsWithDuplicateKeys = [("a", 1), ("b", 2), ("a", 3), ("b", 4)] /// /// let firstValues = Dictionary(pairsWithDuplicateKeys, /// uniquingKeysWith: { (first, _) in first }) /// // ["b": 2, "a": 1] /// /// let lastValues = Dictionary(pairsWithDuplicateKeys, /// uniquingKeysWith: { (_, last) in last }) /// // ["b": 4, "a": 3] /// /// - Parameters: /// - keysAndValues: A sequence of key-value pairs to use for the new /// dictionary. /// - combine: A closure that is called with the values for any duplicate /// keys that are encountered. The closure returns the desired value for /// the final dictionary. @inlinable public init( _ keysAndValues: __owned S, uniquingKeysWith combine: (Value, Value) throws -> Value ) rethrows where S.Element == (Key, Value) { var native = _NativeDictionary( capacity: keysAndValues.underestimatedCount) try native.merge(keysAndValues, isUnique: true, uniquingKeysWith: combine) self.init(_native: native) } /// Creates a new dictionary whose keys are the groupings returned by the /// given closure and whose values are arrays of the elements that returned /// each key. /// /// The arrays in the "values" position of the new dictionary each contain at /// least one element, with the elements in the same order as the source /// sequence. /// /// The following example declares an array of names, and then creates a /// dictionary from that array by grouping the names by first letter: /// /// let students = ["Kofi", "Abena", "Efua", "Kweku", "Akosua"] /// let studentsByLetter = Dictionary(grouping: students, by: { $0.first! }) /// // ["E": ["Efua"], "K": ["Kofi", "Kweku"], "A": ["Abena", "Akosua"]] /// /// The new `studentsByLetter` dictionary has three entries, with students' /// names grouped by the keys `"E"`, `"K"`, and `"A"`. /// /// - Parameters: /// - values: A sequence of values to group into a dictionary. /// - keyForValue: A closure that returns a key for each element in /// `values`. @inlinable public init( grouping values: __owned S, by keyForValue: (S.Element) throws -> Key ) rethrows where Value == [S.Element] { try self.init(_native: _NativeDictionary(grouping: values, by: keyForValue)) } } // // All APIs below should dispatch to `_variant`, without doing any // additional processing. // extension Dictionary: Sequence { /// 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)`. @inlinable @inline(__always) public __consuming func makeIterator() -> Iterator { return _variant.makeIterator() } } // This is not quite Sequence.filter, because that returns [Element], not Self extension Dictionary { /// Returns a new dictionary containing the key-value pairs of the dictionary /// that satisfy the given predicate. /// /// - Parameter isIncluded: A closure that takes a key-value pair as its /// argument and returns a Boolean value indicating whether the pair /// should be included in the returned dictionary. /// - Returns: A dictionary of the key-value pairs that `isIncluded` allows. @inlinable @available(swift, introduced: 4.0) public __consuming func filter( _ isIncluded: (Element) throws -> Bool ) rethrows -> [Key: Value] { #if _runtime(_ObjC) guard _variant.isNative else { // Slow path for bridged dictionaries var result = _NativeDictionary() for element in self { if try isIncluded(element) { result.insertNew(key: element.key, value: element.value) } } return Dictionary(_native: result) } #endif return Dictionary(_native: try _variant.asNative.filter(isIncluded)) } } extension Dictionary: Collection { public typealias SubSequence = Slice /// 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. @inlinable public var startIndex: Index { return _variant.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. @inlinable public var endIndex: Index { return _variant.endIndex } @inlinable public func index(after i: Index) -> Index { return _variant.index(after: i) } @inlinable public func formIndex(after i: inout Index) { _variant.formIndex(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`. @inlinable @inline(__always) public func index(forKey key: Key) -> Index? { // Complexity: amortized O(1) for native dictionary, O(*n*) when wrapping an // NSDictionary. return _variant.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 `firstIndex(where:)` method. /// /// let countryCodes = ["BR": "Brazil", "GH": "Ghana", "JP": "Japan"] /// if let index = countryCodes.firstIndex(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 "(key: "JP", value: "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`. @inlinable public subscript(position: Index) -> Element { return _variant.lookup(position) } /// The number of key-value pairs in the dictionary. /// /// - Complexity: O(1). @inlinable public var count: Int { return _variant.count } // // `Sequence` conformance // /// A Boolean value that indicates whether the dictionary is empty. /// /// Dictionaries are empty when created with an initializer or an empty /// dictionary literal. /// /// var frequencies: [String: Int] = [:] /// print(frequencies.isEmpty) /// // Prints "true" @inlinable public var isEmpty: Bool { return count == 0 } } extension Dictionary { /// 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`. @inlinable public subscript(key: Key) -> Value? { get { return _variant.lookup(key) } set(newValue) { if let x = newValue { _variant.setValue(x, forKey: key) } else { removeValue(forKey: key) } } _modify { defer { _fixLifetime(self) } yield &_variant[key] } } } extension Dictionary: ExpressibleByDictionaryLiteral { /// 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. @inlinable @_semantics("optimize.sil.specialize.generic.size.never") public init(dictionaryLiteral elements: (Key, Value)...) { let native = _NativeDictionary(capacity: elements.count) for (key, value) in elements { let (bucket, found) = native.find(key) _precondition(!found, "Dictionary literal contains duplicate keys") native._insert(at: bucket, key: key, value: value) } self.init(_native: native) } } extension Dictionary { /// Accesses the value with the given key, falling back to the given default /// value if the key isn't found. /// /// Use this subscript when you want either the value for a particular key /// or, when that key is not present in the dictionary, a default value. This /// example uses the subscript with a message to use in case an HTTP response /// code isn't recognized: /// /// var responseMessages = [200: "OK", /// 403: "Access forbidden", /// 404: "File not found", /// 500: "Internal server error"] /// /// let httpResponseCodes = [200, 403, 301] /// for code in httpResponseCodes { /// let message = responseMessages[code, default: "Unknown response"] /// print("Response \(code): \(message)") /// } /// // Prints "Response 200: OK" /// // Prints "Response 403: Access forbidden" /// // Prints "Response 301: Unknown response" /// /// When a dictionary's `Value` type has value semantics, you can use this /// subscript to perform in-place operations on values in the dictionary. /// The following example uses this subscript while counting the occurrences /// of each letter in a string: /// /// let message = "Hello, Elle!" /// var letterCounts: [Character: Int] = [:] /// for letter in message { /// letterCounts[letter, default: 0] += 1 /// } /// // letterCounts == ["H": 1, "e": 2, "l": 4, "o": 1, ...] /// /// When `letterCounts[letter, default: 0] += 1` is executed with a /// value of `letter` that isn't already a key in `letterCounts`, the /// specified default value (`0`) is returned from the subscript, /// incremented, and then added to the dictionary under that key. /// /// - Note: Do not use this subscript to modify dictionary values if the /// dictionary's `Value` type is a class. In that case, the default value /// and key are not written back to the dictionary after an operation. /// /// - Parameters: /// - key: The key the look up in the dictionary. /// - defaultValue: The default value to use if `key` doesn't exist in the /// dictionary. /// - Returns: The value associated with `key` in the dictionary; otherwise, /// `defaultValue`. @inlinable public subscript( key: Key, default defaultValue: @autoclosure () -> Value ) -> Value { @inline(__always) get { return _variant.lookup(key) ?? defaultValue() } @inline(__always) _modify { let (bucket, found) = _variant.mutatingFind(key) let native = _variant.asNative if !found { let value = defaultValue() native._insert(at: bucket, key: key, value: value) } let address = unsafe native._values + bucket.offset defer { _fixLifetime(self) } yield unsafe &address.pointee } } /// Returns a new dictionary containing the keys of this dictionary with the /// values transformed by the given closure. /// /// - Parameter transform: A closure that transforms a value. `transform` /// accepts each value of the dictionary as its parameter and returns a /// transformed value of the same or of a different type. /// - Returns: A dictionary containing the keys and transformed values of /// this dictionary. /// /// - Complexity: O(*n*), where *n* is the length of the dictionary. @inlinable public func mapValues( _ transform: (Value) throws -> T ) rethrows -> Dictionary { return try Dictionary(_native: _variant.mapValues(transform)) } /// Returns a new dictionary containing only the key-value pairs that have /// non-`nil` values as the result of transformation by the given closure. /// /// Use this method to receive a dictionary with non-optional values when /// your transformation produces optional values. /// /// In this example, note the difference in the result of using `mapValues` /// and `compactMapValues` with a transformation that returns an optional /// `Int` value. /// /// let data = ["a": "1", "b": "three", "c": "///4///"] /// /// let m: [String: Int?] = data.mapValues { str in Int(str) } /// // ["a": Optional(1), "b": nil, "c": nil] /// /// let c: [String: Int] = data.compactMapValues { str in Int(str) } /// // ["a": 1] /// /// - Parameter transform: A closure that transforms a value. `transform` /// accepts each value of the dictionary as its parameter and returns an /// optional transformed value of the same or of a different type. /// - Returns: A dictionary containing the keys and non-`nil` transformed /// values of this dictionary. /// /// - Complexity: O(*m* + *n*), where *n* is the length of the original /// dictionary and *m* is the length of the resulting dictionary. @inlinable public func compactMapValues( _ transform: (Value) throws -> T? ) rethrows -> Dictionary { let result: _NativeDictionary = try self.reduce(into: _NativeDictionary()) { (result, element) in if let value = try transform(element.value) { result.insertNew(key: element.key, value: value) } } return Dictionary(_native: result) } /// 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. @inlinable @discardableResult public mutating func updateValue( _ value: __owned Value, forKey key: Key ) -> Value? { return _variant.updateValue(value, forKey: key) } /// Merges the key-value pairs in the given sequence into the dictionary, /// using a combining closure to determine the value for any duplicate keys. /// /// Use the `combine` closure to select a value to use in the updated /// dictionary, or to combine existing and new values. As the key-value /// pairs are merged with the dictionary, the `combine` closure is called /// with the current and new values for any duplicate keys that are /// encountered. /// /// This example shows how to choose the current or new values for any /// duplicate keys: /// /// var dictionary = ["a": 1, "b": 2] /// /// // Keeping existing value for key "a": /// dictionary.merge(zip(["a", "c"], [3, 4])) { (current, _) in current } /// // ["b": 2, "a": 1, "c": 4] /// /// // Taking the new value for key "a": /// dictionary.merge(zip(["a", "d"], [5, 6])) { (_, new) in new } /// // ["b": 2, "a": 5, "c": 4, "d": 6] /// /// - Parameters: /// - other: A sequence of key-value pairs. /// - combine: A closure that takes the current and new values for any /// duplicate keys. The closure returns the desired value for the final /// dictionary. @inlinable public mutating func merge( _ other: __owned S, uniquingKeysWith combine: (Value, Value) throws -> Value ) rethrows where S.Element == (Key, Value) { try _variant.merge(other, uniquingKeysWith: combine) } /// Merges the given dictionary into this dictionary, using a combining /// closure to determine the value for any duplicate keys. /// /// Use the `combine` closure to select a value to use in the updated /// dictionary, or to combine existing and new values. As the key-values /// pairs in `other` are merged with this dictionary, the `combine` closure /// is called with the current and new values for any duplicate keys that /// are encountered. /// /// This example shows how to choose the current or new values for any /// duplicate keys: /// /// var dictionary = ["a": 1, "b": 2] /// /// // Keeping existing value for key "a": /// dictionary.merge(["a": 3, "c": 4]) { (current, _) in current } /// // ["b": 2, "a": 1, "c": 4] /// /// // Taking the new value for key "a": /// dictionary.merge(["a": 5, "d": 6]) { (_, new) in new } /// // ["b": 2, "a": 5, "c": 4, "d": 6] /// /// - Parameters: /// - other: A dictionary to merge. /// - combine: A closure that takes the current and new values for any /// duplicate keys. The closure returns the desired value for the final /// dictionary. @inlinable public mutating func merge( _ other: __owned [Key: Value], uniquingKeysWith combine: (Value, Value) throws -> Value ) rethrows { try _variant.merge( other.lazy.map { ($0, $1) }, uniquingKeysWith: combine) } /// Creates a dictionary by merging key-value pairs in a sequence into the /// dictionary, using a combining closure to determine the value for /// duplicate keys. /// /// Use the `combine` closure to select a value to use in the returned /// dictionary, or to combine existing and new values. As the key-value /// pairs are merged with the dictionary, the `combine` closure is called /// with the current and new values for any duplicate keys that are /// encountered. /// /// This example shows how to choose the current or new values for any /// duplicate keys: /// /// let dictionary = ["a": 1, "b": 2] /// let newKeyValues = zip(["a", "b"], [3, 4]) /// /// let keepingCurrent = dictionary.merging(newKeyValues) { (current, _) in current } /// // ["b": 2, "a": 1] /// let replacingCurrent = dictionary.merging(newKeyValues) { (_, new) in new } /// // ["b": 4, "a": 3] /// /// - Parameters: /// - other: A sequence of key-value pairs. /// - combine: A closure that takes the current and new values for any /// duplicate keys. The closure returns the desired value for the final /// dictionary. /// - Returns: A new dictionary with the combined keys and values of this /// dictionary and `other`. @inlinable public __consuming func merging( _ other: __owned S, uniquingKeysWith combine: (Value, Value) throws -> Value ) rethrows -> [Key: Value] where S.Element == (Key, Value) { var result = self try result._variant.merge(other, uniquingKeysWith: combine) return result } /// Creates a dictionary by merging the given dictionary into this /// dictionary, using a combining closure to determine the value for /// duplicate keys. /// /// Use the `combine` closure to select a value to use in the returned /// dictionary, or to combine existing and new values. As the key-value /// pairs in `other` are merged with this dictionary, the `combine` closure /// is called with the current and new values for any duplicate keys that /// are encountered. /// /// This example shows how to choose the current or new values for any /// duplicate keys: /// /// let dictionary = ["a": 1, "b": 2] /// let otherDictionary = ["a": 3, "b": 4] /// /// let keepingCurrent = dictionary.merging(otherDictionary) /// { (current, _) in current } /// // ["b": 2, "a": 1] /// let replacingCurrent = dictionary.merging(otherDictionary) /// { (_, new) in new } /// // ["b": 4, "a": 3] /// /// - Parameters: /// - other: A dictionary to merge. /// - combine: A closure that takes the current and new values for any /// duplicate keys. The closure returns the desired value for the final /// dictionary. /// - Returns: A new dictionary with the combined keys and values of this /// dictionary and `other`. @inlinable public __consuming func merging( _ other: __owned [Key: Value], uniquingKeysWith combine: (Value, Value) throws -> Value ) rethrows -> [Key: Value] { var result = self try result.merge(other, uniquingKeysWith: combine) return result } /// 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. @inlinable @discardableResult public mutating func remove(at index: Index) -> Element { return _variant.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.removeValue(forKey: "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. @inlinable @discardableResult public mutating func removeValue(forKey key: Key) -> Value? { return _variant.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. @inlinable 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 dictionary with // native dictionary. _variant.removeAll(keepingCapacity: keepCapacity) } } extension Dictionary { /// 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"] /// print(countryCodes) /// // Prints "["BR": "Brazil", "JP": "Japan", "GH": "Ghana"]" /// /// for k in countryCodes.keys { /// print(k) /// } /// // Prints "BR" /// // Prints "JP" /// // Prints "GH" @inlinable @available(swift, introduced: 4.0) public var keys: Keys { // FIXME(accessors): Provide a _read get { return Keys(_dictionary: self) } } /// 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" @inlinable @available(swift, introduced: 4.0) public var values: Values { // FIXME(accessors): Provide a _read get { return Values(_dictionary: self) } _modify { var values = Values(_variant: _Variant(dummy: ())) swap(&values._variant, &_variant) defer { self._variant = values._variant } yield &values } } /// A view of a dictionary's keys. @frozen public struct Keys: Collection, Equatable { public typealias Element = Key public typealias SubSequence = Slice @usableFromInline internal var _variant: Dictionary._Variant @inlinable internal init(_dictionary: __owned Dictionary) { self._variant = _dictionary._variant } // Collection Conformance // ---------------------- @inlinable public var startIndex: Index { return _variant.startIndex } @inlinable public var endIndex: Index { return _variant.endIndex } @inlinable public func index(after i: Index) -> Index { return _variant.index(after: i) } @inlinable public func formIndex(after i: inout Index) { _variant.formIndex(after: &i) } @inlinable public subscript(position: Index) -> Element { return _variant.key(at: position) } // Customization // ------------- /// The number of keys in the dictionary. /// /// - Complexity: O(1). @inlinable public var count: Int { return _variant.count } @inlinable public var isEmpty: Bool { return count == 0 } @inlinable @inline(__always) public func _customContainsEquatableElement(_ element: Element) -> Bool? { return _variant.contains(element) } @inlinable @inline(__always) public func _customIndexOfEquatableElement(_ element: Element) -> Index?? { return Optional(_variant.index(forKey: element)) } @inlinable @inline(__always) public func _customLastIndexOfEquatableElement(_ element: Element) -> Index?? { // The first and last elements are the same because each element is unique. return _customIndexOfEquatableElement(element) } @inlinable public static func ==(lhs: Keys, rhs: Keys) -> Bool { // Equal if the two dictionaries share storage. #if _runtime(_ObjC) if lhs._variant.isNative, rhs._variant.isNative, unsafe (lhs._variant.asNative._storage === rhs._variant.asNative._storage) { return true } if !lhs._variant.isNative, !rhs._variant.isNative, lhs._variant.asCocoa.object === rhs._variant.asCocoa.object { return true } #else if unsafe (lhs._variant.asNative._storage === rhs._variant.asNative._storage) { return true } #endif // Not equal if the dictionaries are different sizes. if lhs.count != rhs.count { return false } // Perform unordered comparison of keys. for key in lhs { if !rhs.contains(key) { return false } } return true } } /// A view of a dictionary's values. @frozen public struct Values: MutableCollection { public typealias Element = Value @usableFromInline internal var _variant: Dictionary._Variant @inlinable internal init(_variant: __owned Dictionary._Variant) { self._variant = _variant } @inlinable internal init(_dictionary: __owned Dictionary) { self._variant = _dictionary._variant } // Collection Conformance // ---------------------- @inlinable public var startIndex: Index { return _variant.startIndex } @inlinable public var endIndex: Index { return _variant.endIndex } @inlinable public func index(after i: Index) -> Index { return _variant.index(after: i) } @inlinable public func formIndex(after i: inout Index) { _variant.formIndex(after: &i) } @inlinable public subscript(position: Index) -> Element { // FIXME(accessors): Provide a _read get { return _variant.value(at: position) } _modify { let native = _variant.ensureUniqueNative() let bucket = native.validatedBucket(for: position) let address = unsafe native._values + bucket.offset defer { _fixLifetime(self) } yield unsafe &address.pointee } } // Customization // ------------- /// The number of values in the dictionary. /// /// - Complexity: O(1). @inlinable public var count: Int { return _variant.count } @inlinable public var isEmpty: Bool { return count == 0 } @inlinable public mutating func swapAt(_ i: Index, _ j: Index) { guard i != j else { return } #if _runtime(_ObjC) if !_variant.isNative { _variant = .init(native: _NativeDictionary(_variant.asCocoa)) } #endif let isUnique = _variant.isUniquelyReferenced() let native = _variant.asNative let a = native.validatedBucket(for: i) let b = native.validatedBucket(for: j) _variant.asNative.swapValuesAt(a, b, isUnique: isUnique) } } } @_unavailableInEmbedded extension Dictionary.Keys : CustomStringConvertible, CustomDebugStringConvertible { public var description: String { return _makeCollectionDescription() } public var debugDescription: String { return _makeCollectionDescription(withTypeName: "Dictionary.Keys") } } @_unavailableInEmbedded extension Dictionary.Values : CustomStringConvertible, CustomDebugStringConvertible { public var description: String { return _makeCollectionDescription() } public var debugDescription: String { return _makeCollectionDescription(withTypeName: "Dictionary.Values") } } extension Dictionary.Keys { @frozen public struct Iterator: IteratorProtocol { @usableFromInline internal var _base: Dictionary.Iterator @inlinable @inline(__always) internal init(_ base: Dictionary.Iterator) { self._base = base } @inlinable @inline(__always) public mutating func next() -> Key? { #if _runtime(_ObjC) if case .cocoa(let cocoa) = _base._variant { _base._cocoaPath() guard let cocoaKey = cocoa.nextKey() else { return nil } return _forceBridgeFromObjectiveC(cocoaKey, Key.self) } #endif return _base._asNative.nextKey() } } @inlinable @inline(__always) public __consuming func makeIterator() -> Iterator { return Iterator(_variant.makeIterator()) } } extension Dictionary.Values { @frozen public struct Iterator: IteratorProtocol { @usableFromInline internal var _base: Dictionary.Iterator @inlinable @inline(__always) internal init(_ base: Dictionary.Iterator) { self._base = base } @inlinable @inline(__always) public mutating func next() -> Value? { #if _runtime(_ObjC) if case .cocoa(let cocoa) = _base._variant { _base._cocoaPath() guard let (_, cocoaValue) = cocoa.next() else { return nil } return _forceBridgeFromObjectiveC(cocoaValue, Value.self) } #endif return _base._asNative.nextValue() } } @inlinable @inline(__always) public __consuming func makeIterator() -> Iterator { return Iterator(_variant.makeIterator()) } } extension Dictionary: Equatable where Value: Equatable { @inlinable public static func == (lhs: [Key: Value], rhs: [Key: Value]) -> Bool { #if _runtime(_ObjC) switch (lhs._variant.isNative, rhs._variant.isNative) { case (true, true): return lhs._variant.asNative.isEqual(to: rhs._variant.asNative) case (false, false): return lhs._variant.asCocoa.isEqual(to: rhs._variant.asCocoa) case (true, false): return lhs._variant.asNative.isEqual(to: rhs._variant.asCocoa) case (false, true): return rhs._variant.asNative.isEqual(to: lhs._variant.asCocoa) } #else return lhs._variant.asNative.isEqual(to: rhs._variant.asNative) #endif } } extension Dictionary: Hashable where Value: Hashable { /// Hashes the essential components of this value by feeding them into the /// given hasher. /// /// - Parameter hasher: The hasher to use when combining the components /// of this instance. @inlinable public func hash(into hasher: inout Hasher) { var commutativeHash = 0 for (k, v) in self { // Note that we use a copy of our own hasher here. This makes hash values // dependent on its state, eliminating static collision patterns. var elementHasher = hasher elementHasher.combine(k) elementHasher.combine(v) commutativeHash ^= elementHasher._finalize() } hasher.combine(commutativeHash) } } @_unavailableInEmbedded extension Dictionary: _HasCustomAnyHashableRepresentation where Value: Hashable { public __consuming func _toCustomAnyHashable() -> AnyHashable? { return AnyHashable(_box: _DictionaryAnyHashableBox(self)) } } @_unavailableInEmbedded internal struct _DictionaryAnyHashableBox : _AnyHashableBox { internal let _value: Dictionary internal let _canonical: Dictionary internal init(_ value: __owned Dictionary) { self._value = value self._canonical = value as Dictionary } internal var _base: Any { return _value } internal var _canonicalBox: _AnyHashableBox { return _DictionaryAnyHashableBox(_canonical) } internal func _isEqual(to other: _AnyHashableBox) -> Bool? { guard let other = other as? _DictionaryAnyHashableBox else { return nil } return _canonical == other._value } internal var _hashValue: Int { return _canonical.hashValue } internal func _hash(into hasher: inout Hasher) { _canonical.hash(into: &hasher) } internal func _rawHashValue(_seed: Int) -> Int { return _canonical._rawHashValue(seed: _seed) } internal func _unbox() -> T? { return _value as? T } internal func _downCastConditional( into result: UnsafeMutablePointer ) -> Bool { guard let value = _value as? T else { return false } unsafe result.initialize(to: value) return true } } @_unavailableInEmbedded extension Collection { // Utility method for KV collections that wish to implement // CustomStringConvertible and CustomDebugStringConvertible using a bracketed // list of elements. // FIXME: Doesn't use the withTypeName argument yet internal func _makeKeyValuePairDescription( withTypeName type: String? = nil ) -> String where Element == (key: K, value: V) { #if !SWIFT_STDLIB_STATIC_PRINT if self.isEmpty { return "[:]" } var result = "[" var first = true for (k, v) in self { if first { first = false } else { result += ", " } #if !$Embedded debugPrint(k, terminator: "", to: &result) result += ": " debugPrint(v, terminator: "", to: &result) #else "(cannot print value in embedded Swift)".write(to: &result) result += ": " "(cannot print value in embedded Swift)".write(to: &result) #endif } result += "]" return result #else return "(collection printing not available)" #endif } } @_unavailableInEmbedded extension Dictionary: CustomStringConvertible, CustomDebugStringConvertible { /// A string that represents the contents of the dictionary. public var description: String { return _makeKeyValuePairDescription() } /// A string that represents the contents of the dictionary, suitable for /// debugging. public var debugDescription: String { return _makeKeyValuePairDescription() } } @usableFromInline @frozen internal enum _MergeError: Error { case keyCollision } extension Dictionary { /// The position of a key-value pair in a dictionary. /// /// 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] @frozen public struct Index { // Index for native dictionary is efficient. Index for bridged NSDictionary // 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 NSDictionary in terms of Cocoa enumeration facilities. @frozen @usableFromInline @safe internal enum _Variant { case native(_HashTable.Index) #if _runtime(_ObjC) case cocoa(__CocoaDictionary.Index) #endif } @usableFromInline internal var _variant: _Variant @inlinable @inline(__always) internal init(_variant: __owned _Variant) { self._variant = _variant } @inlinable @inline(__always) internal init(_native index: _HashTable.Index) { unsafe self.init(_variant: .native(index)) } #if _runtime(_ObjC) @inlinable @inline(__always) internal init(_cocoa index: __owned __CocoaDictionary.Index) { self.init(_variant: .cocoa(index)) } #endif } } extension Dictionary.Index._Variant: @unchecked Sendable {} extension Dictionary.Index { #if _runtime(_ObjC) @usableFromInline @_transparent internal var _guaranteedNative: Bool { return _canBeClass(Key.self) == 0 || _canBeClass(Value.self) == 0 } // Allow the optimizer to consider the surrounding code unreachable if Element // is guaranteed to be native. @usableFromInline @_transparent internal func _cocoaPath() { if _guaranteedNative { _conditionallyUnreachable() } } @inlinable @inline(__always) internal mutating func _isUniquelyReferenced() -> Bool { defer { _fixLifetime(self) } var handle = _asCocoa.handleBitPattern return handle == 0 || _isUnique_native(&handle) } @usableFromInline @_transparent internal var _isNative: Bool { switch _variant { case .native: return true case .cocoa: _cocoaPath() return false } } #endif @usableFromInline @_transparent internal var _asNative: _HashTable.Index { switch _variant { case .native(let nativeIndex): return unsafe nativeIndex #if _runtime(_ObjC) case .cocoa: _preconditionFailure( "Attempting to access Dictionary elements using an invalid index") #endif } } #if _runtime(_ObjC) @usableFromInline internal var _asCocoa: __CocoaDictionary.Index { @_transparent get { switch _variant { case .native: _preconditionFailure( "Attempting to access Dictionary elements using an invalid index") case .cocoa(let cocoaIndex): return cocoaIndex } } _modify { guard case .cocoa(var cocoa) = _variant else { _preconditionFailure( "Attempting to access Dictionary elements using an invalid index") } let dummy = unsafe _HashTable.Index(bucket: _HashTable.Bucket(offset: 0), age: 0) _variant = unsafe .native(dummy) defer { _variant = .cocoa(cocoa) } yield &cocoa } } #endif } extension Dictionary.Index: Equatable { @inlinable public static func == ( lhs: Dictionary.Index, rhs: Dictionary.Index ) -> Bool { switch (lhs._variant, rhs._variant) { case (.native(let lhsNative), .native(let rhsNative)): return unsafe lhsNative == rhsNative #if _runtime(_ObjC) case (.cocoa(let lhsCocoa), .cocoa(let rhsCocoa)): lhs._cocoaPath() return lhsCocoa == rhsCocoa default: _preconditionFailure("Comparing indexes from different dictionaries") #endif } } } extension Dictionary.Index: Comparable { @inlinable public static func < ( lhs: Dictionary.Index, rhs: Dictionary.Index ) -> Bool { switch (lhs._variant, rhs._variant) { case (.native(let lhsNative), .native(let rhsNative)): return unsafe lhsNative < rhsNative #if _runtime(_ObjC) case (.cocoa(let lhsCocoa), .cocoa(let rhsCocoa)): lhs._cocoaPath() return lhsCocoa < rhsCocoa default: _preconditionFailure("Comparing indexes from different dictionaries") #endif } } } extension Dictionary.Index: Hashable { public // FIXME(cocoa-index): Make inlinable func hash(into hasher: inout Hasher) { #if _runtime(_ObjC) guard _isNative else { hasher.combine(1 as UInt8) hasher.combine(_asCocoa._offset) return } hasher.combine(0 as UInt8) unsafe hasher.combine(_asNative.bucket.offset) #else unsafe hasher.combine(_asNative.bucket.offset) #endif } } extension Dictionary { /// An iterator over the members of a `Dictionary`. @frozen public struct Iterator { // Dictionary has a separate IteratorProtocol and Index because of // efficiency and implementability reasons. // // Native dictionaries have efficient indices. // Bridged NSDictionary instances don't. // // Even though fast enumeration is not suitable for implementing // Index, which is multi-pass, it is suitable for implementing a // IteratorProtocol, which is being consumed as iteration proceeds. @usableFromInline @frozen internal enum _Variant { case native(_NativeDictionary.Iterator) #if _runtime(_ObjC) case cocoa(__CocoaDictionary.Iterator) #endif } @usableFromInline internal var _variant: _Variant @inlinable internal init(_variant: __owned _Variant) { self._variant = _variant } @inlinable internal init(_native: __owned _NativeDictionary.Iterator) { self.init(_variant: .native(_native)) } #if _runtime(_ObjC) @inlinable internal init(_cocoa: __owned __CocoaDictionary.Iterator) { self.init(_variant: .cocoa(_cocoa)) } #endif } } extension Dictionary.Iterator._Variant: @unchecked Sendable where Key: Sendable, Value: Sendable {} extension Dictionary.Iterator { #if _runtime(_ObjC) @usableFromInline @_transparent internal var _guaranteedNative: Bool { return _canBeClass(Key.self) == 0 || _canBeClass(Value.self) == 0 } /// Allow the optimizer to consider the surrounding code unreachable if /// Dictionary is guaranteed to be native. @usableFromInline @_transparent internal func _cocoaPath() { if _guaranteedNative { _conditionallyUnreachable() } } @usableFromInline @_transparent internal var _isNative: Bool { switch _variant { case .native: return true case .cocoa: _cocoaPath() return false } } #endif @usableFromInline @_transparent internal var _asNative: _NativeDictionary.Iterator { get { switch _variant { case .native(let nativeIterator): return nativeIterator #if _runtime(_ObjC) case .cocoa: _internalInvariantFailure("internal error: does not contain a native index") #endif } } set { self._variant = .native(newValue) } } #if _runtime(_ObjC) @usableFromInline @_transparent internal var _asCocoa: __CocoaDictionary.Iterator { get { switch _variant { case .native: _internalInvariantFailure("internal error: does not contain a Cocoa index") case .cocoa(let cocoa): return cocoa } } } #endif } extension Dictionary.Iterator: IteratorProtocol { /// Advances to the next element and returns it, or `nil` if no next element /// exists. /// /// Once `nil` has been returned, all subsequent calls return `nil`. @inlinable @inline(__always) public mutating func next() -> (key: Key, value: Value)? { #if _runtime(_ObjC) guard _isNative else { if let (cocoaKey, cocoaValue) = _asCocoa.next() { let nativeKey = _forceBridgeFromObjectiveC(cocoaKey, Key.self) let nativeValue = _forceBridgeFromObjectiveC(cocoaValue, Value.self) return (nativeKey, nativeValue) } return nil } #endif return _asNative.next() } } #if SWIFT_ENABLE_REFLECTION extension Dictionary.Iterator: CustomReflectable { /// A mirror that reflects the iterator. public var customMirror: Mirror { return Mirror( self, children: EmptyCollection<(label: String?, value: Any)>()) } } extension Dictionary: CustomReflectable { /// A mirror that reflects the dictionary. public var customMirror: Mirror { let style = Mirror.DisplayStyle.dictionary return Mirror(self, unlabeledChildren: self, displayStyle: style) } } #endif extension 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()`. @inlinable public mutating func popFirst() -> Element? { guard !isEmpty else { return nil } return remove(at: startIndex) } /// The total number of key-value pairs that the dictionary can contain without /// allocating new storage. @inlinable public var capacity: Int { return _variant.capacity } /// Reserves enough space to store the specified number of key-value pairs. /// /// If you are adding a known number of key-value pairs to a dictionary, use this /// method to avoid multiple reallocations. This method ensures that the /// dictionary has unique, mutable, contiguous storage, with space allocated /// for at least the requested number of key-value pairs. /// /// Calling the `reserveCapacity(_:)` method on a dictionary with bridged /// storage triggers a copy to contiguous storage even if the existing /// storage has room to store `minimumCapacity` key-value pairs. /// /// - Parameter minimumCapacity: The requested number of key-value pairs to /// store. public // FIXME(reserveCapacity): Should be inlinable mutating func reserveCapacity(_ minimumCapacity: Int) { _variant.reserveCapacity(minimumCapacity) _internalInvariant(self.capacity >= minimumCapacity) } } public typealias DictionaryIndex = Dictionary.Index public typealias DictionaryIterator = Dictionary.Iterator extension Dictionary: @unchecked Sendable where Key: Sendable, Value: Sendable {} extension Dictionary.Keys: @unchecked Sendable where Key: Sendable, Value: Sendable {} extension Dictionary.Values: @unchecked Sendable where Key: Sendable, Value: Sendable {} extension Dictionary.Keys.Iterator: @unchecked Sendable where Key: Sendable, Value: Sendable {} extension Dictionary.Values.Iterator: @unchecked Sendable where Key: Sendable, Value: Sendable {} extension Dictionary.Index: @unchecked Sendable where Key: Sendable, Value: Sendable {} extension Dictionary.Iterator: @unchecked Sendable where Key: Sendable, Value: Sendable {}