// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef TOOLS_ANDROID_FORWARDER2_SELF_DELETER_HELPER_H_
#define TOOLS_ANDROID_FORWARDER2_SELF_DELETER_HELPER_H_
#include <memory>
#include "base/check_op.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/location.h"
#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/task/single_thread_task_runner.h"
namespace base {
class SingleThreadTaskRunner;
} // namespace base
namespace forwarder2 {
// Helper template class to be used in the following case:
// * T is the type of an object that implements some work through an internal
// or worker thread.
// * T wants the internal thread to invoke deletion of its own instance, on
// the thread where the instance was created.
//
// To make this easier, do something like:
// 1) Add a SelfDeleteHelper<T> member to your class T, and default-initialize
// it in its constructor.
// 2) In the internal thread, to trigger self-deletion, call the
// MaybeDeleteSoon() method on this member.
//
// MaybeDeleteSoon() posts a task on the message loop where the T instance was
// created to delete it. The task will be safely ignored if the instance is
// otherwise deleted.
//
// Usage example:
// class Object {
// public:
// using ErrorCallback = base::OnceCallback<void (std::unique_ptr<Object>)>;
//
// Object(ErrorCallback error_callback)
// : self_deleter_helper_(this, std::move(error_callback)) {
// }
//
// void StartWork() {
// // Post a callback to DoSomethingOnWorkerThread() below to another
// // thread.
// }
//
// void DoSomethingOnWorkerThread() {
// ...
// if (error_happened)
// self_deleter_helper_.MaybeDeleteSoon();
// }
//
// private:
// SelfDeleterHelper<MySelfDeletingClass> self_deleter_helper_;
// };
//
// class ObjectOwner {
// public:
// ObjectOwner()
// : object_(new Object(base::BindOnce(&ObjectOwner::DeleteObjectOnError,
// base::Unretained(this))) {
// // To keep this example simple base::Unretained(this) is used above but
// // note that in a real world scenario the client would have to make sure
// // that the ObjectOwner instance is still alive when
// // DeleteObjectOnError() gets called below. This can be achieved by
// // using a WeakPtr<ObjectOwner> for instance.
// }
//
// void StartWork() {
// object_->StartWork();
// }
//
// private:
// void DeleteObjectOnError(std::unique_ptr<Object> object) {
// DCHECK(thread_checker_.CalledOnValidThread());
// DCHECK_EQ(object_, object);
// // Do some extra work with |object| before it gets deleted...
// object_.reset();
// std::ignore = object.release();
// }
//
// base::ThreadChecker thread_checker_;
// std::unique_ptr<Object> object_;
// };
//
template <typename T>
class SelfDeleterHelper {
public:
using DeletionCallback = base::OnceCallback<void(std::unique_ptr<T>)>;
SelfDeleterHelper(T* self_deleting_object, DeletionCallback deletion_callback)
: construction_runner_(base::SingleThreadTaskRunner::GetCurrentDefault()),
self_deleting_object_(self_deleting_object),
deletion_callback_(std::move(deletion_callback)) {}
SelfDeleterHelper(const SelfDeleterHelper&) = delete;
SelfDeleterHelper& operator=(const SelfDeleterHelper&) = delete;
~SelfDeleterHelper() {
DCHECK(construction_runner_->RunsTasksInCurrentSequence());
}
void MaybeSelfDeleteSoon() {
DCHECK(!construction_runner_->RunsTasksInCurrentSequence());
construction_runner_->PostTask(
FROM_HERE, base::BindOnce(&SelfDeleterHelper::SelfDelete,
weak_ptr_factory_.GetWeakPtr()));
}
private:
void SelfDelete() {
DCHECK(construction_runner_->RunsTasksInCurrentSequence());
std::move(deletion_callback_).Run(base::WrapUnique(self_deleting_object_));
}
const scoped_refptr<base::SingleThreadTaskRunner> construction_runner_;
T* const self_deleting_object_;
DeletionCallback deletion_callback_;
// WeakPtrFactory's documentation says:
// Member variables should appear before the WeakPtrFactory, to ensure
// that any WeakPtrs to Controller are invalidated before its members
// variable's destructors are executed, rendering them invalid.
base::WeakPtrFactory<SelfDeleterHelper<T>> weak_ptr_factory_{this};
};
} // namespace forwarder2
#endif // TOOLS_ANDROID_FORWARDER2_SELF_DELETER_HELPER_H_