mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2024-11-24 13:27:17 +00:00
71 lines
1.9 KiB
C++
71 lines
1.9 KiB
C++
#pragma once
|
|
|
|
#include <type_traits>
|
|
#include <utility>
|
|
|
|
namespace hr {
|
|
|
|
template<class Sig>
|
|
class function;
|
|
|
|
template<class R, class... Args>
|
|
struct function_state_base {
|
|
virtual R call(Args...) const = 0;
|
|
virtual function_state_base *clone() const = 0;
|
|
virtual ~function_state_base() {}
|
|
};
|
|
|
|
template<class T, class R, class... Args>
|
|
struct function_state : function_state_base<R, Args...> {
|
|
T t_;
|
|
explicit function_state(T t) : t_(std::move(t)) {}
|
|
R call(Args... args) const override {
|
|
return const_cast<T&>(t_)(static_cast<Args&&>(args)...);
|
|
}
|
|
function_state_base<R, Args...> *clone() const override {
|
|
return new function_state(*this);
|
|
}
|
|
};
|
|
|
|
template<class R, class... Args>
|
|
class function<R(Args...)>
|
|
{
|
|
function_state_base<R, Args...> *ptr_;
|
|
public:
|
|
function() : ptr_(nullptr) {}
|
|
|
|
template<class Callable, class = decltype(R(std::declval<typename std::decay<Callable>::type>()(std::declval<Args>()...)))>
|
|
function(Callable&& t) :
|
|
ptr_(new function_state<typename std::decay<Callable>::type, R, Args...>(static_cast<Callable&&>(t)))
|
|
{}
|
|
|
|
~function() {
|
|
delete ptr_;
|
|
}
|
|
|
|
function(function& rhs) : ptr_(rhs.ptr_ ? rhs.ptr_->clone() : nullptr) {}
|
|
function(const function& rhs) : ptr_(rhs.ptr_ ? rhs.ptr_->clone() : nullptr) {}
|
|
function(function&& rhs) noexcept : ptr_(rhs.ptr_) { rhs.ptr_ = nullptr; }
|
|
function(const function&& rhs) = delete;
|
|
|
|
void operator=(function rhs) noexcept {
|
|
std::swap(ptr_, rhs.ptr_);
|
|
}
|
|
|
|
R operator()(Args... args) const {
|
|
return ptr_->call(static_cast<Args&&>(args)...);
|
|
}
|
|
|
|
explicit operator bool() const noexcept {
|
|
return ptr_ != nullptr;
|
|
}
|
|
|
|
template<class T> T* target() {
|
|
auto ptr = dynamic_cast<function_state<T, R, Args...>*> (ptr_);
|
|
if(!ptr) return nullptr;
|
|
return &ptr->t_;
|
|
}
|
|
};
|
|
|
|
} // namespace hr
|