| /* |
| * 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&&) noexcept = 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&&) noexcept = 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) noexcept { |
| 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) noexcept { |
| 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_v<TK, TKey<TValue>>, "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_v<VariantMapKey<TValue>, TKey<TValue>>, |
| "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_ |