123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403 |
- // Copyright 2018 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_VECTOR_H_
- #define BASE_WIN_VECTOR_H_
- #include <ivectorchangedeventargs.h>
- #include <windows.foundation.collections.h>
- #include <wrl/implements.h>
- #include <algorithm>
- #include <iterator>
- #include <utility>
- #include <vector>
- #include "base/base_export.h"
- #include "base/check_op.h"
- #include "base/containers/flat_map.h"
- #include "base/win/winrt_foundation_helpers.h"
- namespace base {
- namespace win {
- template <typename T>
- class Vector;
- namespace internal {
- // Template tricks needed to dispatch to the correct implementation.
- // See base/win/winrt_foundation_helpers.h for explanation.
- template <typename T>
- using VectorComplex =
- typename ABI::Windows::Foundation::Collections::IVector<T>::T_complex;
- template <typename T>
- using VectorLogical = LogicalType<VectorComplex<T>>;
- template <typename T>
- using VectorAbi = AbiType<VectorComplex<T>>;
- template <typename T>
- using VectorStorage = StorageType<VectorComplex<T>>;
- template <typename T>
- class VectorIterator
- : public Microsoft::WRL::RuntimeClass<
- Microsoft::WRL::RuntimeClassFlags<
- Microsoft::WRL::WinRtClassicComMix |
- Microsoft::WRL::InhibitRoOriginateError>,
- ABI::Windows::Foundation::Collections::IIterator<VectorLogical<T>>> {
- public:
- using LogicalT = VectorLogical<T>;
- using AbiT = VectorAbi<T>;
- explicit VectorIterator(
- Microsoft::WRL::ComPtr<
- ABI::Windows::Foundation::Collections::IVectorView<LogicalT>> view)
- : view_(std::move(view)) {}
- // ABI::Windows::Foundation::Collections::IIterator:
- IFACEMETHODIMP get_Current(AbiT* current) override {
- return view_->GetAt(current_index_, current);
- }
- IFACEMETHODIMP get_HasCurrent(boolean* has_current) override {
- *has_current = FALSE;
- unsigned size;
- HRESULT hr = view_->get_Size(&size);
- if (SUCCEEDED(hr)) {
- if (current_index_ < size) {
- *has_current = TRUE;
- }
- }
- return hr;
- }
- IFACEMETHODIMP MoveNext(boolean* has_current) override {
- *has_current = FALSE;
- unsigned size;
- HRESULT hr = view_->get_Size(&size);
- if (FAILED(hr))
- return hr;
- // Check if we're already past the last item.
- if (current_index_ >= size)
- return E_BOUNDS;
- // Move to the next item.
- current_index_++;
- // Set |has_current| to TRUE if we're still on a valid item.
- if (current_index_ < size)
- *has_current = TRUE;
- return hr;
- }
- IFACEMETHODIMP GetMany(unsigned capacity,
- AbiT* value,
- unsigned* actual) override {
- return view_->GetMany(current_index_, capacity, value, actual);
- }
- private:
- Microsoft::WRL::ComPtr<
- ABI::Windows::Foundation::Collections::IVectorView<LogicalT>>
- view_;
- unsigned current_index_ = 0;
- };
- class BASE_EXPORT VectorChangedEventArgs
- : public Microsoft::WRL::RuntimeClass<
- Microsoft::WRL::RuntimeClassFlags<
- Microsoft::WRL::WinRtClassicComMix |
- Microsoft::WRL::InhibitRoOriginateError>,
- ABI::Windows::Foundation::Collections::IVectorChangedEventArgs> {
- public:
- VectorChangedEventArgs(
- ABI::Windows::Foundation::Collections::CollectionChange change,
- unsigned int index)
- : change_(change), index_(index) {}
- ~VectorChangedEventArgs() override = default;
- // ABI::Windows::Foundation::Collections::IVectorChangedEventArgs:
- IFACEMETHODIMP get_CollectionChange(
- ABI::Windows::Foundation::Collections::CollectionChange* value) override;
- IFACEMETHODIMP get_Index(unsigned int* value) override;
- private:
- const ABI::Windows::Foundation::Collections::CollectionChange change_;
- const unsigned int index_;
- };
- template <typename T>
- class VectorView
- : public Microsoft::WRL::RuntimeClass<
- Microsoft::WRL::RuntimeClassFlags<
- Microsoft::WRL::WinRtClassicComMix |
- Microsoft::WRL::InhibitRoOriginateError>,
- ABI::Windows::Foundation::Collections::IVectorView<VectorLogical<T>>,
- ABI::Windows::Foundation::Collections::VectorChangedEventHandler<
- VectorLogical<T>>> {
- public:
- using LogicalT = VectorLogical<T>;
- using AbiT = VectorAbi<T>;
- explicit VectorView(Microsoft::WRL::ComPtr<Vector<LogicalT>> vector)
- : vector_(std::move(vector)) {
- vector_->add_VectorChanged(this, &vector_changed_token_);
- }
- ~VectorView() override {
- if (vector_)
- vector_->remove_VectorChanged(vector_changed_token_);
- }
- // ABI::Windows::Foundation::Collections::IVectorView:
- IFACEMETHODIMP GetAt(unsigned index, AbiT* item) override {
- return vector_ ? vector_->GetAt(index, item) : E_CHANGED_STATE;
- }
- IFACEMETHODIMP get_Size(unsigned* size) override {
- return vector_ ? vector_->get_Size(size) : E_CHANGED_STATE;
- }
- IFACEMETHODIMP IndexOf(AbiT value, unsigned* index, boolean* found) override {
- return vector_ ? vector_->IndexOf(std::move(value), index, found)
- : E_CHANGED_STATE;
- }
- IFACEMETHODIMP GetMany(unsigned start_index,
- unsigned capacity,
- AbiT* value,
- unsigned* actual) override {
- return vector_ ? vector_->GetMany(start_index, capacity, value, actual)
- : E_CHANGED_STATE;
- }
- // ABI::Windows::Foundation::Collections::VectorChangedEventHandler:
- IFACEMETHODIMP Invoke(
- ABI::Windows::Foundation::Collections::IObservableVector<LogicalT>*
- sender,
- ABI::Windows::Foundation::Collections::IVectorChangedEventArgs* e)
- override {
- DCHECK_EQ(vector_.Get(), sender);
- vector_.Reset();
- sender->remove_VectorChanged(vector_changed_token_);
- return S_OK;
- }
- private:
- Microsoft::WRL::ComPtr<Vector<LogicalT>> vector_;
- EventRegistrationToken vector_changed_token_;
- };
- } // namespace internal
- // This file provides an implementation of Windows::Foundation::IVector. It
- // functions as a thin wrapper around an std::vector, and dispatches method
- // calls to either the corresponding std::vector API or appropriate
- // std::algorithms. Furthermore, it notifies its observers whenever its
- // observable state changes. A base::win::Vector can be constructed for any type
- // T, and is implicitly constructible from a std::vector. In the case where T is
- // a pointer derived from IUnknown, the std::vector needs to be of type
- // Microsoft::WRL::ComPtr<T>. This enforces proper reference counting and
- // improves safety.
- template <typename T>
- class Vector
- : public Microsoft::WRL::RuntimeClass<
- Microsoft::WRL::RuntimeClassFlags<
- Microsoft::WRL::WinRt | Microsoft::WRL::InhibitRoOriginateError>,
- ABI::Windows::Foundation::Collections::IVector<
- internal::VectorLogical<T>>,
- ABI::Windows::Foundation::Collections::IObservableVector<
- internal::VectorLogical<T>>,
- ABI::Windows::Foundation::Collections::IIterable<
- internal::VectorLogical<T>>> {
- public:
- using LogicalT = internal::VectorLogical<T>;
- using AbiT = internal::VectorAbi<T>;
- using StorageT = internal::VectorStorage<T>;
- Vector() = default;
- explicit Vector(const std::vector<StorageT>& vector) : vector_(vector) {}
- explicit Vector(std::vector<StorageT>&& vector)
- : vector_(std::move(vector)) {}
- // ABI::Windows::Foundation::Collections::IVector:
- IFACEMETHODIMP GetAt(unsigned index, AbiT* item) override {
- if (index >= vector_.size())
- return E_BOUNDS;
- return internal::CopyTo(vector_[index], item);
- }
- IFACEMETHODIMP get_Size(unsigned* size) override {
- *size = vector_.size();
- return S_OK;
- }
- IFACEMETHODIMP GetView(
- ABI::Windows::Foundation::Collections::IVectorView<LogicalT>** view)
- override {
- return Microsoft::WRL::Make<internal::VectorView<LogicalT>>(this).CopyTo(
- view);
- }
- IFACEMETHODIMP IndexOf(AbiT value, unsigned* index, boolean* found) override {
- auto iter = std::find_if(vector_.begin(), vector_.end(),
- [&value](const StorageT& elem) {
- return internal::IsEqual(elem, value);
- });
- *index = iter != vector_.end() ? std::distance(vector_.begin(), iter) : 0;
- *found = iter != vector_.end();
- return S_OK;
- }
- IFACEMETHODIMP SetAt(unsigned index, AbiT item) override {
- if (index >= vector_.size())
- return E_BOUNDS;
- vector_[index] = std::move(item);
- NotifyVectorChanged(
- ABI::Windows::Foundation::Collections::CollectionChange_ItemChanged,
- index);
- return S_OK;
- }
- IFACEMETHODIMP InsertAt(unsigned index, AbiT item) override {
- if (index > vector_.size())
- return E_BOUNDS;
- vector_.insert(std::next(vector_.begin(), index), std::move(item));
- NotifyVectorChanged(
- ABI::Windows::Foundation::Collections::CollectionChange_ItemInserted,
- index);
- return S_OK;
- }
- IFACEMETHODIMP RemoveAt(unsigned index) override {
- if (index >= vector_.size())
- return E_BOUNDS;
- vector_.erase(std::next(vector_.begin(), index));
- NotifyVectorChanged(
- ABI::Windows::Foundation::Collections::CollectionChange_ItemRemoved,
- index);
- return S_OK;
- }
- IFACEMETHODIMP Append(AbiT item) override {
- vector_.push_back(std::move(item));
- NotifyVectorChanged(
- ABI::Windows::Foundation::Collections::CollectionChange_ItemInserted,
- vector_.size() - 1);
- return S_OK;
- }
- IFACEMETHODIMP RemoveAtEnd() override {
- if (vector_.empty())
- return E_BOUNDS;
- vector_.pop_back();
- NotifyVectorChanged(
- ABI::Windows::Foundation::Collections::CollectionChange_ItemRemoved,
- vector_.size());
- return S_OK;
- }
- IFACEMETHODIMP Clear() override {
- vector_.clear();
- NotifyVectorChanged(
- ABI::Windows::Foundation::Collections::CollectionChange_Reset, 0);
- return S_OK;
- }
- IFACEMETHODIMP GetMany(unsigned start_index,
- unsigned capacity,
- AbiT* value,
- unsigned* actual) override {
- if (start_index > vector_.size())
- return E_BOUNDS;
- *actual = std::min<unsigned>(vector_.size() - start_index, capacity);
- return internal::CopyN(std::next(vector_.begin(), start_index), *actual,
- value);
- }
- IFACEMETHODIMP ReplaceAll(unsigned count, AbiT* value) override {
- vector_.assign(value, std::next(value, count));
- NotifyVectorChanged(
- ABI::Windows::Foundation::Collections::CollectionChange_Reset, 0);
- return S_OK;
- }
- // ABI::Windows::Foundation::Collections::IObservableVector:
- IFACEMETHODIMP add_VectorChanged(
- ABI::Windows::Foundation::Collections::VectorChangedEventHandler<
- LogicalT>* handler,
- EventRegistrationToken* token) override {
- token->value = handler_id_++;
- handlers_.emplace_hint(handlers_.end(), token->value, handler);
- return S_OK;
- }
- IFACEMETHODIMP remove_VectorChanged(EventRegistrationToken token) override {
- handlers_.erase(token.value);
- return S_OK;
- }
- void NotifyVectorChanged(
- ABI::Windows::Foundation::Collections::CollectionChange change,
- unsigned int index) {
- auto args =
- Microsoft::WRL::Make<internal::VectorChangedEventArgs>(change, index);
- // 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());
- }
- // ABI::Windows::Foundation::Collections::IIterable:
- IFACEMETHODIMP First(
- ABI::Windows::Foundation::Collections::IIterator<LogicalT>** first)
- override {
- Microsoft::WRL::ComPtr<
- ABI::Windows::Foundation::Collections::IVectorView<LogicalT>>
- view;
- HRESULT hr = GetView(&view);
- if (SUCCEEDED(hr)) {
- return Microsoft::WRL::Make<internal::VectorIterator<LogicalT>>(view)
- .CopyTo(first);
- } else {
- return hr;
- }
- }
- const std::vector<AbiT>& vector_for_testing() { return vector_; }
- private:
- ~Vector() override {
- // Handlers should not outlive the Vector. Furthermore, they must ensure
- // they are unregistered before the handler is destroyed. This implies
- // there should be no handlers left when the Vector is destructed.
- DCHECK(handlers_.empty());
- }
- std::vector<StorageT> vector_;
- base::flat_map<int64_t,
- ABI::Windows::Foundation::Collections::
- VectorChangedEventHandler<LogicalT>*>
- handlers_;
- int64_t handler_id_ = 0;
- };
- } // namespace win
- } // namespace base
- #endif // BASE_WIN_VECTOR_H_
|