#pragma once #include "./arraylist.hpp" // For std::decay #include template struct Lambda; // intentionally not defined template struct Lambda { using Dispatcher = R(*)(void*, Args...); Dispatcher m_Dispatcher; // A pointer to the static function that will call the // wrapped invokable object void* m_Target; // A pointer to the invokable object // Dispatch() is instantiated by the Lambda constructor, // which will store a pointer to the function in m_Dispatcher. template static R Dispatch(void* target, Args... args) { return (*(S*)target)(args...); } template Lambda(T&& target) : m_Dispatcher(&Dispatch::type>) , m_Target(&target) { } // Specialize for reference-to-function, to ensure that a valid pointer is // stored. using TargetFunctionRef = R(Args...); Lambda(TargetFunctionRef target) : m_Dispatcher(Dispatch) { static_assert(sizeof(void*) == sizeof target, "It will not be possible to pass functions by reference on this platform. " "Please use explicit function pointers i.e. foo(target) -> foo(&target)"); m_Target = (void*)target; } R operator()(Args... args) const { return m_Dispatcher(m_Target, args...); } }; struct Hook { Array_List> lambdas; Hook() { lambdas.alloc(); } ~Hook () { lambdas.dealloc(); } void operator<<(Lambda&& f) { lambdas.append(f); } void operator()() { for (auto l : lambdas) { l(); } lambdas.clear(); } }; // struct __System_Shutdown_Hook : Hook { // void operator()() = delete; // ~__System_Shutdown_Hook() { // Hook::operator()(); // lambdas.dealloc(); // } // } system_shutdown_hook;