#pragma once
#include "refcnt.h"
#include "function_utils.h"
#include <utility>
namespace panda {
template <typename Ret, typename... Args>
class function;
template <typename Ret, typename... Args>
class function {
public:
using Func = iptr<Ifunction<Ret, Args...>>;
Func func;
public:
function(){}
function(std::nullptr_t){}
template <typename Derr>
function(const iptr<Derr>& f) : func(f) {}
template<typename... F,
typename = decltype(function_details::make_abstract_function<Ret, Args...>(std::declval<F>()...)),
typename = typename std::enable_if<!std::is_constructible<function, F...>::value>::type>
function(F&&... f)
: func(function_details::make_abstract_function<Ret, Args...>(std::forward<F>(f)...))
{}
function(Func func) : func(func) {};
function(const function& oth) = default;
function(function&& oth) = default;
function& operator=(const function& oth) = default;
function& operator=(function&& oth) = default;
Ret operator ()(Args... args) const {return func->operator ()(std::forward<Args>(args)...);}
template <typename ORet, typename... OArgs,
typename = typename std::enable_if<std::is_convertible<function<ORet, OArgs...>, function>::value>::type>
bool operator ==(const function<ORet, OArgs...>& oth) const {
return (!func && !oth.func) || (func && oth && func->equals(oth.func.get()));
}
template <typename ORet, typename... OArgs,
typename = typename std::enable_if<std::is_convertible<function<ORet, OArgs...>, function>::value>::type>
bool operator !=(const function<ORet, OArgs...>& oth) const {return !operator ==(oth);}
bool operator ==(const Ifunction<Ret, Args...>& oth) const {
return func && func->equals(&oth);
}
bool operator !=(const Ifunction<Ret, Args...>& oth) const {return !operator ==(oth);}
explicit operator bool() const {
return func;
}
};
template <typename Ret, typename... Args>
class function<Ret (Args...)> : public function<Ret, Args...>{
public:
using function<Ret, Args...>::function;
using ArgsTuple = std::tuple<Args...>;
using RetType = Ret;
};
template <class Class, typename Ret, typename... Args>
inline function<Ret( Args...)> make_function(Ret (Class::*meth)(Args...), iptr<Class> thiz = nullptr) {
return function<Ret(Args...)>(meth, thiz);
}
template <typename Ret, typename... Args>
inline function<Ret (Args...)> make_function(Ret (*f)(Args...)) {
return function<Ret(Args...)>(f);
}
}