#include #include #include #include #include #include #include #define println(...) puts(std::format(__VA_ARGS__).c_str()) struct HijackEntryBase { virtual ~HijackEntryBase() = default; }; template struct HijackEntry : HijackEntryBase { std::vector> entryHooks; TRet invoke(std::function fn, TArgs... args) { for (auto &hook : entryHooks) { hook(args...); } return fn(std::forward(args)...); } }; struct SymbolInfo { std::string name; const std::type_info &type; bool operator==(const SymbolInfo &other) const { return name == other.name && type == other.type; } }; namespace std { template <> struct hash { std::size_t operator()(const SymbolInfo &sym) const { return std::hash()(sym.name) ^ sym.type.hash_code(); } }; } class HijackContext { public: template void register_function(std::string_view n) { auto sym = SymbolInfo { std::string(n), typeid(TRet(TArgs...)) }; entries[sym] = std::make_unique>(); } template HijackEntry &get_entry(std::string_view n) { auto sym = SymbolInfo { std::string(n), typeid(TRet(TArgs...)) }; auto it = entries.find(sym); if (it == entries.end()) { throw std::runtime_error("Function not registered"); } return *static_cast *>(it->second.get()); } template constexpr inline HijackEntry &operator[](std::string_view n) { return get_entry(n); } static HijackContext &instance() { if (not _instanceCreated) { _instance = HijackContext(); _instanceCreated = true; } return _instance; } private: static bool _instanceCreated; static HijackContext _instance; std::unordered_map> entries; }; bool HijackContext::_instanceCreated = false; HijackContext HijackContext::_instance; template struct FunctionSignature; template struct FunctionSignature : FunctionSignature {}; template struct FunctionSignature { using Result = TRet; using Parametres = std::tuple; }; template struct FunctionSignature { using Result = TRet; using Parametres = std::tuple; }; template struct FunctionSignature{ using Result = TRet; using Object = TObj; using Parametres = std::tuple; }; template struct FunctionSignature{ using Result = TRet; using Object = TObj; using Parametres = std::tuple; }; template struct HijackRegister; template struct HijackRegister : public HijackRegister { using Result = typename HijackRegister::Result; using Object = typename HijackRegister::Object; using Parametres = typename HijackRegister::Parametres; HijackRegister(std::string_view n): HijackRegister(n) { HijackContext::instance().register_function(n); } }; template struct HijackRegister { using Result = TRet; using Parametres = std::tuple; HijackRegister(std::string_view n) { HijackContext::instance().register_function(n); } }; template struct HijackRegister { using Result = TRet; using Parametres = std::tuple; HijackRegister(std::string_view n) { HijackContext::instance().register_function(n); } }; template struct HijackRegister { using Result = TRet; using Object = TObj; using Parametres = std::tuple; HijackRegister(std::string_view n) { HijackContext::instance().register_function(n); } }; template struct HijackRegister { using Result = TRet; using Object = TObj; using Parametres = std::tuple; HijackRegister(std::string_view n) { HijackContext::instance().register_function(n); } }; #define $_CONCAT(x, y) x##y #define $concat(...) $_CONCAT(__VA_ARGS__) #define $function(name, lambda)\ template requires std::is_same_v, typename FunctionSignature::Parametres>\ constexpr inline auto name(TArgs &&...args) -> decltype(lambda(std::forward(args)...))\ {\ using TResult = decltype(lambda(std::forward(args)...));\ return HijackContext::instance().get_entry(__FUNCTION__).invoke(lambda, std::forward(args)...);\ }\ namespace {\ auto $concat(_register_##name##_, __COUNTER__) = HijackRegister(#name);\ }\ // Example functions namespace Math { $function(Divide, [](int x, int y) -> int { return (y != 0) ? x / y : 0; }); $function(Divide, [](float x, float y) -> float { return (y != 0) ? x / y : 0.0f; }); $function(Divide, [](double x, double y) -> double { return (y != 0) ? x / y : 0.0; }); $function(Add, [](int x, int y) -> int { return x + y; }); } // Hooks void DivideHook1(int &x, int &) { x += 10; } void DivideHook2(int &x, int &) { x *= 2; } void AddHook1(int &x, int &y) { x *= y; } int main() { HijackContext::instance().get_entry("Divide").entryHooks.push_back(DivideHook1); HijackContext::instance().get_entry("Divide").entryHooks.push_back(DivideHook2); HijackContext::instance().get_entry("Add").entryHooks.push_back(AddHook1); // Test std::println("Divide: {}", Math::Divide(20, 10)); // (20 + 10) * 2 / 10 = 6 std::println("Add: {}", Math::Add(20, 10)); // 20 * 10 + 10 = 210 return 0; }