200 lines
3.4 KiB
C++
200 lines
3.4 KiB
C++
// TJP COPYRIGHT HEADER
|
|
|
|
#pragma once
|
|
|
|
#include "Dispatch.h"
|
|
#include <tjp/core/assert/debug_assert.h>
|
|
#include <tjp/core/exception/Exception.hpp>
|
|
#include <tjp/core/rtti/RTTI.hpp>
|
|
|
|
#include <functional>
|
|
#include <map>
|
|
|
|
|
|
namespace tjp {
|
|
namespace core {
|
|
|
|
struct DispatchException : Exception
|
|
{
|
|
typedef Exception Super;
|
|
DispatchException(const type_index &what) : Super("DispatchException") {}
|
|
};
|
|
|
|
struct Variable
|
|
{
|
|
void *v;
|
|
type_index type;
|
|
|
|
template<typename T>
|
|
Variable(const T &t) :
|
|
type(type_id<T>())
|
|
{
|
|
v = reinterpret_cast<void *>(const_cast<T *>(&t));
|
|
}
|
|
|
|
template<typename T>
|
|
T &deref ()
|
|
{
|
|
debug_assert(type_id<T>() == type);
|
|
return *reinterpret_cast<T *>(v);
|
|
}
|
|
|
|
template<typename T>
|
|
T &&move ()
|
|
{
|
|
debug_assert(type_id<T>() == type);
|
|
return std::move(*reinterpret_cast<T *>(v));
|
|
}
|
|
|
|
template<typename T>
|
|
Variable &operator =(T &&t)
|
|
{
|
|
deref<T>() = std::move(t);
|
|
return *this;
|
|
}
|
|
|
|
template<typename T>
|
|
Variable &operator =(const T &t)
|
|
{
|
|
deref<T>() = t;
|
|
return *this;
|
|
}
|
|
|
|
protected:
|
|
Variable () :
|
|
v(nullptr),
|
|
type(type_id<void>())
|
|
{}
|
|
|
|
template<typename T>
|
|
void ref(const T &t)
|
|
{
|
|
type = { type_id<T>() };
|
|
v = reinterpret_cast<void *>(const_cast<T *>(&t));
|
|
}
|
|
} ;
|
|
|
|
template<typename T>
|
|
struct StackVariable : Variable
|
|
{
|
|
T t;
|
|
|
|
StackVariable()
|
|
{
|
|
ref(t);
|
|
}
|
|
|
|
operator T()
|
|
{
|
|
return t;
|
|
}
|
|
|
|
T &&move()
|
|
{
|
|
return std::move(t);
|
|
}
|
|
} ;
|
|
|
|
typedef std::function<void(Variable &result, Variable &¶m)> DispatchFunction;
|
|
|
|
template<typename R, typename T>
|
|
DispatchFunction asDispatchFunction(std::function<R(T)> &&f)
|
|
{
|
|
return [f](Variable &result, Variable &¶m) -> void {
|
|
auto v = f(param.deref<T>());
|
|
auto &r = result.deref<R>();
|
|
r = v;
|
|
} ;
|
|
}
|
|
|
|
struct FunctionDispatchOnParam
|
|
{
|
|
std::map<type_index, DispatchFunction> dispatch;
|
|
|
|
void execute(Variable &result, Variable &¶m)
|
|
{
|
|
auto &type = param.type;
|
|
|
|
auto i = dispatch.find(type);
|
|
if (i == dispatch.end())
|
|
{
|
|
debug_assert(false);
|
|
throw DispatchException(type);
|
|
}
|
|
|
|
i->second(result, std::move(param));
|
|
}
|
|
|
|
template<typename T>
|
|
T execute(Variable &¶m)
|
|
{
|
|
StackVariable<T> result;
|
|
execute(result, std::move(param));
|
|
return result;
|
|
}
|
|
|
|
void bind(const type_index &type, DispatchFunction &&f)
|
|
{
|
|
dispatch[type] = std::move(f);
|
|
}
|
|
|
|
template<typename T>
|
|
void bind(std::function<void(Variable &result, Variable &¶m)> &&f)
|
|
{
|
|
bind(type_id<T>(), std::move(f));
|
|
}
|
|
|
|
template<typename R, typename T>
|
|
void bind(std::function<R(const T&)> &&f)
|
|
{
|
|
bind(type_id<T>(), asDispatchFunction<R, T>(f));
|
|
}
|
|
} ;
|
|
|
|
struct FunctionDispatchOnReturn
|
|
{
|
|
std::map<type_index, DispatchFunction> dispatch;
|
|
|
|
void execute(Variable &result, Variable &¶m)
|
|
{
|
|
auto &type = result.type;
|
|
auto i = dispatch.find(type);
|
|
if (i == dispatch.end())
|
|
{
|
|
debug_assert(false);
|
|
throw DispatchException(type);
|
|
}
|
|
|
|
i->second(result, std::move(param));
|
|
}
|
|
|
|
template<typename T>
|
|
T execute(Variable &¶m)
|
|
{
|
|
StackVariable<T> result;
|
|
execute(result, std::move(param));
|
|
return result;
|
|
}
|
|
|
|
void bind(const type_index &type, DispatchFunction &&f)
|
|
{
|
|
dispatch[type] = f;
|
|
}
|
|
|
|
template<typename R>
|
|
void bind(std::function<void(Variable &result, Variable &¶m)> &&f)
|
|
{
|
|
bind(type_id<R>(), std::move(f));
|
|
}
|
|
|
|
template<typename R, typename T>
|
|
void bind(std::function<R(const T&)> &&f)
|
|
{
|
|
bind(type_id<R>(), asDispatchFunction<R, T>(f));
|
|
}
|
|
} ;
|
|
|
|
|
|
} // namespace
|
|
} // namespace
|