map.h 15 KB

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