[base] Implement IVector
This change provides implementations for the IVector WinRT interface.
Vector is a thin wrapper around a std::vector, and also implements the
IObservableVector interface.
Bug: 821766
Change-Id: I2e81b843d87e53f023b659a07af46d2752a65cc9
Reviewed-on: https://chromium-review.googlesource.com/1059784
Commit-Queue: Jan Wilken Dörrie <[email protected]>
Reviewed-by: Robert Liao <[email protected]>
Reviewed-by: Daniel Cheng <[email protected]>
Cr-Commit-Position: refs/heads/master@{#565865}
diff --git a/base/win/vector.h b/base/win/vector.h
new file mode 100644
index 0000000..9946861
--- /dev/null
+++ b/base/win/vector.h
@@ -0,0 +1,315 @@
+// 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/containers/flat_map.h"
+#include "base/logging.h"
+
+namespace base {
+namespace win {
+
+template <typename T>
+class Vector;
+
+namespace internal {
+
+template <typename T>
+using Complex =
+ typename ABI::Windows::Foundation::Collections::IVector<T>::T_complex;
+
+template <typename T>
+using Logical = typename ABI::Windows::Foundation::Internal::GetLogicalType<
+ Complex<T>>::type;
+
+template <typename T>
+using Abi =
+ typename ABI::Windows::Foundation::Internal::GetAbiType<Complex<T>>::type;
+
+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<Logical<T>>,
+ ABI::Windows::Foundation::Collections::VectorChangedEventHandler<
+ Logical<T>>> {
+ public:
+ using LogicalT = Logical<T>;
+ using AbiT = Abi<T>;
+
+ explicit VectorView(Microsoft::WRL::ComPtr<Vector<LogicalT>> vector)
+ : vector_(std::move(vector)) {
+ vector_->add_VectorChanged(this, &vector_changed_token_);
+ }
+
+ ~VectorView() {
+ 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.
+template <typename T>
+class Vector
+ : public Microsoft::WRL::RuntimeClass<
+ Microsoft::WRL::RuntimeClassFlags<
+ Microsoft::WRL::WinRt | Microsoft::WRL::InhibitRoOriginateError>,
+ ABI::Windows::Foundation::Collections::IVector<internal::Logical<T>>,
+ ABI::Windows::Foundation::Collections::IObservableVector<
+ internal::Logical<T>>> {
+ public:
+ // windows.foundation.collections.h defines the following template and
+ // semantics in Windows::Foundation::Internal:
+ //
+ // template <class LogicalType, class AbiType>
+ // struct AggregateType;
+ //
+ // LogicalType - the Windows Runtime type (eg, runtime class, interface
+ // group, etc) being provided as an argument to an _impl
+ // template, when that type cannot be represented at the ABI.
+ // AbiType - the type used for marshalling, ie "at the ABI", for the
+ // logical type.
+ using LogicalT = internal::Logical<T>;
+ using AbiT = internal::Abi<T>;
+
+ Vector() = default;
+ explicit Vector(const std::vector<AbiT>& vector) : vector_(vector) {}
+ explicit Vector(std::vector<AbiT>&& vector) : vector_(std::move(vector)) {}
+ // ABI::Windows::Foundation::Collections::IVector:
+ IFACEMETHODIMP GetAt(unsigned index, AbiT* item) override {
+ if (index >= vector_.size())
+ return E_BOUNDS;
+
+ *item = vector_[index];
+ return S_OK;
+ }
+
+ 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(vector_.begin(), vector_.end(), 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);
+ std::copy_n(std::next(vector_.begin(), start_index), *actual, value);
+ return S_OK;
+ }
+
+ 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());
+ }
+
+ 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 the handler is destroyed. This implies
+ // there should be no handlers left when the Vector is destructed.
+ DCHECK(handlers_.empty());
+ }
+
+ std::vector<AbiT> 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_