blob: 89803773949cafff8cf914bf4649013ff86a043d [file] [log] [blame]
Chris Simpsona9b6c702018-04-08 07:11:37 -04001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20public struct TMap<Key : TSerializable & Hashable, Value : TSerializable>: Collection, ExpressibleByDictionaryLiteral, Hashable, TSerializable {
Chris Simpson2566ecd2018-08-29 14:40:44 -040021 public typealias Storage = Dictionary<Key, Value>
Chris Simpsona9b6c702018-04-08 07:11:37 -040022 public typealias Element = Storage.Element
23 public typealias Index = Storage.Index
24 public typealias IndexDistance = Storage.IndexDistance
25 public typealias Indices = Storage.Indices
26 public typealias SubSequence = Storage.SubSequence
27 internal var storage = Storage()
28
29 /// Mark: Be Like Dictionary
30
31 public func indexForKey(_ key: Key) -> Index? {
32 return storage.index(forKey: key)
33 }
34
35 public mutating func updateValue(_ value: Value, forKey key: Key) -> Value? {
36 return updateValue(value, forKey: key)
37 }
38
39 public mutating func removeAtIndex(_ index: DictionaryIndex<Key, Value>) -> (Key, Value) {
40 return removeAtIndex(index)
41 }
42
43 public mutating func removeValueForKey(_ key: Key) -> Value? {
44 return storage.removeValue(forKey: key)
45 }
46
47 public init(minimumCapacity: Int) {
48 storage = Storage(minimumCapacity: minimumCapacity)
49 }
50
51 /// init from Dictionary<K,V>
52 public init(_ dict: [Key: Value]) {
53 storage = dict
54 }
55
56 /// read only access to storage if needed as Dictionary<K,V>
57 public var dictionary: [Key: Value] {
58 return storage
59 }
60
61 public subscript (key: Key) -> Value? {
62 get {
63 return storage[key]
64 }
65 set {
66 storage[key] = newValue
67 }
68 }
69
70 /// Mark: Collection
71
72 public var indices: Indices {
73 return storage.indices
74 }
75
76 public func distance(from start: Index, to end: Index) -> IndexDistance {
77 return storage.distance(from: start, to: end)
78 }
79
80 public func index(_ i: Index, offsetBy n: IndexDistance) -> Index {
81 return storage.index(i, offsetBy: n)
82 }
83
84 public func index(_ i: Index, offsetBy n: IndexDistance, limitedBy limit: Index) -> Index? {
85 return storage.index(i, offsetBy: n, limitedBy: limit)
86 }
87
88 public subscript(position: Index) -> Element {
89 return storage[position]
90 }
91
92 /// Mark: IndexableBase
93
94 public var startIndex: Index { return storage.startIndex }
95 public var endIndex: Index { return storage.endIndex }
96 public func index(after i: Index) -> Index {
97 return storage.index(after: i)
98 }
99
100 public func formIndex(after i: inout Index) {
101 storage.formIndex(after: &i)
102 }
103
104 public subscript(bounds: Range<Index>) -> SubSequence {
105 return storage[bounds]
106 }
107
108 /// Mark: DictionaryLiteralConvertible
109
110 public init(dictionaryLiteral elements: (Key, Value)...) {
111 storage = Storage()
112 for (key, value) in elements {
113 storage[key] = value
114 }
115 }
116
117 /// Mark: Hashable
118
119 public var hashValue: Int {
120 let prime = 31
121 var result = 1
122 for (key, value) in storage {
123 result = prime &* result &+ key.hashValue
124 result = prime &* result &+ value.hashValue
125 }
126 return result
127 }
128
129 /// Mark: TSerializable
130
131 public static var thriftType : TType { return .map }
132 public init() {
133 storage = Storage()
134 }
135
136 public static func read(from proto: TProtocol) throws -> TMap {
137
138 let (keyType, valueType, size) = try proto.readMapBegin()
139 if size > 0 {
140 if keyType != Key.thriftType {
141 throw TProtocolError(error: .invalidData,
142 message: "Unexpected TMap Key Type",
143 extendedError: .unexpectedType(type: keyType))
144 }
145 if valueType != Value.thriftType {
146 throw TProtocolError(error: .invalidData,
147 message: "Unexpected TMap Value Type",
148 extendedError: .unexpectedType(type: valueType))
149 }
150 }
151
152 var map = TMap()
153 for _ in 0..<size {
154 let key = try Key.read(from: proto)
155 let value = try Value.read(from: proto)
156 map.storage[key] = value
157 }
158 try proto.readMapEnd()
159 return map
160 }
161
162 public func write(to proto: TProtocol) throws {
163 try proto.writeMapBegin(keyType: Key.thriftType,
164 valueType: Value.thriftType, size: Int32(self.count))
165 for (key, value) in self.storage {
166 try Key.write(key, to: proto)
167 try Value.write(value, to: proto)
168 }
169 try proto.writeMapEnd()
170 }
171}
172
173/// Mark: CustomStringConvertible, CustomDebugStringConvertible
174
175extension TMap : CustomStringConvertible, CustomDebugStringConvertible {
176
177 public var description : String {
178 return storage.description
179 }
180
181 public var debugDescription : String {
182 return storage.debugDescription
183 }
184
185}
186
187/// Mark: Equatable
188
189public func ==<Key, Value>(lhs: TMap<Key,Value>, rhs: TMap<Key, Value>) -> Bool {
190 if lhs.count != rhs.count {
191 return false
192 }
193 return lhs.storage.elementsEqual(rhs.storage) { $0.key == $1.key && $0.value == $1.value }
194}