]>
Commit | Line | Data |
---|---|---|
f67539c2 TL |
1 | /* |
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 | ||
20 | public struct TMap<Key : TSerializable & Hashable, Value : TSerializable>: Collection, ExpressibleByDictionaryLiteral, Hashable, TSerializable { | |
21 | public typealias Storage = Dictionary<Key, Value> | |
22 | public typealias Element = Storage.Element | |
23 | public typealias Index = Storage.Index | |
24 | public typealias IndexDistance = Int | |
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 storage.updateValue(value, forKey: key) | |
37 | } | |
38 | ||
39 | public mutating func removeValueForKey(_ key: Key) -> Value? { | |
40 | return storage.removeValue(forKey: key) | |
41 | } | |
42 | ||
43 | public init(minimumCapacity: Int) { | |
44 | storage = Storage(minimumCapacity: minimumCapacity) | |
45 | } | |
46 | ||
47 | /// init from Dictionary<K,V> | |
48 | public init(_ dict: [Key: Value]) { | |
49 | storage = dict | |
50 | } | |
51 | ||
52 | /// read only access to storage if needed as Dictionary<K,V> | |
53 | public var dictionary: [Key: Value] { | |
54 | return storage | |
55 | } | |
56 | ||
57 | public subscript (key: Key) -> Value? { | |
58 | get { | |
59 | return storage[key] | |
60 | } | |
61 | set { | |
62 | storage[key] = newValue | |
63 | } | |
64 | } | |
65 | ||
66 | /// Mark: Collection | |
67 | ||
68 | public var indices: Indices { | |
69 | return storage.indices | |
70 | } | |
71 | ||
72 | public func distance(from start: Index, to end: Index) -> IndexDistance { | |
73 | return storage.distance(from: start, to: end) | |
74 | } | |
75 | ||
76 | public func index(_ i: Index, offsetBy n: IndexDistance) -> Index { | |
77 | return storage.index(i, offsetBy: n) | |
78 | } | |
79 | ||
80 | public func index(_ i: Index, offsetBy n: IndexDistance, limitedBy limit: Index) -> Index? { | |
81 | return storage.index(i, offsetBy: n, limitedBy: limit) | |
82 | } | |
83 | ||
84 | public subscript(position: Index) -> Element { | |
85 | return storage[position] | |
86 | } | |
87 | ||
88 | /// Mark: IndexableBase | |
89 | ||
90 | public var startIndex: Index { return storage.startIndex } | |
91 | public var endIndex: Index { return storage.endIndex } | |
92 | public func index(after i: Index) -> Index { | |
93 | return storage.index(after: i) | |
94 | } | |
95 | ||
96 | public func formIndex(after i: inout Index) { | |
97 | storage.formIndex(after: &i) | |
98 | } | |
99 | ||
100 | public subscript(bounds: Range<Index>) -> SubSequence { | |
101 | return storage[bounds] | |
102 | } | |
103 | ||
104 | /// Mark: DictionaryLiteralConvertible | |
105 | ||
106 | public init(dictionaryLiteral elements: (Key, Value)...) { | |
107 | storage = Storage() | |
108 | for (key, value) in elements { | |
109 | storage[key] = value | |
110 | } | |
111 | } | |
112 | ||
113 | /// Mark: Hashable | |
114 | ||
115 | public var hashValue: Int { | |
116 | let prime = 31 | |
117 | var result = 1 | |
118 | for (key, value) in storage { | |
119 | result = prime &* result &+ key.hashValue | |
120 | result = prime &* result &+ value.hashValue | |
121 | } | |
122 | return result | |
123 | } | |
124 | ||
125 | /// Mark: TSerializable | |
126 | ||
127 | public static var thriftType : TType { return .map } | |
128 | public init() { | |
129 | storage = Storage() | |
130 | } | |
131 | ||
132 | public static func read(from proto: TProtocol) throws -> TMap { | |
133 | ||
134 | let (keyType, valueType, size) = try proto.readMapBegin() | |
135 | if size > 0 { | |
136 | if keyType != Key.thriftType { | |
137 | throw TProtocolError(error: .invalidData, | |
138 | message: "Unexpected TMap Key Type", | |
139 | extendedError: .unexpectedType(type: keyType)) | |
140 | } | |
141 | if valueType != Value.thriftType { | |
142 | throw TProtocolError(error: .invalidData, | |
143 | message: "Unexpected TMap Value Type", | |
144 | extendedError: .unexpectedType(type: valueType)) | |
145 | } | |
146 | } | |
147 | ||
148 | var map = TMap() | |
149 | for _ in 0..<size { | |
150 | let key = try Key.read(from: proto) | |
151 | let value = try Value.read(from: proto) | |
152 | map.storage[key] = value | |
153 | } | |
154 | try proto.readMapEnd() | |
155 | return map | |
156 | } | |
157 | ||
158 | public func write(to proto: TProtocol) throws { | |
159 | try proto.writeMapBegin(keyType: Key.thriftType, | |
160 | valueType: Value.thriftType, size: Int32(self.count)) | |
161 | for (key, value) in self.storage { | |
162 | try Key.write(key, to: proto) | |
163 | try Value.write(value, to: proto) | |
164 | } | |
165 | try proto.writeMapEnd() | |
166 | } | |
167 | } | |
168 | ||
169 | /// Mark: CustomStringConvertible, CustomDebugStringConvertible | |
170 | ||
171 | extension TMap : CustomStringConvertible, CustomDebugStringConvertible { | |
172 | ||
173 | public var description : String { | |
174 | return storage.description | |
175 | } | |
176 | ||
177 | public var debugDescription : String { | |
178 | return storage.debugDescription | |
179 | } | |
180 | ||
181 | } | |
182 | ||
183 | /// Mark: Equatable | |
184 | ||
185 | public func ==<Key, Value>(lhs: TMap<Key,Value>, rhs: TMap<Key, Value>) -> Bool { | |
186 | if lhs.count != rhs.count { | |
187 | return false | |
188 | } | |
189 | return lhs.storage.elementsEqual(rhs.storage) { $0.key == $1.key && $0.value == $1.value } | |
190 | } |