// TJP COPYRIGHT HEADER #pragma once #include "Dispatch.h" #include #include #include #include #include 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 Variable(const T &t) : type(type_id()) { v = reinterpret_cast(const_cast(&t)); } template T &deref () { debug_assert(type_id() == type); return *reinterpret_cast(v); } template T &&move () { debug_assert(type_id() == type); return std::move(*reinterpret_cast(v)); } template Variable &operator =(T &&t) { deref() = std::move(t); return *this; } template Variable &operator =(const T &t) { deref() = t; return *this; } protected: Variable () : v(nullptr), type(type_id()) {} template void ref(const T &t) { type = { type_id() }; v = reinterpret_cast(const_cast(&t)); } } ; template struct StackVariable : Variable { T t; StackVariable() { ref(t); } operator T() { return t; } T &&move() { return std::move(t); } } ; typedef std::function DispatchFunction; template DispatchFunction asDispatchFunction(std::function &&f) { return [f](Variable &result, Variable &¶m) -> void { auto v = f(param.deref()); auto &r = result.deref(); r = v; } ; } struct FunctionDispatchOnParam { std::map 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 T execute(Variable &¶m) { StackVariable result; execute(result, std::move(param)); return result; } void bind(const type_index &type, DispatchFunction &&f) { dispatch[type] = std::move(f); } template void bind(std::function &&f) { bind(type_id(), std::move(f)); } template void bind(std::function &&f) { bind(type_id(), asDispatchFunction(f)); } } ; struct FunctionDispatchOnReturn { std::map 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 T execute(Variable &¶m) { StackVariable result; execute(result, std::move(param)); return result; } void bind(const type_index &type, DispatchFunction &&f) { dispatch[type] = f; } template void bind(std::function &&f) { bind(type_id(), std::move(f)); } template void bind(std::function &&f) { bind(type_id(), asDispatchFunction(f)); } } ; } // namespace } // namespace