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 <florian.fleissner@inpartik.de>
pull/735/head
Florian Fleissner 5 years ago
parent 686044264e
commit 7aa2c0e859

@ -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

@ -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__ \

@ -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)

@ -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<ARG2, ARG3, ...>' 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__)

@ -82,7 +82,9 @@ inline void registerLEDModeActivated(Bool2Type<false>,
// 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.
//

@ -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<bool hook_is_implemented__, __NL__ \
typename Plugin__, __NL__ \
typename... Args__> __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<typename Plugin__, __NL__ \
typename... Args__> __NL__ \
template<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__ \
<false, Plugin__, Args__...> { __NL__ \
<false, Plugin__ UNWRAP TMPL_PARAM_LIST, Args__...> { __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<typename Plugin__, typename... Args__> __NL__ \
template<typename Plugin__, __NL__ \
typename... Args__> __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<kaleidoscope_internal __NL__ \
::_NAME4(EventHandler_, HOOK_NAME, _v, HOOK_VERSION)> __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__ \
}

@ -92,13 +92,17 @@ template<typename Plugin__> 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<typename Plugin__> struct
*/ __NL__ \
template<typename Plugin__> __NL__ \
struct HookVersionImplemented_##HOOK_NAME<Plugin__, HOOK_VERSION> __NL__ \
: public GLUE4(Plugin, HOOK_VERSION, _HasMethod_, HOOK_NAME)<Plugin__> __NL__ \
: public GLUE4(Plugin, HOOK_VERSION, _HasMethod_, HOOK_NAME) __NL__ \
<Plugin__ UNWRAP TMPL_DUMMY_ARGS_LIST> __NL__ \
{};
#define _PREPARE_EVENT_HANDLER_SIGNATURE_CHECK_START(HOOK_NAME, ...) \

@ -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<typename Class__> __NL__ \
template<typename Class__ UNWRAP TMPL_PARAM_TYPE_LIST> __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<MethodType__>(&ClassAux__::METHOD_NAME), bool{} __NL__ \
static_cast<MethodType__>( __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__ \

Loading…
Cancel
Save