Refactor to make EventSystem public with id instead of opaque type
This commit is contained in:
		| @@ -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,86 +35,100 @@ 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; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   EventSlot *event_slots_array = get_event_slots_array(es); |   ESInternal *es                = get_event_system_internal(event_system); | ||||||
|  |   EventSlot *event_slots_array  = get_event_slots_array(es); | ||||||
|  |  | ||||||
|   if (es->free_count > 0) { |   if (es->free_count > 0) { | ||||||
|     u64 *free_array = get_free_array(es); |     u64 *free_array = get_free_array(es); | ||||||
| @@ -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; | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user