Refactor to make EventSystem public with id instead of opaque type
This commit is contained in:
parent
f438091d49
commit
f1ae847e0c
@ -5,13 +5,16 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
|
|
||||||
|
#define INVALID_SYSTEM ((EventSystem){ .id = 0 })
|
||||||
#define INVALID_EVENT ((Event) { .id = 0 })
|
#define INVALID_EVENT ((Event) { .id = 0 })
|
||||||
#define INVALID_LISTENER ((EventListener){ .event = INVALID_EVENT, .id = 0 })
|
#define INVALID_LISTENER ((EventListener){ .event = INVALID_EVENT, .id = 0 })
|
||||||
|
|
||||||
|
#define IS_INVALID_SYSTEM(ES) (ES.id == 0)
|
||||||
#define IS_INVALID_EVENT(EV) (EV.id == 0)
|
#define IS_INVALID_EVENT(EV) (EV.id == 0)
|
||||||
#define IS_INVALID_LISTENER(LS) (LS.id == 0)
|
#define IS_INVALID_LISTENER(LS) (LS.id == 0)
|
||||||
|
|
||||||
struct event_system {
|
typedef struct es_internal ESInternal;
|
||||||
|
struct es_internal {
|
||||||
u64 alloc_size;
|
u64 alloc_size;
|
||||||
u64 event_capacity;
|
u64 event_capacity;
|
||||||
u64 event_count;
|
u64 event_count;
|
||||||
@ -32,85 +35,99 @@ typedef struct event_internal EventInternal;
|
|||||||
struct event_internal {
|
struct event_internal {
|
||||||
u64 capacity;
|
u64 capacity;
|
||||||
u64 count;
|
u64 count;
|
||||||
EventCallback *callbacks[];
|
u64 free_count;
|
||||||
|
u64 *free;
|
||||||
|
EventCallback *callbacks;
|
||||||
};
|
};
|
||||||
|
|
||||||
void *alloc(u64 size);
|
internal void *alloc(u64 size);
|
||||||
EventSlot *get_event_slots_array(const EventSystem *es);
|
internal ESInternal *get_event_system_internal(EventSystem event_system);
|
||||||
u64 *get_free_array(const EventSystem *es);
|
internal EventSlot *get_event_slots_array(const ESInternal *es);
|
||||||
EventInternal *get_event(const EventSystem *es, Event event);
|
internal u64 *get_free_array(const ESInternal *es);
|
||||||
|
internal EventInternal *get_event(const ESInternal *es, Event event);
|
||||||
u32 es_init(EventSystem **es, u64 initial_event_capacity, u64 initial_listeners_capacity) {
|
internal EventInternal *get_event_from_offset(const ESInternal *es, u64 offset);
|
||||||
if (!es) {
|
|
||||||
return ES_INIT_NULL_POINTER;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*es) {
|
|
||||||
return ES_INIT_ALREADY_INITIALISED;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
EventSystem es_init(u64 initial_event_capacity, u64 initial_listeners_capacity) {
|
||||||
// Double event capacity to reduce chances of reallocation
|
// Double event capacity to reduce chances of reallocation
|
||||||
u64 event_capacity = initial_event_capacity * 2;
|
u64 event_capacity = initial_event_capacity * 2;
|
||||||
// Increase listener capacity by one to account for 0th EventListener being invalid
|
|
||||||
u64 listeners_capacity = initial_listeners_capacity + 1;
|
|
||||||
// Double listener capacity to reduce chances of reallocation
|
// Double listener capacity to reduce chances of reallocation
|
||||||
u64 callback_capacity = listeners_capacity * 2;
|
u64 callback_capacity = initial_listeners_capacity * 2;
|
||||||
u64 system = sizeof(EventSystem);
|
u64 system = sizeof(ESInternal);
|
||||||
// Increase event capacity by one to account for 0th Event being invalid
|
// Increase event capacity by one to account for 0th Event being invalid
|
||||||
u64 event_offsets = (event_capacity + 1) * sizeof(EventSlot);
|
u64 event_offsets = (event_capacity + 1) * sizeof(EventSlot);
|
||||||
u64 free_slots = event_capacity * sizeof(u64);
|
u64 free_slots = event_capacity * sizeof(u64);
|
||||||
u64 events = event_capacity * sizeof(EventInternal);
|
u64 events = event_capacity * sizeof(EventInternal);
|
||||||
u64 callbacks = event_capacity * callback_capacity * sizeof(EventCallback *);
|
// Increase listener capacity by one to account for 0th EventListener being invalid
|
||||||
u64 alloc_size = system + event_offsets + free_slots + events + callbacks;
|
u64 event_callbacks = (callback_capacity + 1) * sizeof(EventCallback *);
|
||||||
|
u64 event_free = callback_capacity * sizeof(u64 *);
|
||||||
|
u64 callbacks = event_capacity * event_callbacks;
|
||||||
|
u64 free_callbacks = event_capacity * event_free;
|
||||||
|
u64 alloc_size = system + event_offsets + free_slots + events + callbacks + free_callbacks;
|
||||||
|
|
||||||
|
EventSystem es = INVALID_SYSTEM;
|
||||||
|
|
||||||
|
// NOTE (Abdelrahman): The idea here is to have a single buffer that holds all the data.
|
||||||
|
// For the purposes of this test, offsets are manually calculated to different parts of the buffer.
|
||||||
|
// An actual implementation of this should probably use an internal memory arena making allocations
|
||||||
|
// easier, while still maintaining all data in a single buffer.
|
||||||
u8 *buffer = alloc(alloc_size);
|
u8 *buffer = alloc(alloc_size);
|
||||||
if (!buffer) {
|
if (!buffer) {
|
||||||
return ES_INIT_ALLOCATION_FAILED;
|
goto RETURN_SYSTEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(buffer, 0, alloc_size);
|
memset(buffer, 0, alloc_size);
|
||||||
|
|
||||||
*es = (EventSystem *)buffer;
|
es.id = (u64)buffer;
|
||||||
|
|
||||||
EventSystem *event_system = *es;
|
ESInternal *event_system = (ESInternal *)buffer;
|
||||||
|
|
||||||
event_system->alloc_size = alloc_size;
|
event_system->alloc_size = alloc_size;
|
||||||
event_system->event_capacity = event_capacity;
|
event_system->event_capacity = event_capacity;
|
||||||
event_system->event_count = 0;
|
event_system->event_count = 0;
|
||||||
event_system->free_count = 0;
|
event_system->free_count = 0;
|
||||||
event_system->initial_callback_capacity = callback_capacity - 1;
|
event_system->initial_callback_capacity = callback_capacity;
|
||||||
event_system->events_offset = (uptr)system;
|
event_system->events_offset = (uptr)system;
|
||||||
event_system->free_offset = (uptr)(system + event_offsets);
|
event_system->free_offset = (uptr)(system + event_offsets);
|
||||||
event_system->callbacks_offset = (uptr)(system + event_offsets + free_slots);
|
event_system->callbacks_offset = (uptr)(system + event_offsets + free_slots);
|
||||||
|
|
||||||
EventSlot *ev_slots_array = get_event_slots_array(event_system);
|
EventSlot *ev_slots = get_event_slots_array(event_system);
|
||||||
|
|
||||||
u64 event_item_capacity = sizeof(EventInternal) + callback_capacity * sizeof(EventCallback *);
|
u64 event_item_capacity = sizeof(EventInternal) + event_callbacks + event_free;
|
||||||
|
EventInternal *event;
|
||||||
|
uptr offset;
|
||||||
for (u64 i = 0; i < event_capacity; ++i) {
|
for (u64 i = 0; i < event_capacity; ++i) {
|
||||||
ev_slots_array[i].offset = event_system->callbacks_offset + i * event_item_capacity;
|
offset = event_system->callbacks_offset + i * event_item_capacity;
|
||||||
|
ev_slots[i + 1].offset = offset;
|
||||||
|
event = get_event_from_offset(event_system, offset);
|
||||||
|
event->capacity = callback_capacity;
|
||||||
|
// WARN (Abdelrahman): As mentioned above, an actual arena would be very useful here. The below
|
||||||
|
// would break if the order of the EventInternal struct changes
|
||||||
|
event->free = (u64 *)((uptr)event_system + offset + sizeof(EventInternal));
|
||||||
|
event->callbacks = (EventCallback *)((uptr)event_system + offset + sizeof(EventInternal) + event_free);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ES_INIT_SUCCESS;
|
RETURN_SYSTEM:
|
||||||
|
return es;
|
||||||
}
|
}
|
||||||
|
|
||||||
void es_deinit(EventSystem **es) {
|
void es_deinit(EventSystem event_system) {
|
||||||
if (!es || !*es) {
|
if (IS_INVALID_SYSTEM(event_system)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
EventSystem *system = *es;
|
ESInternal *es = get_event_system_internal(event_system);
|
||||||
|
|
||||||
munmap(system, system->alloc_size);
|
munmap(system, es->alloc_size);
|
||||||
*es = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Event es_register_event(EventSystem *es) {
|
Event es_register_event(EventSystem event_system) {
|
||||||
Event event = INVALID_EVENT;
|
Event event = INVALID_EVENT;
|
||||||
|
|
||||||
if (!es) {
|
if (IS_INVALID_SYSTEM(event_system)) {
|
||||||
goto RETURN_EVENT;
|
goto RETURN_EVENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ESInternal *es = get_event_system_internal(event_system);
|
||||||
EventSlot *event_slots_array = get_event_slots_array(es);
|
EventSlot *event_slots_array = get_event_slots_array(es);
|
||||||
|
|
||||||
if (es->free_count > 0) {
|
if (es->free_count > 0) {
|
||||||
@ -125,6 +142,7 @@ Event es_register_event(EventSystem *es) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (es->event_count >= es->event_capacity) {
|
if (es->event_count >= es->event_capacity) {
|
||||||
|
// TODO (Abdelrahman): Handle reallocating when out of events
|
||||||
goto RETURN_EVENT;
|
goto RETURN_EVENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,8 +153,13 @@ RETURN_EVENT:
|
|||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
void es_deregister_event(EventSystem *es, Event event) {
|
void es_deregister_event(EventSystem event_system, Event event) {
|
||||||
if (!es || IS_INVALID_EVENT(event)) {
|
if (IS_INVALID_SYSTEM(event_system) || IS_INVALID_EVENT(event)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESInternal *es = get_event_system_internal(event_system);
|
||||||
|
if (event.id > es->event_count) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,27 +174,35 @@ void es_deregister_event(EventSystem *es, Event event) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EventListener es_add_event_listener(EventSystem *es, u64 id, EventCallback *listener) {}
|
EventListener es_add_event_listener(EventSystem event_system, Event event, EventCallback *listener) {}
|
||||||
|
|
||||||
void es_remove_event_listener(EventSystem *es, EventListener listener) {}
|
void es_remove_event_listener(EventSystem event_system, EventListener listener) {}
|
||||||
|
|
||||||
void es_emit_event(EventSystem *es, u64 id, void *data) {}
|
void es_emit_event(EventSystem event_system, Event event, void *data) {}
|
||||||
|
|
||||||
// INTERNAL
|
// INTERNAL
|
||||||
|
|
||||||
void *alloc(u64 size) {
|
internal void *alloc(u64 size) {
|
||||||
return mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE | MAP_NORESERVE, -1, 0);
|
return mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE | MAP_NORESERVE, -1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
EventSlot *get_event_slots_array(const EventSystem *es) {
|
internal ESInternal *get_event_system_internal(EventSystem event_system) {
|
||||||
|
return (ESInternal *)event_system.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal EventSlot *get_event_slots_array(const ESInternal *es) {
|
||||||
return (EventSlot *)((uptr)es + es->events_offset);
|
return (EventSlot *)((uptr)es + es->events_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 *get_free_array(const EventSystem *es) {
|
internal u64 *get_free_array(const ESInternal *es) {
|
||||||
return (u64 *)((uptr)es + es->free_offset);
|
return (u64 *)((uptr)es + es->free_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
EventInternal *get_event(const EventSystem *es, Event event) {
|
internal EventInternal *get_event(const ESInternal *es, Event event) {
|
||||||
EventSlot *event_slots_array = get_event_slots_array(es);
|
EventSlot *event_slots_array = get_event_slots_array(es);
|
||||||
return (EventInternal *)((uptr)es + event_slots_array[event.id].offset);
|
return get_event_from_offset(es, event_slots_array[event.id].offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal EventInternal *get_event_from_offset(const ESInternal *es, u64 offset) {
|
||||||
|
return (EventInternal *)((uptr)es + offset);
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,11 @@ enum {
|
|||||||
ES_INIT_ALLOCATION_FAILED,
|
ES_INIT_ALLOCATION_FAILED,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct event_system EventSystem;
|
||||||
|
struct event_system {
|
||||||
|
u64 id;
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct event Event;
|
typedef struct event Event;
|
||||||
struct event {
|
struct event {
|
||||||
u64 id;
|
u64 id;
|
||||||
@ -20,14 +25,12 @@ struct event_listener {
|
|||||||
u64 id;
|
u64 id;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct event_system EventSystem;
|
|
||||||
|
|
||||||
typedef void (EventCallback)(void *data);
|
typedef void (EventCallback)(void *data);
|
||||||
|
|
||||||
u32 es_init(EventSystem **es, u64 initial_event_capacity, u64 initial_listeners_capacity);
|
EventSystem es_init(u64 initial_event_capacity, u64 initial_listeners_capacity);
|
||||||
void es_deinit(EventSystem **es);
|
void es_deinit(EventSystem event_system);
|
||||||
Event es_register_event(EventSystem *es);
|
Event es_register_event(EventSystem event_system);
|
||||||
void es_deregister_event(EventSystem *es, Event event);
|
void es_deregister_event(EventSystem event_system, Event event);
|
||||||
EventListener es_add_event_listener(EventSystem *es, u64 id, EventCallback *listener);
|
EventListener es_add_event_listener(EventSystem event_system, Event event, EventCallback *listener);
|
||||||
void es_remove_event_listener(EventSystem *es, EventListener listener);
|
void es_remove_event_listener(EventSystem event_system, EventListener listener);
|
||||||
void es_emit_event(EventSystem *es, u64 id, void *data);
|
void es_emit_event(EventSystem event_system, Event event, void *data);
|
||||||
|
@ -1,13 +1,8 @@
|
|||||||
#include "event_system.h"
|
#include "event_system.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
EventSystem *es = NULL;
|
EventSystem es = es_init(16, 64);
|
||||||
if (es_init(&es, 16, 64) != ES_INIT_SUCCESS) {
|
|
||||||
printf("INITIALISATION FAILED\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < 40; ++i) {
|
for (int i = 0; i < 40; ++i) {
|
||||||
Event ev = es_register_event(es);
|
Event ev = es_register_event(es);
|
||||||
@ -27,7 +22,7 @@ int main(void) {
|
|||||||
printf("%lu\n", ev.id);
|
printf("%lu\n", ev.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
es_deinit(&es);
|
es_deinit(es);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user