|  | /* | 
|  | * Copyright (C) 2015 The Android Open Source Project | 
|  | * | 
|  | * Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | * you may not use this file except in compliance with the License. | 
|  | * You may obtain a copy of the License at | 
|  | * | 
|  | *      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | * | 
|  | * Unless required by applicable law or agreed to in writing, software | 
|  | * distributed under the License is distributed on an "AS IS" BASIS, | 
|  | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | * See the License for the specific language governing permissions and | 
|  | * limitations under the License. | 
|  | */ | 
|  |  | 
|  | #ifndef ART_LIBARTBASE_BASE_VARIANT_MAP_H_ | 
|  | #define ART_LIBARTBASE_BASE_VARIANT_MAP_H_ | 
|  |  | 
|  | #include <memory.h> | 
|  | #include <map> | 
|  | #include <type_traits> | 
|  | #include <utility> | 
|  |  | 
|  | #include "android-base/logging.h" | 
|  | #include "stl_util_identity.h" | 
|  |  | 
|  | namespace art { | 
|  |  | 
|  | // | 
|  | // A variant map is a heterogenous, type safe key->value map. It allows | 
|  | // for multiple different value types to be stored dynamically in the same map. | 
|  | // | 
|  | // It provides the following interface in a nutshell: | 
|  | // | 
|  | // struct VariantMap { | 
|  | //   template <typename TValue> | 
|  | //   TValue* Get(Key<T> key);  // null if the value was never set, otherwise the value. | 
|  | // | 
|  | //   template <typename TValue> | 
|  | //   void Set(Key<T> key, TValue value); | 
|  | // }; | 
|  | // | 
|  | // Since the key is strongly typed at compile-time, it is impossible to accidentally | 
|  | // read/write a value with a different type than the key at either compile-time or run-time. | 
|  | // | 
|  | // Do not use VariantMap/VariantMapKey directly. Instead subclass each of them and use | 
|  | // the subclass, for example: | 
|  | // | 
|  | // template <typename TValue> | 
|  | // struct FruitMapKey : VariantMapKey<TValue> { | 
|  | //   FruitMapKey() {} | 
|  | // }; | 
|  | // | 
|  | // struct FruitMap : VariantMap<FruitMap, FruitMapKey> { | 
|  | //   // This 'using' line is necessary to inherit the variadic constructor. | 
|  | //   using VariantMap<FruitMap, FruitMapKey>::VariantMap; | 
|  | // | 
|  | //   // Make the next '4' usages of Key slightly shorter to type. | 
|  | //   template <typename TValue> | 
|  | //   using Key = FruitMapKey<TValue>; | 
|  | // | 
|  | //   static const Key<int> Apple; | 
|  | //   static const Key<double> Orange; | 
|  | //   static const Key<std::string> Banana; | 
|  | // }; | 
|  | // | 
|  | // const FruitMap::Key<int> FruitMap::Apple; | 
|  | // const FruitMap::Key<double> FruitMap::Orange; | 
|  | // const FruitMap::Key<std::string> Banana; | 
|  | // | 
|  | // See variant_map_test.cc for more examples. | 
|  | // | 
|  |  | 
|  | // Implementation details for VariantMap. | 
|  | namespace detail { | 
|  | // Allocate a unique counter value each time it's called. | 
|  | struct VariantMapKeyCounterAllocator { | 
|  | static size_t AllocateCounter() { | 
|  | static size_t counter = 0; | 
|  | counter++; | 
|  |  | 
|  | return counter; | 
|  | } | 
|  | }; | 
|  |  | 
|  | // Type-erased version of VariantMapKey<T> | 
|  | struct VariantMapKeyRaw { | 
|  | // TODO: this may need to call a virtual function to support string comparisons | 
|  | bool operator<(const VariantMapKeyRaw& other) const { | 
|  | return key_counter_ < other.key_counter_; | 
|  | } | 
|  |  | 
|  | // The following functions need to be virtual since we don't know the compile-time type anymore: | 
|  |  | 
|  | // Clone the key, creating a copy of the contents. | 
|  | virtual VariantMapKeyRaw* Clone() const = 0; | 
|  |  | 
|  | // Delete a value whose runtime type is that of the non-erased key's TValue. | 
|  | virtual void ValueDelete(void* value) const = 0; | 
|  |  | 
|  | // Clone a value whose runtime type is that of the non-erased key's TValue. | 
|  | virtual void* ValueClone(void* value) const = 0; | 
|  |  | 
|  | // Compare one key to another (same as operator<). | 
|  | virtual bool Compare(const VariantMapKeyRaw* other) const { | 
|  | if (other == nullptr) { | 
|  | return false; | 
|  | } | 
|  | return key_counter_ < other->key_counter_; | 
|  | } | 
|  |  | 
|  | virtual ~VariantMapKeyRaw() {} | 
|  |  | 
|  | protected: | 
|  | VariantMapKeyRaw() | 
|  | : key_counter_(VariantMapKeyCounterAllocator::AllocateCounter()) {} | 
|  | // explicit VariantMapKeyRaw(size_t counter) | 
|  | //     : key_counter_(counter) {} | 
|  |  | 
|  | size_t GetCounter() const { | 
|  | return key_counter_; | 
|  | } | 
|  |  | 
|  | protected: | 
|  | // Avoid the object slicing problem; use Clone() instead. | 
|  | VariantMapKeyRaw(const VariantMapKeyRaw&) = default; | 
|  | VariantMapKeyRaw(VariantMapKeyRaw&&) = default; | 
|  |  | 
|  | private: | 
|  | size_t key_counter_;  // Runtime type ID. Unique each time a new type is reified. | 
|  | }; | 
|  | }  // namespace detail | 
|  |  | 
|  | // The base type for keys used by the VariantMap. Users must subclass this type. | 
|  | template <typename TValue> | 
|  | struct VariantMapKey : detail::VariantMapKeyRaw { | 
|  | // Instantiate a default value for this key. If an explicit default value was provided | 
|  | // then that is used. Otherwise, the default value for the type TValue{} is returned. | 
|  | TValue CreateDefaultValue() const { | 
|  | if (default_value_ == nullptr) { | 
|  | return TValue{}; | 
|  | } else { | 
|  | return TValue(*default_value_); | 
|  | } | 
|  | } | 
|  |  | 
|  | protected: | 
|  | // explicit VariantMapKey(size_t counter) : detail::VariantMapKeyRaw(counter) {} | 
|  | explicit VariantMapKey(const TValue& default_value) | 
|  | : default_value_(std::make_shared<TValue>(default_value)) {} | 
|  | explicit VariantMapKey(TValue&& default_value) | 
|  | : default_value_(std::make_shared<TValue>(default_value)) {} | 
|  | VariantMapKey() {} | 
|  | virtual ~VariantMapKey() {} | 
|  |  | 
|  | private: | 
|  | virtual VariantMapKeyRaw* Clone() const { | 
|  | return new VariantMapKey<TValue>(*this); | 
|  | } | 
|  |  | 
|  | virtual void* ValueClone(void* value) const { | 
|  | if (value == nullptr) { | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | TValue* strong_value = reinterpret_cast<TValue*>(value); | 
|  | return new TValue(*strong_value); | 
|  | } | 
|  |  | 
|  | virtual void ValueDelete(void* value) const { | 
|  | if (value == nullptr) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | // Smartly invoke the proper delete/delete[]/etc | 
|  | const std::default_delete<TValue> deleter = std::default_delete<TValue>(); | 
|  | deleter(reinterpret_cast<TValue*>(value)); | 
|  | } | 
|  |  | 
|  | VariantMapKey(const VariantMapKey&) = default; | 
|  | VariantMapKey(VariantMapKey&&) = default; | 
|  |  | 
|  | template <typename Base, template <typename TV> class TKey> friend struct VariantMap; | 
|  |  | 
|  | // Store a prototype of the key's default value, for usage with VariantMap::GetOrDefault | 
|  | std::shared_ptr<TValue> default_value_; | 
|  | }; | 
|  |  | 
|  | // Implementation details for a stringified VariantMapStringKey. | 
|  | namespace detail { | 
|  | struct VariantMapStringKeyRegistry { | 
|  | // TODO | 
|  | }; | 
|  | }  // namespace detail | 
|  |  | 
|  | // Alternative base type for all keys used by VariantMap, supports runtime strings as the name. | 
|  | template <typename TValue> | 
|  | struct VariantMapStringKey : VariantMapKey<TValue> { | 
|  | explicit VariantMapStringKey(const char* name) | 
|  | :   // VariantMapKey(/*std::hash<std::string>()(name)*/), | 
|  | name_(name) { | 
|  | } | 
|  |  | 
|  | private: | 
|  | const char* name_; | 
|  | }; | 
|  |  | 
|  | // A variant map allows type-safe heteregeneous key->value mappings. | 
|  | // All possible key types must be specified at compile-time. Values may be added/removed | 
|  | // at runtime. | 
|  | template <typename Base, template <typename TV> class TKey> | 
|  | struct VariantMap { | 
|  | // Allow users of this static interface to use the key type. | 
|  | template <typename TValue> | 
|  | using Key = TKey<TValue>; | 
|  |  | 
|  | // Look up the value from the key. The pointer becomes invalid if this key is overwritten/removed. | 
|  | // A null value is returned only when the key does not exist in this map. | 
|  | template <typename TValue> | 
|  | const TValue* Get(const TKey<TValue>& key) const { | 
|  | return GetValuePtr(key); | 
|  | } | 
|  |  | 
|  | // Look up the value from the key. The pointer becomes invalid if this key is overwritten/removed. | 
|  | // A null value is returned only when the key does not exist in this map. | 
|  | template <typename TValue> | 
|  | TValue* Get(const TKey<TValue>& key) { | 
|  | return GetValuePtr(key); | 
|  | } | 
|  |  | 
|  | // Look up the value from the key and return the value wrapped in a std::optional. If it was not | 
|  | // set in the map, return an empty std::optional. | 
|  | template <typename TValue> | 
|  | std::optional<TValue> GetOptional(const TKey<TValue>& key) const { | 
|  | auto* ptr = Get(key); | 
|  | return (ptr == nullptr) ? std::optional<TValue>{} : std::make_optional(*ptr); | 
|  | } | 
|  |  | 
|  | // Lookup the value from the key. If it was not set in the map, return the default value. | 
|  | // The default value is either the key's default, or TValue{} if the key doesn't have a default. | 
|  | template <typename TValue> | 
|  | TValue GetOrDefault(const TKey<TValue>& key) const { | 
|  | auto* ptr = Get(key); | 
|  | return (ptr == nullptr) ? key.CreateDefaultValue() : *ptr; | 
|  | } | 
|  |  | 
|  | template <typename T, typename U> | 
|  | void AssignIfExists(const TKey<T>& key, U* out) { | 
|  | DCHECK(out != nullptr); | 
|  | if (Exists(key)) { | 
|  | *out = std::move(*Get(key)); | 
|  | } | 
|  | } | 
|  |  | 
|  | private: | 
|  | // TODO: move to detail, or make it more generic like a ScopeGuard(function) | 
|  | template <typename TValue> | 
|  | struct ScopedRemove { | 
|  | ScopedRemove(VariantMap& map, const TKey<TValue>& key) : map_(map), key_(key) {} | 
|  | ~ScopedRemove() { | 
|  | map_.Remove(key_); | 
|  | } | 
|  |  | 
|  | VariantMap& map_; | 
|  | const TKey<TValue>& key_; | 
|  | }; | 
|  |  | 
|  | public: | 
|  | // Release the value from the key. If it was not set in the map, returns the default value. | 
|  | // If the key was set, it is removed as a side effect. | 
|  | template <typename TValue> | 
|  | TValue ReleaseOrDefault(const TKey<TValue>& key) { | 
|  | ScopedRemove<TValue> remove_on_return(*this, key); | 
|  |  | 
|  | TValue* ptr = Get(key); | 
|  | if (ptr != nullptr) { | 
|  | return std::move(*ptr); | 
|  | } else { | 
|  | return key.CreateDefaultValue(); | 
|  | } | 
|  | } | 
|  |  | 
|  | // See if a value is stored for this key. | 
|  | template <typename TValue> | 
|  | bool Exists(const TKey<TValue>& key) const { | 
|  | return GetKeyValueIterator(key) != storage_map_.end(); | 
|  | } | 
|  |  | 
|  | // Set a value for a given key, overwriting the previous value if any. | 
|  | // Note: Omit the `value` from TValue type deduction, deduce only from the `key` argument. | 
|  | template <typename TValue> | 
|  | void Set(const TKey<TValue>& key, const typename Identity<TValue>::type& value) { | 
|  | // Clone the value first, to protect against &value == GetValuePtr(key). | 
|  | auto* new_value = new TValue(value); | 
|  |  | 
|  | Remove(key); | 
|  | bool inserted = storage_map_.insert({key.Clone(), new_value}).second; | 
|  | DCHECK(inserted);  // ensure key.Clone() does not leak memory. | 
|  | } | 
|  |  | 
|  | // Set a value for a given key, only if there was no previous value before. | 
|  | // Returns true if the value was set, false if a previous value existed. | 
|  | // Note: Omit the `value` from TValue type deduction, deduce only from the `key` argument. | 
|  | template <typename TValue> | 
|  | bool SetIfMissing(const TKey<TValue>& key, const typename Identity<TValue>::type& value) { | 
|  | TValue* ptr = Get(key); | 
|  | if (ptr == nullptr) { | 
|  | Set(key, value); | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Remove the value for a given key, or a no-op if there was no previously set value. | 
|  | template <typename TValue> | 
|  | void Remove(const TKey<TValue>& key) { | 
|  | StaticAssertKeyType<TValue>(); | 
|  |  | 
|  | auto&& it = GetKeyValueIterator(key); | 
|  | if (it != storage_map_.end()) { | 
|  | key.ValueDelete(it->second); | 
|  | delete it->first; | 
|  | storage_map_.erase(it); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Remove all key/value pairs. | 
|  | void Clear() { | 
|  | DeleteStoredValues(); | 
|  | storage_map_.clear(); | 
|  | } | 
|  |  | 
|  | // How many key/value pairs are stored in this map. | 
|  | size_t Size() const { | 
|  | return storage_map_.size(); | 
|  | } | 
|  |  | 
|  | // Construct an empty map. | 
|  | VariantMap() {} | 
|  |  | 
|  | template <typename ... TKeyValue> | 
|  | explicit VariantMap(const TKeyValue& ... key_value_list) { | 
|  | static_assert(sizeof...(TKeyValue) % 2 == 0, "Must be an even number of key/value elements"); | 
|  | InitializeParameters(key_value_list...); | 
|  | } | 
|  |  | 
|  | // Create a new map from an existing map, copying all the key/value pairs. | 
|  | VariantMap(const VariantMap& other) { | 
|  | operator=(other); | 
|  | } | 
|  |  | 
|  | // Copy the key/value pairs from the other map into this one. Existing key/values are cleared. | 
|  | VariantMap& operator=(const VariantMap& other) { | 
|  | if (this == &other) { | 
|  | return *this; | 
|  | } | 
|  |  | 
|  | Clear(); | 
|  |  | 
|  | for (auto&& kv_pair : other.storage_map_) { | 
|  | const detail::VariantMapKeyRaw* raw_key_other = kv_pair.first; | 
|  | void* value = kv_pair.second; | 
|  |  | 
|  | detail::VariantMapKeyRaw* cloned_raw_key = raw_key_other->Clone(); | 
|  | void* cloned_value = raw_key_other->ValueClone(value); | 
|  |  | 
|  | storage_map_.insert({{ cloned_raw_key, cloned_value }}); | 
|  | } | 
|  |  | 
|  | return *this; | 
|  | } | 
|  |  | 
|  | // Create a new map by moving an existing map into this one. The other map becomes empty. | 
|  | VariantMap(VariantMap&& other) { | 
|  | operator=(std::forward<VariantMap>(other)); | 
|  | } | 
|  |  | 
|  | // Move the existing map's key/value pairs into this one. The other map becomes empty. | 
|  | VariantMap& operator=(VariantMap&& other) { | 
|  | if (this != &other) { | 
|  | Clear(); | 
|  | storage_map_.swap(other.storage_map_); | 
|  | other.storage_map_.clear(); | 
|  | } | 
|  | return *this; | 
|  | } | 
|  |  | 
|  | ~VariantMap() { | 
|  | DeleteStoredValues(); | 
|  | } | 
|  |  | 
|  | private: | 
|  | void InitializeParameters() {} | 
|  |  | 
|  | template <typename TK, typename TValue, typename ... Rest> | 
|  | void InitializeParameters(const TK& key, const TValue& value, const Rest& ... rest) { | 
|  | static_assert( | 
|  | std::is_same<TK, TKey<TValue>>::value, "The 0th/2nd/4th/etc parameters must be a key"); | 
|  |  | 
|  | const TKey<TValue>& key_refined = key; | 
|  |  | 
|  | Set(key_refined, value); | 
|  | InitializeParameters(rest...); | 
|  | } | 
|  |  | 
|  | // Custom key comparator for std::map, needed since we are storing raw pointers as the keys. | 
|  | struct KeyComparator { | 
|  | bool operator()(const detail::VariantMapKeyRaw* lhs, | 
|  | const detail::VariantMapKeyRaw* rhs) const { | 
|  | if (lhs == nullptr) { | 
|  | return lhs != rhs; | 
|  | } | 
|  |  | 
|  | return lhs->Compare(rhs); | 
|  | } | 
|  | }; | 
|  |  | 
|  | // Map of key pointers to value pointers. Pointers are never null. | 
|  | using StorageMap = std::map<const detail::VariantMapKeyRaw*, void*, KeyComparator>; | 
|  |  | 
|  | template <typename TValue> | 
|  | typename StorageMap::iterator GetKeyValueIterator(const TKey<TValue>& key) { | 
|  | StaticAssertKeyType<TValue>(); | 
|  |  | 
|  | const TKey<TValue>* key_ptr = &key; | 
|  | const detail::VariantMapKeyRaw* raw_ptr = key_ptr; | 
|  | return storage_map_.find(raw_ptr); | 
|  | } | 
|  |  | 
|  | template <typename TValue> | 
|  | typename StorageMap::const_iterator GetKeyValueIterator(const TKey<TValue>& key) const { | 
|  | StaticAssertKeyType<TValue>(); | 
|  |  | 
|  | const TKey<TValue>* key_ptr = &key; | 
|  | const detail::VariantMapKeyRaw* raw_ptr = key_ptr; | 
|  | return storage_map_.find(raw_ptr); | 
|  | } | 
|  |  | 
|  | template <typename TValue> | 
|  | TValue* GetValuePtr(const TKey<TValue>& key) { | 
|  | return const_cast<TValue*>(GetValueConstPtr(key)); | 
|  | } | 
|  |  | 
|  | template <typename TValue> | 
|  | const TValue* GetValuePtr(const TKey<TValue>& key) const { | 
|  | return GetValueConstPtr(key); | 
|  | } | 
|  |  | 
|  | template <typename TValue> | 
|  | const TValue* GetValueConstPtr(const TKey<TValue>& key) const { | 
|  | auto&& it = GetKeyValueIterator(key); | 
|  | if (it == storage_map_.end()) { | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | return reinterpret_cast<const TValue*>(it->second); | 
|  | } | 
|  |  | 
|  | template <typename TValue> | 
|  | static void StaticAssertKeyType() { | 
|  | static_assert(std::is_base_of<VariantMapKey<TValue>, TKey<TValue>>::value, | 
|  | "The provided key type (TKey) must be a subclass of VariantMapKey"); | 
|  | } | 
|  |  | 
|  | void DeleteStoredValues() { | 
|  | for (auto&& kv_pair : storage_map_) { | 
|  | kv_pair.first->ValueDelete(kv_pair.second); | 
|  | delete kv_pair.first; | 
|  | } | 
|  | } | 
|  |  | 
|  | StorageMap storage_map_; | 
|  | }; | 
|  |  | 
|  | }  // namespace art | 
|  |  | 
|  | #endif  // ART_LIBARTBASE_BASE_VARIANT_MAP_H_ |