From 3e11c380c946464360f18b058afca783cde3ddde Mon Sep 17 00:00:00 2001 From: Tom Hacohen Date: Fri, 12 Apr 2013 11:06:30 +0100 Subject: [PATCH] Eo: Added eo_event_callback_array_* functions. These functions let you pass an array of callbacks instead of just one. It's more memory efficient to use this if you just add a bulk of events on the same object. This commits breaks ABI, and breaks API of the EO_EV_CALLBACK_ADD/DEL signals (the event info passed). --- src/lib/eo/Eo.h | 56 +++++++++++++++- src/lib/eo/eo_base_class.c | 107 ++++++++++++++++++++++++++---- src/tests/eo/signals/signals_simple.c | 8 +-- src/tests/eo/suite/eo_test_class_simple.c | 5 ++ src/tests/eo/suite/eo_test_class_simple.h | 4 +- src/tests/eo/suite/eo_test_general.c | 71 ++++++++++++++++++++ 6 files changed, 231 insertions(+), 20 deletions(-) diff --git a/src/lib/eo/Eo.h b/src/lib/eo/Eo.h index 4b44505..a8cac52 100644 --- a/src/lib/eo/Eo.h +++ b/src/lib/eo/Eo.h @@ -988,6 +988,8 @@ enum { EO_BASE_SUB_ID_WREF_DEL, EO_BASE_SUB_ID_EVENT_CALLBACK_PRIORITY_ADD, EO_BASE_SUB_ID_EVENT_CALLBACK_DEL, + EO_BASE_SUB_ID_EVENT_CALLBACK_ARRAY_PRIORITY_ADD, + EO_BASE_SUB_ID_EVENT_CALLBACK_ARRAY_DEL, EO_BASE_SUB_ID_EVENT_CALLBACK_CALL, EO_BASE_SUB_ID_EVENT_CALLBACK_FORWARDER_ADD, EO_BASE_SUB_ID_EVENT_CALLBACK_FORWARDER_DEL, @@ -1199,6 +1201,23 @@ typedef short Eo_Callback_Priority; typedef Eina_Bool (*Eo_Event_Cb)(void *data, Eo *obj, const Eo_Event_Description *desc, void *event_info); /** + * @typedef Eo_Callback_Array_Item + * A convenience typedef for #_Eo_Callback_Array_Item + */ +typedef struct _Eo_Callback_Array_Item Eo_Callback_Array_Item; + +/** + * @struct _Eo_Callback_Array_Item + * An item in an array of callback desc/func. + * @see eo_event_callback_array_add() + */ +struct _Eo_Callback_Array_Item +{ + const Eo_Event_Description *desc; /**< The event description. */ + Eo_Event_Cb func; /**< The callback function. */ +}; + +/** * @def eo_event_callback_forwarder_add * @brief Add an event callback forwarder for an event and an object. * @param[in] desc The description of the event to listen to. @@ -1316,7 +1335,6 @@ typedef Eina_Bool (*Eo_Event_Cb)(void *data, Eo *obj, const Eo_Event_Description */ #define eo_event_callback_priority_add(desc, priority, cb, data) EO_BASE_ID(EO_BASE_SUB_ID_EVENT_CALLBACK_PRIORITY_ADD), EO_TYPECHECK(const Eo_Event_Description *, desc), EO_TYPECHECK(Eo_Callback_Priority, priority), EO_TYPECHECK(Eo_Event_Cb, cb), EO_TYPECHECK(const void *, data) - /** * @def eo_event_callback_del * @brief Del a callback with a specific data associated to it for an event. @@ -1328,6 +1346,42 @@ typedef Eina_Bool (*Eo_Event_Cb)(void *data, Eo *obj, const Eo_Event_Description #define eo_event_callback_del(desc, func, user_data) EO_BASE_ID(EO_BASE_SUB_ID_EVENT_CALLBACK_DEL), EO_TYPECHECK(const Eo_Event_Description *, desc), EO_TYPECHECK(Eo_Event_Cb, func), EO_TYPECHECK(const void *, user_data) /** + * @def eo_event_callback_array_add(obj, desc, cb, data) + * Add a callback array for an event. + * @param[in] array an #Eo_Callback_Array_Item of events to listen to. + * @param[in] data additional data to pass to the callback. + * + * callbacks of the same priority are called in reverse order of creation. + * + * @see eo_event_callback_array_priority_add() + */ +#define eo_event_callback_array_add(array, data) \ + eo_event_callback_array_priority_add(array, \ + EO_CALLBACK_PRIORITY_DEFAULT, data) + +/** + * @def eo_event_callback_priority_add + * @brief Add a callback array for an event with a specific priority. + * @param[in] array an #Eo_Callback_Array_Item of events to listen to. + * @param[in] priority The priority of the callback. + * @param[in] data additional data to pass to the callback. + * + * callbacks of the same priority are called in reverse order of creation. + * + * @see #eo_event_callback_add + */ +#define eo_event_callback_array_priority_add(array, priority, data) EO_BASE_ID(EO_BASE_SUB_ID_EVENT_CALLBACK_ARRAY_PRIORITY_ADD), EO_TYPECHECK(const Eo_Callback_Array_Item *, array), EO_TYPECHECK(Eo_Callback_Priority, priority), EO_TYPECHECK(const void *, data) + +/** + * @def eo_event_callback_del + * @brief Del a callback array with a specific data associated to it for an event. + * @param[in] array an #Eo_Callback_Array_Item of events to listen to. + * @param[in] user_data The data to compare. + * + */ +#define eo_event_callback_array_del(array, user_data) EO_BASE_ID(EO_BASE_SUB_ID_EVENT_CALLBACK_ARRAY_DEL), EO_TYPECHECK(const Eo_Callback_Array_Item *, array), EO_TYPECHECK(const void *, user_data) + +/** * @def eo_event_callback_call * @brief Call the callbacks for an event of an object. * @param[in] desc The description of the event to call. diff --git a/src/lib/eo/eo_base_class.c b/src/lib/eo/eo_base_class.c index 01def69..6399ca8 100644 --- a/src/lib/eo/eo_base_class.c +++ b/src/lib/eo/eo_base_class.c @@ -247,11 +247,15 @@ _wref_destruct(Private_Data *pd) struct _Eo_Callback_Description { Eo_Callback_Description *next; - const Eo_Event_Description *event; - Eo_Event_Cb func; + union + { + Eo_Callback_Array_Item item; + const Eo_Callback_Array_Item *item_array; + } items; void *func_data; Eo_Callback_Priority priority; Eina_Bool delete_me : 1; + Eina_Bool func_array : 1; }; /* Actually remove, doesn't care about walking list, or delete_me */ @@ -352,13 +356,16 @@ _ev_cb_priority_add(Eo *obj, void *class_data, va_list *list) const void *data = va_arg(*list, const void *); Eo_Callback_Description *cb = calloc(1, sizeof(*cb)); - cb->event = desc; - cb->func = func; + cb->items.item.desc = desc; + cb->items.item.func = func; cb->func_data = (void *) data; cb->priority = priority; _eo_callbacks_sorted_insert(pd, cb); - eo_do(obj, eo_event_callback_call(EO_EV_CALLBACK_ADD, desc, NULL)); + { + const Eo_Callback_Array_Item arr[] = { {desc, func}, {NULL, NULL}}; + eo_do(obj, eo_event_callback_call(EO_EV_CALLBACK_ADD, arr, NULL)); + } } static void @@ -372,13 +379,15 @@ _ev_cb_del(Eo *obj, void *class_data, va_list *list) Eo_Callback_Description *cb; for (cb = pd->callbacks ; cb ; cb = cb->next) { - if ((cb->event == desc) && (cb->func == func) && + if ((cb->items.item.desc == desc) && (cb->items.item.func == func) && (cb->func_data == user_data)) { + const Eo_Callback_Array_Item arr[] = { {desc, func}, {NULL, NULL}}; + cb->delete_me = EINA_TRUE; pd->deletions_waiting = EINA_TRUE; _eo_callbacks_clear(pd); - eo_do(obj, eo_event_callback_call(EO_EV_CALLBACK_DEL, desc, NULL)); + eo_do(obj, eo_event_callback_call(EO_EV_CALLBACK_DEL, arr, NULL)); return; } } @@ -387,6 +396,50 @@ _ev_cb_del(Eo *obj, void *class_data, va_list *list) } static void +_ev_cb_array_priority_add(Eo *obj, void *class_data, va_list *list) +{ + Private_Data *pd = (Private_Data *) class_data; + const Eo_Callback_Array_Item *array = va_arg(*list, const Eo_Callback_Array_Item *); + Eo_Callback_Priority priority = va_arg(*list, int); + const void *data = va_arg(*list, const void *); + + Eo_Callback_Description *cb = calloc(1, sizeof(*cb)); + cb->func_data = (void *) data; + cb->priority = priority; + cb->items.item_array = array; + cb->func_array = EINA_TRUE; + _eo_callbacks_sorted_insert(pd, cb); + + { + eo_do(obj, eo_event_callback_call(EO_EV_CALLBACK_ADD, array, NULL)); + } +} + +static void +_ev_cb_array_del(Eo *obj, void *class_data, va_list *list) +{ + Private_Data *pd = (Private_Data *) class_data; + const Eo_Callback_Array_Item *array = va_arg(*list, const Eo_Callback_Array_Item *); + void *user_data = va_arg(*list, void *); + + Eo_Callback_Description *cb; + for (cb = pd->callbacks ; cb ; cb = cb->next) + { + if ((cb->items.item_array == array) && (cb->func_data == user_data)) + { + cb->delete_me = EINA_TRUE; + pd->deletions_waiting = EINA_TRUE; + _eo_callbacks_clear(pd); + + eo_do(obj, eo_event_callback_call(EO_EV_CALLBACK_DEL, array, NULL)); + return; + } + } + + ERR("Callback of object %p with function array %p and data %p not found.", obj, array, user_data); +} + +static void _ev_cb_call(Eo *obj, void *class_data, va_list *list) { Private_Data *pd = (Private_Data *) class_data; @@ -406,17 +459,41 @@ _ev_cb_call(Eo *obj, void *class_data, va_list *list) Eo_Callback_Description *cb; for (cb = pd->callbacks ; cb ; cb = cb->next) { - if (!cb->delete_me && (cb->event == desc)) + if (!cb->delete_me) { - /* Abort callback calling if the func says so. */ - if (!cb->func((void *) cb->func_data, obj, desc, - (void *) event_info)) + if (cb->func_array) { - if (ret) *ret = EINA_FALSE; - break; + const Eo_Callback_Array_Item *it; + for (it = cb->items.item_array ; it->func ; it++) + { + if (it->desc != desc) + continue; + /* Abort callback calling if the func says so. */ + if (!it->func((void *) cb->func_data, obj, desc, + (void *) event_info)) + { + if (ret) *ret = EINA_FALSE; + goto end; + } + } + } + else + { + if (cb->items.item.desc == desc) + { + /* Abort callback calling if the func says so. */ + if (!cb->items.item.func((void *) cb->func_data, obj, desc, + (void *) event_info)) + { + if (ret) *ret = EINA_FALSE; + goto end; + } + } } } } + +end: pd->walking_list--; _eo_callbacks_clear(pd); eo_unref(obj); @@ -558,6 +635,8 @@ _class_constructor(Eo_Class *klass) EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_WREF_DEL), _wref_del), EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_EVENT_CALLBACK_PRIORITY_ADD), _ev_cb_priority_add), EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_EVENT_CALLBACK_DEL), _ev_cb_del), + EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_EVENT_CALLBACK_ARRAY_PRIORITY_ADD), _ev_cb_array_priority_add), + EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_EVENT_CALLBACK_ARRAY_DEL), _ev_cb_array_del), EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_EVENT_CALLBACK_CALL), _ev_cb_call), EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_EVENT_CALLBACK_FORWARDER_ADD), _ev_cb_forwarder_add), EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_EVENT_CALLBACK_FORWARDER_DEL), _ev_cb_forwarder_del), @@ -584,6 +663,8 @@ static const Eo_Op_Description op_desc[] = { EO_OP_DESCRIPTION(EO_BASE_SUB_ID_WREF_DEL, "Delete the weak ref."), EO_OP_DESCRIPTION(EO_BASE_SUB_ID_EVENT_CALLBACK_PRIORITY_ADD, "Add an event callback with a priority."), EO_OP_DESCRIPTION(EO_BASE_SUB_ID_EVENT_CALLBACK_DEL, "Delete an event callback"), + EO_OP_DESCRIPTION(EO_BASE_SUB_ID_EVENT_CALLBACK_ARRAY_PRIORITY_ADD, "Add an event callback array with a priority."), + EO_OP_DESCRIPTION(EO_BASE_SUB_ID_EVENT_CALLBACK_ARRAY_DEL, "Delete an event callback array"), EO_OP_DESCRIPTION(EO_BASE_SUB_ID_EVENT_CALLBACK_CALL, "Call the event callbacks for an event."), EO_OP_DESCRIPTION(EO_BASE_SUB_ID_EVENT_CALLBACK_FORWARDER_ADD, "Add an event forwarder."), EO_OP_DESCRIPTION(EO_BASE_SUB_ID_EVENT_CALLBACK_FORWARDER_DEL, "Delete an event forwarder."), diff --git a/src/tests/eo/signals/signals_simple.c b/src/tests/eo/signals/signals_simple.c index 77d1574..37a38a9 100644 --- a/src/tests/eo/signals/signals_simple.c +++ b/src/tests/eo/signals/signals_simple.c @@ -34,11 +34,11 @@ Eina_Bool _cb_added(void *data, Eo *obj, const Eo_Event_Description *desc, void *event_info) { Simple_Public_Data *pd = eo_data_get(obj, MY_CLASS); - const Eo_Event_Description *cb_desc = event_info; + const Eo_Callback_Array_Item *callback_array = event_info; (void) data; (void) desc; - if (cb_desc != EV_A_CHANGED) + if (callback_array->desc != EV_A_CHANGED) return EINA_TRUE; pd->cb_count++; @@ -51,11 +51,11 @@ Eina_Bool _cb_deled(void *data, Eo *obj, const Eo_Event_Description *desc, void *event_info) { Simple_Public_Data *pd = eo_data_get(obj, MY_CLASS); - const Eo_Event_Description *cb_desc = event_info; + const Eo_Callback_Array_Item *callback_array = event_info; (void) data; (void) desc; - if (cb_desc != EV_A_CHANGED) + if (callback_array->desc != EV_A_CHANGED) return EINA_TRUE; pd->cb_count--; diff --git a/src/tests/eo/suite/eo_test_class_simple.c b/src/tests/eo/suite/eo_test_class_simple.c index 224f5b5..e21c54f 100644 --- a/src/tests/eo/suite/eo_test_class_simple.c +++ b/src/tests/eo/suite/eo_test_class_simple.c @@ -9,6 +9,9 @@ EAPI Eo_Op SIMPLE_BASE_ID = 0; +EAPI const Eo_Event_Description _EV_A_CHANGED = + EO_EVENT_DESCRIPTION("a,changed", "Called when a has changed."); + static void _a_set(Eo *obj EINA_UNUSED, void *class_data, va_list *list) { @@ -17,6 +20,8 @@ _a_set(Eo *obj EINA_UNUSED, void *class_data, va_list *list) a = va_arg(*list, int); printf("%s %d\n", eo_class_name_get(MY_CLASS), a); pd->a = a; + + eo_do(obj, eo_event_callback_call(EV_A_CHANGED, &pd->a, NULL)); } static void diff --git a/src/tests/eo/suite/eo_test_class_simple.h b/src/tests/eo/suite/eo_test_class_simple.h index 9980b7b..699ddb8 100644 --- a/src/tests/eo/suite/eo_test_class_simple.h +++ b/src/tests/eo/suite/eo_test_class_simple.h @@ -21,8 +21,8 @@ typedef struct #define simple_a_print() SIMPLE_ID(SIMPLE_SUB_ID_A_PRINT) #define simple_class_hi_print() SIMPLE_ID(SIMPLE_SUB_ID_CLASS_HI_PRINT) -extern const Eo_Event_Description _SIG_A_CHANGED; -#define SIG_A_CHANGED (&(_SIG_A_CHANGED)) +extern const Eo_Event_Description _EV_A_CHANGED; +#define EV_A_CHANGED (&(_EV_A_CHANGED)) #define SIMPLE_CLASS simple_class_get() const Eo_Class *simple_class_get(void); diff --git a/src/tests/eo/suite/eo_test_general.c b/src/tests/eo/suite/eo_test_general.c index d6a4eec..01ae11c 100644 --- a/src/tests/eo/suite/eo_test_general.c +++ b/src/tests/eo/suite/eo_test_general.c @@ -24,6 +24,76 @@ START_TEST(eo_simple) } END_TEST +static int _eo_signals_cb_curent = 0; +static int _eo_signals_cb_flag = 0; + +static Eina_Bool +_eo_signals_a_changed_cb(void *_data, Eo *obj EINA_UNUSED, const Eo_Event_Description *desc EINA_UNUSED, void *event_info EINA_UNUSED) +{ + int data = (intptr_t) _data; + _eo_signals_cb_curent++; + ck_assert_int_eq(data, _eo_signals_cb_curent); + _eo_signals_cb_flag |= 0x1; + return EO_CALLBACK_CONTINUE; +} + +static Eina_Bool +_eo_signals_a_changed_cb2(void *_data EINA_UNUSED, Eo *obj EINA_UNUSED, const Eo_Event_Description *desc EINA_UNUSED, void *event_info EINA_UNUSED) +{ + _eo_signals_cb_flag |= 0x2; + return EO_CALLBACK_CONTINUE; +} + +static Eina_Bool +_eo_signals_eo_del_cb(void *_data EINA_UNUSED, Eo *obj EINA_UNUSED, const Eo_Event_Description *desc EINA_UNUSED, void *event_info EINA_UNUSED) +{ + _eo_signals_cb_flag |= 0x4; + return EO_CALLBACK_CONTINUE; +} + +Eina_Bool +_eo_signals_cb_added_deled(void *data, Eo *obj EINA_UNUSED, const Eo_Event_Description *desc EINA_UNUSED, void *event_info) +{ + const Eo_Callback_Array_Item *callback_array = event_info; + + fail_if((callback_array != data) && + (callback_array->func != _eo_signals_cb_added_deled)); + + return EO_CALLBACK_CONTINUE; +} + +START_TEST(eo_signals) +{ + eo_init(); + static const Eo_Callback_Array_Item callbacks[] = { + { EV_A_CHANGED, _eo_signals_a_changed_cb }, + { EV_A_CHANGED, _eo_signals_a_changed_cb2 }, + { EO_EV_DEL, _eo_signals_eo_del_cb }, + { NULL, NULL } + }; + Eo *obj = eo_add(SIMPLE_CLASS, NULL); + + eo_do(obj, eo_event_callback_add(EO_EV_CALLBACK_ADD, _eo_signals_cb_added_deled, callbacks)); + eo_do(obj, eo_event_callback_add(EO_EV_CALLBACK_DEL, _eo_signals_cb_added_deled, callbacks)); + eo_do(obj, eo_event_callback_array_priority_add(callbacks, -100, (void *) 1)); + eo_do(obj, eo_event_callback_array_add(callbacks, (void *) 3)); + eo_do(obj, eo_event_callback_array_priority_add(callbacks, -50, (void *) 2)); + fail_if(!eo_do(obj, simple_a_set(1))); + ck_assert_int_eq(_eo_signals_cb_flag, 0x3); + + eo_do(obj, eo_event_callback_array_del(callbacks, (void *) 1)); + eo_do(obj, eo_event_callback_array_del(callbacks, (void *) 2)); + eo_do(obj, eo_event_callback_array_del(callbacks, (void *) 3)); + _eo_signals_cb_flag = 0; + fail_if(!eo_do(obj, simple_a_set(1))); + ck_assert_int_eq(_eo_signals_cb_flag, 0x0); + + eo_unref(obj); + + eo_shutdown(); +} +END_TEST + START_TEST(eo_data_fetch) { eo_init(); @@ -755,4 +825,5 @@ void eo_test_general(TCase *tc) tcase_add_test(tc, eo_isa_tests); tcase_add_test(tc, eo_multiple_do); tcase_add_test(tc, eo_add_do_and_custom); + tcase_add_test(tc, eo_signals); } -- 2.7.4