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