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