blob: 8655a9e2e8f9215ff02f2c8de978ebfa6c1372d7 [file] [log] [blame]
Igor Murashkinaaebaa02015-01-26 10:55:53 -08001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef ART_RUNTIME_BASE_VARIANT_MAP_H_
18#define ART_RUNTIME_BASE_VARIANT_MAP_H_
19
20#include <memory.h>
21#include <map>
22#include <utility>
23
24namespace art {
25
26//
27// A variant map is a heterogenous, type safe key->value map. It allows
28// for multiple different value types to be stored dynamically in the same map.
29//
30// It provides the following interface in a nutshell:
31//
32// struct VariantMap {
33// template <typename TValue>
34// TValue* Get(Key<T> key); // nullptr if the value was never set, otherwise the value.
35//
36// template <typename TValue>
37// void Set(Key<T> key, TValue value);
38// };
39//
40// Since the key is strongly typed at compile-time, it is impossible to accidentally
41// read/write a value with a different type than the key at either compile-time or run-time.
42//
43// Do not use VariantMap/VariantMapKey directly. Instead subclass each of them and use
44// the subclass, for example:
45//
46// template <typename TValue>
47// struct FruitMapKey : VariantMapKey<TValue> {
48// FruitMapKey() {}
49// };
50//
51// struct FruitMap : VariantMap<FruitMap, FruitMapKey> {
52// // This 'using' line is necessary to inherit the variadic constructor.
53// using VariantMap<FruitMap, FruitMapKey>::VariantMap;
54//
55// // Make the next '4' usages of Key slightly shorter to type.
56// template <typename TValue>
57// using Key = FruitMapKey<TValue>;
58//
59// static const Key<int> Apple;
60// static const Key<double> Orange;
61// static const Key<std::string> Banana;
62// };
63//
64// const FruitMap::Key<int> FruitMap::Apple;
65// const FruitMap::Key<double> FruitMap::Orange;
66// const FruitMap::Key<std::string> Banana;
67//
68// See variant_map_test.cc for more examples.
69//
70
71// Implementation details for VariantMap.
72namespace detail {
73 // Allocate a unique counter value each time it's called.
74 struct VariantMapKeyCounterAllocator {
75 static size_t AllocateCounter() {
76 static size_t counter = 0;
77 counter++;
78
79 return counter;
80 }
81 };
82
83 // Type-erased version of VariantMapKey<T>
84 struct VariantMapKeyRaw {
85 // TODO: this may need to call a virtual function to support string comparisons
86 bool operator<(const VariantMapKeyRaw& other) const {
87 return key_counter_ < other.key_counter_;
88 }
89
90 // The following functions need to be virtual since we don't know the compile-time type anymore:
91
92 // Clone the key, creating a copy of the contents.
93 virtual VariantMapKeyRaw* Clone() const = 0;
94
95 // Delete a value whose runtime type is that of the non-erased key's TValue.
96 virtual void ValueDelete(void* value) const = 0;
97
98 // Clone a value whose runtime type is that of the non-erased key's TValue.
99 virtual void* ValueClone(void* value) const = 0;
100
101 // Compare one key to another (same as operator<).
102 virtual bool Compare(const VariantMapKeyRaw* other) const {
103 if (other == nullptr) {
104 return false;
105 }
106 return key_counter_ < other->key_counter_;
107 }
108
109 virtual ~VariantMapKeyRaw() {}
110
111 protected:
112 VariantMapKeyRaw()
113 : key_counter_(VariantMapKeyCounterAllocator::AllocateCounter()) {}
114 // explicit VariantMapKeyRaw(size_t counter)
115 // : key_counter_(counter) {}
116
117 size_t GetCounter() const {
118 return key_counter_;
119 }
120
121 protected:
122 // Avoid the object slicing problem; use Clone() instead.
Andreas Gampec801f0d2015-02-24 20:55:16 -0800123 VariantMapKeyRaw(const VariantMapKeyRaw&) = default;
124 VariantMapKeyRaw(VariantMapKeyRaw&&) = default;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800125
126 private:
127 size_t key_counter_; // Runtime type ID. Unique each time a new type is reified.
128 };
129} // namespace detail
130
131// The base type for keys used by the VariantMap. Users must subclass this type.
132template <typename TValue>
133struct VariantMapKey : detail::VariantMapKeyRaw {
134 // Instantiate a default value for this key. If an explicit default value was provided
135 // then that is used. Otherwise, the default value for the type TValue{} is returned.
136 TValue CreateDefaultValue() const {
137 if (default_value_ == nullptr) {
138 return TValue{}; // NOLINT [readability/braces] [4]
139 } else {
140 return TValue(*default_value_);
141 }
142 }
143
144 protected:
145 // explicit VariantMapKey(size_t counter) : detail::VariantMapKeyRaw(counter) {}
146 explicit VariantMapKey(const TValue& default_value)
147 : default_value_(std::make_shared<TValue>(default_value)) {}
148 explicit VariantMapKey(TValue&& default_value)
149 : default_value_(std::make_shared<TValue>(default_value)) {}
150 VariantMapKey() {}
151 virtual ~VariantMapKey() {}
152
153 private:
154 virtual VariantMapKeyRaw* Clone() const {
155 return new VariantMapKey<TValue>(*this);
156 }
157
158 virtual void* ValueClone(void* value) const {
159 if (value == nullptr) {
160 return nullptr;
161 }
162
163 TValue* strong_value = reinterpret_cast<TValue*>(value);
164 return new TValue(*strong_value);
165 }
166
167 virtual void ValueDelete(void* value) const {
168 if (value == nullptr) {
169 return;
170 }
171
172 // Smartly invoke the proper delete/delete[]/etc
173 const std::default_delete<TValue> deleter = std::default_delete<TValue>();
174 deleter(reinterpret_cast<TValue*>(value));
175 }
176
Andreas Gampec801f0d2015-02-24 20:55:16 -0800177 VariantMapKey(const VariantMapKey&) = default;
178 VariantMapKey(VariantMapKey&&) = default;
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800179
180 template <typename Base, template <typename TV> class TKey> friend struct VariantMap;
181
182 // Store a prototype of the key's default value, for usage with VariantMap::GetOrDefault
183 std::shared_ptr<TValue> default_value_;
184};
185
186// Implementation details for a stringified VariantMapStringKey.
187namespace detail {
188 struct VariantMapStringKeyRegistry {
189 // TODO
190 };
191} // namespace detail
192
193// Alternative base type for all keys used by VariantMap, supports runtime strings as the name.
194template <typename TValue>
195struct VariantMapStringKey : VariantMapKey<TValue> {
196 explicit VariantMapStringKey(const char* name)
197 : // VariantMapKey(/*std::hash<std::string>()(name)*/),
198 name_(name) {
199 }
200
201 private:
202 const char* name_;
203};
204
205// A variant map allows type-safe heteregeneous key->value mappings.
206// All possible key types must be specified at compile-time. Values may be added/removed
207// at runtime.
208template <typename Base, template <typename TV> class TKey>
209struct VariantMap {
210 // Allow users of this static interface to use the key type.
211 template <typename TValue>
212 using Key = TKey<TValue>;
213
214 // Look up the value from the key. The pointer becomes invalid if this key is overwritten/removed.
215 // A null value is returned only when the key does not exist in this map.
216 template <typename TValue>
217 const TValue* Get(const TKey<TValue>& key) const {
218 return GetValuePtr(key);
219 }
220
221 // Look up the value from the key. The pointer becomes invalid if this key is overwritten/removed.
222 // A null value is returned only when the key does not exist in this map.
223 template <typename TValue>
224 TValue* Get(const TKey<TValue>& key) {
225 return GetValuePtr(key);
226 }
227
228 // Lookup the value from the key. If it was not set in the map, return the default value.
229 // The default value is either the key's default, or TValue{} if the key doesn't have a default.
230 template <typename TValue>
231 TValue GetOrDefault(const TKey<TValue>& key) const {
232 auto* ptr = Get(key);
233 return (ptr == nullptr) ? key.CreateDefaultValue() : *ptr;
234 }
235
236 private:
237 // TODO: move to detail, or make it more generic like a ScopeGuard(function)
238 template <typename TValue>
239 struct ScopedRemove {
240 ScopedRemove(VariantMap& map, const TKey<TValue>& key) : map_(map), key_(key) {}
241 ~ScopedRemove() {
242 map_.Remove(key_);
243 }
244
245 VariantMap& map_;
246 const TKey<TValue>& key_;
247 };
248
249 public:
250 // Release the value from the key. If it was not set in the map, returns the default value.
251 // If the key was set, it is removed as a side effect.
252 template <typename TValue>
253 TValue ReleaseOrDefault(const TKey<TValue>& key) {
254 ScopedRemove<TValue> remove_on_return(*this, key);
255
256 TValue* ptr = Get(key);
257 if (ptr != nullptr) {
258 return std::move(*ptr);
259 } else {
260 TValue default_value = key.CreateDefaultValue();
261 return std::move(default_value);
262 }
263 }
264
265 // See if a value is stored for this key.
266 template <typename TValue>
267 bool Exists(const TKey<TValue>& key) const {
268 return GetKeyValueIterator(key) != storage_map_.end();
269 }
270
271 // Set a value for a given key, overwriting the previous value if any.
272 template <typename TValue>
273 void Set(const TKey<TValue>& key, const TValue& value) {
Igor Murashkin2798da12015-02-06 17:59:39 -0800274 // Clone the value first, to protect against &value == GetValuePtr(key).
275 auto* new_value = new TValue(value);
276
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800277 Remove(key);
Igor Murashkin2798da12015-02-06 17:59:39 -0800278 storage_map_.insert({{key.Clone(), new_value}});
Igor Murashkinaaebaa02015-01-26 10:55:53 -0800279 }
280
281 // Set a value for a given key, only if there was no previous value before.
282 // Returns true if the value was set, false if a previous value existed.
283 template <typename TValue>
284 bool SetIfMissing(const TKey<TValue>& key, const TValue& value) {
285 TValue* ptr = Get(key);
286 if (ptr == nullptr) {
287 Set(key, value);
288 return true;
289 }
290 return false;
291 }
292
293 // Remove the value for a given key, or a no-op if there was no previously set value.
294 template <typename TValue>
295 void Remove(const TKey<TValue>& key) {
296 StaticAssertKeyType<TValue>();
297
298 auto&& it = GetKeyValueIterator(key);
299 if (it != storage_map_.end()) {
300 key.ValueDelete(it->second);
301 delete it->first;
302 storage_map_.erase(it);
303 }
304 }
305
306 // Remove all key/value pairs.
307 void Clear() {
308 DeleteStoredValues();
309 storage_map_.clear();
310 }
311
312 // How many key/value pairs are stored in this map.
313 size_t Size() const {
314 return storage_map_.size();
315 }
316
317 // Construct an empty map.
318 explicit VariantMap() {}
319
320 template <typename ... TKeyValue>
321 explicit VariantMap(const TKeyValue& ... key_value_list) {
322 static_assert(sizeof...(TKeyValue) % 2 == 0, "Must be an even number of key/value elements");
323 InitializeParameters(key_value_list...);
324 }
325
326 // Create a new map from an existing map, copying all the key/value pairs.
327 VariantMap(const VariantMap& other) {
328 operator=(other);
329 }
330
331 // Copy the key/value pairs from the other map into this one. Existing key/values are cleared.
332 VariantMap& operator=(const VariantMap& other) {
333 if (this == &other) {
334 return *this;
335 }
336
337 Clear();
338
339 for (auto&& kv_pair : other.storage_map_) {
340 const detail::VariantMapKeyRaw* raw_key_other = kv_pair.first;
341 void* value = kv_pair.second;
342
343 detail::VariantMapKeyRaw* cloned_raw_key = raw_key_other->Clone();
344 void* cloned_value = raw_key_other->ValueClone(value);
345
346 storage_map_.insert({{ cloned_raw_key, cloned_value }});
347 }
348
349 return *this;
350 }
351
352 // Create a new map by moving an existing map into this one. The other map becomes empty.
353 VariantMap(VariantMap&& other) {
354 operator=(std::forward<VariantMap>(other));
355 }
356
357 // Move the existing map's key/value pairs into this one. The other map becomes empty.
358 VariantMap& operator=(VariantMap&& other) {
359 if (this != &other) {
360 Clear();
361 storage_map_.swap(other.storage_map_);
362 other.storage_map_.clear();
363 }
364 return *this;
365 }
366
367 ~VariantMap() {
368 DeleteStoredValues();
369 }
370
371 private:
372 void InitializeParameters() {}
373
374 template <typename TK, typename TValue, typename ... Rest>
375 void InitializeParameters(const TK& key, const TValue& value, const Rest& ... rest) {
376 static_assert(
377 std::is_same<TK, TKey<TValue>>::value, "The 0th/2nd/4th/etc parameters must be a key");
378
379 const TKey<TValue>& key_refined = key;
380
381 Set(key_refined, value);
382 InitializeParameters(rest...);
383 }
384
385 // Custom key comparator for std::map, needed since we are storing raw pointers as the keys.
386 struct KeyComparator {
387 bool operator()(const detail::VariantMapKeyRaw* lhs,
388 const detail::VariantMapKeyRaw* rhs) const {
389 if (lhs == nullptr) {
390 return lhs != rhs;
391 }
392
393 return lhs->Compare(rhs);
394 }
395 };
396
397 // Map of key pointers to value pointers. Pointers are never null.
398 using StorageMap = std::map<const detail::VariantMapKeyRaw*, void*, KeyComparator>;
399
400 template <typename TValue>
401 typename StorageMap::iterator GetKeyValueIterator(const TKey<TValue>& key) {
402 StaticAssertKeyType<TValue>();
403
404 const TKey<TValue>* key_ptr = &key;
405 const detail::VariantMapKeyRaw* raw_ptr = key_ptr;
406 return storage_map_.find(raw_ptr);
407 }
408
409 template <typename TValue>
410 typename StorageMap::const_iterator GetKeyValueIterator(const TKey<TValue>& key) const {
411 StaticAssertKeyType<TValue>();
412
413 const TKey<TValue>* key_ptr = &key;
414 const detail::VariantMapKeyRaw* raw_ptr = key_ptr;
415 return storage_map_.find(raw_ptr);
416 }
417
418 template <typename TValue>
419 TValue* GetValuePtr(const TKey<TValue>& key) {
420 return const_cast<TValue*>(GetValueConstPtr(key));
421 }
422
423 template <typename TValue>
424 const TValue* GetValuePtr(const TKey<TValue>& key) const {
425 return GetValueConstPtr(key);
426 }
427
428 template <typename TValue>
429 const TValue* GetValueConstPtr(const TKey<TValue>& key) const {
430 auto&& it = GetKeyValueIterator(key);
431 if (it == storage_map_.end()) {
432 return nullptr;
433 }
434
435 return reinterpret_cast<const TValue*>(it->second);
436 }
437
438 template <typename TValue>
439 static void StaticAssertKeyType() {
440 static_assert(std::is_base_of<VariantMapKey<TValue>, TKey<TValue>>::value,
441 "The provided key type (TKey) must be a subclass of VariantMapKey");
442 }
443
444 void DeleteStoredValues() {
445 for (auto&& kv_pair : storage_map_) {
446 kv_pair.first->ValueDelete(kv_pair.second);
447 delete kv_pair.first;
448 }
449 }
450
451 StorageMap storage_map_;
452};
453
454} // namespace art
455
456#endif // ART_RUNTIME_BASE_VARIANT_MAP_H_