blob: 97734159a1510348fbfe3cd790b16b7b5b49dd4c [file] [log] [blame]
Jan Wilken Dörrie22229672018-06-09 05:40:001// Copyright 2018 The Chromium Authors. All rights reserved.
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"
Hans Wennborg7b533712020-06-22 20:52:2718#include "base/check_op.h"
Jan Wilken Dörrie22229672018-06-09 05:40:0019#include "base/containers/flat_map.h"
Jan Wilken Dörrie8f953472019-07-23 11:29:3120#include "base/win/winrt_foundation_helpers.h"
Jan Wilken Dörrie22229672018-06-09 05:40:0021
22namespace base {
23namespace win {
24
25template <typename T>
26class Vector;
27
28namespace internal {
29
Jan Wilken Dörrie8f953472019-07-23 11:29:3130// Template tricks needed to dispatch to the correct implementation.
31// See base/win/winrt_foundation_helpers.h for explanation.
32
Jan Wilken Dörrie22229672018-06-09 05:40:0033template <typename T>
Julien Raclecd8a64b2019-08-15 16:08:4334using VectorComplex =
Jan Wilken Dörrie22229672018-06-09 05:40:0035 typename ABI::Windows::Foundation::Collections::IVector<T>::T_complex;
36
37template <typename T>
Julien Raclecd8a64b2019-08-15 16:08:4338using VectorLogical = LogicalType<VectorComplex<T>>;
Jan Wilken Dörrie22229672018-06-09 05:40:0039
40template <typename T>
Julien Raclecd8a64b2019-08-15 16:08:4341using VectorAbi = AbiType<VectorComplex<T>>;
Jan Wilken Dörrie8f953472019-07-23 11:29:3142
43template <typename T>
Julien Raclecd8a64b2019-08-15 16:08:4344using VectorStorage = StorageType<VectorComplex<T>>;
Jan Wilken Dörrie22229672018-06-09 05:40:0045
Julien Raclea20702962019-04-10 17:19:4546template <typename T>
47class VectorIterator
48 : public Microsoft::WRL::RuntimeClass<
49 Microsoft::WRL::RuntimeClassFlags<
50 Microsoft::WRL::WinRtClassicComMix |
51 Microsoft::WRL::InhibitRoOriginateError>,
Julien Raclecd8a64b2019-08-15 16:08:4352 ABI::Windows::Foundation::Collections::IIterator<VectorLogical<T>>> {
Julien Raclea20702962019-04-10 17:19:4553 public:
Julien Raclecd8a64b2019-08-15 16:08:4354 using LogicalT = VectorLogical<T>;
55 using AbiT = VectorAbi<T>;
Julien Raclea20702962019-04-10 17:19:4556
57 explicit VectorIterator(
58 Microsoft::WRL::ComPtr<
59 ABI::Windows::Foundation::Collections::IVectorView<LogicalT>> view)
60 : view_(std::move(view)) {}
61
62 // ABI::Windows::Foundation::Collections::IIterator:
63 IFACEMETHODIMP get_Current(AbiT* current) override {
64 return view_->GetAt(current_index_, current);
65 }
66
67 IFACEMETHODIMP get_HasCurrent(boolean* has_current) override {
68 *has_current = FALSE;
69 unsigned size;
70 HRESULT hr = view_->get_Size(&size);
71 if (SUCCEEDED(hr)) {
Sunggook Chue94514012019-11-20 01:10:5172 if (current_index_ < size) {
Julien Raclea20702962019-04-10 17:19:4573 *has_current = TRUE;
74 }
75 }
76 return hr;
77 }
78
79 IFACEMETHODIMP MoveNext(boolean* has_current) override {
Sunggook Chue94514012019-11-20 01:10:5180 *has_current = FALSE;
Richard Knoll55ea4722020-06-26 14:43:5781 unsigned size;
82 HRESULT hr = view_->get_Size(&size);
Sunggook Chue94514012019-11-20 01:10:5183 if (FAILED(hr))
84 return hr;
85
Richard Knoll55ea4722020-06-26 14:43:5786 // Check if we're already past the last item.
87 if (current_index_ >= size)
88 return E_BOUNDS;
89
90 // Move to the next item.
91 current_index_++;
92
93 // Set |has_current| to TRUE if we're still on a valid item.
94 if (current_index_ < size)
95 *has_current = TRUE;
96
97 return hr;
Julien Raclea20702962019-04-10 17:19:4598 }
99
100 IFACEMETHODIMP GetMany(unsigned capacity,
101 AbiT* value,
102 unsigned* actual) override {
103 return view_->GetMany(current_index_, capacity, value, actual);
104 }
105
106 private:
107 Microsoft::WRL::ComPtr<
108 ABI::Windows::Foundation::Collections::IVectorView<LogicalT>>
109 view_;
110 unsigned current_index_ = 0;
111};
112
Jan Wilken Dörrie22229672018-06-09 05:40:00113class BASE_EXPORT VectorChangedEventArgs
114 : public Microsoft::WRL::RuntimeClass<
115 Microsoft::WRL::RuntimeClassFlags<
116 Microsoft::WRL::WinRtClassicComMix |
117 Microsoft::WRL::InhibitRoOriginateError>,
118 ABI::Windows::Foundation::Collections::IVectorChangedEventArgs> {
119 public:
120 VectorChangedEventArgs(
121 ABI::Windows::Foundation::Collections::CollectionChange change,
122 unsigned int index)
123 : change_(change), index_(index) {}
124
125 ~VectorChangedEventArgs() override = default;
126
127 // ABI::Windows::Foundation::Collections::IVectorChangedEventArgs:
128 IFACEMETHODIMP get_CollectionChange(
129 ABI::Windows::Foundation::Collections::CollectionChange* value) override;
130 IFACEMETHODIMP get_Index(unsigned int* value) override;
131
132 private:
133 const ABI::Windows::Foundation::Collections::CollectionChange change_;
134 const unsigned int index_;
135};
136
137template <typename T>
138class VectorView
139 : public Microsoft::WRL::RuntimeClass<
140 Microsoft::WRL::RuntimeClassFlags<
141 Microsoft::WRL::WinRtClassicComMix |
142 Microsoft::WRL::InhibitRoOriginateError>,
Julien Raclecd8a64b2019-08-15 16:08:43143 ABI::Windows::Foundation::Collections::IVectorView<VectorLogical<T>>,
Jan Wilken Dörrie22229672018-06-09 05:40:00144 ABI::Windows::Foundation::Collections::VectorChangedEventHandler<
Julien Raclecd8a64b2019-08-15 16:08:43145 VectorLogical<T>>> {
Jan Wilken Dörrie22229672018-06-09 05:40:00146 public:
Julien Raclecd8a64b2019-08-15 16:08:43147 using LogicalT = VectorLogical<T>;
148 using AbiT = VectorAbi<T>;
Jan Wilken Dörrie22229672018-06-09 05:40:00149
150 explicit VectorView(Microsoft::WRL::ComPtr<Vector<LogicalT>> vector)
151 : vector_(std::move(vector)) {
152 vector_->add_VectorChanged(this, &vector_changed_token_);
153 }
154
Robert Liaoa37b8e62019-12-23 05:28:20155 ~VectorView() override {
Jan Wilken Dörrie22229672018-06-09 05:40:00156 if (vector_)
157 vector_->remove_VectorChanged(vector_changed_token_);
158 }
159
160 // ABI::Windows::Foundation::Collections::IVectorView:
161 IFACEMETHODIMP GetAt(unsigned index, AbiT* item) override {
162 return vector_ ? vector_->GetAt(index, item) : E_CHANGED_STATE;
163 }
164
165 IFACEMETHODIMP get_Size(unsigned* size) override {
166 return vector_ ? vector_->get_Size(size) : E_CHANGED_STATE;
167 }
168
169 IFACEMETHODIMP IndexOf(AbiT value, unsigned* index, boolean* found) override {
170 return vector_ ? vector_->IndexOf(std::move(value), index, found)
171 : E_CHANGED_STATE;
172 }
173
174 IFACEMETHODIMP GetMany(unsigned start_index,
175 unsigned capacity,
176 AbiT* value,
177 unsigned* actual) override {
178 return vector_ ? vector_->GetMany(start_index, capacity, value, actual)
179 : E_CHANGED_STATE;
180 }
181
182 // ABI::Windows::Foundation::Collections::VectorChangedEventHandler:
183 IFACEMETHODIMP Invoke(
184 ABI::Windows::Foundation::Collections::IObservableVector<LogicalT>*
185 sender,
186 ABI::Windows::Foundation::Collections::IVectorChangedEventArgs* e)
187 override {
188 DCHECK_EQ(vector_.Get(), sender);
189 vector_.Reset();
190 sender->remove_VectorChanged(vector_changed_token_);
191 return S_OK;
192 }
193
194 private:
195 Microsoft::WRL::ComPtr<Vector<LogicalT>> vector_;
196 EventRegistrationToken vector_changed_token_;
197};
198
199} // namespace internal
200
201// This file provides an implementation of Windows::Foundation::IVector. It
202// functions as a thin wrapper around an std::vector, and dispatches method
203// calls to either the corresponding std::vector API or appropriate
204// std::algorithms. Furthermore, it notifies its observers whenever its
jdoerriece19c6d2018-07-03 09:42:51205// observable state changes. A base::win::Vector can be constructed for any type
206// T, and is implicitly constructible from a std::vector. In the case where T is
207// a pointer derived from IUnknown, the std::vector needs to be of type
208// Microsoft::WRL::ComPtr<T>. This enforces proper reference counting and
209// improves safety.
Jan Wilken Dörrie22229672018-06-09 05:40:00210template <typename T>
211class Vector
212 : public Microsoft::WRL::RuntimeClass<
213 Microsoft::WRL::RuntimeClassFlags<
214 Microsoft::WRL::WinRt | Microsoft::WRL::InhibitRoOriginateError>,
Julien Raclecd8a64b2019-08-15 16:08:43215 ABI::Windows::Foundation::Collections::IVector<
216 internal::VectorLogical<T>>,
Jan Wilken Dörrie22229672018-06-09 05:40:00217 ABI::Windows::Foundation::Collections::IObservableVector<
Julien Raclecd8a64b2019-08-15 16:08:43218 internal::VectorLogical<T>>,
Julien Raclea20702962019-04-10 17:19:45219 ABI::Windows::Foundation::Collections::IIterable<
Julien Raclecd8a64b2019-08-15 16:08:43220 internal::VectorLogical<T>>> {
Jan Wilken Dörrie22229672018-06-09 05:40:00221 public:
Julien Raclecd8a64b2019-08-15 16:08:43222 using LogicalT = internal::VectorLogical<T>;
223 using AbiT = internal::VectorAbi<T>;
224 using StorageT = internal::VectorStorage<T>;
jdoerriece19c6d2018-07-03 09:42:51225
Jan Wilken Dörrie22229672018-06-09 05:40:00226 Vector() = default;
jdoerriece19c6d2018-07-03 09:42:51227 explicit Vector(const std::vector<StorageT>& vector) : vector_(vector) {}
228 explicit Vector(std::vector<StorageT>&& vector)
229 : vector_(std::move(vector)) {}
230
Jan Wilken Dörrie22229672018-06-09 05:40:00231 // ABI::Windows::Foundation::Collections::IVector:
232 IFACEMETHODIMP GetAt(unsigned index, AbiT* item) override {
233 if (index >= vector_.size())
234 return E_BOUNDS;
jdoerriece19c6d2018-07-03 09:42:51235 return internal::CopyTo(vector_[index], item);
Jan Wilken Dörrie22229672018-06-09 05:40:00236 }
237
238 IFACEMETHODIMP get_Size(unsigned* size) override {
239 *size = vector_.size();
240 return S_OK;
241 }
242
243 IFACEMETHODIMP GetView(
244 ABI::Windows::Foundation::Collections::IVectorView<LogicalT>** view)
245 override {
246 return Microsoft::WRL::Make<internal::VectorView<LogicalT>>(this).CopyTo(
247 view);
248 }
249
250 IFACEMETHODIMP IndexOf(AbiT value, unsigned* index, boolean* found) override {
jdoerriece19c6d2018-07-03 09:42:51251 auto iter = std::find_if(vector_.begin(), vector_.end(),
252 [&value](const StorageT& elem) {
253 return internal::IsEqual(elem, value);
254 });
Jan Wilken Dörrie22229672018-06-09 05:40:00255 *index = iter != vector_.end() ? std::distance(vector_.begin(), iter) : 0;
256 *found = iter != vector_.end();
257 return S_OK;
258 }
259
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
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
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
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
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
312 IFACEMETHODIMP Clear() override {
313 vector_.clear();
314 NotifyVectorChanged(
315 ABI::Windows::Foundation::Collections::CollectionChange_Reset, 0);
316 return S_OK;
317 }
318
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);
jdoerriece19c6d2018-07-03 09:42:51327 return internal::CopyN(std::next(vector_.begin(), start_index), *actual,
328 value);
Jan Wilken Dörrie22229672018-06-09 05:40:00329 }
330
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:
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
348 IFACEMETHODIMP remove_VectorChanged(EventRegistrationToken token) override {
349 handlers_.erase(token.value);
350 return S_OK;
351 }
352
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
Julien Raclea20702962019-04-10 17:19:45366 // ABI::Windows::Foundation::Collections::IIterable:
367 IFACEMETHODIMP First(
Julien Racle2ed8c252019-08-08 15:56:50368 ABI::Windows::Foundation::Collections::IIterator<LogicalT>** first)
369 override {
Julien Raclea20702962019-04-10 17:19:45370 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
Jan Wilken Dörrie22229672018-06-09 05:40:00382 const std::vector<AbiT>& vector_for_testing() { return vector_; }
383
384 private:
385 ~Vector() override {
386 // Handlers should not outlive the Vector. Furthermore, they must ensure
Lei Zhang20b21af82020-08-10 18:31:58387 // they are unregistered before the handler is destroyed. This implies
Jan Wilken Dörrie22229672018-06-09 05:40:00388 // there should be no handlers left when the Vector is destructed.
389 DCHECK(handlers_.empty());
390 }
391
jdoerriece19c6d2018-07-03 09:42:51392 std::vector<StorageT> vector_;
Jan Wilken Dörrie22229672018-06-09 05:40:00393 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_