Skip to content

Instantly share code, notes, and snippets.

@FergusInLondon
Last active April 27, 2017 20:13
Show Gist options
  • Save FergusInLondon/761e675950ee37e80645b50d67ed2aec to your computer and use it in GitHub Desktop.
Save FergusInLondon/761e675950ee37e80645b50d67ed2aec to your computer and use it in GitHub Desktop.
Really simple events/listeners registry in C
/**
* Simple little event registry built around the worlds most simplistic
* linked list implementation. Allows you to register a function (void())
* against a integer value, and provides a mechanism for triggering the
* associated functions for an integer.
*
* Not a great deal of use beyond those fun little weekend Arduino type
* projects.
*
* @see example.c
*/
#include <stdlib.h>
#include <stdint.h>
/* Our Callback Type; simple function that accepts no parameters and provides
no return. Could possibly expand upon this so that it takes some form of
callback_parameter_t struct, which holds event data.. but we're making this
as generic as possible. */
typedef void(*evt_callback_t)();
/* Listener Struct; this is essentially a Linked List entry which additionally
contains a numerical identifier for an event, and a callback_t for the
listener */
typedef struct listener_entry {
struct listener_entry *next;
struct listener_entry *prev;
uint8_t ident;
evt_callback_t callback;
} evt_listener_t;
/* Pointers for referencing the beginning and end elements of our list */
typedef struct listener_registry {
evt_listener_t *base;
evt_listener_t *tail;
} evt_listener_registry_t;
/**
* Create a new registry to store our events and callbacks.
*/
evt_listener_registry_t *evt_create_registry() {
evt_listener_registry_t *registry = malloc(sizeof(evt_listener_registry_t));
registry->base = NULL;
registry->tail = NULL;
return registry;
}
/**
* Triggers an event, accepts the numerical identifier of the event before
* iterating through our Linked List and finding relevant listener callbacks.
*/
void evt_trigger(evt_listener_registry_t *registry, uint8_t ident) {
if (registry->base == NULL) return;
evt_listener_t *cursor = registry->base;
do {
if (cursor->ident == ident) cursor->callback();
} while ((cursor = cursor->next) != NULL);
}
/**
* Registers a new listener, accepts a numerical event identifier and a callback_t
* listener, and appends it to the Linked List.
*/
evt_listener_t *evt_register_listener(evt_listener_registry_t *registry, uint8_t event, evt_callback_t cb) {
evt_listener_t *entry = malloc(sizeof(evt_listener_t));
entry->callback = cb;
entry->ident = event;
if (registry->base == NULL){
registry->base = entry;
} else {
entry->prev = registry->tail;
registry->tail->next = entry;
}
registry->tail = entry;
return registry->tail;
}
/**
* Removes a listener callback from the Linked List.
*/
void evt_remove_listener(evt_listener_registry_t *registry, evt_listener_t *listener) {
if (listener == registry->base) {
registry->base = listener->next;
registry->base->prev = NULL;
} else if(listener == registry->tail) {
registry->tail->prev->next = NULL;
registry->tail = registry->tail->prev;
} else {
listener->prev->next = listener->next;
listener->prev->next->prev = listener->prev;
}
free(listener);
}
@FergusInLondon
Copy link
Author

Example Usage

#include <stdio.h>
#include <stdlib.h>
#include "events.h"

void listener_a() {
  printf(" - This is listener A!\n");
}
void listener_b() {
  printf(" - This is listener B!\n");
}
void listener_c() {
  printf(" - This is listener C!\n");
}

int main(int argc, char *argv[]) {
    int events[] = {5, 2, 6, 1, 2, 5};

    evt_listener_registry_t *registry = evt_create_registry();

    evt_listener_t* first = evt_register_listener(registry, 5, &listener_a);
    evt_listener_t* secon = evt_register_listener(registry, 2, &listener_b);
    evt_register_listener(registry, 6, &listener_c);
    evt_register_listener(registry, 1, &listener_c);
    evt_register_listener(registry, 2, &listener_a);
    evt_register_listener(registry, 5, &listener_b);

    for (int i; i < 6; i++) {
        printf("\nTriggering event %d!\n\n", events[i]);
        evt_trigger(registry, events[i]);
    }

    // remove two event listeners
    evt_remove_listener(registry, first);
    evt_remove_listener(registry, secon);
    printf("Removed two listeners.\n");

    for (int i; i < 6; i++) {
        printf("\nTriggering event %d!\n\n", events[i]);
        evt_trigger(registry, events[i]);
    }

    return 0;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment