diff options
author | Max Kellermann <max@duempel.org> | 2016-06-17 17:00:05 +0200 |
---|---|---|
committer | Max Kellermann <max@duempel.org> | 2016-06-17 18:20:19 +0200 |
commit | 863f4d8366b985b48f4140c969bb5ea7935d47da (patch) | |
tree | c5420263a05bb64d07007879031eadceb9d3af2f /src/util | |
parent | bdd0c3686da403b0fcf3d673a81a9090e9ead0d6 (diff) |
util/BindMethod: new utility class for callbacks
Replaces the old BoundMethod template.
Diffstat (limited to 'src/util')
-rw-r--r-- | src/util/BindMethod.hxx | 193 | ||||
-rw-r--r-- | src/util/BoundMethod.hxx | 62 |
2 files changed, 193 insertions, 62 deletions
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 <max@duempel.org> + * + * 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 <type_traits> +#include <utility> + +/** + * 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<typename S=void()> +class BoundMethod; + +template<typename R, typename... Args> +class BoundMethod<R(Args...)> { + 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>(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<typename T, typename S> +struct MethodWithSignature; + +template<typename T, typename R, typename... Args> +struct MethodWithSignature<T, R(Args...)> { + typedef R (T::*method_pointer)(Args...); +}; + +/** + * Helper class which introspects a method pointer type. + * + * @param M the method pointer type + */ +template<typename M> +struct MethodSignatureHelper; + +template<typename R, typename T, typename... Args> +struct MethodSignatureHelper<R (T::*)(Args...)> { + /** + * 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<typename S> +struct MethodWrapperWithSignature; + +template<typename R, typename... Args> +struct MethodWrapperWithSignature<R(Args...)> { + 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<typename T, typename M, M method, typename R, typename... Args> +struct BindMethodWrapperGenerator2 { + static R Invoke(void *_instance, Args... args) { + auto &t = *(T *)_instance; + return (t.*method)(std::forward<Args>(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<typename T, typename M, M method, typename S> +struct BindMethodWrapperGenerator; + +template<typename T, typename M, M method, typename R, typename... Args> +struct BindMethodWrapperGenerator<T, M, method, R(Args...)> + : BindMethodWrapperGenerator2<T, M, method, R, Args...> { +}; + +template<typename T, typename S, + typename MethodWithSignature<T, S>::method_pointer method> +typename MethodWrapperWithSignature<S>::function_pointer +MakeBindMethodWrapper() +{ + return BindMethodWrapperGenerator<T, typename MethodWithSignature<T, S>::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<typename T, typename S, + typename BindMethodDetail::MethodWithSignature<T, S>::method_pointer method> +constexpr BoundMethod<S> +BindMethod(T &_instance) +{ + return BoundMethod<S>(&_instance, + BindMethodDetail::MakeBindMethodWrapper<T, S, method>()); +} + +/** + * Shortcut macro which takes an instance and a method pointer and + * constructs a #BoundMethod instance. + */ +#define BIND_METHOD(instance, method) \ + BindMethod<typename BindMethodDetail::MethodSignatureHelper<decltype(method)>::class_type, \ + typename BindMethodDetail::MethodSignatureHelper<decltype(method)>::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<decltype(*this)>::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 <max@duempel.org> - * - * 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 <utility> - -/** - * 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<typename T, typename R, typename... Args> -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<typename... Args2> - R operator()(Args2&&... args) { - return (instance.*method)(std::forward<Args2>(args)...); - } -}; - -#endif |