OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef MOJO_PUBLIC_CPP_BINDINGS_MAP_H_ | 5 #ifndef MOJO_PUBLIC_CPP_BINDINGS_MAP_H_ |
6 #define MOJO_PUBLIC_CPP_BINDINGS_MAP_H_ | 6 #define MOJO_PUBLIC_CPP_BINDINGS_MAP_H_ |
7 | 7 |
8 #include <stddef.h> | |
9 #include <map> | 8 #include <map> |
10 #include <unordered_map> | 9 #include <unordered_map> |
11 #include <utility> | 10 #include <utility> |
12 | 11 |
13 #include "base/logging.h" | |
14 #include "base/macros.h" | |
15 #include "mojo/public/cpp/bindings/array.h" | |
16 #include "mojo/public/cpp/bindings/lib/map_data_internal.h" | |
17 #include "mojo/public/cpp/bindings/lib/template_util.h" | |
18 #include "mojo/public/cpp/bindings/type_converter.h" | |
19 | |
20 namespace mojo { | 12 namespace mojo { |
21 | 13 |
22 // A move-only map that can handle move-only values. Map has the following | |
23 // characteristics: | |
24 // - The map itself can be null, and this is distinct from empty. | |
25 // - Keys must not be move-only. | |
26 // - The Key-type's "<" operator is used to sort the entries, and also is | |
27 // used to determine equality of the key values. | |
28 // - There can only be one entry per unique key. | |
29 // - Values of move-only types will be moved into the Map when they are added | |
30 // using the insert() method. | |
31 template <typename K, typename V> | |
32 class Map { | |
33 public: | |
34 using Key = K; | |
35 using Value = V; | |
36 | |
37 // Map keys cannot be move only classes. | |
38 static_assert(!internal::IsMoveOnlyType<Key>::value, | |
39 "Map keys cannot be move only types."); | |
40 | |
41 using Iterator = typename std::map<Key, Value>::iterator; | |
42 using ConstIterator = typename std::map<Key, Value>::const_iterator; | |
43 | |
44 // Constructs an empty map. | |
45 Map() : is_null_(false) {} | |
46 // Constructs a null map. | |
47 Map(std::nullptr_t null_pointer) : is_null_(true) {} | |
48 | |
49 // Constructs a non-null Map containing the specified |keys| mapped to the | |
50 // corresponding |values|. | |
51 Map(mojo::Array<Key> keys, mojo::Array<Value> values) : is_null_(false) { | |
52 DCHECK(keys.size() == values.size()); | |
53 for (size_t i = 0; i < keys.size(); ++i) | |
54 map_.insert(std::make_pair(keys[i], std::move(values[i]))); | |
55 } | |
56 | |
57 ~Map() {} | |
58 | |
59 Map(std::map<Key, Value>&& other) : map_(std::move(other)), is_null_(false) {} | |
60 Map(Map&& other) : is_null_(true) { Take(&other); } | |
61 | |
62 Map& operator=(std::map<Key, Value>&& other) { | |
63 is_null_ = false; | |
64 map_ = std::move(other); | |
65 return *this; | |
66 } | |
67 Map& operator=(Map&& other) { | |
68 Take(&other); | |
69 return *this; | |
70 } | |
71 | |
72 Map& operator=(std::nullptr_t null_pointer) { | |
73 is_null_ = true; | |
74 map_.clear(); | |
75 return *this; | |
76 } | |
77 | |
78 // Copies the contents of some other type of map into a new Map using a | |
79 // TypeConverter. A TypeConverter for std::map to Map is defined below. | |
80 template <typename U> | |
81 static Map From(const U& other) { | |
82 return TypeConverter<Map, U>::Convert(other); | |
83 } | |
84 | |
85 // Copies the contents of the Map into some other type of map. A TypeConverter | |
86 // for Map to std::map is defined below. | |
87 template <typename U> | |
88 U To() const { | |
89 return TypeConverter<U, Map>::Convert(*this); | |
90 } | |
91 | |
92 // Indicates whether the map is null (which is distinct from empty). | |
93 bool is_null() const { return is_null_; } | |
94 | |
95 // Indicates whether the map is empty (which is distinct from null). | |
96 bool empty() const { return map_.empty() && !is_null_; } | |
97 | |
98 // Indicates the number of keys in the map, which will be zero if the map is | |
99 // null. | |
100 size_t size() const { return map_.size(); } | |
101 | |
102 // Inserts a key-value pair into the map. Like std::map, this does not insert | |
103 // |value| if |key| is already a member of the map. | |
104 void insert(const Key& key, const Value& value) { | |
105 is_null_ = false; | |
106 map_.insert(std::make_pair(key, value)); | |
107 } | |
108 void insert(const Key& key, Value&& value) { | |
109 is_null_ = false; | |
110 map_.insert(std::make_pair(key, std::move(value))); | |
111 } | |
112 | |
113 // Returns a reference to the value associated with the specified key, | |
114 // crashing the process if the key is not present in the map. | |
115 Value& at(const Key& key) { return map_.at(key); } | |
116 const Value& at(const Key& key) const { return map_.at(key); } | |
117 | |
118 // Returns a reference to the value associated with the specified key, | |
119 // creating a new entry if the key is not already present in the map. A | |
120 // newly-created value will be value-initialized (meaning that it will be | |
121 // initialized by the default constructor of the value type, if any, or else | |
122 // will be zero-initialized). | |
123 Value& operator[](const Key& key) { | |
124 is_null_ = false; | |
125 return map_[key]; | |
126 } | |
127 | |
128 // Sets the map to empty (even if previously it was null). | |
129 void SetToEmpty() { | |
130 is_null_ = false; | |
131 map_.clear(); | |
132 } | |
133 | |
134 // Returns a const reference to the std::map managed by this class. If this | |
135 // object is null, the return value will be an empty map. | |
136 const std::map<Key, Value>& storage() const { return map_; } | |
137 | |
138 // Passes the underlying storage and resets this map to null. | |
139 std::map<Key, Value> PassStorage() { | |
140 is_null_ = true; | |
141 return std::move(map_); | |
142 } | |
143 | |
144 operator const std::map<Key, Value>&() const { return map_; } | |
145 | |
146 // Swaps the contents of this Map with another Map of the same type (including | |
147 // nullness). | |
148 void Swap(Map<Key, Value>* other) { | |
149 std::swap(is_null_, other->is_null_); | |
150 map_.swap(other->map_); | |
151 } | |
152 | |
153 // Swaps the contents of this Map with an std::map containing keys and values | |
154 // of the same type. Since std::map cannot represent the null state, the | |
155 // std::map will be empty if Map is null. The Map will always be left in a | |
156 // non-null state. | |
157 void Swap(std::map<Key, Value>* other) { | |
158 is_null_ = false; | |
159 map_.swap(*other); | |
160 } | |
161 | |
162 // Removes all contents from the Map and places them into parallel key/value | |
163 // arrays. Each key will be copied from the source to the destination, and | |
164 // values will be copied unless their type is designated move-only, in which | |
165 // case they will be moved. Either way, the Map will be left in a null state. | |
166 void DecomposeMapTo(mojo::Array<Key>* keys, mojo::Array<Value>* values) { | |
167 std::vector<Key> key_vector; | |
168 key_vector.reserve(map_.size()); | |
169 std::vector<Value> value_vector; | |
170 value_vector.reserve(map_.size()); | |
171 | |
172 for (auto& entry : map_) { | |
173 key_vector.push_back(entry.first); | |
174 value_vector.push_back(std::move(entry.second)); | |
175 } | |
176 | |
177 map_.clear(); | |
178 is_null_ = true; | |
179 | |
180 keys->Swap(&key_vector); | |
181 values->Swap(&value_vector); | |
182 } | |
183 | |
184 // Returns a new Map that contains a copy of the contents of this map. If the | |
185 // key/value type defines a Clone() method, it will be used; otherwise copy | |
186 // constructor/assignment will be used. | |
187 // | |
188 // Please note that calling this method will fail compilation if the key/value | |
189 // type cannot be cloned (which usually means that it is a Mojo handle type or | |
190 // a type containing Mojo handles). | |
191 Map Clone() const { | |
192 Map result; | |
193 result.is_null_ = is_null_; | |
194 for (auto it = map_.begin(); it != map_.end(); ++it) { | |
195 result.map_.insert(std::make_pair(internal::Clone(it->first), | |
196 internal::Clone(it->second))); | |
197 } | |
198 return result; | |
199 } | |
200 | |
201 // Indicates whether the contents of this map are equal to those of another | |
202 // Map (including nullness). If the key/value type defines an Equals() method, | |
203 // it will be used; otherwise == operator will be used. | |
204 bool Equals(const Map& other) const { | |
205 if (is_null() != other.is_null()) | |
206 return false; | |
207 if (size() != other.size()) | |
208 return false; | |
209 auto i = begin(); | |
210 auto j = other.begin(); | |
211 while (i != end()) { | |
212 if (!internal::Equals(i->first, j->first)) | |
213 return false; | |
214 if (!internal::Equals(i->second, j->second)) | |
215 return false; | |
216 ++i; | |
217 ++j; | |
218 } | |
219 return true; | |
220 } | |
221 | |
222 // Provide read-only iteration over map members in a way similar to STL | |
223 // collections. | |
224 ConstIterator begin() const { return map_.begin(); } | |
225 Iterator begin() { return map_.begin(); } | |
226 | |
227 ConstIterator end() const { return map_.end(); } | |
228 Iterator end() { return map_.end(); } | |
229 | |
230 // Returns the iterator pointing to the entry for |key|, if present, or else | |
231 // returns end(). | |
232 ConstIterator find(const Key& key) const { return map_.find(key); } | |
233 Iterator find(const Key& key) { return map_.find(key); } | |
234 | |
235 private: | |
236 typedef std::map<Key, Value> Map::*Testable; | |
237 | |
238 public: | |
239 // The Map may be used in boolean expressions to determine if it is non-null, | |
240 // but is not implicitly convertible to an actual bool value (which would be | |
241 // dangerous). | |
242 operator Testable() const { return is_null_ ? 0 : &Map::map_; } | |
243 | |
244 private: | |
245 // Forbid the == and != operators explicitly, otherwise Map will be converted | |
246 // to Testable to do == or != comparison. | |
247 template <typename T, typename U> | |
248 bool operator==(const Map<T, U>& other) const = delete; | |
249 template <typename T, typename U> | |
250 bool operator!=(const Map<T, U>& other) const = delete; | |
251 | |
252 void Take(Map* other) { | |
253 operator=(nullptr); | |
254 Swap(other); | |
255 } | |
256 | |
257 std::map<Key, Value> map_; | |
258 bool is_null_; | |
259 | |
260 DISALLOW_COPY_AND_ASSIGN(Map); | |
261 }; | |
262 | |
263 // Copies the contents of an std::map to a new Map, optionally changing the | |
264 // types of the keys and values along the way using TypeConverter. | |
265 template <typename MojoKey, | |
266 typename MojoValue, | |
267 typename STLKey, | |
268 typename STLValue> | |
269 struct TypeConverter<Map<MojoKey, MojoValue>, std::map<STLKey, STLValue>> { | |
270 static Map<MojoKey, MojoValue> Convert( | |
271 const std::map<STLKey, STLValue>& input) { | |
272 Map<MojoKey, MojoValue> result; | |
273 for (auto& pair : input) { | |
274 result.insert(TypeConverter<MojoKey, STLKey>::Convert(pair.first), | |
275 TypeConverter<MojoValue, STLValue>::Convert(pair.second)); | |
276 } | |
277 return result; | |
278 } | |
279 }; | |
280 | |
281 // Copies the contents of a Map to an std::map, optionally changing the types of | |
282 // the keys and values along the way using TypeConverter. | |
283 template <typename MojoKey, | |
284 typename MojoValue, | |
285 typename STLKey, | |
286 typename STLValue> | |
287 struct TypeConverter<std::map<STLKey, STLValue>, Map<MojoKey, MojoValue>> { | |
288 static std::map<STLKey, STLValue> Convert( | |
289 const Map<MojoKey, MojoValue>& input) { | |
290 std::map<STLKey, STLValue> result; | |
291 if (!input.is_null()) { | |
292 for (auto it = input.begin(); it != input.end(); ++it) { | |
293 result.insert(std::make_pair( | |
294 TypeConverter<STLKey, MojoKey>::Convert(it->first), | |
295 TypeConverter<STLValue, MojoValue>::Convert(it->second))); | |
296 } | |
297 } | |
298 return result; | |
299 } | |
300 }; | |
301 | |
302 // TODO(yzshen): These conversion functions should be removed and callsites | 14 // TODO(yzshen): These conversion functions should be removed and callsites |
303 // should be revisited and changed to use the same map type. | 15 // should be revisited and changed to use the same map type. |
304 template <typename Key, typename Value> | 16 template <typename Key, typename Value> |
305 std::unordered_map<Key, Value> MapToUnorderedMap( | 17 std::unordered_map<Key, Value> MapToUnorderedMap( |
306 const std::map<Key, Value>& input) { | 18 const std::map<Key, Value>& input) { |
307 return std::unordered_map<Key, Value>(input.begin(), input.end()); | 19 return std::unordered_map<Key, Value>(input.begin(), input.end()); |
308 } | 20 } |
309 | 21 |
310 template <typename Key, typename Value> | 22 template <typename Key, typename Value> |
311 std::unordered_map<Key, Value> MapToUnorderedMap(std::map<Key, Value>&& input) { | 23 std::unordered_map<Key, Value> MapToUnorderedMap(std::map<Key, Value>&& input) { |
312 return std::unordered_map<Key, Value>(std::make_move_iterator(input.begin()), | 24 return std::unordered_map<Key, Value>(std::make_move_iterator(input.begin()), |
313 std::make_move_iterator(input.end())); | 25 std::make_move_iterator(input.end())); |
314 } | 26 } |
315 | 27 |
316 template <typename Key, typename Value> | 28 template <typename Key, typename Value> |
317 std::map<Key, Value> UnorderedMapToMap( | 29 std::map<Key, Value> UnorderedMapToMap( |
318 const std::unordered_map<Key, Value>& input) { | 30 const std::unordered_map<Key, Value>& input) { |
319 return std::map<Key, Value>(input.begin(), input.end()); | 31 return std::map<Key, Value>(input.begin(), input.end()); |
320 } | 32 } |
321 | 33 |
322 template <typename Key, typename Value> | 34 template <typename Key, typename Value> |
323 std::map<Key, Value> UnorderedMapToMap(std::unordered_map<Key, Value>&& input) { | 35 std::map<Key, Value> UnorderedMapToMap(std::unordered_map<Key, Value>&& input) { |
324 return std::map<Key, Value>(std::make_move_iterator(input.begin()), | 36 return std::map<Key, Value>(std::make_move_iterator(input.begin()), |
325 std::make_move_iterator(input.end())); | 37 std::make_move_iterator(input.end())); |
326 } | 38 } |
327 | 39 |
328 } // namespace mojo | 40 } // namespace mojo |
329 | 41 |
330 #endif // MOJO_PUBLIC_CPP_BINDINGS_MAP_H_ | 42 #endif // MOJO_PUBLIC_CPP_BINDINGS_MAP_H_ |
OLD | NEW |