From 74a7f7e63bf2453034f5538ec3115fa18bf12c5c Mon Sep 17 00:00:00 2001 From: James Devine Date: Sun, 26 Aug 2018 22:51:09 -0700 Subject: [PATCH] add the ability to add / ignore based on the cb_arg This commit introduces differentiation of listeners based on the cb_arg. This means that multiple listeners can be registered for the same event source and value, but with different cb_args. Upon listener deletion, the listener_deletion_callback is invoked if non-NULL. Motivation: MakeCode uses cb_arg as context for higher level function pointer mapping (key / value), it can currently hold only one function pointer due to dal limitations. MakeCode currently has an indirection layer for events that could be first class listener invocations, this is due to omitting cb_arg when ignoring / adding listeners. Implementation: there is probably a "cooler" way of doing this, i.e. a meta listener where the cb arg is set with a pointer to the listener being removed. reasons why a callback function is superior: 1) fast and immediate 2) requires far less configuration (could be really complex with a meta listener) 3) smaller memory and processing overhead --- source/drivers/MicroBitMessageBus.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/source/drivers/MicroBitMessageBus.cpp b/source/drivers/MicroBitMessageBus.cpp index 7621f56..c2ad221 100644 --- a/source/drivers/MicroBitMessageBus.cpp +++ b/source/drivers/MicroBitMessageBus.cpp @@ -409,7 +409,7 @@ int MicroBitMessageBus::add(MicroBitListener *newListener) { methodCallback = (newListener->flags & MESSAGE_BUS_LISTENER_METHOD) && (l->flags & MESSAGE_BUS_LISTENER_METHOD); - if (l->id == newListener->id && l->value == newListener->value && (methodCallback ? *l->cb_method == *newListener->cb_method : l->cb == newListener->cb)) + if (l->id == newListener->id && l->value == newListener->value && (methodCallback ? *l->cb_method == *newListener->cb_method : l->cb == newListener->cb) && newListener->cb_arg == l->cb_arg) { // We have a perfect match for this event listener already registered. // If it's marked for deletion, we simply resurrect the listener, and we're done. @@ -447,7 +447,7 @@ int MicroBitMessageBus::add(MicroBitListener *newListener) l = l->next; } - while (l != NULL && l->id == newListener->id && l->value < newListener->value) + while (l != NULL && l->id == newListener->id && l->value <= newListener->value) { p = l; l = l->next; @@ -499,8 +499,12 @@ int MicroBitMessageBus::remove(MicroBitListener *listener) if(((listener->flags & MESSAGE_BUS_LISTENER_METHOD) && (*l->cb_method == *listener->cb_method)) || ((!(listener->flags & MESSAGE_BUS_LISTENER_METHOD) && l->cb == listener->cb))) { - if ((listener->id == MICROBIT_ID_ANY || listener->id == l->id) && (listener->value == MICROBIT_EVT_ANY || listener->value == l->value)) + if ((listener->id == MICROBIT_ID_ANY || listener->id == l->id) && (listener->value == MICROBIT_EVT_ANY || listener->value == l->value) && (listener->cb_arg == l->cb_arg || listener->cb_arg == NULL)) { + // if notification of deletion has been requested, invoke the listener deletion callback. + if (listener_deletion_callback) + listener_deletion_callback(l); + // Found a match. mark this to be removed from the list. l->flags |= MESSAGE_BUS_LISTENER_DELETING; removed++;