Handle reallocating when out of events
This commit is contained in:
		| @@ -17,6 +17,9 @@ | ||||
| #define IS_INVALID_EVENT(EV) (EV.id == 0) | ||||
| #define IS_INVALID_LISTENER(LS) (LS.id == 0 || IS_INVALID_EVENT(LS.event)) | ||||
|  | ||||
| #define CB_ARR_SIZE(CAPACITY) ((CAPACITY + 1) * sizeof(EventCallback *)) | ||||
| #define FREE_CB_ARR_SIZE(CAPACITY) (CAPACITY * sizeof(u64 *)) | ||||
|  | ||||
| typedef struct es_internal ESInternal; | ||||
| struct es_internal { | ||||
|   u64  magic; | ||||
| @@ -49,8 +52,10 @@ internal void          *alloc(u64 size); | ||||
| internal ESInternal    *get_event_system_internal(EventSystem event_system); | ||||
| internal EventSlot     *get_event_slots_array(const ESInternal *es); | ||||
| internal u64           *get_free_array(const ESInternal *es); | ||||
| internal void          copy_event_data(const ESInternal *src, ESInternal *dst); | ||||
| internal EventInternal *get_event(const ESInternal *es, Event event); | ||||
| internal EventInternal *get_event_from_offset(const ESInternal *es, u64 offset); | ||||
| internal u64           get_largest_capacity(const ESInternal *es); | ||||
|  | ||||
| EventSystem es_init(u64 initial_event_capacity, u64 initial_listeners_capacity) { | ||||
|   // Double event capacity to reduce chances of reallocation | ||||
| @@ -62,9 +67,9 @@ EventSystem es_init(u64 initial_event_capacity, u64 initial_listeners_capacity) | ||||
|   u64 event_offsets      = (event_capacity + 1) * sizeof(EventSlot); | ||||
|   u64 free_slots         = event_capacity * sizeof(u64); | ||||
|   u64 events             = event_capacity * sizeof(EventInternal); | ||||
|   // Increase listener capacity by one to account for 0th EventListener being invalid | ||||
|   u64 event_callbacks    = (callback_capacity + 1) * sizeof(EventCallback *); | ||||
|   u64 event_free         = callback_capacity * sizeof(u64 *); | ||||
|   // Increases listener capacity by one to account for 0th EventListener being invalid | ||||
|   u64 event_callbacks    = CB_ARR_SIZE(callback_capacity); | ||||
|   u64 event_free         = FREE_CB_ARR_SIZE(callback_capacity); | ||||
|   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; | ||||
| @@ -143,8 +148,6 @@ Event es_register_event(EventSystem *event_system) { | ||||
|     goto RETURN_EVENT; | ||||
|   } | ||||
|  | ||||
|   event.system = *event_system; | ||||
|  | ||||
|   EventSlot *event_slots_array = get_event_slots_array(es); | ||||
|  | ||||
|   if (es->free_count > 0) { | ||||
| @@ -159,8 +162,17 @@ Event es_register_event(EventSystem *event_system) { | ||||
|   } | ||||
|  | ||||
|   if (es->event_count >= es->event_capacity) { | ||||
|     // TODO (Abdelrahman): Handle reallocating when out of events | ||||
|     goto RETURN_EVENT; | ||||
|     u64 new_callback_capacity    = get_largest_capacity(es); | ||||
|     EventSystem event_system_new = es_init(es->event_capacity, new_callback_capacity); | ||||
|     ESInternal  *es_new          = get_event_system_internal(event_system_new); | ||||
|  | ||||
|     es_new->event_count = es->event_count; | ||||
|  | ||||
|     copy_event_data(es, es_new); | ||||
|  | ||||
|     es_deinit(event_system); | ||||
|     event_system->id = (u64)es_new; | ||||
|     es = es_new; | ||||
|   } | ||||
|  | ||||
|   event.id = ++(es->event_count); | ||||
| @@ -171,7 +183,7 @@ RETURN_EVENT: | ||||
| } | ||||
|  | ||||
| void es_deregister_event(EventSystem event_system, Event *event) { | ||||
|   if (IS_INVALID_SYSTEM(event_system) || IS_INVALID_EVENT((*event)) || event_system.id != event->system.id) { | ||||
|   if (IS_INVALID_SYSTEM(event_system) || IS_INVALID_EVENT((*event))) { | ||||
|     return; | ||||
|   } | ||||
|  | ||||
| @@ -196,7 +208,7 @@ void es_deregister_event(EventSystem event_system, Event *event) { | ||||
| EventListener es_add_event_listener(EventSystem *event_system, Event event, EventCallback callback) { | ||||
|   EventListener listener = INVALID_LISTENER; | ||||
|  | ||||
|   if (!event_system || IS_INVALID_SYSTEM((*event_system)) || IS_INVALID_EVENT(event) || event_system->id != event.system.id || !callback) { | ||||
|   if (!event_system || IS_INVALID_SYSTEM((*event_system)) || IS_INVALID_EVENT(event) || !callback) { | ||||
|     goto RETURN_LISTENER; | ||||
|   } | ||||
|  | ||||
| @@ -236,7 +248,7 @@ RETURN_LISTENER: | ||||
| } | ||||
|  | ||||
| void es_remove_event_listener(EventSystem event_system, EventListener listener) { | ||||
|   if (IS_INVALID_SYSTEM(event_system) || IS_INVALID_LISTENER(listener) || event_system.id != listener.event.system.id) { | ||||
|   if (IS_INVALID_SYSTEM(event_system) || IS_INVALID_LISTENER(listener)) { | ||||
|     return; | ||||
|   } | ||||
|  | ||||
| @@ -264,7 +276,7 @@ void es_remove_event_listener(EventSystem event_system, EventListener listener) | ||||
| } | ||||
|  | ||||
| void es_emit_event(EventSystem event_system, Event event, void *data) { | ||||
|   if (IS_INVALID_SYSTEM(event_system) || IS_INVALID_EVENT(event) || event_system.id != event.system.id) { | ||||
|   if (IS_INVALID_SYSTEM(event_system) || IS_INVALID_EVENT(event)) { | ||||
|     return; | ||||
|   } | ||||
|  | ||||
| @@ -302,6 +314,26 @@ internal u64 *get_free_array(const ESInternal *es) { | ||||
|   return (u64 *)((uptr)es + es->free_offset); | ||||
| } | ||||
|  | ||||
| internal void copy_event_data(const ESInternal *src, ESInternal *dst) { | ||||
|   EventSlot *slots_src = get_event_slots_array(src); | ||||
|   EventSlot *slots_dst = get_event_slots_array(dst); | ||||
|  | ||||
|   EventInternal *ev_src; | ||||
|   EventInternal *ev_dst; | ||||
|   for (u64 i = 1; i <= src->event_count; ++i) { | ||||
|     slots_dst[i].registered = slots_src[i].registered; | ||||
|  | ||||
|     ev_src = get_event_from_offset(src, slots_src[i].offset); | ||||
|     ev_dst = get_event_from_offset(dst, slots_dst[i].offset); | ||||
|  | ||||
|     ev_dst->count      = ev_src->count; | ||||
|     ev_dst->free_count = ev_src->free_count; | ||||
|  | ||||
|     memcpy((void *)(ev_dst->free), (void *)(ev_src->free), FREE_CB_ARR_SIZE(ev_src->capacity)); | ||||
|     memcpy((void *)(ev_dst->callbacks), (void *)(ev_src->callbacks), CB_ARR_SIZE(ev_src->capacity)); | ||||
|   } | ||||
| } | ||||
|  | ||||
| internal EventInternal *get_event(const ESInternal *es, Event event) { | ||||
|   EventSlot *event_slots_array = get_event_slots_array(es); | ||||
|   return get_event_from_offset(es, event_slots_array[event.id].offset); | ||||
| @@ -310,3 +342,18 @@ internal EventInternal *get_event(const ESInternal *es, Event event) { | ||||
| internal EventInternal *get_event_from_offset(const ESInternal *es, u64 offset) { | ||||
|   return (EventInternal *)((uptr)es + offset); | ||||
| } | ||||
|  | ||||
| internal u64 get_largest_capacity(const ESInternal *es) { | ||||
|   EventSlot *event_slots_array   = get_event_slots_array(es); | ||||
|   u64 capacity                   = es->initial_callback_capacity; | ||||
|  | ||||
|   EventInternal *event; | ||||
|   for (u64 i = 1; i <= es->event_count; ++i) { | ||||
|     event = get_event_from_offset(es, event_slots_array[i].offset); | ||||
|     if (event->capacity > capacity) { | ||||
|       capacity = event->capacity; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   return capacity; | ||||
| } | ||||
|   | ||||
| @@ -16,7 +16,6 @@ struct event_system { | ||||
|  | ||||
| typedef struct event Event; | ||||
| struct event { | ||||
|   EventSystem system; | ||||
|   u64 id; | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -67,6 +67,14 @@ int main(void) { | ||||
|   es_remove_event_listener(es, listener); | ||||
|   es_deregister_event(es, &extra_event); | ||||
|  | ||||
|   for (int i = 0; i < 10; ++i) { | ||||
|     es_register_event(&es); | ||||
|   } | ||||
|  | ||||
|   es_emit_event(es, events[EVENT_WINDOW],   (void *)&window_event); | ||||
|   es_emit_event(es, events[EVENT_KEYBOARD], (void *)&keyboard_event); | ||||
|   es_emit_event(es, events[EVENT_MOUSE],    (void *)&mouse_event); | ||||
|  | ||||
|   for (int i = 0; i < COUNT_EVENTS; ++i) { | ||||
|     es_remove_event_listener(es, listeners[i]); | ||||
|     es_deregister_event(es, &events[i]); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user