chromium/tools/android/forwarder2/self_deleter_helper.h

// 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_