123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431 |
- // Copyright 2019 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #ifndef BASE_WIN_MAP_H_
- #define BASE_WIN_MAP_H_
- #include <windows.foundation.collections.h>
- #include <wrl/implements.h>
- #include <map>
- #include "base/check_op.h"
- #include "base/notreached.h"
- #include "base/stl_util.h"
- #include "base/win/vector.h"
- #include "base/win/winrt_foundation_helpers.h"
- namespace base {
- namespace win {
- template <typename K, typename V>
- class Map;
- namespace internal {
- // Template tricks needed to dispatch to the correct implementation.
- // See base/win/winrt_foundation_helpers.h for explanation.
- template <typename K, typename V>
- using ComplexK =
- typename ABI::Windows::Foundation::Collections::IMap<K, V>::K_complex;
- template <typename K, typename V>
- using ComplexV =
- typename ABI::Windows::Foundation::Collections::IMap<K, V>::V_complex;
- template <typename K, typename V>
- using LogicalK = LogicalType<ComplexK<K, V>>;
- template <typename K, typename V>
- using LogicalV = LogicalType<ComplexV<K, V>>;
- template <typename K, typename V>
- using AbiK = AbiType<ComplexK<K, V>>;
- template <typename K, typename V>
- using AbiV = AbiType<ComplexV<K, V>>;
- template <typename K, typename V>
- using StorageK = StorageType<ComplexK<K, V>>;
- template <typename K, typename V>
- using StorageV = StorageType<ComplexV<K, V>>;
- template <typename K, typename V>
- class KeyValuePair : public Microsoft::WRL::RuntimeClass<
- Microsoft::WRL::RuntimeClassFlags<
- Microsoft::WRL::WinRtClassicComMix |
- Microsoft::WRL::InhibitRoOriginateError>,
- ABI::Windows::Foundation::Collections::
- IKeyValuePair<LogicalK<K, V>, LogicalV<K, V>>> {
- public:
- using AbiK = AbiK<K, V>;
- using AbiV = AbiV<K, V>;
- using StorageK = StorageK<K, V>;
- using StorageV = StorageV<K, V>;
- KeyValuePair(StorageK key, StorageV value)
- : key_(std::move(key)), value_(std::move(value)) {}
- // ABI::Windows::Foundation::Collections::IKeyValuePair:
- IFACEMETHODIMP get_Key(AbiK* key) { return CopyTo(key_, key); }
- IFACEMETHODIMP get_Value(AbiV* value) { return CopyTo(value_, value); }
- private:
- StorageK key_;
- StorageV value_;
- };
- template <typename K>
- class MapChangedEventArgs
- : public Microsoft::WRL::RuntimeClass<
- Microsoft::WRL::RuntimeClassFlags<
- Microsoft::WRL::WinRtClassicComMix |
- Microsoft::WRL::InhibitRoOriginateError>,
- ABI::Windows::Foundation::Collections::IMapChangedEventArgs<K>> {
- public:
- MapChangedEventArgs(
- ABI::Windows::Foundation::Collections::CollectionChange change,
- K key)
- : change_(change), key_(std::move(key)) {}
- ~MapChangedEventArgs() override = default;
- // ABI::Windows::Foundation::Collections::IMapChangedEventArgs:
- IFACEMETHODIMP get_CollectionChange(
- ABI::Windows::Foundation::Collections::CollectionChange* value) override {
- *value = change_;
- return S_OK;
- }
- IFACEMETHODIMP get_Key(K* value) override {
- *value = key_;
- return S_OK;
- }
- private:
- const ABI::Windows::Foundation::Collections::CollectionChange change_;
- K key_;
- };
- } // namespace internal
- // This file provides an implementation of Windows::Foundation::IMap. It
- // functions as a thin wrapper around an std::map, and dispatches
- // method calls to either the corresponding std::map API or
- // appropriate std algorithms. Furthermore, it notifies its observers whenever
- // its observable state changes, and is iterable. Please notice also that if the
- // map is modified while iterating over it, iterator methods will return
- // E_CHANGED_STATE. A base::win::Map can be constructed for any types <K,V>, and
- // is implicitly constructible from a std::map. In the case where K or V is a
- // pointer derived from IUnknown, the std::map needs to be of type
- // Microsoft::WRL::ComPtr<K> or Microsoft::WRL::ComPtr<V>. This enforces proper
- // reference counting and improves safety.
- template <typename K, typename V>
- class Map
- : public Microsoft::WRL::RuntimeClass<
- Microsoft::WRL::RuntimeClassFlags<
- Microsoft::WRL::WinRt | Microsoft::WRL::InhibitRoOriginateError>,
- ABI::Windows::Foundation::Collections::IMap<internal::LogicalK<K, V>,
- internal::LogicalV<K, V>>,
- ABI::Windows::Foundation::Collections::IObservableMap<
- internal::LogicalK<K, V>,
- internal::LogicalV<K, V>>,
- ABI::Windows::Foundation::Collections::IIterable<
- ABI::Windows::Foundation::Collections::IKeyValuePair<
- internal::LogicalK<K, V>,
- internal::LogicalV<K, V>>*>> {
- public:
- using LogicalK = internal::LogicalK<K, V>;
- using LogicalV = internal::LogicalV<K, V>;
- using AbiK = internal::AbiK<K, V>;
- using AbiV = internal::AbiV<K, V>;
- using StorageK = internal::StorageK<K, V>;
- using StorageV = internal::StorageV<K, V>;
- private:
- class MapView;
- // Iterates over base::win::Map.
- // Its methods return E_CHANGED_STATE is the map is modified.
- // TODO(https://crbug.com/987533): Refactor MapIterator to leverage
- // std::map::iterator.
- class MapIterator
- : public Microsoft::WRL::RuntimeClass<
- Microsoft::WRL::RuntimeClassFlags<
- Microsoft::WRL::WinRtClassicComMix |
- Microsoft::WRL::InhibitRoOriginateError>,
- ABI::Windows::Foundation::Collections::IIterator<
- ABI::Windows::Foundation::Collections::IKeyValuePair<
- internal::LogicalK<K, V>,
- internal::LogicalV<K, V>>*>> {
- public:
- explicit MapIterator(Microsoft::WRL::ComPtr<MapView> view)
- : view_(std::move(view)) {
- DCHECK(view_->ValidState());
- ConvertMapToVectorIterator();
- }
- // ABI::Windows::Foundation::Collections::IIterator:
- IFACEMETHODIMP get_Current(
- ABI::Windows::Foundation::Collections::IKeyValuePair<LogicalK,
- LogicalV>**
- current) override {
- return view_->ValidState() ? iterator_->get_Current(current)
- : E_CHANGED_STATE;
- }
- IFACEMETHODIMP get_HasCurrent(boolean* has_current) override {
- return view_->ValidState() ? iterator_->get_HasCurrent(has_current)
- : E_CHANGED_STATE;
- }
- IFACEMETHODIMP MoveNext(boolean* has_current) override {
- return view_->ValidState() ? iterator_->MoveNext(has_current)
- : E_CHANGED_STATE;
- }
- IFACEMETHODIMP GetMany(
- unsigned capacity,
- ABI::Windows::Foundation::Collections::IKeyValuePair<LogicalK,
- LogicalV>** value,
- unsigned* actual) override {
- return view_->ValidState() ? iterator_->GetMany(capacity, value, actual)
- : E_CHANGED_STATE;
- }
- private:
- // Helper for iteration:
- void ConvertMapToVectorIterator() {
- // Create a vector that will hold Map's key-value pairs.
- auto vector = Microsoft::WRL::Make<
- Vector<ABI::Windows::Foundation::Collections::IKeyValuePair<
- LogicalK, LogicalV>*>>();
- // Fill the vector with container data.
- for (const auto& pair : view_->get_map()) {
- auto key_value_pair =
- Microsoft::WRL::Make<internal::KeyValuePair<AbiK, AbiV>>(
- pair.first, pair.second);
- vector->Append(key_value_pair.Get());
- }
- // Return an iterator to that vector.
- // Iterator is immutable (wraps an IVectorView) and Vector's lifecycle is
- // ensured cause the view holds a reference to the vector, and iterator
- // holds a reference to the view.
- HRESULT hr = vector->First(&iterator_);
- DCHECK(SUCCEEDED(hr));
- }
- Microsoft::WRL::ComPtr<MapView> view_;
- Microsoft::WRL::ComPtr<ABI::Windows::Foundation::Collections::IIterator<
- ABI::Windows::Foundation::Collections::IKeyValuePair<LogicalK,
- LogicalV>*>>
- iterator_;
- };
- class MapView
- : public Microsoft::WRL::RuntimeClass<
- Microsoft::WRL::RuntimeClassFlags<
- Microsoft::WRL::WinRtClassicComMix |
- Microsoft::WRL::InhibitRoOriginateError>,
- ABI::Windows::Foundation::Collections::
- IMapView<internal::LogicalK<K, V>, internal::LogicalV<K, V>>,
- ABI::Windows::Foundation::Collections::IIterable<
- ABI::Windows::Foundation::Collections::IKeyValuePair<
- internal::LogicalK<K, V>,
- internal::LogicalV<K, V>>*>,
- ABI::Windows::Foundation::Collections::MapChangedEventHandler<
- internal::LogicalK<K, V>,
- internal::LogicalV<K, V>>> {
- public:
- explicit MapView(Microsoft::WRL::ComPtr<Map<LogicalK, LogicalV>> map)
- : map_(std::move(map)) {
- map_->add_MapChanged(this, &map_changed_token_);
- }
- ~MapView() override {
- if (map_)
- map_->remove_MapChanged(map_changed_token_);
- }
- // ABI::Windows::Foundation::Collections::IMapView:
- IFACEMETHODIMP Lookup(AbiK key, AbiV* value) override {
- return map_ ? map_->Lookup(key, value) : E_CHANGED_STATE;
- }
- IFACEMETHODIMP get_Size(unsigned int* size) override {
- return map_ ? map_->get_Size(size) : E_CHANGED_STATE;
- }
- IFACEMETHODIMP HasKey(AbiK key, boolean* found) override {
- return map_ ? map_->HasKey(key, found) : E_CHANGED_STATE;
- }
- IFACEMETHODIMP Split(
- ABI::Windows::Foundation::Collections::IMapView<LogicalK, LogicalV>**
- first_partition,
- ABI::Windows::Foundation::Collections::IMapView<LogicalK, LogicalV>**
- second_partition) override {
- NOTIMPLEMENTED();
- return E_NOTIMPL;
- }
- // ABI::Windows::Foundation::Collections::IIterable:
- IFACEMETHODIMP First(
- ABI::Windows::Foundation::Collections::IIterator<
- ABI::Windows::Foundation::Collections::IKeyValuePair<LogicalK,
- LogicalV>*>**
- first) override {
- return map_ ? map_->First(first) : E_CHANGED_STATE;
- }
- // ABI::Windows::Foundation::Collections::MapChangedEventHandler:
- IFACEMETHODIMP Invoke(
- ABI::Windows::Foundation::Collections::IObservableMap<LogicalK,
- LogicalV>* sender,
- ABI::Windows::Foundation::Collections::IMapChangedEventArgs<LogicalK>*
- e) override {
- DCHECK_EQ(map_.Get(), sender);
- map_.Reset();
- sender->remove_MapChanged(map_changed_token_);
- return S_OK;
- }
- // Accessor used in MapIterator for iterating over Map's container.
- // Will remain valid during the entire iteration.
- const std::map<StorageK, StorageV, internal::Less>& get_map() {
- DCHECK(map_);
- return map_->map_;
- }
- bool ValidState() const { return map_; }
- private:
- Microsoft::WRL::ComPtr<Map<LogicalK, LogicalV>> map_;
- EventRegistrationToken map_changed_token_;
- };
- public:
- Map() = default;
- explicit Map(const std::map<StorageK, StorageV, internal::Less>& map)
- : map_(map) {}
- explicit Map(std::map<StorageK, StorageV, internal::Less>&& map)
- : map_(std::move(map)) {}
- // ABI::Windows::Foundation::Collections::IMap:
- IFACEMETHODIMP Lookup(AbiK key, AbiV* value) override {
- auto it = map_.find(key);
- if (it == map_.cend())
- return E_BOUNDS;
- return internal::CopyTo(it->second, value);
- }
- IFACEMETHODIMP get_Size(unsigned int* size) override {
- *size = map_.size();
- return S_OK;
- }
- IFACEMETHODIMP HasKey(AbiK key, boolean* found) override {
- *found = Contains(map_, key);
- return S_OK;
- }
- IFACEMETHODIMP GetView(
- ABI::Windows::Foundation::Collections::IMapView<LogicalK, LogicalV>**
- view) override {
- return Microsoft::WRL::Make<MapView>(this).CopyTo(view);
- }
- IFACEMETHODIMP Insert(AbiK key, AbiV value, boolean* replaced) override {
- *replaced = !InsertOrAssign(map_, key, std::move(value)).second;
- NotifyMapChanged(*replaced ? ABI::Windows::Foundation::Collections::
- CollectionChange_ItemChanged
- : ABI::Windows::Foundation::Collections::
- CollectionChange_ItemInserted,
- key);
- return S_OK;
- }
- IFACEMETHODIMP Remove(AbiK key) override {
- if (!map_.erase(key))
- return E_BOUNDS;
- NotifyMapChanged(
- ABI::Windows::Foundation::Collections::CollectionChange_ItemRemoved,
- key);
- return S_OK;
- }
- IFACEMETHODIMP Clear() override {
- map_.clear();
- NotifyMapChanged(
- ABI::Windows::Foundation::Collections::CollectionChange_Reset,
- 0); // NOLINT(modernize-use-nullptr): AbiK may not be a pointer.
- return S_OK;
- }
- // ABI::Windows::Foundation::Collections::IObservableMap:
- IFACEMETHODIMP add_MapChanged(
- ABI::Windows::Foundation::Collections::MapChangedEventHandler<LogicalK,
- LogicalV>*
- handler,
- EventRegistrationToken* token) override {
- token->value = handler_id_++;
- handlers_.emplace_hint(handlers_.end(), token->value, handler);
- return S_OK;
- }
- IFACEMETHODIMP remove_MapChanged(EventRegistrationToken token) override {
- return handlers_.erase(token.value) ? S_OK : E_BOUNDS;
- }
- // ABI::Windows::Foundation::Collections::IIterable:
- IFACEMETHODIMP First(
- ABI::Windows::Foundation::Collections::IIterator<
- ABI::Windows::Foundation::Collections::IKeyValuePair<LogicalK,
- LogicalV>*>**
- first) override {
- return Microsoft::WRL::Make<MapIterator>(
- Microsoft::WRL::Make<MapView>(this))
- .CopyTo(first);
- }
- private:
- ~Map() override {
- // Handlers should not outlive the Map. Furthermore, they must ensure
- // they are unregistered before the handler is destroyed. This implies
- // there should be no handlers left when the Map is destructed.
- DCHECK(handlers_.empty());
- }
- void NotifyMapChanged(
- ABI::Windows::Foundation::Collections::CollectionChange change,
- AbiK key) {
- auto args =
- Microsoft::WRL::Make<internal::MapChangedEventArgs<AbiK>>(change, key);
- // Invoking the handlers could result in mutations to the map, thus we make
- // a copy beforehand.
- auto handlers = handlers_;
- for (auto& handler : handlers)
- handler.second->Invoke(this, args.Get());
- }
- std::map<StorageK, StorageV, internal::Less> map_;
- base::flat_map<int64_t,
- ABI::Windows::Foundation::Collections::
- MapChangedEventHandler<LogicalK, LogicalV>*>
- handlers_;
- int64_t handler_id_ = 0;
- };
- } // namespace win
- } // namespace base
- #endif // BASE_WIN_MAP_H_
|