From 7aa2c0e8596bd18412990067ebb5ee2ac6902f84 Mon Sep 17 00:00:00 2001 From: Florian Fleissner Date: Wed, 27 Nov 2019 11:45:53 +0100 Subject: [PATCH] Enabled templated hook methods Hook methods can now be templated. A template parameter type list, a list of template parameters and a list of dummy template arguments have been added to the macro arguments used in _FOR_EACH_EVENT_HANDLER. Non-template hooks pass empty parenthesis for the three newly introduced macro arguments. Signed-off-by: Florian Fleissner --- src/kaleidoscope/event_handlers.h | 36 ++++++++++++++ src/kaleidoscope/hooks.cpp | 5 +- src/kaleidoscope/hooks.h | 5 +- src/kaleidoscope/macro_helpers.h | 49 +++++++++++++++++++ src/kaleidoscope_internal/LEDModeManager.h | 4 +- src/kaleidoscope_internal/event_dispatch.h | 36 +++++++++----- .../eventhandler_signature_check.h | 11 +++-- .../type_traits/has_method.h | 11 +++-- 8 files changed, 136 insertions(+), 21 deletions(-) diff --git a/src/kaleidoscope/event_handlers.h b/src/kaleidoscope/event_handlers.h index 4bd8b38c..b35985d7 100644 --- a/src/kaleidoscope/event_handlers.h +++ b/src/kaleidoscope/event_handlers.h @@ -76,6 +76,25 @@ // kaleidoscope::EventHandlerResult::EVENT_CONSUMED. To enable this // pass the abortable flag value _ABORTABLE, _NOT_ABORTABLE otherwise. // +// template parameter type list: +// The hook's template type list in parenthesis, with a trailing comma. +// e.g. (, typename _T1, typename _T2) +// Pass empty parenthesis if the hook is non templatized. +// +// template parameters: +// The hook's template parameters in parenthesis, with a trailing comma. +// The template parameter names must match the template type list. +// e.g. (, _T1, _T2) +// Pass empty parenthesis if the hook is non templatized. +// +// dummy template arguments: +// Supply a list of already defined dummy types that could realistically +// be used to instantiate the template hook. Those types are only used +// during hook method signature checks. +// Please add parenthesis and a trailing comma. +// e.g. (, int, int) +// Pass empty parenthesis if the hook is non templatized. +// // call signature: // The type of arguments passed to the handlers as a comma separated // list in brackets. Every parameter must be named. @@ -93,12 +112,21 @@ " uint8_t keyState)\n" __NL__ \ "instead." +namespace kaleidoscope { + +// This dummy class can be used as dummy template argument to +// be passed in the definition of template hooks. +// +class SignatureCheckDummy {}; +} // namespace kaleidoscope + #define _FOR_EACH_EVENT_HANDLER(OPERATION, ...) __NL__ \ __NL__ \ OPERATION(onSetup, __NL__ \ 1, __NL__ \ _CURRENT_IMPLEMENTATION, __NL__ \ _NOT_ABORTABLE, __NL__ \ + (),(),(), /* non template */ __NL__ \ (),(), ##__VA_ARGS__) __NL__ \ __NL__ \ /* Called at the very start of each cycle, before gathering */ __NL__ \ @@ -107,6 +135,7 @@ 1, __NL__ \ _CURRENT_IMPLEMENTATION, __NL__ \ _NOT_ABORTABLE, __NL__ \ + (),(),(), /* non template */ __NL__ \ (), (), ##__VA_ARGS__) __NL__ \ __NL__ \ /* DEPRECATED */ __NL__ \ @@ -121,6 +150,7 @@ 1, __NL__ \ DEPRECATED(ON_KEYSWITCH_EVENT_HANDLER_V1), __NL__ \ _ABORTABLE, __NL__ \ + (),(),(), /* non template */ __NL__ \ (Key &mappedKey, byte row, byte col, uint8_t keyState), __NL__ \ (mappedKey, row, col, keyState), ##__VA_ARGS__) __NL__ \ __NL__ \ @@ -135,6 +165,7 @@ 2, __NL__ \ _CURRENT_IMPLEMENTATION, __NL__ \ _ABORTABLE, __NL__ \ + (),(),(), /* non template */ __NL__ \ (Key &mappedKey, KeyAddr key_addr, uint8_t keyState), __NL__ \ (mappedKey, key_addr, keyState), ##__VA_ARGS__) __NL__ \ __NL__ \ @@ -150,6 +181,7 @@ 1, __NL__ \ _CURRENT_IMPLEMENTATION, __NL__ \ _ABORTABLE, __NL__ \ + (),(),(), /* non template */ __NL__ \ (const char *command), __NL__ \ (command), ##__VA_ARGS__) __NL__ \ __NL__ \ @@ -160,6 +192,7 @@ 1, __NL__ \ _CURRENT_IMPLEMENTATION, __NL__ \ _NOT_ABORTABLE, __NL__ \ + (),(),(), /* non template */ __NL__ \ (), (), ##__VA_ARGS__) __NL__ \ /* Called when the LED mode changes. If one needs to know what */ __NL__ \ /* from and what to the mode changed, they should track that */ __NL__ \ @@ -168,6 +201,7 @@ 1, __NL__ \ _CURRENT_IMPLEMENTATION, __NL__ \ _NOT_ABORTABLE, __NL__ \ + (),(),(), /* non template */ __NL__ \ (), (), ##__VA_ARGS__) __NL__ \ /* Called before reporting our state to the host. This is the */ __NL__ \ /* last point in a cycle where a plugin can alter what gets */ __NL__ \ @@ -176,6 +210,7 @@ 1, __NL__ \ _CURRENT_IMPLEMENTATION, __NL__ \ _NOT_ABORTABLE, __NL__ \ + (),(),(), /* non template */ __NL__ \ (),(),##__VA_ARGS__) __NL__ \ __NL__ \ /* Called at the very end of a cycle, after everything's */ __NL__ \ @@ -184,6 +219,7 @@ 1, __NL__ \ _CURRENT_IMPLEMENTATION, __NL__ \ _NOT_ABORTABLE, __NL__ \ + (),(),(), /* non template */ __NL__ \ (),(),##__VA_ARGS__) // The following function macro lists event handler/hook method names and diff --git a/src/kaleidoscope/hooks.cpp b/src/kaleidoscope/hooks.cpp index ac25c44c..9ad71c50 100644 --- a/src/kaleidoscope/hooks.cpp +++ b/src/kaleidoscope/hooks.cpp @@ -31,8 +31,11 @@ namespace kaleidoscope { #define INSTANTIATE_WEAK_HOOK_FUNCTION( \ HOOK_NAME, HOOK_VERSION, DEPRECATION_TAG, \ - SHOULD_ABORT_ON_CONSUMED_EVENT, SIGNATURE, ARGS_LIST) __NL__ \ + SHOULD_ABORT_ON_CONSUMED_EVENT, \ + TMPL_PARAM_TYPE_LIST, TMPL_PARAM_LIST, TMPL_DUMMY_ARGS_LIST, \ + SIGNATURE, ARGS_LIST) __NL__ \ __NL__ \ + MAKE_TEMPLATE_SIGNATURE(UNWRAP TMPL_PARAM_TYPE_LIST) __NL__ \ __attribute__((weak)) __NL__ \ EventHandlerResult Hooks::HOOK_NAME SIGNATURE { __NL__ \ return EventHandlerResult::OK; __NL__ \ diff --git a/src/kaleidoscope/hooks.h b/src/kaleidoscope/hooks.h index abc6d5f1..012196cc 100644 --- a/src/kaleidoscope/hooks.h +++ b/src/kaleidoscope/hooks.h @@ -72,8 +72,11 @@ class Hooks { #define DEFINE_WEAK_HOOK_FUNCTION( \ HOOK_NAME, HOOK_VERSION, DEPRECATION_TAG, \ - SHOULD_ABORT_ON_CONSUMED_EVENT, SIGNATURE, ARGS_LIST) __NL__ \ + SHOULD_ABORT_ON_CONSUMED_EVENT, \ + TMPL_PARAM_TYPE_LIST, TMPL_PARAM_LIST, TMPL_DUMMY_ARGS_LIST, \ + SIGNATURE, ARGS_LIST) __NL__ \ __NL__ \ + MAKE_TEMPLATE_SIGNATURE(UNWRAP TMPL_PARAM_TYPE_LIST) __NL__ \ static EventHandlerResult HOOK_NAME SIGNATURE; _FOR_EACH_EVENT_HANDLER(DEFINE_WEAK_HOOK_FUNCTION) diff --git a/src/kaleidoscope/macro_helpers.h b/src/kaleidoscope/macro_helpers.h index c056bf25..eeb50a24 100644 --- a/src/kaleidoscope/macro_helpers.h +++ b/src/kaleidoscope/macro_helpers.h @@ -52,6 +52,8 @@ #define GLUE3(A, B, C) A##B##C #define GLUE4(A, B, C, D) A##B##C##D +#define UNWRAP(...) __VA_ARGS__ + // Allow for the creation of verbose messages in static_asserts // #define VERBOSE_STATIC_ASSERT_HEADER \ @@ -142,3 +144,50 @@ int array[] = { A, B, RESTRICT_ARGS_COUNT(C, 3, B_MACRO, ##__VA_ARGS__) }; /* Count the args in a list */ #define NUM_ARGS(...) (sizeof((int[])__VA_ARGS__)/sizeof(int)) + +// Macro MAKE_TEMPLATE_SIGNATURE(...) wraps arguments 2..last in a template +// signature like 'template' only if it is passed more +// than one argument. Otherwise it generates an empty string. +// +#define MAKE_TEMPLATE_SIGNATURE(UNUSED, ...) \ + SELECT_ON_EMPTY_SIGNATURE(MAKE_TEMPLATE_SIGNATURE_, UNUSED,##__VA_ARGS__) +#define MAKE_TEMPLATE_SIGNATURE_0(...) +#define MAKE_TEMPLATE_SIGNATURE_1(...) template<__VA_ARGS__> + +// Macro ADD_TEMPLATE_BRACES(...) wraps arguments 2..last in angle brackets +// only if it is passed more than one argument. Otherwise it generates an +// empty string. +// +#define ADD_TEMPLATE_BRACES(UNUSED, ...) \ + SELECT_ON_EMPTY_SIGNATURE(ADD_TEMPLATE_BRACES_, UNUSED,##__VA_ARGS__) +#define ADD_TEMPLATE_BRACES_0(...) +#define ADD_TEMPLATE_BRACES_1(...) <__VA_ARGS__> + +// Macro TEMPLATE_KEYWORD(...) generates the 'template' keyword only if it is +// passed more than one argument. +// +#define TEMPLATE_KEYWORD(UNUSED, ...) \ + SELECT_ON_EMPTY_SIGNATURE(TEMPLATE_KEYWORD_, UNUSED,##__VA_ARGS__) +#define TEMPLATE_KEYWORD_0(...) +#define TEMPLATE_KEYWORD_1(...) template + +// Helper macros for template parameter list treatment + +#define GLUE2_AUX(...) GLUE2(__VA_ARGS__) + +#define TEST1(UNUSED, A, B, C, D, \ + E, F, G, H, \ + I, J, K, L, \ + M, N, O, P, \ + Q, ...) Q +#define TEST(...) TEST1(__VA_ARGS__) +#define CHOICE(UNUSED, ...) ,##__VA_ARGS__, 1, 1, 1, 1, \ + 1, 1, 1, 1, \ + 1, 1, 1, 1, \ + 1, 1, 1, 1, \ + 0 +#define SELECT_ON_EMPTY_SIGNATURE(MACRO_BASE_NAME, UNUSED, ...) \ + GLUE2_AUX( \ + MACRO_BASE_NAME, \ + TEST(CHOICE(1,##__VA_ARGS__)) \ + )(__VA_ARGS__) diff --git a/src/kaleidoscope_internal/LEDModeManager.h b/src/kaleidoscope_internal/LEDModeManager.h index 2c93fccd..a1277f78 100644 --- a/src/kaleidoscope_internal/LEDModeManager.h +++ b/src/kaleidoscope_internal/LEDModeManager.h @@ -82,7 +82,9 @@ inline void registerLEDModeActivated(Bool2Type, // Noop } -DEFINE_HAS_METHOD_TRAITS(Plugin, registerLEDModeActivated, void, (uint8_t led_mode_id)) +DEFINE_HAS_METHOD_TRAITS(Plugin, + /* registerLEDModeActivated not templated */ (), (), + registerLEDModeActivated, void, (uint8_t led_mode_id)) // A templated implementation of LEDModeFactoryFunc. // diff --git a/src/kaleidoscope_internal/event_dispatch.h b/src/kaleidoscope_internal/event_dispatch.h index a93a024f..4186c6ae 100644 --- a/src/kaleidoscope_internal/event_dispatch.h +++ b/src/kaleidoscope_internal/event_dispatch.h @@ -38,6 +38,7 @@ #include "kaleidoscope/hooks.h" #include "kaleidoscope_internal/eventhandler_signature_check.h" #include "kaleidoscope/event_handlers.h" +#include "kaleidoscope_internal/keymap_exploration.h" // Some words about the design of hook routing: // @@ -79,40 +80,48 @@ #define _REGISTER_EVENT_HANDLER( \ HOOK_NAME, HOOK_VERSION, DEPRECATION_TAG, \ - SHOULD_ABORT_ON_CONSUMED_EVENT, SIGNATURE, ARGS_LIST) \ + SHOULD_ABORT_ON_CONSUMED_EVENT, \ + TMPL_PARAM_TYPE_LIST, TMPL_PARAM_LIST, TMPL_DUMMY_ARGS_LIST, \ + SIGNATURE, ARGS_LIST) __NL__ \ __NL__ \ namespace kaleidoscope_internal { __NL__ \ __NL__ \ template __NL__ \ + typename Plugin__ __NL__ \ + UNWRAP TMPL_PARAM_TYPE_LIST /* may evaluate empty */ __NL__ \ + , typename... Args__> __NL__ \ struct _NAME5(EventHandler_, HOOK_NAME, _v, HOOK_VERSION, _caller) { __NL__ \ static DEPRECATION_TAG kaleidoscope::EventHandlerResult __NL__ \ call(Plugin__ &plugin, Args__&&... hook_args) { __NL__ \ - return plugin.HOOK_NAME(hook_args...); __NL__ \ + return plugin.TEMPLATE_KEYWORD(UNWRAP TMPL_PARAM_LIST) HOOK_NAME __NL__ \ + ADD_TEMPLATE_BRACES(UNWRAP TMPL_PARAM_LIST) __NL__ \ + (hook_args...); __NL__ \ } __NL__ \ }; __NL__ \ __NL__ \ /* This specialization is used for those hooks that a plugin does not __NL__ \ * implement. __NL__ \ */ __NL__ \ - template __NL__ \ + template __NL__ \ struct _NAME5(EventHandler_, HOOK_NAME, _v, HOOK_VERSION, _caller) __NL__ \ - { __NL__ \ + { __NL__ \ static kaleidoscope::EventHandlerResult __NL__ \ call(Plugin__ &/*plugin*/, Args__&&... /*hook_args*/) { __NL__ \ return kaleidoscope::EventHandlerResult::OK; __NL__ \ } __NL__ \ }; __NL__ \ __NL__ \ + MAKE_TEMPLATE_SIGNATURE(UNWRAP TMPL_PARAM_TYPE_LIST) __NL__ \ struct _NAME4(EventHandler_, HOOK_NAME, _v, HOOK_VERSION) { __NL__ \ __NL__ \ static bool shouldAbortOnConsumedEvent() { __NL__ \ return SHOULD_ABORT_ON_CONSUMED_EVENT; __NL__ \ } __NL__ \ __NL__ \ - template __NL__ \ + template __NL__ \ static kaleidoscope::EventHandlerResult __NL__ \ call(Plugin__ &plugin, Args__&&... hook_args) { __NL__ \ __NL__ \ @@ -129,8 +138,9 @@ typedef _NAME5(EventHandler_, HOOK_NAME, _v, HOOK_VERSION, _caller) __NL__ \ < __NL__ \ derived_implements_hook, __NL__ \ - Plugin__, __NL__ \ - Args__... __NL__ \ + Plugin__ __NL__ \ + UNWRAP TMPL_PARAM_LIST __NL__ \ + , Args__... __NL__ \ > Caller; __NL__ \ __NL__ \ return Caller::call(plugin, hook_args...); __NL__ \ @@ -141,11 +151,13 @@ __NL__ \ namespace kaleidoscope { __NL__ \ __NL__ \ + MAKE_TEMPLATE_SIGNATURE(UNWRAP TMPL_PARAM_TYPE_LIST) __NL__ \ EventHandlerResult Hooks::HOOK_NAME SIGNATURE { __NL__ \ return kaleidoscope_internal::EventDispatcher::template __NL__ \ apply __NL__ \ - ARGS_LIST; __NL__ \ + ::_NAME4(EventHandler_, HOOK_NAME, _v, HOOK_VERSION) __NL__ \ + ADD_TEMPLATE_BRACES(UNWRAP TMPL_PARAM_LIST) __NL__ \ + >ARGS_LIST; __NL__ \ } __NL__ \ __NL__ \ } diff --git a/src/kaleidoscope_internal/eventhandler_signature_check.h b/src/kaleidoscope_internal/eventhandler_signature_check.h index 97ac9c89..5fdf3c31 100644 --- a/src/kaleidoscope_internal/eventhandler_signature_check.h +++ b/src/kaleidoscope_internal/eventhandler_signature_check.h @@ -92,13 +92,17 @@ template struct #define _DEFINE_IMPLEMENTATION_CHECK_CLASS_SPECIALIZATION( \ HOOK_NAME, HOOK_VERSION, DEPRECATION_TAG, \ - SHOULD_ABORT_ON_CONSUMED_EVENT, SIGNATURE, ARGS_LIST) \ + SHOULD_ABORT_ON_CONSUMED_EVENT, \ + TMPL_PARAM_TYPE_LIST, TMPL_PARAM_LIST, TMPL_DUMMY_ARGS_LIST, \ + SIGNATURE, ARGS_LIST) \ \ /* We use the generalized traits class found in header has_method.h __NL__ \ * to do check if a plugin defines a hook method with a specific __NL__ \ * signature. __NL__ \ */ __NL__ \ - DEFINE_HAS_METHOD_TRAITS(GLUE2(Plugin, HOOK_VERSION), HOOK_NAME, __NL__ \ + DEFINE_HAS_METHOD_TRAITS(GLUE2(Plugin, HOOK_VERSION), __NL__ \ + TMPL_PARAM_TYPE_LIST, TMPL_PARAM_LIST, __NL__ \ + HOOK_NAME, __NL__ \ kaleidoscope::EventHandlerResult, __NL__ \ SIGNATURE) __NL__ \ __NL__ \ @@ -107,7 +111,8 @@ template struct */ __NL__ \ template __NL__ \ struct HookVersionImplemented_##HOOK_NAME __NL__ \ - : public GLUE4(Plugin, HOOK_VERSION, _HasMethod_, HOOK_NAME) __NL__ \ + : public GLUE4(Plugin, HOOK_VERSION, _HasMethod_, HOOK_NAME) __NL__ \ + __NL__ \ {}; #define _PREPARE_EVENT_HANDLER_SIGNATURE_CHECK_START(HOOK_NAME, ...) \ diff --git a/src/kaleidoscope_internal/type_traits/has_method.h b/src/kaleidoscope_internal/type_traits/has_method.h index 3051deca..11431ced 100644 --- a/src/kaleidoscope_internal/type_traits/has_method.h +++ b/src/kaleidoscope_internal/type_traits/has_method.h @@ -18,13 +18,15 @@ #include "kaleidoscope/macro_helpers.h" -#define DEFINE_HAS_METHOD_TRAITS(PREFIX, METHOD_NAME, \ +#define DEFINE_HAS_METHOD_TRAITS(PREFIX, \ + TMPL_PARAM_TYPE_LIST, TMPL_PARAM_LIST, \ + METHOD_NAME, \ RETURN_TYPE, ARGUMENTS) \ __NL__ \ /* This traits checks if a class of type Class__ __NL__ \ * implements a method with given signature. __NL__ \ */ __NL__ \ - template __NL__ \ + template __NL__ \ struct GLUE3(PREFIX, _HasMethod_, METHOD_NAME) __NL__ \ { __NL__ \ /* Define a pointer to member function with the correct __NL__ \ @@ -55,7 +57,10 @@ * (SFINAE = substitution failure is not an error) __NL__ \ * and the test(...) overload is used instead. __NL__ \ */ __NL__ \ - static_cast(&ClassAux__::METHOD_NAME), bool{} __NL__ \ + static_cast( __NL__ \ + &ClassAux__::TEMPLATE_KEYWORD(UNWRAP TMPL_PARAM_LIST) __NL__ \ + METHOD_NAME ADD_TEMPLATE_BRACES(UNWRAP TMPL_PARAM_LIST) __NL__ \ + ), bool{} __NL__ \ ) __NL__ \ test(int /* unused */) __NL__ \ { __NL__ \