chromium/base/threading/sequence_bound.h

// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef BASE_THREADING_SEQUENCE_BOUND_H_
#define BASE_THREADING_SEQUENCE_BOUND_H_

#include <concepts>
#include <new>
#include <tuple>
#include <type_traits>
#include <utility>

#include "base/check.h"
#include "base/location.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/run_loop.h"
#include "base/sequence_checker.h"
#include "base/task/sequenced_task_runner.h"
#include "base/threading/sequence_bound_internal.h"

namespace base {

// Performing blocking work on a different task runner is a common pattern for
// improving responsiveness of foreground task runners. `SequenceBound<T>`
// provides an abstraction for an owner object living on the owner sequence, to
// construct, call methods on, and destroy an object of type T that lives on a
// different sequence (the bound sequence).
//
// This makes it natural for code running on different sequences to be
// partitioned along class boundaries, e.g.:
//
// class Tab {
//  private:
//   void OnScroll() {
//     // ...
//     io_helper_.AsyncCall(&IOHelper::SaveScrollPosition);
//   }
//   base::SequenceBound<IOHelper> io_helper_{GetBackgroundTaskRunner()};
// };
//
// Note: `SequenceBound<T>` intentionally does not expose a raw pointer to the
// managed `T` to ensure its internal sequence-safety invariants are not
// violated. As a result, `AsyncCall()` cannot simply use `base::OnceCallback`
//
// SequenceBound also supports replies:
//
//   class Database {
//    public:
//     int Query(int value) {
//       return value * value;
//     }
//   };
//
//   // SequenceBound itself is owned on
//   // `SequencedTaskRunner::GetCurrentDefault()`. The managed Database
//   // instance managed by it is constructed and owned on `GetDBTaskRunner()`.
//   base::SequenceBound<Database> db(GetDBTaskRunner());
//
//   // `Database::Query()` runs on `GetDBTaskRunner()`, but
//   // `reply_callback` will run on the owner task runner.
//   auto reply_callback = [] (int result) {
//     LOG(ERROR) << result;  // Prints 25.
//   };
//   db.AsyncCall(&Database::Query).WithArgs(5)
//     .Then(base::BindOnce(reply_callback));
//
//   // When `db` goes out of scope, the Database instance will also be
//   // destroyed via a task posted to `GetDBTaskRunner()`.
//
// Sequence safety:
//
// Const-qualified methods may be used concurrently from multiple sequences,
// e.g. `AsyncCall()` or `is_null()`. Calls that are forwarded to the
// managed `T` will be posted to the bound sequence and executed serially
// there.
//
// Mutable methods (e.g. `Reset()`, destruction, or move assignment) require
// external synchronization if used concurrently with any other methods,
// including const-qualified methods.
//
// Advanced usage:
//
// Using `SequenceBound<std::unique_ptr<T>>` allows transferring ownership of an
// already-constructed `T` to `SequenceBound`. This can be helpful for more
// complex situations, where `T` needs to be constructed on a specific sequence
// that is different from where `T` will ultimately live.
//
// Construction (via the constructor or emplace) takes a `std::unique_ptr<T>`
// instead of forwarding the arguments to `T`'s constructor:
//
//   std::unique_ptr<Database> db_impl = MakeDatabaseOnMainThread();
//   base::SequenceBound<std::unique_ptr<Database>> db(GetDbTaskRunner(),
//                                                     std::move(db_impl));
//
// All other usage (e.g. `AsyncCall()`, `Reset()`) functions identically to a
// regular `SequenceBound<T>`:
//
//   // No need to dereference the `std::unique_ptr` explicitly:
//   db.AsyncCall(&Database::Query).WithArgs(5).Then(base::BindOnce(...));
template <typename T,
          typename CrossThreadTraits =
              sequence_bound_internal::CrossThreadTraits>
class SequenceBound {};

}  // namespace base

#endif  // BASE_THREADING_SEQUENCE_BOUND_H_