#pragma once #include #include #include #include #include #include #include namespace glbinding { template struct BasicCallHelper { inline static ReturnType call(const glbinding::Function * function, Arguments&&... arguments) { return reinterpret_cast::Signature>(function->address())(std::forward(arguments)...); } }; // Special case for booleans because of MSVC differing behavior template struct BasicCallHelper { inline static glbinding::Boolean8 call(const glbinding::Function * function, Arguments&&... arguments) { return reinterpret_cast::Signature>(function->address())(std::forward(arguments)...); } }; template struct FunctionHelper { inline static ReturnType call(const glbinding::Function * function, Arguments&&... arguments) { glbinding::FunctionCall functionCall(function); if (function->isAnyEnabled(glbinding::CallbackMask::Parameters)) { functionCall.parameters = glbinding::createValues(std::forward(arguments)...); } if (function->isEnabled(glbinding::CallbackMask::Before)) { AbstractFunction::before(functionCall); if (function->beforeCallback()) { function->beforeCallback()(std::forward(arguments)...); } } auto value = BasicCallHelper::call(function, std::forward(arguments)...); if (function->isAnyEnabled(glbinding::CallbackMask::ReturnValue)) { functionCall.returnValue = glbinding::createValue(value); } if (function->isEnabled(glbinding::CallbackMask::After)) { AbstractFunction::after(functionCall); if (function->afterCallback()) { function->afterCallback()(value, std::forward(arguments)...); } } if (function->isEnabled(glbinding::CallbackMask::Logging)) { AbstractFunction::log(std::move(functionCall)); } return value; } }; template struct FunctionHelper { inline static void call(const glbinding::Function * function, Arguments&&... arguments) { glbinding::FunctionCall functionCall(function); if (function->isAnyEnabled(glbinding::CallbackMask::Parameters)) { functionCall.parameters = glbinding::createValues(std::forward(arguments)...); } if (function->isEnabled(glbinding::CallbackMask::Before)) { AbstractFunction::before(functionCall); if (function->beforeCallback()) { function->beforeCallback()(std::forward(arguments)...); } } BasicCallHelper::call(function, std::forward(arguments)...); if (function->isEnabled(glbinding::CallbackMask::After)) { AbstractFunction::after(functionCall); if (function->afterCallback()) { function->afterCallback()(std::forward(arguments)...); } } if (function->isEnabled(glbinding::CallbackMask::Logging)) { AbstractFunction::log(std::move(functionCall)); } } }; template Function::Function(const char * _name) : AbstractFunction{_name} , m_beforeCallback{nullptr} , m_afterCallback{nullptr} { } template ReturnType Function::operator()(Arguments&... arguments) const { return call(arguments...); } template ReturnType Function::call(Arguments&... arguments) const { const auto myAddress = address(); if (myAddress == nullptr) { if (isEnabled(CallbackMask::Unresolved)) { AbstractFunction::unresolved(this); } else { // Trying to call a function without check if it is resolvable is considered a programming error. // You may try to call AbstractFunction::resolve first and check the address for validity (a pointer // unequal to nullptr is considered valid) or check the exposition of associated extensions. assert(false); } return ReturnType(); } if (isAnyEnabled(CallbackMask::Before | CallbackMask::After | CallbackMask::Logging)) { return FunctionHelper::call(this, std::forward(arguments)...); } else { return BasicCallHelper::call(this, std::forward(arguments)...); } } template ReturnType Function::directCall(Arguments... arguments) const { if (address() == nullptr) { return ReturnType(); } return BasicCallHelper::call(this, std::forward(arguments)...); } template void Function::setBeforeCallback(BeforeCallback callback) { m_beforeCallback = std::move(callback); } template void Function::clearBeforeCallback() { m_beforeCallback = nullptr; } template void Function::setAfterCallback(AfterCallback callback) { m_afterCallback = std::move(callback); } template void Function::clearAfterCallback() { m_afterCallback = nullptr; } template typename Function::BeforeCallback Function::beforeCallback() const { return m_beforeCallback; } template typename Function::AfterCallback Function::afterCallback() const { return m_afterCallback; } template bool Function::hasState() const { return hasState(AbstractFunction::currentPos()); } template bool Function::hasState(const int pos) const { return pos > -1 && AbstractFunction::maxPos() <= pos; } template AbstractState & Function::state() const { return state(AbstractFunction::currentPos()); } template AbstractState & Function::state(const int pos) const { assert(AbstractFunction::maxPos() >= pos); assert(pos > -1); return m_states.at(pos); } template void Function::resizeStates(int count) { m_states.resize(static_cast(count)); } } // namespace glbinding