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