1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
|
/*
This source file is part of the Swift.org open source project
Copyright (c) 2018 Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception
See http://swift.org/LICENSE.txt for license information
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
*/
/// A generic collection to store key-value pairs in the order they were inserted in.
///
/// This is modelled after the stdlib's Dictionary.
public struct OrderedDictionary<Key: Hashable, Value> {
/// The element type of a dictionary: a tuple containing an individual
/// key-value pair.
public typealias Element = (key: Key, value: Value)
/// The underlying storage for the OrderedDictionary.
fileprivate var array: [Key]
fileprivate var dict: [Key: Value]
/// Create an empty OrderedDictionary object.
public init() {
self.array = []
self.dict = [:]
}
/// 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.
public subscript(key: Key) -> Value? {
get {
return dict[key]
}
set {
if let newValue = newValue {
updateValue(newValue, forKey: key)
} else {
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.
@discardableResult
public mutating func updateValue(_ value: Value, forKey key: Key) -> Value? {
// If there is already a value for this key, replace and return the old value.
if let oldValue = dict[key] {
dict[key] = value
return oldValue
}
// Otherwise, create a new entry.
dict[key] = value
array.append(key)
return nil
}
/// 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.
@discardableResult
public mutating func removeValue(forKey key: Key) -> Value? {
guard let value = dict[key] else {
return nil
}
dict[key] = nil
array.remove(at: array.firstIndex(of: key)!)
return value
}
/// An array containing just the values of the ordered dictionary.
public var values: [Value] {
return self.array.map { self.dict[$0]! }
}
/// Remove all key-value pairs from the ordered dictionary.
public mutating func removeAll() {
self.array.removeAll()
self.dict.removeAll()
}
}
extension OrderedDictionary: ExpressibleByDictionaryLiteral {
public init(dictionaryLiteral elements: (Key, Value)...) {
self.init()
for element in elements {
updateValue(element.1, forKey: element.0)
}
}
}
extension OrderedDictionary: CustomStringConvertible {
public var description: String {
var string = "["
for (idx, key) in array.enumerated() {
string += "\(key): \(dict[key]!)"
if idx != array.count - 1 {
string += ", "
}
}
string += "]"
return string
}
}
extension OrderedDictionary: RandomAccessCollection {
public var startIndex: Int { return array.startIndex }
public var endIndex: Int { return array.endIndex }
public subscript(index: Int) -> Element {
let key = array[index]
let value = dict[key]!
return (key, value)
}
}
extension OrderedDictionary: Sendable where Key: Sendable, Value: Sendable {}
|