#ifndef BASE_THREADING_SEQUENCE_BOUND_INTERNAL_H_
#define BASE_THREADING_SEQUENCE_BOUND_INTERNAL_H_
#include <memory>
#include <type_traits>
#include <utility>
#include "base/compiler_specific.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/functional/callback_helpers.h"
#include "base/location.h"
#include "base/memory/aligned_memory.h"
#include "base/memory/raw_ptr.h"
#include "base/task/sequenced_task_runner.h"
namespace base::sequence_bound_internal {
struct CrossThreadTraits {
template <typename Signature>
using CrossThreadTask = OnceCallback<Signature>;
template <typename Functor, typename... Args>
static inline auto BindOnce(Functor&& functor, Args&&... args) {
return ::base::BindOnce(std::forward<Functor>(functor),
std::forward<Args>(args)...);
}
template <typename T>
static inline auto Unretained(T ptr) {
return ::base::Unretained(ptr);
}
static inline bool PostTask(SequencedTaskRunner& task_runner,
const Location& location,
OnceClosure&& task) {
return task_runner.PostTask(location, std::move(task));
}
static inline bool PostTaskAndReply(SequencedTaskRunner& task_runner,
const Location& location,
OnceClosure&& task,
OnceClosure&& reply) {
return task_runner.PostTaskAndReply(location, std::move(task),
std::move(reply));
}
template <typename TaskReturnType, typename ReplyArgType>
static inline bool PostTaskAndReplyWithResult(
SequencedTaskRunner& task_runner,
const Location& location,
OnceCallback<TaskReturnType()>&& task,
OnceCallback<void(ReplyArgType)>&& reply) {
return task_runner.PostTaskAndReplyWithResult(location, std::move(task),
std::move(reply));
}
template <template <typename> class CallbackType>
static constexpr bool IsCrossThreadTask =
IsBaseCallback<CallbackType<void()>>;
};
template <typename T, typename CrossThreadTraits>
class Storage {
public:
using element_type = T;
bool is_null() const { return ptr_ == nullptr; }
auto GetPtrForBind() const { return CrossThreadTraits::Unretained(ptr_); }
auto GetRefForBind() const { return std::cref(*ptr_); }
template <typename... Args>
NO_SANITIZE("cfi-unrelated-cast")
void Construct(SequencedTaskRunner& task_runner, Args&&... args) {
DCHECK(!alloc_);
DCHECK(!ptr_);
alloc_ = AlignedAlloc(
sizeof(T), sizeof(void*) > alignof(T) ? sizeof(void*) : alignof(T));
ptr_ = reinterpret_cast<T*>(alloc_.get());
CrossThreadTraits::PostTask(
task_runner, FROM_HERE,
CrossThreadTraits::BindOnce(&InternalConstruct<Args...>,
CrossThreadTraits::Unretained(ptr_),
std::forward<Args>(args)...));
}
template <typename U>
NO_SANITIZE("cfi-unrelated-cast")
void TakeFrom(Storage<U, CrossThreadTraits>&& other) {
ptr_ = std::exchange(other.ptr_, nullptr);
alloc_ = std::exchange(other.alloc_, nullptr);
}
void Destruct(SequencedTaskRunner& task_runner) {
CrossThreadTraits::PostTask(
task_runner, FROM_HERE,
CrossThreadTraits::BindOnce(
&InternalDestruct,
CrossThreadTraits::Unretained(std::exchange(ptr_, nullptr)),
CrossThreadTraits::Unretained(std::exchange(alloc_, nullptr))));
}
private:
template <typename U, typename V>
friend class Storage;
template <typename... Args>
static void InternalConstruct(T* ptr, std::decay_t<Args>&&... args) {
new (ptr) T(std::move(args)...);
}
static void InternalDestruct(T* ptr, void* alloc) {
ptr->~T();
AlignedFree(alloc);
}
raw_ptr<T> ptr_ = nullptr;
raw_ptr<void> alloc_ = nullptr;
};
template <typename T, typename CrossThreadTraits>
struct Storage<std::unique_ptr<T>, CrossThreadTraits> {
public:
using element_type = T;
bool is_null() const { return ptr_ == nullptr; }
auto GetPtrForBind() const { return CrossThreadTraits::Unretained(ptr_); }
auto GetRefForBind() const { return std::cref(*ptr_); }
template <typename U>
void Construct(SequencedTaskRunner& task_runner, std::unique_ptr<U> arg) {
DCHECK(!ptr_);
ptr_ = arg.release();
}
template <typename U>
void TakeFrom(Storage<std::unique_ptr<U>, CrossThreadTraits>&& other) {
ptr_ = std::exchange(other.ptr_, nullptr);
}
void Destruct(SequencedTaskRunner& task_runner) {
CrossThreadTraits::PostTask(
task_runner, FROM_HERE,
CrossThreadTraits::BindOnce(
&InternalDestruct,
CrossThreadTraits::Unretained(std::exchange(ptr_, nullptr))));
}
private:
template <typename U, typename V>
friend class Storage;
static void InternalDestruct(T* ptr) { delete ptr; }
raw_ptr<T> ptr_ = nullptr;
};
}
#endif