flatten 20260225
This commit is contained in:
199
tjp/core/functions/Dispatch.hpp
Normal file
199
tjp/core/functions/Dispatch.hpp
Normal file
@@ -0,0 +1,199 @@
|
||||
// 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
|
||||
Reference in New Issue
Block a user