mirror of
https://github.com/klzgrad/naiveproxy.git
synced 2024-11-24 22:36:09 +03:00
367 lines
12 KiB
C
367 lines
12 KiB
C
|
// 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_;
|
||
|
};
|
||
|
|
||
|
template <typename T>
|
||
|
HRESULT CopyTo(const T& value, T* ptr) {
|
||
|
*ptr = value;
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
template <typename T>
|
||
|
HRESULT CopyTo(const Microsoft::WRL::ComPtr<T>& com_ptr, T** ptr) {
|
||
|
return com_ptr.CopyTo(ptr);
|
||
|
}
|
||
|
|
||
|
template <typename T>
|
||
|
HRESULT CopyN(typename std::vector<T>::const_iterator first,
|
||
|
unsigned count,
|
||
|
T* result) {
|
||
|
std::copy_n(first, count, result);
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
template <typename T>
|
||
|
HRESULT CopyN(
|
||
|
typename std::vector<Microsoft::WRL::ComPtr<T>>::const_iterator first,
|
||
|
unsigned count,
|
||
|
T** result) {
|
||
|
for (unsigned i = 0; i < count; ++i)
|
||
|
CopyTo(*first++, result++);
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
template <typename T>
|
||
|
bool IsEqual(const T& lhs, const T& rhs) {
|
||
|
return lhs == rhs;
|
||
|
}
|
||
|
|
||
|
template <typename T>
|
||
|
bool IsEqual(const Microsoft::WRL::ComPtr<T>& com_ptr, const T* ptr) {
|
||
|
return com_ptr.Get() == ptr;
|
||
|
}
|
||
|
|
||
|
} // 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. A base::win::Vector can be constructed for any type
|
||
|
// T, and is implicitly constructible from a std::vector. In the case where T is
|
||
|
// a pointer derived from IUnknown, the std::vector needs to be of type
|
||
|
// Microsoft::WRL::ComPtr<T>. This enforces proper reference counting and
|
||
|
// improves safety.
|
||
|
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>;
|
||
|
|
||
|
using StorageT =
|
||
|
std::conditional_t<std::is_convertible<AbiT, IUnknown*>::value,
|
||
|
Microsoft::WRL::ComPtr<std::remove_pointer_t<AbiT>>,
|
||
|
AbiT>;
|
||
|
|
||
|
Vector() = default;
|
||
|
explicit Vector(const std::vector<StorageT>& vector) : vector_(vector) {}
|
||
|
explicit Vector(std::vector<StorageT>&& vector)
|
||
|
: vector_(std::move(vector)) {}
|
||
|
|
||
|
// ABI::Windows::Foundation::Collections::IVector:
|
||
|
IFACEMETHODIMP GetAt(unsigned index, AbiT* item) override {
|
||
|
if (index >= vector_.size())
|
||
|
return E_BOUNDS;
|
||
|
return internal::CopyTo(vector_[index], item);
|
||
|
}
|
||
|
|
||
|
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_if(vector_.begin(), vector_.end(),
|
||
|
[&value](const StorageT& elem) {
|
||
|
return internal::IsEqual(elem, 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);
|
||
|
return internal::CopyN(std::next(vector_.begin(), start_index), *actual,
|
||
|
value);
|
||
|
}
|
||
|
|
||
|
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<StorageT> 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_
|