// SPDX-License-Identifier: BSD-2-Clause // author: Max Kellermann #pragma once #include #include /** * This object stores a function pointer wrapping a method, and a * reference to an instance of the method's class. It can be used to * wrap instance methods as callback functions. * * @param S the plain function signature type */ template class BoundMethod; template class BoundMethod { typedef R (*function_pointer)(void *instance, Args... args) noexcept(NoExcept); void *instance_; function_pointer function; public: /** * Non-initializing trivial constructor */ BoundMethod() = default; constexpr BoundMethod(void *_instance, function_pointer _function) noexcept :instance_(_instance), function(_function) {} /** * Construct an "undefined" object. It must not be called, * and its "bool" operator returns false. */ BoundMethod(std::nullptr_t) noexcept:function(nullptr) {} /** * Was this object initialized with a valid function pointer? */ operator bool() const noexcept { return function != nullptr; } R operator()(Args... args) const { return function(instance_, std::forward(args)...); } }; namespace BindMethodDetail { /** * Helper class which introspects a method/function pointer type. * * @param M the method/function pointer type */ template struct SignatureHelper; template struct SignatureHelper { /** * The class which contains the given method (signature). */ typedef T class_type; /** * A function type which describes the "plain" function * signature. */ typedef R plain_signature(Args...) noexcept(NoExcept); typedef R (*function_pointer)(void *instance, Args...) noexcept(NoExcept); }; template struct SignatureHelper { typedef R plain_signature(Args...) noexcept(NoExcept); typedef R (*function_pointer)(void *instance, Args...) noexcept(NoExcept); }; /** * Generate a wrapper function. * * @param method the method/function pointer */ template struct WrapperGenerator; template struct WrapperGenerator { static R Invoke(void *_instance, Args... args) noexcept(NoExcept) { auto &t = *(T *)_instance; return (t.*method)(std::forward(args)...); } }; template struct WrapperGenerator { static R Invoke(void *, Args... args) noexcept(NoExcept) { return function(std::forward(args)...); } }; template typename SignatureHelper::function_pointer MakeWrapperFunction() noexcept { return WrapperGenerator::Invoke; } } /* namespace BindMethodDetail */ /** * Construct a #BoundMethod instance. * * @param method the method pointer * @param instance the instance of #T to be bound */ template constexpr auto BindMethod(typename BindMethodDetail::SignatureHelper::class_type &instance) noexcept { using H = BindMethodDetail::SignatureHelper; using plain_signature = typename H::plain_signature; return BoundMethod{ &instance, BindMethodDetail::MakeWrapperFunction(), }; } /** * Shortcut macro which takes an instance and a method pointer and * constructs a #BoundMethod instance. */ #define BIND_METHOD(instance, method) \ BindMethod(instance) /** * Shortcut wrapper for BIND_METHOD() which assumes "*this" is the * instance to be bound. */ #define BIND_THIS_METHOD(method) BIND_METHOD(*this, &std::remove_reference_t::method) /** * Construct a #BoundMethod instance for a plain function. * * @param function the function pointer */ template constexpr auto BindFunction() noexcept { using H = BindMethodDetail::SignatureHelper; using plain_signature = typename H::plain_signature; return BoundMethod{ nullptr, BindMethodDetail::MakeWrapperFunction(), }; } /** * Shortcut macro which takes a function pointer and constructs a * #BoundMethod instance. */ #define BIND_FUNCTION(function) \ BindFunction<&function>()