#ifndef BASE_INCLUDE_CLOSURE_H_
#define BASE_INCLUDE_CLOSURE_H_
#include <cstddef>
#include <functional>
#include <type_traits>
#include <utility>
#include "base/include/base_defines.h"
#include "base/include/fml/macros.h"
namespace lynx {
namespace base {
template <typename Ret, typename... Args>
class ClosureBase {
public:
ClosureBase() = default;
virtual ~ClosureBase() = default;
virtual Ret operator()(Args...) = 0;
ClosureBase(const ClosureBase&) = delete;
ClosureBase& operator=(const ClosureBase&) = delete;
ClosureBase(ClosureBase&&) = default;
ClosureBase& operator=(ClosureBase&&) = default;
};
template <typename F, typename Ret, typename... Args>
class ClosureImpl : public ClosureBase<Ret, Args...> {
public:
explicit ClosureImpl(F&& func) : func_(std::move(func)) {}
~ClosureImpl() override = default;
Ret operator()(Args... arguments) override {
return func_(std::forward<Args>(arguments)...);
}
ClosureImpl(const ClosureImpl&) = delete;
ClosureImpl& operator=(const ClosureImpl&) = delete;
ClosureImpl(ClosureImpl&&) = default;
ClosureImpl& operator=(ClosureImpl&&) = default;
private:
F func_;
};
template <typename Ret = void, typename... Args>
class MoveOnlyClosure {
public:
MoveOnlyClosure() : impl_(nullptr) {}
MoveOnlyClosure(std::nullptr_t) : impl_(nullptr) {}
template <typename F, typename = std::enable_if_t<
std::is_invocable_r_v<Ret, F, Args...> &&
!std::is_same_v<std::decay_t<F>, MoveOnlyClosure>>>
MoveOnlyClosure(F&& func)
: impl_(new ClosureImpl<F, Ret, Args...>(std::move(func))) {}
~MoveOnlyClosure() { delete impl_; }
template <typename F>
MoveOnlyClosure(F&) = delete;
MoveOnlyClosure(const MoveOnlyClosure&) = delete;
MoveOnlyClosure& operator=(const MoveOnlyClosure&) = delete;
BASE_INLINE MoveOnlyClosure(MoveOnlyClosure&& other) {
impl_ = other.impl_;
other.impl_ = nullptr;
}
BASE_INLINE MoveOnlyClosure& operator=(MoveOnlyClosure&& other) {
delete impl_;
impl_ = other.impl_;
other.impl_ = nullptr;
return *this;
}
MoveOnlyClosure& operator=(std::nullptr_t) {
delete impl_;
impl_ = nullptr;
return *this;
}
Ret operator()(Args... arguments) const {
return (*impl_)(std::forward<Args>(arguments)...);
}
explicit operator bool() const { return impl_ != nullptr; }
bool operator==(std::nullptr_t) const { return impl_ == nullptr; }
bool operator!=(std::nullptr_t) const { return impl_ != nullptr; }
private:
ClosureBase<Ret, Args...>* impl_;
};
using closure = base::MoveOnlyClosure<>;
}
}
namespace fml {
using closure = std::function<void()>;
class ScopedCleanupClosure {
public:
ScopedCleanupClosure() = default;
explicit ScopedCleanupClosure(const fml::closure& closure)
: closure_(closure) {}
~ScopedCleanupClosure() {
if (closure_) {
closure_();
}
}
fml::closure SetClosure(const fml::closure& closure) {
auto old_closure = closure_;
closure_ = closure;
return old_closure;
}
fml::closure Release() {
fml::closure closure = closure_;
closure_ = nullptr;
return closure;
}
private:
fml::closure closure_;
BASE_DISALLOW_COPY_AND_ASSIGN(ScopedCleanupClosure);
};
}
#endif