Files
core_misc/tjp/core/functions/Dispatch.hpp
Timothy Prepscius fa54be052a flatten 20260225
2026-02-25 12:39:24 -05:00

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 &&param)> DispatchFunction;
template<typename R, typename T>
DispatchFunction asDispatchFunction(std::function<R(T)> &&f)
{
return [f](Variable &result, Variable &&param) -> 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 &&param)
{
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 &&param)
{
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 &&param)> &&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 &&param)
{
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 &&param)
{
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 &&param)> &&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