#ifndef _HEADER_TEA_CALLBACK #define _HEADER_TEA_CALLBACK #include #include namespace TeaLib { namespace Utility { #define NOVOIDFUNC(FuncRetVal) template typename std::enable_if::value, FuncRetVal>::type template class ReturnCallback { private: // Typedef for comparing function pointers. typedef ReturnValue(ReturnCallback::*CompareHandle)(Arguments...); struct CallbackStructBase { public: virtual ~CallbackStructBase() {}; virtual ReturnValue Call(Arguments...) = 0; virtual bool Compare(ReturnValue(*a_CallbackFunction)(Arguments...)) { return false; }; virtual bool Compare(void* a_ClassInstance, CompareHandle a_CallbackFunction) { return false; }; }; struct CallbackStruct : public CallbackStructBase { public: virtual ReturnValue Call(Arguments... a_Arg) { return m_CallbackFunction(a_Arg...); } virtual bool Compare(ReturnValue(*a_CallbackFunction)(Arguments...)) { return (a_CallbackFunction == m_CallbackFunction); }; ReturnValue(*m_CallbackFunction)(Arguments...); }; template struct ClassCallbackStruct : public CallbackStructBase { public: virtual ReturnValue Call(Arguments... a_Arg) { return (m_ClassInstance->*m_CallbackFunction)(a_Arg...); } virtual bool Compare(void* a_ClassInstance, CompareHandle a_CallbackFunction) { CompareHandle compareHandle; memcpy(&compareHandle, &m_CallbackFunction, sizeof(CompareHandle)); return ((a_ClassInstance == m_ClassInstance) && (a_CallbackFunction == compareHandle)); }; ClassType* m_ClassInstance; ReturnValue(ClassType::*m_CallbackFunction)(Arguments...); }; public: virtual ~ReturnCallback() { for (int i = (int)m_CallbackFunctions.size() - 1; i >= 0; i--) { delete m_CallbackFunctions[i]; } m_CallbackFunctions.clear(); } void Call(Arguments... a_Arg) { for (auto it : m_CallbackFunctions) { it->Call(a_Arg...); } } NOVOIDFUNC(void) Call(std::vector* a_ReturnValues, Arguments... a_Arg) { for (auto it : m_CallbackFunctions) { a_ReturnValues->push_back(it->Call(a_Arg...)); } } void Register(ReturnValue(*a_CallbackFunction)(Arguments...)) { CallbackStruct* newCallback = new CallbackStruct(); newCallback->m_CallbackFunction = a_CallbackFunction; m_CallbackFunctions.push_back(newCallback); } template void Register(ClassType* a_ClassInstance, ReturnValue(ClassType::*a_CallbackFunction)(Arguments...)) { ClassCallbackStruct* newCallback = new ClassCallbackStruct(); newCallback->m_ClassInstance = a_ClassInstance; newCallback->m_CallbackFunction = a_CallbackFunction; m_CallbackFunctions.push_back(newCallback); } // Removes the first registered callback that matches the function. void Deregister(ReturnValue(*a_CallbackFunction)(Arguments...)) { for (unsigned int i = 0; i < m_CallbackFunctions.size(); i++) { if (m_CallbackFunctions[i]->Compare(a_CallbackFunction)) { delete m_CallbackFunctions[i]; m_CallbackFunctions.erase(m_CallbackFunctions.begin() + i); break; } } } // Removes the first registered callback that matches the class instance and the function. template void Deregister(ClassType* a_ClassInstance, ReturnValue(ClassType::*a_CallbackFunction)(Arguments...)) { CompareHandle compareHandle; memcpy(&compareHandle, &a_CallbackFunction, sizeof(CompareHandle)); for (unsigned int i = 0; i < m_CallbackFunctions.size(); i++) { if (m_CallbackFunctions[i]->Compare(a_ClassInstance, compareHandle)) { delete m_CallbackFunctions[i]; m_CallbackFunctions.erase(m_CallbackFunctions.begin() + i); break; } } } private: std::vector m_CallbackFunctions; }; // Alias template for callbacks that return void. template using Callback = ReturnCallback; #undef NOVOIDFUNC }; }; #endif