From 863f4d8366b985b48f4140c969bb5ea7935d47da Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 17 Jun 2016 17:00:05 +0200 Subject: util/BindMethod: new utility class for callbacks Replaces the old BoundMethod template. --- src/util/BindMethod.hxx | 193 +++++++++++++++++++++++++++++++++++++++++++++++ src/util/BoundMethod.hxx | 62 --------------- 2 files changed, 193 insertions(+), 62 deletions(-) create mode 100644 src/util/BindMethod.hxx delete mode 100644 src/util/BoundMethod.hxx (limited to 'src/util') diff --git a/src/util/BindMethod.hxx b/src/util/BindMethod.hxx new file mode 100644 index 000000000..17db48450 --- /dev/null +++ b/src/util/BindMethod.hxx @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2016 Max Kellermann + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef BIND_METHOD_HXX +#define BIND_METHOD_HXX + +#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); + + void *instance_; + function_pointer function; + +public: + BoundMethod() = default; + + constexpr + BoundMethod(void *_instance, function_pointer _function) + :instance_(_instance), function(_function) {} + + R operator()(Args... args) const { + return function(instance_, std::forward(args)...); + } +}; + +namespace BindMethodDetail { + +/** + * Helper class which converts a signature type to a method pointer + * type. + * + * @param T the wrapped class + * @param S the function signature type (plain, without instance + * pointer) + */ +template +struct MethodWithSignature; + +template +struct MethodWithSignature { + typedef R (T::*method_pointer)(Args...); +}; + +/** + * Helper class which introspects a method pointer type. + * + * @param M the method pointer type + */ +template +struct MethodSignatureHelper; + +template +struct MethodSignatureHelper { + /** + * 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...); +}; + +/** + * Helper class which converts a plain function signature type to a + * wrapper function pointer type. + */ +template +struct MethodWrapperWithSignature; + +template +struct MethodWrapperWithSignature { + typedef R (*function_pointer)(void *instance, Args...); +}; + +/** + * Generate a wrapper function. Helper class for + * #BindMethodWrapperGenerator. + * + * @param T the containing class + * @param M the method pointer type + * @param method the method pointer + * @param R the return type + * @param Args the method arguments + */ +template +struct BindMethodWrapperGenerator2 { + static R Invoke(void *_instance, Args... args) { + auto &t = *(T *)_instance; + return (t.*method)(std::forward(args)...); + } +}; + +/** + * Generate a wrapper function. + * + * @param T the containing class + * @param M the method pointer type + * @param method the method pointer + * @param S the plain function signature type + */ +template +struct BindMethodWrapperGenerator; + +template +struct BindMethodWrapperGenerator + : BindMethodWrapperGenerator2 { +}; + +template::method_pointer method> +typename MethodWrapperWithSignature::function_pointer +MakeBindMethodWrapper() +{ + return BindMethodWrapperGenerator::method_pointer, method, S>::Invoke; +} + +} /* namespace BindMethodDetail */ + +/** + * Construct a #BoundMethod instance. + * + * @param T the containing class + * @param S the plain function signature type + * @param method the method pointer + * @param instance the instance of #T to be bound + */ +template::method_pointer method> +constexpr BoundMethod +BindMethod(T &_instance) +{ + return BoundMethod(&_instance, + BindMethodDetail::MakeBindMethodWrapper()); +} + +/** + * Shortcut macro which takes an instance and a method pointer and + * constructs a #BoundMethod instance. + */ +#define BIND_METHOD(instance, method) \ + BindMethod::class_type, \ + typename BindMethodDetail::MethodSignatureHelper::plain_signature, \ + method>(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::type::method) + +#endif diff --git a/src/util/BoundMethod.hxx b/src/util/BoundMethod.hxx deleted file mode 100644 index 5d4154634..000000000 --- a/src/util/BoundMethod.hxx +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2016 Max Kellermann - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef BOUND_METHOD_HXX -#define BOUND_METHOD_HXX - -#include - -/** - * This class can invoke a method of a given object. To do this, it - * stores a pointer to the member function and a reference to the - * object. - * - * This is a utility to build callbacks. - * - * @param T the class whose method is going to be invoked - * @param R the method's return type - * @param Args argument types - */ -template -class BoundMethod final { - T &instance; - R (T::*method)(Args... args); - -public: - explicit constexpr BoundMethod(T &_instance, - R (T::*_method)(Args... args)) - :instance(_instance), method(_method) {} - - template - R operator()(Args2&&... args) { - return (instance.*method)(std::forward(args)...); - } -}; - -#endif -- cgit v1.2.3