xref: /aosp_15_r20/external/cronet/base/win/map.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2019 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef BASE_WIN_MAP_H_
6 #define BASE_WIN_MAP_H_
7 
8 #include <windows.foundation.collections.h>
9 #include <wrl/implements.h>
10 
11 #include <map>
12 #include <utility>
13 
14 #include "base/check_op.h"
15 #include "base/containers/contains.h"
16 #include "base/notimplemented.h"
17 #include "base/win/vector.h"
18 #include "base/win/winrt_foundation_helpers.h"
19 
20 namespace base {
21 namespace win {
22 
23 template <typename K, typename V>
24 class Map;
25 
26 namespace internal {
27 
28 // Template tricks needed to dispatch to the correct implementation.
29 // See base/win/winrt_foundation_helpers.h for explanation.
30 
31 template <typename K, typename V>
32 using ComplexK =
33     typename ABI::Windows::Foundation::Collections::IMap<K, V>::K_complex;
34 
35 template <typename K, typename V>
36 using ComplexV =
37     typename ABI::Windows::Foundation::Collections::IMap<K, V>::V_complex;
38 
39 template <typename K, typename V>
40 using LogicalK = LogicalType<ComplexK<K, V>>;
41 
42 template <typename K, typename V>
43 using LogicalV = LogicalType<ComplexV<K, V>>;
44 
45 template <typename K, typename V>
46 using AbiK = AbiType<ComplexK<K, V>>;
47 
48 template <typename K, typename V>
49 using AbiV = AbiType<ComplexV<K, V>>;
50 
51 template <typename K, typename V>
52 using StorageK = StorageType<ComplexK<K, V>>;
53 
54 template <typename K, typename V>
55 using StorageV = StorageType<ComplexV<K, V>>;
56 
57 template <typename K, typename V>
58 class KeyValuePair : public Microsoft::WRL::RuntimeClass<
59                          Microsoft::WRL::RuntimeClassFlags<
60                              Microsoft::WRL::WinRtClassicComMix |
61                              Microsoft::WRL::InhibitRoOriginateError>,
62                          ABI::Windows::Foundation::Collections::
63                              IKeyValuePair<LogicalK<K, V>, LogicalV<K, V>>> {
64  public:
65   using AbiK = AbiK<K, V>;
66   using AbiV = AbiV<K, V>;
67   using StorageK = StorageK<K, V>;
68   using StorageV = StorageV<K, V>;
69 
KeyValuePair(StorageK key,StorageV value)70   KeyValuePair(StorageK key, StorageV value)
71       : key_(std::move(key)), value_(std::move(value)) {}
72 
73   // ABI::Windows::Foundation::Collections::IKeyValuePair:
get_Key(AbiK * key)74   IFACEMETHODIMP get_Key(AbiK* key) { return CopyTo(key_, key); }
75 
get_Value(AbiV * value)76   IFACEMETHODIMP get_Value(AbiV* value) { return CopyTo(value_, value); }
77 
78  private:
79   StorageK key_;
80   StorageV value_;
81 };
82 
83 template <typename K>
84 class MapChangedEventArgs
85     : public Microsoft::WRL::RuntimeClass<
86           Microsoft::WRL::RuntimeClassFlags<
87               Microsoft::WRL::WinRtClassicComMix |
88               Microsoft::WRL::InhibitRoOriginateError>,
89           ABI::Windows::Foundation::Collections::IMapChangedEventArgs<K>> {
90  public:
MapChangedEventArgs(ABI::Windows::Foundation::Collections::CollectionChange change,K key)91   MapChangedEventArgs(
92       ABI::Windows::Foundation::Collections::CollectionChange change,
93       K key)
94       : change_(change), key_(std::move(key)) {}
95 
96   ~MapChangedEventArgs() override = default;
97 
98   // ABI::Windows::Foundation::Collections::IMapChangedEventArgs:
get_CollectionChange(ABI::Windows::Foundation::Collections::CollectionChange * value)99   IFACEMETHODIMP get_CollectionChange(
100       ABI::Windows::Foundation::Collections::CollectionChange* value) override {
101     *value = change_;
102     return S_OK;
103   }
104 
get_Key(K * value)105   IFACEMETHODIMP get_Key(K* value) override {
106     *value = key_;
107     return S_OK;
108   }
109 
110  private:
111   const ABI::Windows::Foundation::Collections::CollectionChange change_;
112   K key_;
113 };
114 
115 }  // namespace internal
116 
117 // This file provides an implementation of Windows::Foundation::IMap. It
118 // functions as a thin wrapper around an std::map, and dispatches
119 // method calls to either the corresponding std::map API or
120 // appropriate std algorithms. Furthermore, it notifies its observers whenever
121 // its observable state changes, and is iterable. Please notice also that if the
122 // map is modified while iterating over it, iterator methods will return
123 // E_CHANGED_STATE. A base::win::Map can be constructed for any types <K,V>, and
124 // is implicitly constructible from a std::map. In the case where K or V is a
125 // pointer derived from IUnknown, the std::map needs to be of type
126 // Microsoft::WRL::ComPtr<K> or Microsoft::WRL::ComPtr<V>. This enforces proper
127 // reference counting and improves safety.
128 template <typename K, typename V>
129 class Map
130     : public Microsoft::WRL::RuntimeClass<
131           Microsoft::WRL::RuntimeClassFlags<
132               Microsoft::WRL::WinRt | Microsoft::WRL::InhibitRoOriginateError>,
133           ABI::Windows::Foundation::Collections::IMap<internal::LogicalK<K, V>,
134                                                       internal::LogicalV<K, V>>,
135           ABI::Windows::Foundation::Collections::IObservableMap<
136               internal::LogicalK<K, V>,
137               internal::LogicalV<K, V>>,
138           ABI::Windows::Foundation::Collections::IIterable<
139               ABI::Windows::Foundation::Collections::IKeyValuePair<
140                   internal::LogicalK<K, V>,
141                   internal::LogicalV<K, V>>*>> {
142  public:
143   using LogicalK = internal::LogicalK<K, V>;
144   using LogicalV = internal::LogicalV<K, V>;
145   using AbiK = internal::AbiK<K, V>;
146   using AbiV = internal::AbiV<K, V>;
147   using StorageK = internal::StorageK<K, V>;
148   using StorageV = internal::StorageV<K, V>;
149 
150  private:
151   class MapView;
152 
153   // Iterates over base::win::Map.
154   // Its methods return E_CHANGED_STATE is the map is modified.
155   // TODO(https://crbug.com/987533): Refactor MapIterator to leverage
156   // std::map::iterator.
157   class MapIterator
158       : public Microsoft::WRL::RuntimeClass<
159             Microsoft::WRL::RuntimeClassFlags<
160                 Microsoft::WRL::WinRtClassicComMix |
161                 Microsoft::WRL::InhibitRoOriginateError>,
162             ABI::Windows::Foundation::Collections::IIterator<
163                 ABI::Windows::Foundation::Collections::IKeyValuePair<
164                     internal::LogicalK<K, V>,
165                     internal::LogicalV<K, V>>*>> {
166    public:
MapIterator(Microsoft::WRL::ComPtr<MapView> view)167     explicit MapIterator(Microsoft::WRL::ComPtr<MapView> view)
168         : view_(std::move(view)) {
169       DCHECK(view_->ValidState());
170       ConvertMapToVectorIterator();
171     }
172 
173     // ABI::Windows::Foundation::Collections::IIterator:
get_Current(ABI::Windows::Foundation::Collections::IKeyValuePair<LogicalK,LogicalV> ** current)174     IFACEMETHODIMP get_Current(
175         ABI::Windows::Foundation::Collections::IKeyValuePair<LogicalK,
176                                                              LogicalV>**
177             current) override {
178       return view_->ValidState() ? iterator_->get_Current(current)
179                                  : E_CHANGED_STATE;
180     }
181 
get_HasCurrent(boolean * has_current)182     IFACEMETHODIMP get_HasCurrent(boolean* has_current) override {
183       return view_->ValidState() ? iterator_->get_HasCurrent(has_current)
184                                  : E_CHANGED_STATE;
185     }
186 
MoveNext(boolean * has_current)187     IFACEMETHODIMP MoveNext(boolean* has_current) override {
188       return view_->ValidState() ? iterator_->MoveNext(has_current)
189                                  : E_CHANGED_STATE;
190     }
191 
GetMany(unsigned capacity,ABI::Windows::Foundation::Collections::IKeyValuePair<LogicalK,LogicalV> ** value,unsigned * actual)192     IFACEMETHODIMP GetMany(
193         unsigned capacity,
194         ABI::Windows::Foundation::Collections::IKeyValuePair<LogicalK,
195                                                              LogicalV>** value,
196         unsigned* actual) override {
197       return view_->ValidState() ? iterator_->GetMany(capacity, value, actual)
198                                  : E_CHANGED_STATE;
199     }
200 
201    private:
202     // Helper for iteration:
ConvertMapToVectorIterator()203     void ConvertMapToVectorIterator() {
204       // Create a vector that will hold Map's key-value pairs.
205       auto vector = Microsoft::WRL::Make<
206           Vector<ABI::Windows::Foundation::Collections::IKeyValuePair<
207               LogicalK, LogicalV>*>>();
208 
209       // Fill the vector with container data.
210       for (const auto& pair : view_->get_map()) {
211         auto key_value_pair =
212             Microsoft::WRL::Make<internal::KeyValuePair<AbiK, AbiV>>(
213                 pair.first, pair.second);
214         vector->Append(key_value_pair.Get());
215       }
216 
217       // Return an iterator to that vector.
218       // Iterator is immutable (wraps an IVectorView) and Vector's lifecycle is
219       // ensured cause the view holds a reference to the vector, and iterator
220       // holds a reference to the view.
221       HRESULT hr = vector->First(&iterator_);
222       DCHECK(SUCCEEDED(hr));
223     }
224 
225     Microsoft::WRL::ComPtr<MapView> view_;
226     Microsoft::WRL::ComPtr<ABI::Windows::Foundation::Collections::IIterator<
227         ABI::Windows::Foundation::Collections::IKeyValuePair<LogicalK,
228                                                              LogicalV>*>>
229         iterator_;
230   };
231 
232   class MapView
233       : public Microsoft::WRL::RuntimeClass<
234             Microsoft::WRL::RuntimeClassFlags<
235                 Microsoft::WRL::WinRtClassicComMix |
236                 Microsoft::WRL::InhibitRoOriginateError>,
237             ABI::Windows::Foundation::Collections::
238                 IMapView<internal::LogicalK<K, V>, internal::LogicalV<K, V>>,
239             ABI::Windows::Foundation::Collections::IIterable<
240                 ABI::Windows::Foundation::Collections::IKeyValuePair<
241                     internal::LogicalK<K, V>,
242                     internal::LogicalV<K, V>>*>,
243             ABI::Windows::Foundation::Collections::MapChangedEventHandler<
244                 internal::LogicalK<K, V>,
245                 internal::LogicalV<K, V>>> {
246    public:
MapView(Microsoft::WRL::ComPtr<Map<LogicalK,LogicalV>> map)247     explicit MapView(Microsoft::WRL::ComPtr<Map<LogicalK, LogicalV>> map)
248         : map_(std::move(map)) {
249       map_->add_MapChanged(this, &map_changed_token_);
250     }
251 
~MapView()252     ~MapView() override {
253       if (map_)
254         map_->remove_MapChanged(map_changed_token_);
255     }
256 
257     // ABI::Windows::Foundation::Collections::IMapView:
Lookup(AbiK key,AbiV * value)258     IFACEMETHODIMP Lookup(AbiK key, AbiV* value) override {
259       return map_ ? map_->Lookup(key, value) : E_CHANGED_STATE;
260     }
261 
get_Size(unsigned int * size)262     IFACEMETHODIMP get_Size(unsigned int* size) override {
263       return map_ ? map_->get_Size(size) : E_CHANGED_STATE;
264     }
265 
HasKey(AbiK key,boolean * found)266     IFACEMETHODIMP HasKey(AbiK key, boolean* found) override {
267       return map_ ? map_->HasKey(key, found) : E_CHANGED_STATE;
268     }
269 
Split(ABI::Windows::Foundation::Collections::IMapView<LogicalK,LogicalV> ** first_partition,ABI::Windows::Foundation::Collections::IMapView<LogicalK,LogicalV> ** second_partition)270     IFACEMETHODIMP Split(
271         ABI::Windows::Foundation::Collections::IMapView<LogicalK, LogicalV>**
272             first_partition,
273         ABI::Windows::Foundation::Collections::IMapView<LogicalK, LogicalV>**
274             second_partition) override {
275       NOTIMPLEMENTED();
276       return E_NOTIMPL;
277     }
278 
279     // ABI::Windows::Foundation::Collections::IIterable:
First(ABI::Windows::Foundation::Collections::IIterator<ABI::Windows::Foundation::Collections::IKeyValuePair<LogicalK,LogicalV> * > ** first)280     IFACEMETHODIMP First(
281         ABI::Windows::Foundation::Collections::IIterator<
282             ABI::Windows::Foundation::Collections::IKeyValuePair<LogicalK,
283                                                                  LogicalV>*>**
284             first) override {
285       return map_ ? map_->First(first) : E_CHANGED_STATE;
286     }
287 
288     // ABI::Windows::Foundation::Collections::MapChangedEventHandler:
Invoke(ABI::Windows::Foundation::Collections::IObservableMap<LogicalK,LogicalV> * sender,ABI::Windows::Foundation::Collections::IMapChangedEventArgs<LogicalK> * e)289     IFACEMETHODIMP Invoke(
290         ABI::Windows::Foundation::Collections::IObservableMap<LogicalK,
291                                                               LogicalV>* sender,
292         ABI::Windows::Foundation::Collections::IMapChangedEventArgs<LogicalK>*
293             e) override {
294       DCHECK_EQ(map_.Get(), sender);
295       map_.Reset();
296       sender->remove_MapChanged(map_changed_token_);
297       return S_OK;
298     }
299 
300     // Accessor used in MapIterator for iterating over Map's container.
301     // Will remain valid during the entire iteration.
get_map()302     const std::map<StorageK, StorageV, internal::Less>& get_map() {
303       DCHECK(map_);
304       return map_->map_;
305     }
306 
ValidState()307     bool ValidState() const { return map_; }
308 
309    private:
310     Microsoft::WRL::ComPtr<Map<LogicalK, LogicalV>> map_;
311     EventRegistrationToken map_changed_token_;
312   };
313 
314  public:
315   Map() = default;
Map(const std::map<StorageK,StorageV,internal::Less> & map)316   explicit Map(const std::map<StorageK, StorageV, internal::Less>& map)
317       : map_(map) {}
Map(std::map<StorageK,StorageV,internal::Less> && map)318   explicit Map(std::map<StorageK, StorageV, internal::Less>&& map)
319       : map_(std::move(map)) {}
320 
321   // ABI::Windows::Foundation::Collections::IMap:
Lookup(AbiK key,AbiV * value)322   IFACEMETHODIMP Lookup(AbiK key, AbiV* value) override {
323     auto it = map_.find(key);
324     if (it == map_.cend())
325       return E_BOUNDS;
326 
327     return internal::CopyTo(it->second, value);
328   }
329 
get_Size(unsigned int * size)330   IFACEMETHODIMP get_Size(unsigned int* size) override {
331     *size = map_.size();
332     return S_OK;
333   }
334 
HasKey(AbiK key,boolean * found)335   IFACEMETHODIMP HasKey(AbiK key, boolean* found) override {
336     *found = Contains(map_, key);
337     return S_OK;
338   }
339 
GetView(ABI::Windows::Foundation::Collections::IMapView<LogicalK,LogicalV> ** view)340   IFACEMETHODIMP GetView(
341       ABI::Windows::Foundation::Collections::IMapView<LogicalK, LogicalV>**
342           view) override {
343     return Microsoft::WRL::Make<MapView>(this).CopyTo(view);
344   }
345 
Insert(AbiK key,AbiV value,boolean * replaced)346   IFACEMETHODIMP Insert(AbiK key, AbiV value, boolean* replaced) override {
347     auto [it, inserted] = map_.insert_or_assign(key, std::move(value));
348     *replaced = !inserted;
349     NotifyMapChanged(*replaced ? ABI::Windows::Foundation::Collections::
350                                      CollectionChange_ItemChanged
351                                : ABI::Windows::Foundation::Collections::
352                                      CollectionChange_ItemInserted,
353                      key);
354     return S_OK;
355   }
356 
Remove(AbiK key)357   IFACEMETHODIMP Remove(AbiK key) override {
358     if (!map_.erase(key))
359       return E_BOUNDS;
360 
361     NotifyMapChanged(
362         ABI::Windows::Foundation::Collections::CollectionChange_ItemRemoved,
363         key);
364     return S_OK;
365   }
366 
Clear()367   IFACEMETHODIMP Clear() override {
368     map_.clear();
369     NotifyMapChanged(
370         ABI::Windows::Foundation::Collections::CollectionChange_Reset, 0);
371     return S_OK;
372   }
373 
374   // ABI::Windows::Foundation::Collections::IObservableMap:
add_MapChanged(ABI::Windows::Foundation::Collections::MapChangedEventHandler<LogicalK,LogicalV> * handler,EventRegistrationToken * token)375   IFACEMETHODIMP add_MapChanged(
376       ABI::Windows::Foundation::Collections::MapChangedEventHandler<LogicalK,
377                                                                     LogicalV>*
378           handler,
379       EventRegistrationToken* token) override {
380     token->value = handler_id_++;
381     handlers_.emplace_hint(handlers_.end(), token->value, handler);
382     return S_OK;
383   }
384 
remove_MapChanged(EventRegistrationToken token)385   IFACEMETHODIMP remove_MapChanged(EventRegistrationToken token) override {
386     return handlers_.erase(token.value) ? S_OK : E_BOUNDS;
387   }
388 
389   // ABI::Windows::Foundation::Collections::IIterable:
First(ABI::Windows::Foundation::Collections::IIterator<ABI::Windows::Foundation::Collections::IKeyValuePair<LogicalK,LogicalV> * > ** first)390   IFACEMETHODIMP First(
391       ABI::Windows::Foundation::Collections::IIterator<
392           ABI::Windows::Foundation::Collections::IKeyValuePair<LogicalK,
393                                                                LogicalV>*>**
394           first) override {
395     return Microsoft::WRL::Make<MapIterator>(
396                Microsoft::WRL::Make<MapView>(this))
397         .CopyTo(first);
398   }
399 
400  private:
~Map()401   ~Map() override {
402     // Handlers should not outlive the Map. Furthermore, they must ensure
403     // they are unregistered before the handler is destroyed. This implies
404     // there should be no handlers left when the Map is destructed.
405     DCHECK(handlers_.empty());
406   }
407 
NotifyMapChanged(ABI::Windows::Foundation::Collections::CollectionChange change,AbiK key)408   void NotifyMapChanged(
409       ABI::Windows::Foundation::Collections::CollectionChange change,
410       AbiK key) {
411     auto args =
412         Microsoft::WRL::Make<internal::MapChangedEventArgs<AbiK>>(change, key);
413 
414     // Invoking the handlers could result in mutations to the map, thus we make
415     // a copy beforehand.
416     auto handlers = handlers_;
417     for (auto& handler : handlers)
418       handler.second->Invoke(this, args.Get());
419   }
420 
421   std::map<StorageK, StorageV, internal::Less> map_;
422   base::flat_map<int64_t,
423                  ABI::Windows::Foundation::Collections::
424                      MapChangedEventHandler<LogicalK, LogicalV>*>
425       handlers_;
426   int64_t handler_id_ = 0;
427 };
428 
429 }  // namespace win
430 }  // namespace base
431 
432 #endif  // BASE_WIN_MAP_H_
433