#pragma once #include #include #include #include "terminate.hpp" namespace geode::utils { template class MiniFunction; template class MiniFunctionStateBase { public: virtual ~MiniFunctionStateBase() = default; virtual Ret call(Args... args) const = 0; virtual MiniFunctionStateBase* clone() const = 0; }; template class MiniFunctionState final : public MiniFunctionStateBase { public: Type m_func; explicit MiniFunctionState(Type func) : m_func(func) {} Ret call(Args... args) const override { return const_cast(m_func)(args...); } MiniFunctionStateBase* clone() const override { return new MiniFunctionState(*this); } }; template class MiniFunctionStatePointer final : public MiniFunctionStateBase { public: Type m_func; explicit MiniFunctionStatePointer(Type func) : m_func(func) {} Ret call(Args... args) const override { return const_cast(*m_func)(args...); } MiniFunctionStateBase* clone() const override { return new MiniFunctionStatePointer(*this); } }; template class MiniFunctionStateMemberPointer final : public MiniFunctionStateBase { public: Type m_func; explicit MiniFunctionStateMemberPointer(Type func) : m_func(func) {} Ret call(Class self, Args... args) const override { return const_cast(self->*m_func)(args...); } MiniFunctionStateBase* clone() const override { return new MiniFunctionStateMemberPointer(*this); } }; template concept MiniFunctionCallable = requires(Callable&& func, Args... args) { { func(args...) } -> std::same_as; }; template class MiniFunction { public: using FunctionType = Ret(Args...); using StateType = MiniFunctionStateBase; private: StateType* m_state; public: MiniFunction() : m_state(nullptr) {} MiniFunction(std::nullptr_t) : MiniFunction() {} MiniFunction(MiniFunction const& other) : m_state(other.m_state ? other.m_state->clone() : nullptr) {} MiniFunction(MiniFunction&& other) : m_state(other.m_state) { other.m_state = nullptr; } ~MiniFunction() { delete m_state; } template requires(MiniFunctionCallable && !std::is_same_v, MiniFunction>) MiniFunction(Callable&& func) : m_state(new MiniFunctionState, Ret, Args...>(std::forward(func))) {} template requires(!MiniFunctionCallable && std::is_pointer_v && std::is_function_v>) MiniFunction(FunctionPointer func) : m_state(new MiniFunctionStatePointer(func)) {} template requires(std::is_member_function_pointer_v) MiniFunction(MemberFunctionPointer func) : m_state(new MiniFunctionStateMemberPointer(func)) {} MiniFunction& operator=(MiniFunction const& other) { delete m_state; m_state = other.m_state ? other.m_state->clone() : nullptr; return *this; } MiniFunction& operator=(MiniFunction&& other) { delete m_state; m_state = other.m_state; other.m_state = nullptr; return *this; } Ret operator()(Args... args) const { if (!m_state) { utils::terminate("Attempted to call a MiniFunction that has already been moved"); } return m_state->call(args...); } explicit operator bool() const { return m_state; } }; }