Rework Kaleidoscope.use to be a compile-time recursive function

Based on suggestions from Wez Furlong (@wez) in #135, this replaces the
`Kaleidoscope.use` function with one that does its thing at compile time.

The net result is that we save a considerable amount of code, while still having
all of the benefits, and being 100% backwards compatible, no code needs to
change.

We may want to adjust existing code to use `Kaleidoscope.use` directly, and drop
any trailing NULLs we may have had. But there is no rush to do so.

Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
pull/136/head
Gergely Nagy 8 years ago
parent 5bc7f49dce
commit 636dfc3ba6

@ -34,19 +34,6 @@ Kaleidoscope_::loop(void) {
} }
} }
void
Kaleidoscope_::use(KaleidoscopePlugin *plugin, ...) {
va_list ap;
KaleidoscopePlugin *p;
plugin->begin();
va_start(ap, plugin);
while ((p = va_arg(ap, KaleidoscopePlugin*)) != NULL) {
p->begin();
}
va_end(ap);
}
void void
Kaleidoscope_::replaceEventHandlerHook(eventHandlerHook oldHook, eventHandlerHook newHook) { Kaleidoscope_::replaceEventHandlerHook(eventHandlerHook oldHook, eventHandlerHook newHook) {
for (byte i = 0; i < HOOK_MAX; i++) { for (byte i = 0; i < HOOK_MAX; i++) {

@ -33,23 +33,7 @@ extern HARDWARE_IMPLEMENTATION KeyboardHardware;
#define KEYMAP_SIZE (sizeof(keymaps) / ROWS / COLS / sizeof(Key)) #define KEYMAP_SIZE (sizeof(keymaps) / ROWS / COLS / sizeof(Key))
/* #define USE_PLUGINS(plugins...) Kaleidoscope.use(plugins)
* The `USE_PLUGINS()` macro is a clever hack, to make it seem like
* `Kaleidoscope.use()` is type-safe. It pushes its arguments into an
* appropriately typed array, so anything that does not fit the criteria, will
* trigger a compiler error.
*
* It then never uses the array, and passes the plugins over to
* `Kaleidoscope.use`, adding the trailing `NULL`, making it even easier to use.
*
* Since the array this macro creates is never used, the compiler will optimize
* it out fully. As such, by using this macro, we incur neither any size
* penalties, nor any run-time penalties. Everything happens at compile-time.
*/
#define USE_PLUGINS(plugins...) ({ \
static KaleidoscopePlugin *__p[] = {plugins, NULL}; \
Kaleidoscope.use(plugins, NULL); \
})
class KaleidoscopePlugin { class KaleidoscopePlugin {
public: public:
@ -65,7 +49,34 @@ class Kaleidoscope_ {
} }
void setup(void); void setup(void);
void loop(void); void loop(void);
void use(KaleidoscopePlugin *plugin, ...) __attribute__((sentinel));
// ---- Kaleidoscope.use() ----
// First, we have the zero-argument version, which will satisfy the tail case.
inline void use() {
}
// Then, the one-argument version, that gives us type safety for a single
// plugin.
inline void use(KaleidoscopePlugin *p) {
p->begin();
}
// We have a no-op with a int argument, as a temporary hack until we remove
// the last instance of a NULL-terminated Kaleidoscope.use() call.
inline void use(int) {
}
// And the magic is in the last one, a template. The first parameter is
// matched out by the compiler, and passed to one of the functions above. The
// rest of the parameter pack (which may be an empty set in a recursive case),
// are passed back to either ourselves, or the zero-argument version a few
// lines above.
template <typename... Plugins>
void use(KaleidoscopePlugin *first, Plugins&&... plugins) {
use(first);
use(plugins...);
}
// ---- hooks ---- // ---- hooks ----

Loading…
Cancel
Save