Created
May 15, 2020 01:59
-
-
Save dabrahams/b3540deac52bc541031d800f633e24b8 to your computer and use it in GitHub Desktop.
Plain Swift Dictionary uses a tuple as its Element type, which prevents the Element from conforming to anything
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /// A Dictionary with a nominal `Element` type, that can conform to things. | |
| @frozen public struct Dictionary2<Key: Hashable, Value> { | |
| public typealias Base = [Key : Value] | |
| /// A view of a dictionary's keys. | |
| public typealias Keys = Base.Keys | |
| /// A view of a dictionary's values. | |
| public typealias Values = Base.Values | |
| /// The position of a key-value pair in a dictionary. | |
| public typealias Index = Base.Index | |
| /// The underlying Swift Dictionary | |
| public var base: Base | |
| /// Creates an instance equivalent to `base`. | |
| @inlinable public init(_ base: Base) { | |
| self.base = base | |
| } | |
| /// The element type of a dictionary, just like a tuple containing an | |
| /// individual key-value pair, but nominal. | |
| @frozen public struct Element { | |
| public var key: Key | |
| public var value: Value | |
| @inlinable public init(key: Key, value: Value) { | |
| (self.key, self.value) = (key, value) | |
| } | |
| @inlinable | |
| internal init(tuple x: (key: Key, value: Value)) { | |
| (self.key, self.value) = (x.key, x.value) | |
| } | |
| internal var tuple: (key: Key, value: Value) { (key, value) } | |
| } | |
| /// Creates an empty dictionary. | |
| @inlinable public init() { base = .init() } | |
| /// Creates an empty dictionary with preallocated space for at least the | |
| /// specified number of elements. | |
| public init(minimumCapacity: Int) { | |
| base = .init(minimumCapacity: minimumCapacity) | |
| } | |
| /// Creates a new dictionary from the key-value pairs in the given sequence. | |
| @inlinable public init<S>( | |
| uniqueKeysWithValues keysAndValues: S) | |
| where S : Sequence, S.Element == (Key, Value) | |
| { | |
| base = .init(uniqueKeysWithValues: keysAndValues) | |
| } | |
| /// 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. | |
| @inlinable public init<S>( | |
| _ keysAndValues: S, | |
| uniquingKeysWith combine: (Value, Value) throws -> Value | |
| ) rethrows where S : Sequence, S.Element == (Key, Value) { | |
| try base = .init(keysAndValues, uniquingKeysWith: combine) | |
| } | |
| /// 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. | |
| @inlinable public init<S>( | |
| grouping values: S, by keyForValue: (S.Element) throws -> Key) | |
| rethrows where Value == [S.Element], S : Sequence | |
| { | |
| try base = .init(grouping: values, by: keyForValue) | |
| } | |
| /// Returns a new dictionary containing the key-value pairs of the dictionary | |
| /// that satisfy the given predicate. | |
| @available(swift 4.0) | |
| @inlinable public func filter( | |
| _ isIncluded: (Dictionary<Key, Value>.Element) throws -> Bool | |
| ) rethrows -> Dictionary2 { | |
| try .init(base.filter(isIncluded)) | |
| } | |
| /// Accesses the value associated with the given key for reading and writing. | |
| @inlinable public subscript(key: Key) -> Value? { | |
| base[key] | |
| } | |
| /// Accesses the value with the given key. If the dictionary doesn't contain | |
| /// the given key, accesses the provided default value as if the key and | |
| /// default value existed in the dictionary. | |
| @inlinable public subscript( | |
| key: Key, default defaultValue: @autoclosure () -> Value | |
| ) -> Value { | |
| base[key, default: defaultValue()] | |
| } | |
| /// Returns a new dictionary containing the keys of this dictionary with the | |
| /// values transformed by the given closure. | |
| @inlinable public func mapValues<T>( | |
| _ transform: (Value) throws -> T | |
| ) rethrows -> [Key : T] { | |
| try base.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. | |
| @inlinable public func compactMapValues<T>( | |
| _ transform: (Value) throws -> T? | |
| ) rethrows -> [Key : T] { try base.compactMapValues(transform) } | |
| /// Updates the value stored in the dictionary for the given key, or adds a | |
| /// new key-value pair if the key does not exist. | |
| @inlinable public mutating func updateValue( | |
| _ value: Value, forKey key: Key | |
| ) -> Value? { | |
| base.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. | |
| @inlinable public mutating func merge<S>( | |
| _ other: S, | |
| uniquingKeysWith combine: (Value, Value) throws -> Value | |
| ) rethrows where S : Sequence, S.Element == (Key, Value) | |
| { | |
| try base.merge(other, uniquingKeysWith: combine) | |
| } | |
| /// Merges the given dictionary into this dictionary, using a combining | |
| /// closure to determine the value for any duplicate keys. | |
| @inlinable public mutating func merge( | |
| _ other: Self, | |
| uniquingKeysWith combine: (Value, Value) throws -> Value | |
| ) rethrows { | |
| try base.merge(other.base, 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. | |
| @inlinable public func merging<S>( | |
| _ other: S, uniquingKeysWith combine: (Value, Value) throws -> Value | |
| ) rethrows -> Self where S : Sequence, S.Element == (Key, Value) { | |
| try .init(base.merging(other, uniquingKeysWith: combine)) | |
| } | |
| /// Creates a dictionary by merging the given dictionary into this | |
| /// dictionary, using a combining closure to determine the value for | |
| /// duplicate keys. | |
| @inlinable public func merging( | |
| _ other: Self, uniquingKeysWith combine: (Value, Value) throws -> Value | |
| ) rethrows -> Self { | |
| try .init(base.merging(other.base, uniquingKeysWith: combine)) | |
| } | |
| /// Removes and returns the key-value pair at the specified index. | |
| @inlinable public mutating func remove(at index: Index) -> Element { | |
| .init(tuple: base.remove(at: index)) | |
| } | |
| /// Removes the given key and its associated value from the dictionary. | |
| @inlinable public mutating func removeValue(forKey key: Key) -> Value? { | |
| base.removeValue(forKey: key) | |
| } | |
| /// Removes all key-value pairs from the dictionary. | |
| @inlinable public mutating func removeAll( | |
| keepingCapacity keepCapacity: Bool = false | |
| ) { | |
| base.removeAll(keepingCapacity: keepCapacity) | |
| } | |
| /// A collection containing just the keys of the dictionary. | |
| @available(swift 4.0) | |
| @inlinable public var keys: Keys { base.keys } | |
| /// A collection containing just the values of the dictionary. | |
| @available(swift 4.0) | |
| @inlinable public var values: Values { base.values } | |
| /// An iterator over the members of a `Dictionary2<Key, Value>`. | |
| @frozen public struct Iterator : IteratorProtocol { | |
| @usableFromInline | |
| internal typealias Base = Swift.Dictionary<Key,Value>.Iterator | |
| @usableFromInline | |
| init(base: Base) { self.base = base } | |
| @usableFromInline | |
| var base: Base | |
| @inlinable | |
| public mutating func next() -> Element? { | |
| return base.next().map(Element.init(tuple:)) | |
| } | |
| } | |
| /// Removes and returns the first key-value pair of the dictionary if the | |
| /// dictionary isn't empty. | |
| @inlinable public mutating func popFirst() -> Element? { | |
| base.popFirst().map(Element.init(tuple:)) | |
| } | |
| /// The total number of key-value pairs that the dictionary can contain without | |
| /// allocating new storage. | |
| @inlinable public var capacity: Int { base.capacity } | |
| /// Reserves enough space to store the specified number of key-value pairs. | |
| public mutating func reserveCapacity(_ minimumCapacity: Int) { | |
| base.reserveCapacity(minimumCapacity) | |
| } | |
| } | |
| extension Dictionary2 : Collection { | |
| /// The position of the first element in a nonempty dictionary. | |
| @inlinable public var startIndex: Index { base.startIndex } | |
| /// The dictionary's "past the end" position---that is, the position one | |
| /// greater than the last valid subscript argument. | |
| @inlinable public var endIndex: Index { base.endIndex } | |
| /// Returns the position immediately after the given index. | |
| @inlinable public func index(after i: Index) -> Index { | |
| base.index(after: i) | |
| } | |
| /// Replaces the given index with its successor. | |
| @inlinable public func formIndex(after i: inout Index) { | |
| base.formIndex(after: &i) | |
| } | |
| /// Returns the index for the given key. | |
| @inlinable public func index(forKey key: Key) -> Index? { | |
| base.index(forKey: key) | |
| } | |
| /// Accesses the key-value pair at the specified position. | |
| @inlinable public subscript(position: Index) -> Element { | |
| .init(tuple: base[position]) | |
| } | |
| /// The number of key-value pairs in the dictionary. | |
| @inlinable public var count: Int { base.count } | |
| /// A Boolean value that indicates whether the dictionary is empty. | |
| @inlinable public var isEmpty: Bool { base.isEmpty } | |
| } | |
| extension Dictionary2 : Sequence { | |
| /// Returns an iterator over the dictionary's key-value pairs. | |
| @inlinable public func makeIterator() -> Iterator { | |
| return .init(base: base.makeIterator()) | |
| } | |
| } | |
| extension Dictionary2 : CustomReflectable { | |
| /// A mirror that reflects the dictionary. | |
| public var customMirror: Mirror { base.customMirror } | |
| } | |
| /* | |
| extension Dictionary2 : KeyPathIterable { | |
| /// A type that can represent a collection of all key paths of this type. | |
| public typealias AllKeyPaths = [PartialKeyPath<Dictionary2>] | |
| /// A collection of all custom key paths of this value. | |
| public var allKeyPaths: [PartialKeyPath<Dictionary2>] { base.allKeyPaths } | |
| } | |
| */ | |
| extension Dictionary2 : CustomStringConvertible, CustomDebugStringConvertible { | |
| /// A string that represents the contents of the dictionary. | |
| public var description: String { base.description } | |
| /// A string that represents the contents of the dictionary, suitable for | |
| /// debugging. | |
| public var debugDescription: String { base.debugDescription } | |
| } | |
| extension Dictionary2 : Hashable where Value : Hashable {} | |
| extension Dictionary2 : Equatable where Value : Equatable {} | |
| extension Dictionary2 : Decodable where Key : Decodable, Value : Decodable { | |
| /// Creates a new dictionary by decoding from the given decoder. | |
| public init(from decoder: Decoder) throws { | |
| try base = .init(from: decoder) | |
| } | |
| } | |
| extension Dictionary2 : Encodable where Key : Encodable, Value : Encodable { | |
| /// Encodes the contents of this dictionary into the given encoder. | |
| public func encode(to encoder: Encoder) throws { | |
| try base.encode(to: encoder) | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment