[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_