Eo: Added eo_event_callback_array_* functions.
authorTom Hacohen <tom@stosb.com>
Fri, 12 Apr 2013 10:06:30 +0000 (11:06 +0100)
committerTom Hacohen <tom@stosb.com>
Fri, 12 Apr 2013 11:02:49 +0000 (12:02 +0100)
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
src/lib/eo/eo_base_class.c
src/tests/eo/signals/signals_simple.c
src/tests/eo/suite/eo_test_class_simple.c
src/tests/eo/suite/eo_test_class_simple.h
src/tests/eo/suite/eo_test_general.c

index 4b44505..a8cac52 100644 (file)
@@ -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.
index 01def69..6399ca8 100644 (file)
@@ -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."),
index 77d1574..37a38a9 100644 (file)
@@ -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--;
index 224f5b5..e21c54f 100644 (file)
@@ -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
index 9980b7b..699ddb8 100644 (file)
@@ -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);
index d6a4eec..01ae11c 100644 (file)
@@ -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);
 }