From 83d95d396ea243585b34faea7767f130865768ff Mon Sep 17 00:00:00 2001 From: Gergely Nagy Date: Tue, 7 Mar 2017 16:02:42 +0100 Subject: [PATCH] Turn hooks into linked lists Instead of pre-allocating 64 items for event-handler and loop hooks (128 bytes total!), use a linked list instead. This is a little more memory used per hook, but the memory use scales with the number of hooks we have. Up until 32 hooks, the linked list wins. At this time, we do not have that many hooks, not even if all the plugins were in use at the same time. Another benefit is that we can have more than 64 hooks now, if so we wish, and memory is the only limit. Furthermore, turning both event-handler and loop hooks into a linked list allowed some code to be cleaned up, so they're only implemented once (using some careful templating). Fixes #118. Signed-off-by: Gergely Nagy --- src/Kaleidoscope.cpp | 79 ++++++++++++++++++++++++-------------------- src/Kaleidoscope.h | 79 ++++++++++++++++++++++++++------------------ src/key_events.cpp | 12 ++++--- 3 files changed, 98 insertions(+), 72 deletions(-) diff --git a/src/Kaleidoscope.cpp b/src/Kaleidoscope.cpp index 8718da3d..4275934c 100644 --- a/src/Kaleidoscope.cpp +++ b/src/Kaleidoscope.cpp @@ -1,8 +1,8 @@ #include "Kaleidoscope.h" #include -Kaleidoscope_::eventHandlerHook Kaleidoscope_::eventHandlers[HOOK_MAX]; -Kaleidoscope_::loopHook Kaleidoscope_::loopHooks[HOOK_MAX]; +Kaleidoscope_::listItem *Kaleidoscope_::eventHandlerRootNode; +Kaleidoscope_::listItem *Kaleidoscope_::loopHookRootNode; Kaleidoscope_::Kaleidoscope_(void) { } @@ -20,10 +20,12 @@ Kaleidoscope_::setup(void) { void Kaleidoscope_::runLoopHooks (bool postClear) { - for (byte i = 0; loopHooks[i] != NULL && i < HOOK_MAX; i++) { - loopHook hook = loopHooks[i]; - (*hook)(postClear); - } + auto *node = loopHookRootNode; + + while (node) { + (*(node->hook))(postClear); + node = node->next; + } } void @@ -51,52 +53,57 @@ Kaleidoscope_::use(KaleidoscopePlugin *plugin, ...) { va_end(ap); } -void -Kaleidoscope_::replaceEventHandlerHook(eventHandlerHook oldHook, eventHandlerHook newHook) { - for (byte i = 0; i < HOOK_MAX; i++) { - if (eventHandlers[i] == oldHook) { - eventHandlers[i] = newHook; - return; +template +void Kaleidoscope_::appendHook(T **rootNode, T *newNode) { + if (!*rootNode) { + *rootNode = newNode; + return; + } + + T *node = *rootNode; + + while (node->next) { + node = node->next; } - } + node->next = newNode; } +template void -Kaleidoscope_::appendEventHandlerHook (eventHandlerHook hook) { - replaceEventHandlerHook((eventHandlerHook)NULL, hook); +Kaleidoscope_::useHook(T **rootNode, T *newNode) { + if (!*rootNode) { + *rootNode = newNode; + return; + } + + T *node = *rootNode; + + while (node->next) { + if (node->hook == newNode->hook) + return; + node = node->next; + } + node->next = newNode; } void -Kaleidoscope_::useEventHandlerHook (eventHandlerHook hook) { - for (byte i = 0; i < HOOK_MAX; i++) { - if (eventHandlers[i] == hook) - return; - } - appendEventHandlerHook(hook); +Kaleidoscope_::useHook(listItem *newNode) { + useHook(&eventHandlerRootNode, newNode); } void -Kaleidoscope_::replaceLoopHook(loopHook oldHook, loopHook newHook) { - for (byte i = 0; i < HOOK_MAX; i++) { - if (loopHooks[i] == oldHook) { - loopHooks[i] = newHook; - return; - } - } +Kaleidoscope_::useHook(listItem *newNode) { + useHook(&loopHookRootNode, newNode); } void -Kaleidoscope_::appendLoopHook(loopHook hook) { - replaceLoopHook((loopHook)NULL, hook); +Kaleidoscope_::appendHook(listItem *newNode) { + appendHook(&eventHandlerRootNode, newNode); } void -Kaleidoscope_::useLoopHook(loopHook hook) { - for (byte i = 0; i < HOOK_MAX; i++) { - if (loopHooks[i] == hook) - return; - } - appendLoopHook (hook); +Kaleidoscope_::appendHook(listItem *newNode) { + appendHook(&loopHookRootNode, newNode); } Kaleidoscope_ Kaleidoscope; diff --git a/src/Kaleidoscope.h b/src/Kaleidoscope.h index c79d6f6e..5453290e 100644 --- a/src/Kaleidoscope.h +++ b/src/Kaleidoscope.h @@ -24,8 +24,6 @@ void setup(); #include "key_events.h" #include "layers.h" -#define HOOK_MAX 64 - extern HARDWARE_IMPLEMENTATION KeyboardHardware; #ifndef VERSION @@ -53,20 +51,32 @@ extern HARDWARE_IMPLEMENTATION KeyboardHardware; }) class KaleidoscopePlugin { - public: - virtual void begin(void) = 0; + public: + virtual void begin(void) = 0; }; class Kaleidoscope_ { public: Kaleidoscope_(void); - void setup(const byte keymap_count) { setup(); }; + void setup(const byte keymap_count) { + setup(); + }; void setup(void); void loop(void); void use(KaleidoscopePlugin *plugin, ...) __attribute__((sentinel)); // ---- hooks ---- + typedef Key (*eventHandlerHook)(Key mappedKey, byte row, byte col, uint8_t keyState); + typedef void (*loopHook)(bool postClear); + + template struct listItem { + T hook; + listItem *next; + }; + + static listItem *eventHandlerRootNode; + static listItem *loopHookRootNode; /* * In most cases, one only wants a single copy of a hook. On the other hand, @@ -75,38 +85,43 @@ class Kaleidoscope_ { * plugins too. In case the end-user calls the same setup function, we'd end up * with hooks registered multiple times. * - * To avoid this, protection against double-registration has been introduced. - * The `event_handler_hook_use` and `loop_hook_use` functions will only allow - * one copy of the hook. The `event_handler_hook_append` and `loop_hook_append` - * functions will, on the other hand, just append the hooks, and not care about - * protection. + * To avoid this, protection against double-registration has been + * introduced. The `useHook` functions will only allow one copy of the hook. + * The `appendHook` functions will, on the other hand, just append the + * hooks, and not care about protection. */ - typedef Key (*eventHandlerHook)(Key mappedKey, byte row, byte col, uint8_t keyState); - static eventHandlerHook eventHandlers[HOOK_MAX]; - - static void replaceEventHandlerHook(eventHandlerHook oldHook, eventHandlerHook newHook); - static void appendEventHandlerHook(eventHandlerHook hook); - static void useEventHandlerHook(eventHandlerHook hook); - - typedef void (*loopHook)(bool postClear); - static loopHook loopHooks[HOOK_MAX]; + static void appendHook(listItem *newNode); + static void appendHook(listItem *newNode); + static void useHook(listItem *newNode); + static void useHook(listItem *newNode); - static void replaceLoopHook(loopHook oldHook, loopHook newHook); - static void appendLoopHook(loopHook hook); - static void useLoopHook(loopHook hook); + private: + template static void appendHook(T **rootNode, T *newNode); + template static void useHook(T **rootNode, T *newNode); - private: static void runLoopHooks(bool postClear); }; extern Kaleidoscope_ Kaleidoscope; -/* -- DEPRECATED aliases; remove them when there are no more users. -- */ - -#define event_handler_hook_use(hook) Kaleidoscope.useEventHandlerHook(hook); -#define event_handler_hook_append(hook) Kaleidoscope.appendEventHandlerHook(hook) -#define event_handler_hook_replace(oldHook, newHook) Kaleidoscope.replaceEventHandlerHook(oldHook, newHook) - -#define loop_hook_use(hook) Kaleidoscope.useLoopHook(hook) -#define loop_hook_append(hook) Kaleidoscope.appendLoopHook(hook) -#define loop_hook_replace(oldHook, newHook) Kaleidoscope.replaceLoopHook(oldHook, newHook) +#define event_handler_hook_use(hook) { \ + static Kaleidoscope_::listItem \ + eventHandlerHookNode = {&hook, NULL}; \ + Kaleidoscope.useHook(&eventHandlerHookNode); \ + } +#define event_handler_hook_append(hook) { \ + static Kaleidoscope_::listItem \ + eventHandlerHookNode = {&hook, NULL}; \ + Kaleidoscope.appendHook(&eventHandlerHookNode); \ + } + +#define loop_hook_use(hook) { \ + static Kaleidoscope_::listItem \ + loopHookNode = {&hook, NULL}; \ + Kaleidoscope.useHook(&loopHookNode); \ + } +#define loop_hook_append(hook) { \ + static Kaleidoscope_::listItem \ + loopHookNode = {&hook, NULL}; \ + Kaleidoscope.appendHook(&loopHookNode); \ + } diff --git a/src/key_events.cpp b/src/key_events.cpp index 38a7cc0a..27340ab8 100644 --- a/src/key_events.cpp +++ b/src/key_events.cpp @@ -80,12 +80,16 @@ void handle_key_event(Key mappedKey, byte row, byte col, uint8_t keyState) { if (!(keyState & INJECTED)) { mappedKey = Layer.lookup(row, col); } - for (byte i = 0; Kaleidoscope.eventHandlers[i] != NULL && i < HOOK_MAX; i++) { - Kaleidoscope_::eventHandlerHook handler = Kaleidoscope.eventHandlers[i]; - mappedKey = (*handler)(mappedKey, row, col, keyState); - if (mappedKey.raw == Key_NoKey.raw) + + auto *node = Kaleidoscope.eventHandlerRootNode; + + while (node) { + mappedKey = (*(node->hook))(mappedKey, row, col, keyState); + if (mappedKey == Key_NoKey) return; + node = node->next; } + mappedKey = Layer.eventHandler(mappedKey, row, col, keyState); if (mappedKey.raw == Key_NoKey.raw) return;