Commit 3c19d0ea authored by Jan Wilken Doerrie's avatar Jan Wilken Doerrie Committed by Commit Bot

[base] Simplify IAsyncOperation Implementation

This change simplifies base/win/async_operation.h by deduplicating logic
and flattening the class hierarchy. This is possible by introducing two
compile time switches, that pick the correct storage and result type
depending on the provided template instantiation.

Bug: 821766
Change-Id: Ia04dc4cdbc42a4005204491cc47650d35f413cdb
Reviewed-on: https://chromium-review.googlesource.com/1106382Reviewed-by: default avatarRobert Liao <robliao@chromium.org>
Commit-Queue: Jan Wilken Dörrie <jdoerrie@chromium.org>
Cr-Commit-Position: refs/heads/master@{#568758}
parent 5eefd62a
...@@ -108,57 +108,46 @@ using LogicalT = typename ABI::Windows::Foundation::Internal::GetLogicalType< ...@@ -108,57 +108,46 @@ using LogicalT = typename ABI::Windows::Foundation::Internal::GetLogicalType<
template <typename T> template <typename T>
using InterfaceT = std::remove_pointer_t<AbiT<T>>; using InterfaceT = std::remove_pointer_t<AbiT<T>>;
// Implementation of shared functionality. // Compile time switch to decide what container to use for the async results for
template <class T> // |T|. Depends on whether the underlying Abi type is a pointer to IUnknown or
class AsyncOperationBase // not. It queries the internals of Windows::Foundation to obtain this
: public Microsoft::WRL::RuntimeClass< // information.
Microsoft::WRL::RuntimeClassFlags< template <typename T>
Microsoft::WRL::WinRt | Microsoft::WRL::InhibitRoOriginateError>, using ResultT =
ABI::Windows::Foundation::IAsyncOperation<T>> { std::conditional_t<std::is_convertible<AbiT<T>, IUnknown*>::value,
public: Microsoft::WRL::ComPtr<std::remove_pointer_t<AbiT<T>>>,
using Handler = ABI::Windows::Foundation::IAsyncOperationCompletedHandler<T>; AbiT<T>>;
AsyncOperationBase() = default;
~AsyncOperationBase() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); }
// ABI::Windows::Foundation::IAsyncOperation:
IFACEMETHODIMP put_Completed(Handler* handler) override {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
handler_ = handler;
return S_OK;
}
IFACEMETHODIMP get_Completed(Handler** handler) override {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
return handler_.CopyTo(handler);
}
protected:
void InvokeCompletedHandler() {
handler_->Invoke(this, ABI::Windows::Foundation::AsyncStatus::Completed);
}
THREAD_CHECKER(thread_checker_); template <typename T>
using StorageT =
std::conditional_t<std::is_convertible<AbiT<T>, IUnknown*>::value,
Microsoft::WRL::ComPtr<std::remove_pointer_t<AbiT<T>>>,
base::Optional<AbiT<T>>>;
private: template <typename T>
Microsoft::WRL::ComPtr<Handler> handler_; HRESULT CopyStorage(const Microsoft::WRL::ComPtr<T>& storage, T** results) {
return storage.CopyTo(results);
}
DISALLOW_COPY_AND_ASSIGN(AsyncOperationBase); template <typename T>
}; HRESULT CopyStorage(const base::Optional<T>& storage, T* results) {
*results = *storage;
return S_OK;
}
} // namespace internal } // namespace internal
template <typename T, typename Enable = void> template <class T>
class AsyncOperation; class AsyncOperation
: public Microsoft::WRL::RuntimeClass<
template <typename T> Microsoft::WRL::RuntimeClassFlags<
class AsyncOperation< Microsoft::WRL::WinRt | Microsoft::WRL::InhibitRoOriginateError>,
T, ABI::Windows::Foundation::IAsyncOperation<T>> {
std::enable_if_t<std::is_base_of<IUnknown, internal::InterfaceT<T>>::value>>
: public internal::AsyncOperationBase<T> {
public: public:
using InterfacePointer = Microsoft::WRL::ComPtr<internal::InterfaceT<T>>; using StorageT = internal::StorageT<T>;
using ResultCallback = base::OnceCallback<void(InterfacePointer)>; using ResultT = internal::ResultT<T>;
using Handler = ABI::Windows::Foundation::IAsyncOperationCompletedHandler<T>;
using ResultCallback = base::OnceCallback<void(ResultT)>;
AsyncOperation() : weak_factory_(this) { AsyncOperation() : weak_factory_(this) {
// Note: This can't be done in the constructor initializer list. This is // Note: This can't be done in the constructor initializer list. This is
...@@ -168,74 +157,49 @@ class AsyncOperation< ...@@ -168,74 +157,49 @@ class AsyncOperation<
base::BindOnce(&AsyncOperation::OnResult, weak_factory_.GetWeakPtr()); base::BindOnce(&AsyncOperation::OnResult, weak_factory_.GetWeakPtr());
} }
ResultCallback callback() { ~AsyncOperation() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); }
// Note: `this->` here and below is necessary due to the
// -Wmicrosoft-template compiler warning.
DCHECK_CALLED_ON_VALID_THREAD(this->thread_checker_);
DCHECK(!callback_.is_null());
return std::move(callback_);
}
// ABI::Windows::Foundation::IAsyncOperation: // ABI::Windows::Foundation::IAsyncOperation:
IFACEMETHODIMP GetResults(internal::AbiT<T>* results) override { IFACEMETHODIMP put_Completed(Handler* handler) override {
DCHECK_CALLED_ON_VALID_THREAD(this->thread_checker_); DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
return ptr_ ? ptr_.CopyTo(results) : E_PENDING; handler_ = handler;
return S_OK;
} }
IFACEMETHODIMP get_Completed(Handler** handler) override {
private: DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
void OnResult(InterfacePointer ptr) { return handler_.CopyTo(handler);
DCHECK_CALLED_ON_VALID_THREAD(this->thread_checker_);
DCHECK(!ptr_);
ptr_ = std::move(ptr);
this->InvokeCompletedHandler();
} }
IFACEMETHODIMP GetResults(internal::AbiT<T>* results) override {
ResultCallback callback_; DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
InterfacePointer ptr_; return storage_ ? internal::CopyStorage(storage_, results) : E_PENDING;
base::WeakPtrFactory<AsyncOperation> weak_factory_;
};
template <typename T>
class AsyncOperation<
T,
std::enable_if_t<
!std::is_base_of<IUnknown, internal::InterfaceT<T>>::value>>
: public internal::AsyncOperationBase<T> {
public:
using ResultCallback = base::OnceCallback<void(T)>;
AsyncOperation() : weak_factory_(this) {
callback_ =
base::BindOnce(&AsyncOperation::OnResult, weak_factory_.GetWeakPtr());
} }
ResultCallback callback() { ResultCallback callback() {
DCHECK_CALLED_ON_VALID_THREAD(this->thread_checker_); DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(!callback_.is_null()); DCHECK(!callback_.is_null());
return std::move(callback_); return std::move(callback_);
} }
// ABI::Windows::Foundation::IAsyncOperation: private:
IFACEMETHODIMP GetResults(internal::AbiT<T>* results) override { void InvokeCompletedHandler() {
DCHECK_CALLED_ON_VALID_THREAD(this->thread_checker_); handler_->Invoke(this, ABI::Windows::Foundation::AsyncStatus::Completed);
if (!value_)
return E_PENDING;
*results = *value_;
return S_OK;
} }
private: void OnResult(ResultT result) {
void OnResult(T result) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK_CALLED_ON_VALID_THREAD(this->thread_checker_); DCHECK(!storage_);
DCHECK(!value_); storage_ = std::move(result);
value_.emplace(std::move(result)); InvokeCompletedHandler();
this->InvokeCompletedHandler();
} }
ResultCallback callback_; ResultCallback callback_;
base::Optional<T> value_; Microsoft::WRL::ComPtr<Handler> handler_;
StorageT storage_;
THREAD_CHECKER(thread_checker_);
base::WeakPtrFactory<AsyncOperation> weak_factory_; base::WeakPtrFactory<AsyncOperation> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(AsyncOperation);
}; };
} // namespace win } // namespace win
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment