/* * 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 #include #include #include #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 // TValue* Get(Key key); // null if the value was never set, otherwise the value. // // template // void Set(Key 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 // struct FruitMapKey : VariantMapKey { // FruitMapKey() {} // }; // // struct FruitMap : VariantMap { // // This 'using' line is necessary to inherit the variadic constructor. // using VariantMap::VariantMap; // // // Make the next '4' usages of Key slightly shorter to type. // template // using Key = FruitMapKey; // // static const Key Apple; // static const Key Orange; // static const Key Banana; // }; // // const FruitMap::Key FruitMap::Apple; // const FruitMap::Key FruitMap::Orange; // const FruitMap::Key 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 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 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(default_value)) {} explicit VariantMapKey(TValue&& default_value) : default_value_(std::make_shared(default_value)) {} VariantMapKey() {} virtual ~VariantMapKey() {} private: virtual VariantMapKeyRaw* Clone() const { return new VariantMapKey(*this); } virtual void* ValueClone(void* value) const { if (value == nullptr) { return nullptr; } TValue* strong_value = reinterpret_cast(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 deleter = std::default_delete(); deleter(reinterpret_cast(value)); } VariantMapKey(const VariantMapKey&) = default; VariantMapKey(VariantMapKey&&) = default; template class TKey> friend struct VariantMap; // Store a prototype of the key's default value, for usage with VariantMap::GetOrDefault std::shared_ptr 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 struct VariantMapStringKey : VariantMapKey { explicit VariantMapStringKey(const char* name) : // VariantMapKey(/*std::hash()(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 class TKey> struct VariantMap { // Allow users of this static interface to use the key type. template using Key = TKey; // 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 const TValue* Get(const TKey& 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 TValue* Get(const TKey& 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 TValue GetOrDefault(const TKey& key) const { auto* ptr = Get(key); return (ptr == nullptr) ? key.CreateDefaultValue() : *ptr; } template void AssignIfExists(const TKey& 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 struct ScopedRemove { ScopedRemove(VariantMap& map, const TKey& key) : map_(map), key_(key) {} ~ScopedRemove() { map_.Remove(key_); } VariantMap& map_; const TKey& 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 TValue ReleaseOrDefault(const TKey& key) { ScopedRemove 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 bool Exists(const TKey& 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 void Set(const TKey& key, const typename Identity::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 bool SetIfMissing(const TKey& key, const typename Identity::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 void Remove(const TKey& key) { StaticAssertKeyType(); 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 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(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 void InitializeParameters(const TK& key, const TValue& value, const Rest& ... rest) { static_assert( std::is_same>::value, "The 0th/2nd/4th/etc parameters must be a key"); const TKey& 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; template typename StorageMap::iterator GetKeyValueIterator(const TKey& key) { StaticAssertKeyType(); const TKey* key_ptr = &key; const detail::VariantMapKeyRaw* raw_ptr = key_ptr; return storage_map_.find(raw_ptr); } template typename StorageMap::const_iterator GetKeyValueIterator(const TKey& key) const { StaticAssertKeyType(); const TKey* key_ptr = &key; const detail::VariantMapKeyRaw* raw_ptr = key_ptr; return storage_map_.find(raw_ptr); } template TValue* GetValuePtr(const TKey& key) { return const_cast(GetValueConstPtr(key)); } template const TValue* GetValuePtr(const TKey& key) const { return GetValueConstPtr(key); } template const TValue* GetValueConstPtr(const TKey& key) const { auto&& it = GetKeyValueIterator(key); if (it == storage_map_.end()) { return nullptr; } return reinterpret_cast(it->second); } template static void StaticAssertKeyType() { static_assert(std::is_base_of, TKey>::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_