• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
3 // found in the LICENSE file.
4 
5 #ifndef MOJO_PUBLIC_CPP_BINDINGS_MAP_H_
6 #define MOJO_PUBLIC_CPP_BINDINGS_MAP_H_
7 
8 #include <stddef.h>
9 #include <map>
10 #include <unordered_map>
11 #include <utility>
12 
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 {
21 
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.
Map()45   Map() : is_null_(false) {}
46   // Constructs a null map.
Map(std::nullptr_t null_pointer)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|.
Map(mojo::Array<Key> keys,mojo::Array<Value> 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 
~Map()57   ~Map() {}
58 
Map(std::map<Key,Value> && other)59   Map(std::map<Key, Value>&& other) : map_(std::move(other)), is_null_(false) {}
Map(Map && other)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>
From(const U & other)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>
To()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).
is_null()93   bool is_null() const { return is_null_; }
94 
95   // Indicates whether the map is empty (which is distinct from null).
empty()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.
size()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.
insert(const Key & key,const Value & value)104   void insert(const Key& key, const Value& value) {
105     is_null_ = false;
106     map_.insert(std::make_pair(key, value));
107   }
insert(const Key & key,Value && value)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.
at(const Key & key)115   Value& at(const Key& key) { return map_.at(key); }
at(const Key & 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).
SetToEmpty()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.
storage()136   const std::map<Key, Value>& storage() const { return map_; }
137 
138   // Passes the underlying storage and resets this map to null.
PassStorage()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).
Swap(Map<Key,Value> * other)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.
Swap(std::map<Key,Value> * other)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.
DecomposeMapTo(mojo::Array<Key> * keys,mojo::Array<Value> * values)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).
Clone()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.
Equals(const Map & other)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.
begin()224   ConstIterator begin() const { return map_.begin(); }
begin()225   Iterator begin() { return map_.begin(); }
226 
end()227   ConstIterator end() const { return map_.end(); }
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().
find(const Key & key)232   ConstIterator find(const Key& key) const { return map_.find(key); }
find(const Key & 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).
Testable()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 
Take(Map * other)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 }  // namespace mojo
303 
304 #endif  // MOJO_PUBLIC_CPP_BINDINGS_MAP_H_
305