/* * 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 "base/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); } // 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_