• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef BASE_WIN_VECTOR_H_
6 #define BASE_WIN_VECTOR_H_
7 
8 #include <ivectorchangedeventargs.h>
9 #include <windows.foundation.collections.h>
10 #include <wrl/implements.h>
11 
12 #include <algorithm>
13 #include <iterator>
14 #include <utility>
15 #include <vector>
16 
17 #include "base/base_export.h"
18 #include "base/check_op.h"
19 #include "base/containers/flat_map.h"
20 #include "base/ranges/algorithm.h"
21 #include "base/win/winrt_foundation_helpers.h"
22 
23 namespace base {
24 namespace win {
25 
26 template <typename T>
27 class Vector;
28 
29 namespace internal {
30 
31 // Template tricks needed to dispatch to the correct implementation.
32 // See base/win/winrt_foundation_helpers.h for explanation.
33 
34 template <typename T>
35 using VectorComplex =
36     typename ABI::Windows::Foundation::Collections::IVector<T>::T_complex;
37 
38 template <typename T>
39 using VectorLogical = LogicalType<VectorComplex<T>>;
40 
41 template <typename T>
42 using VectorAbi = AbiType<VectorComplex<T>>;
43 
44 template <typename T>
45 using VectorStorage = StorageType<VectorComplex<T>>;
46 
47 template <typename T>
48 class VectorIterator
49     : public Microsoft::WRL::RuntimeClass<
50           Microsoft::WRL::RuntimeClassFlags<
51               Microsoft::WRL::WinRtClassicComMix |
52               Microsoft::WRL::InhibitRoOriginateError>,
53           ABI::Windows::Foundation::Collections::IIterator<VectorLogical<T>>> {
54  public:
55   using LogicalT = VectorLogical<T>;
56   using AbiT = VectorAbi<T>;
57 
VectorIterator(Microsoft::WRL::ComPtr<ABI::Windows::Foundation::Collections::IVectorView<LogicalT>> view)58   explicit VectorIterator(
59       Microsoft::WRL::ComPtr<
60           ABI::Windows::Foundation::Collections::IVectorView<LogicalT>> view)
61       : view_(std::move(view)) {}
62 
63   // ABI::Windows::Foundation::Collections::IIterator:
get_Current(AbiT * current)64   IFACEMETHODIMP get_Current(AbiT* current) override {
65     return view_->GetAt(current_index_, current);
66   }
67 
get_HasCurrent(boolean * has_current)68   IFACEMETHODIMP get_HasCurrent(boolean* has_current) override {
69     *has_current = FALSE;
70     unsigned size;
71     HRESULT hr = view_->get_Size(&size);
72     if (SUCCEEDED(hr)) {
73       if (current_index_ < size) {
74         *has_current = TRUE;
75       }
76     }
77     return hr;
78   }
79 
MoveNext(boolean * has_current)80   IFACEMETHODIMP MoveNext(boolean* has_current) override {
81     *has_current = FALSE;
82     unsigned size;
83     HRESULT hr = view_->get_Size(&size);
84     if (FAILED(hr))
85       return hr;
86 
87     // Check if we're already past the last item.
88     if (current_index_ >= size)
89       return E_BOUNDS;
90 
91     // Move to the next item.
92     current_index_++;
93 
94     // Set |has_current| to TRUE if we're still on a valid item.
95     if (current_index_ < size)
96       *has_current = TRUE;
97 
98     return hr;
99   }
100 
GetMany(unsigned capacity,AbiT * value,unsigned * actual)101   IFACEMETHODIMP GetMany(unsigned capacity,
102                          AbiT* value,
103                          unsigned* actual) override {
104     return view_->GetMany(current_index_, capacity, value, actual);
105   }
106 
107  private:
108   Microsoft::WRL::ComPtr<
109       ABI::Windows::Foundation::Collections::IVectorView<LogicalT>>
110       view_;
111   unsigned current_index_ = 0;
112 };
113 
114 class BASE_EXPORT VectorChangedEventArgs
115     : public Microsoft::WRL::RuntimeClass<
116           Microsoft::WRL::RuntimeClassFlags<
117               Microsoft::WRL::WinRtClassicComMix |
118               Microsoft::WRL::InhibitRoOriginateError>,
119           ABI::Windows::Foundation::Collections::IVectorChangedEventArgs> {
120  public:
VectorChangedEventArgs(ABI::Windows::Foundation::Collections::CollectionChange change,unsigned int index)121   VectorChangedEventArgs(
122       ABI::Windows::Foundation::Collections::CollectionChange change,
123       unsigned int index)
124       : change_(change), index_(index) {}
125 
126   ~VectorChangedEventArgs() override = default;
127 
128   // ABI::Windows::Foundation::Collections::IVectorChangedEventArgs:
129   IFACEMETHODIMP get_CollectionChange(
130       ABI::Windows::Foundation::Collections::CollectionChange* value) override;
131   IFACEMETHODIMP get_Index(unsigned int* value) override;
132 
133  private:
134   const ABI::Windows::Foundation::Collections::CollectionChange change_;
135   const unsigned int index_;
136 };
137 
138 template <typename T>
139 class VectorView
140     : public Microsoft::WRL::RuntimeClass<
141           Microsoft::WRL::RuntimeClassFlags<
142               Microsoft::WRL::WinRtClassicComMix |
143               Microsoft::WRL::InhibitRoOriginateError>,
144           ABI::Windows::Foundation::Collections::IVectorView<VectorLogical<T>>,
145           ABI::Windows::Foundation::Collections::VectorChangedEventHandler<
146               VectorLogical<T>>> {
147  public:
148   using LogicalT = VectorLogical<T>;
149   using AbiT = VectorAbi<T>;
150 
VectorView(Microsoft::WRL::ComPtr<Vector<LogicalT>> vector)151   explicit VectorView(Microsoft::WRL::ComPtr<Vector<LogicalT>> vector)
152       : vector_(std::move(vector)) {
153     vector_->add_VectorChanged(this, &vector_changed_token_);
154   }
155 
~VectorView()156   ~VectorView() override {
157     if (vector_)
158       vector_->remove_VectorChanged(vector_changed_token_);
159   }
160 
161   // ABI::Windows::Foundation::Collections::IVectorView:
GetAt(unsigned index,AbiT * item)162   IFACEMETHODIMP GetAt(unsigned index, AbiT* item) override {
163     return vector_ ? vector_->GetAt(index, item) : E_CHANGED_STATE;
164   }
165 
get_Size(unsigned * size)166   IFACEMETHODIMP get_Size(unsigned* size) override {
167     return vector_ ? vector_->get_Size(size) : E_CHANGED_STATE;
168   }
169 
IndexOf(AbiT value,unsigned * index,boolean * found)170   IFACEMETHODIMP IndexOf(AbiT value, unsigned* index, boolean* found) override {
171     return vector_ ? vector_->IndexOf(std::move(value), index, found)
172                    : E_CHANGED_STATE;
173   }
174 
GetMany(unsigned start_index,unsigned capacity,AbiT * value,unsigned * actual)175   IFACEMETHODIMP GetMany(unsigned start_index,
176                          unsigned capacity,
177                          AbiT* value,
178                          unsigned* actual) override {
179     return vector_ ? vector_->GetMany(start_index, capacity, value, actual)
180                    : E_CHANGED_STATE;
181   }
182 
183   // ABI::Windows::Foundation::Collections::VectorChangedEventHandler:
Invoke(ABI::Windows::Foundation::Collections::IObservableVector<LogicalT> * sender,ABI::Windows::Foundation::Collections::IVectorChangedEventArgs * e)184   IFACEMETHODIMP Invoke(
185       ABI::Windows::Foundation::Collections::IObservableVector<LogicalT>*
186           sender,
187       ABI::Windows::Foundation::Collections::IVectorChangedEventArgs* e)
188       override {
189     DCHECK_EQ(vector_.Get(), sender);
190     vector_.Reset();
191     sender->remove_VectorChanged(vector_changed_token_);
192     return S_OK;
193   }
194 
195  private:
196   Microsoft::WRL::ComPtr<Vector<LogicalT>> vector_;
197   EventRegistrationToken vector_changed_token_;
198 };
199 
200 }  // namespace internal
201 
202 // This file provides an implementation of Windows::Foundation::IVector. It
203 // functions as a thin wrapper around an std::vector, and dispatches method
204 // calls to either the corresponding std::vector API or appropriate
205 // std::algorithms. Furthermore, it notifies its observers whenever its
206 // observable state changes. A base::win::Vector can be constructed for any type
207 // T, and is implicitly constructible from a std::vector. In the case where T is
208 // a pointer derived from IUnknown, the std::vector needs to be of type
209 // Microsoft::WRL::ComPtr<T>. This enforces proper reference counting and
210 // improves safety.
211 template <typename T>
212 class Vector
213     : public Microsoft::WRL::RuntimeClass<
214           Microsoft::WRL::RuntimeClassFlags<
215               Microsoft::WRL::WinRt | Microsoft::WRL::InhibitRoOriginateError>,
216           ABI::Windows::Foundation::Collections::IVector<
217               internal::VectorLogical<T>>,
218           ABI::Windows::Foundation::Collections::IObservableVector<
219               internal::VectorLogical<T>>,
220           ABI::Windows::Foundation::Collections::IIterable<
221               internal::VectorLogical<T>>> {
222  public:
223   using LogicalT = internal::VectorLogical<T>;
224   using AbiT = internal::VectorAbi<T>;
225   using StorageT = internal::VectorStorage<T>;
226 
227   Vector() = default;
Vector(const std::vector<StorageT> & vector)228   explicit Vector(const std::vector<StorageT>& vector) : vector_(vector) {}
Vector(std::vector<StorageT> && vector)229   explicit Vector(std::vector<StorageT>&& vector)
230       : vector_(std::move(vector)) {}
231 
232   // ABI::Windows::Foundation::Collections::IVector:
GetAt(unsigned index,AbiT * item)233   IFACEMETHODIMP GetAt(unsigned index, AbiT* item) override {
234     if (index >= vector_.size())
235       return E_BOUNDS;
236     return internal::CopyTo(vector_[index], item);
237   }
238 
get_Size(unsigned * size)239   IFACEMETHODIMP get_Size(unsigned* size) override {
240     *size = vector_.size();
241     return S_OK;
242   }
243 
GetView(ABI::Windows::Foundation::Collections::IVectorView<LogicalT> ** view)244   IFACEMETHODIMP GetView(
245       ABI::Windows::Foundation::Collections::IVectorView<LogicalT>** view)
246       override {
247     return Microsoft::WRL::Make<internal::VectorView<LogicalT>>(this).CopyTo(
248         view);
249   }
250 
IndexOf(AbiT value,unsigned * index,boolean * found)251   IFACEMETHODIMP IndexOf(AbiT value, unsigned* index, boolean* found) override {
252     auto iter = base::ranges::find_if(vector_, [&value](const StorageT& elem) {
253       return internal::IsEqual(elem, value);
254     });
255     *index = iter != vector_.end() ? std::distance(vector_.begin(), iter) : 0;
256     *found = iter != vector_.end();
257     return S_OK;
258   }
259 
SetAt(unsigned index,AbiT item)260   IFACEMETHODIMP SetAt(unsigned index, AbiT item) override {
261     if (index >= vector_.size())
262       return E_BOUNDS;
263 
264     vector_[index] = std::move(item);
265     NotifyVectorChanged(
266         ABI::Windows::Foundation::Collections::CollectionChange_ItemChanged,
267         index);
268     return S_OK;
269   }
270 
InsertAt(unsigned index,AbiT item)271   IFACEMETHODIMP InsertAt(unsigned index, AbiT item) override {
272     if (index > vector_.size())
273       return E_BOUNDS;
274 
275     vector_.insert(std::next(vector_.begin(), index), std::move(item));
276     NotifyVectorChanged(
277         ABI::Windows::Foundation::Collections::CollectionChange_ItemInserted,
278         index);
279     return S_OK;
280   }
281 
RemoveAt(unsigned index)282   IFACEMETHODIMP RemoveAt(unsigned index) override {
283     if (index >= vector_.size())
284       return E_BOUNDS;
285 
286     vector_.erase(std::next(vector_.begin(), index));
287     NotifyVectorChanged(
288         ABI::Windows::Foundation::Collections::CollectionChange_ItemRemoved,
289         index);
290     return S_OK;
291   }
292 
Append(AbiT item)293   IFACEMETHODIMP Append(AbiT item) override {
294     vector_.push_back(std::move(item));
295     NotifyVectorChanged(
296         ABI::Windows::Foundation::Collections::CollectionChange_ItemInserted,
297         vector_.size() - 1);
298     return S_OK;
299   }
300 
RemoveAtEnd()301   IFACEMETHODIMP RemoveAtEnd() override {
302     if (vector_.empty())
303       return E_BOUNDS;
304 
305     vector_.pop_back();
306     NotifyVectorChanged(
307         ABI::Windows::Foundation::Collections::CollectionChange_ItemRemoved,
308         vector_.size());
309     return S_OK;
310   }
311 
Clear()312   IFACEMETHODIMP Clear() override {
313     vector_.clear();
314     NotifyVectorChanged(
315         ABI::Windows::Foundation::Collections::CollectionChange_Reset, 0);
316     return S_OK;
317   }
318 
GetMany(unsigned start_index,unsigned capacity,AbiT * value,unsigned * actual)319   IFACEMETHODIMP GetMany(unsigned start_index,
320                          unsigned capacity,
321                          AbiT* value,
322                          unsigned* actual) override {
323     if (start_index > vector_.size())
324       return E_BOUNDS;
325 
326     *actual = std::min<unsigned>(vector_.size() - start_index, capacity);
327     return internal::CopyN(std::next(vector_.begin(), start_index), *actual,
328                            value);
329   }
330 
ReplaceAll(unsigned count,AbiT * value)331   IFACEMETHODIMP ReplaceAll(unsigned count, AbiT* value) override {
332     vector_.assign(value, std::next(value, count));
333     NotifyVectorChanged(
334         ABI::Windows::Foundation::Collections::CollectionChange_Reset, 0);
335     return S_OK;
336   }
337 
338   // ABI::Windows::Foundation::Collections::IObservableVector:
add_VectorChanged(ABI::Windows::Foundation::Collections::VectorChangedEventHandler<LogicalT> * handler,EventRegistrationToken * token)339   IFACEMETHODIMP add_VectorChanged(
340       ABI::Windows::Foundation::Collections::VectorChangedEventHandler<
341           LogicalT>* handler,
342       EventRegistrationToken* token) override {
343     token->value = handler_id_++;
344     handlers_.emplace_hint(handlers_.end(), token->value, handler);
345     return S_OK;
346   }
347 
remove_VectorChanged(EventRegistrationToken token)348   IFACEMETHODIMP remove_VectorChanged(EventRegistrationToken token) override {
349     handlers_.erase(token.value);
350     return S_OK;
351   }
352 
NotifyVectorChanged(ABI::Windows::Foundation::Collections::CollectionChange change,unsigned int index)353   void NotifyVectorChanged(
354       ABI::Windows::Foundation::Collections::CollectionChange change,
355       unsigned int index) {
356     auto args =
357         Microsoft::WRL::Make<internal::VectorChangedEventArgs>(change, index);
358 
359     // Invoking the handlers could result in mutations to the map, thus we make
360     // a copy beforehand.
361     auto handlers = handlers_;
362     for (auto& handler : handlers)
363       handler.second->Invoke(this, args.Get());
364   }
365 
366   // ABI::Windows::Foundation::Collections::IIterable:
First(ABI::Windows::Foundation::Collections::IIterator<LogicalT> ** first)367   IFACEMETHODIMP First(
368       ABI::Windows::Foundation::Collections::IIterator<LogicalT>** first)
369       override {
370     Microsoft::WRL::ComPtr<
371         ABI::Windows::Foundation::Collections::IVectorView<LogicalT>>
372         view;
373     HRESULT hr = GetView(&view);
374     if (SUCCEEDED(hr)) {
375       return Microsoft::WRL::Make<internal::VectorIterator<LogicalT>>(view)
376           .CopyTo(first);
377     } else {
378       return hr;
379     }
380   }
381 
vector_for_testing()382   const std::vector<AbiT>& vector_for_testing() { return vector_; }
383 
384  private:
~Vector()385   ~Vector() override {
386     // Handlers should not outlive the Vector. Furthermore, they must ensure
387     // they are unregistered before the handler is destroyed. This implies
388     // there should be no handlers left when the Vector is destructed.
389     DCHECK(handlers_.empty());
390   }
391 
392   std::vector<StorageT> vector_;
393   base::flat_map<int64_t,
394                  ABI::Windows::Foundation::Collections::
395                      VectorChangedEventHandler<LogicalT>*>
396       handlers_;
397   int64_t handler_id_ = 0;
398 };
399 
400 }  // namespace win
401 }  // namespace base
402 
403 #endif  // BASE_WIN_VECTOR_H_
404