Eobj: Fixed a bug in event_callback_del.
[profile/ivi/eobj.git] / lib / eobj.c
index a07b943..26552a8 100644 (file)
@@ -46,7 +46,6 @@ struct _Eobj {
      Eobj *parent;
      const Eobj_Class *klass;
      void *data_blob;
-     void **datas;
      int refcount;
      Eina_List *composite_objects;
 
@@ -55,7 +54,7 @@ struct _Eobj {
 
      Eina_Inlist *generic_data;
 
-     Eina_List *kls_itr;
+     Eina_Inlist *kls_itr;
 
      Eina_Bool delete:1;
      EINA_MAGIC
@@ -120,6 +119,8 @@ struct _Eobj_Class
 
    const Eobj_Class **mro;
 
+   size_t data_offset; /* < Offset of the data within object data. */
+
    Eina_Bool constructed : 1;
 };
 
@@ -207,26 +208,70 @@ dich_func_clean_all(Eobj_Class *klass)
 
 /* END OF DICH */
 
-static inline void
-_eobj_kls_itr_init(Eobj *obj)
+typedef struct
+{
+   EINA_INLIST;
+   Eobj_Op op;
+   const Eobj_Class **kls_itr;
+} Eobj_Kls_Itr_Node;
+
+static inline Eina_Bool
+_eobj_kls_itr_init(Eobj *obj, Eobj_Op op)
 {
-   obj->kls_itr = eina_list_prepend(obj->kls_itr, obj->klass->mro);
+   if (obj->kls_itr)
+     {
+        Eobj_Kls_Itr_Node *node =
+           EINA_INLIST_CONTAINER_GET(obj->kls_itr, Eobj_Kls_Itr_Node);
+        if (node->op == op)
+          {
+             return EINA_FALSE;
+          }
+     }
+
+
+     {
+        Eobj_Kls_Itr_Node *node = calloc(1, sizeof(*node));
+        node->op = op;
+        node->kls_itr = obj->klass->mro;
+        obj->kls_itr = eina_inlist_prepend(obj->kls_itr,
+              EINA_INLIST_GET(node));
+
+        return EINA_TRUE;
+     }
 }
 
 static inline void
-_eobj_kls_itr_end(Eobj *obj)
+_eobj_kls_itr_end(Eobj *obj, Eobj_Op op)
 {
-   obj->kls_itr = eina_list_remove_list(obj->kls_itr, obj->kls_itr);
+   Eobj_Kls_Itr_Node *node =
+      EINA_INLIST_CONTAINER_GET(obj->kls_itr, Eobj_Kls_Itr_Node);
+
+   if (node->op != op)
+      return;
+
+   obj->kls_itr = eina_inlist_remove(obj->kls_itr, obj->kls_itr);
+   free(node);
+}
+
+static inline const Eobj_Class *
+_eobj_kls_itr_get(Eobj *obj)
+{
+   Eobj_Kls_Itr_Node *node =
+      EINA_INLIST_CONTAINER_GET(obj->kls_itr, Eobj_Kls_Itr_Node);
+
+   return (node) ? *(node->kls_itr) : NULL;
 }
 
 static inline const Eobj_Class *
 _eobj_kls_itr_next(Eobj *obj)
 {
-   const Eobj_Class **kls_itr = eina_list_data_get(obj->kls_itr);
+   Eobj_Kls_Itr_Node *node =
+      EINA_INLIST_CONTAINER_GET(obj->kls_itr, Eobj_Kls_Itr_Node);
+   const Eobj_Class **kls_itr = node->kls_itr;
    if (*kls_itr)
      {
         kls_itr++;
-        eina_list_data_set(obj->kls_itr, kls_itr);
+        node->kls_itr = kls_itr;
         return *kls_itr;
      }
    else
@@ -238,7 +283,9 @@ _eobj_kls_itr_next(Eobj *obj)
 static inline Eina_Bool
 _eobj_kls_itr_reached_end(const Eobj *obj)
 {
-   const Eobj_Class **kls_itr = eina_list_data_get(obj->kls_itr);
+   Eobj_Kls_Itr_Node *node =
+      EINA_INLIST_CONTAINER_GET(obj->kls_itr, Eobj_Kls_Itr_Node);
+   const Eobj_Class **kls_itr = node->kls_itr;
    return !(*kls_itr && *(kls_itr + 1));
 }
 
@@ -272,70 +319,50 @@ _eobj_op_id_desc_get(Eobj_Op op)
 }
 
 static Eina_Bool
-_eobj_op_internal(Eobj *obj, const Eobj_Class *obj_klass, Eobj_Op op, va_list *p_list, Eina_Bool recursive)
+_eobj_op_internal(Eobj *obj, Eobj_Op op, va_list *p_list)
 {
-   const Eobj_Class *klass = obj_klass;
-   eobj_op_func_type func;
-
-   if (!obj_klass)
-      return EINA_FALSE;
+   const Eobj_Class *klass;
+   Eina_Bool ret = EINA_FALSE;
+   Eina_Bool _itr_init;
 
+   _itr_init = _eobj_kls_itr_init(obj, op);
+   klass = _eobj_kls_itr_get(obj);
    while (klass)
      {
-        func = dich_func_get(klass, op);
+        eobj_op_func_type func = dich_func_get(klass, op);
 
         if (func)
           {
              func(obj, op, p_list);
-             return EINA_TRUE;
-          }
-        else
-          {
-             klass = klass->parent;
+             ret = EINA_TRUE;
+             goto end;
           }
-     }
 
-   if (!recursive)
-      return EINA_FALSE;
+        klass = _eobj_kls_itr_next(obj);
+     }
 
-   if (!klass)
+   /* Try composite objects */
      {
-        klass = obj_klass;
-        /* FIXME: Should probably flatten everything. to be faster. */
-          {
-             /* Try MIXINS */
-             Eobj_Extension_Node *itr;
-             EINA_INLIST_FOREACH(klass->extensions, itr)
-               {
-                  if (_eobj_op_internal(obj, itr->klass, op, p_list, recursive))
-                    {
-                       return EINA_TRUE;
-                    }
-               }
-          }
-
-        /* Try composite objects */
+        Eina_List *itr;
+        Eobj *emb_obj;
+        EINA_LIST_FOREACH(obj->composite_objects, itr, emb_obj)
           {
-             Eina_List *itr;
-             Eobj *emb_obj;
-             EINA_LIST_FOREACH(obj->composite_objects, itr, emb_obj)
+             if (_eobj_op_internal(emb_obj, op, p_list))
                {
-                  if (_eobj_op_internal(emb_obj, eobj_class_get(emb_obj), op, p_list, recursive))
-                    {
-                       return EINA_TRUE;
-                    }
+                  ret = EINA_TRUE;
+                  goto end;
                }
           }
-
-        /* If haven't found anything, return FALSE */
-        return EINA_FALSE;
      }
 
-   return EINA_TRUE;
+end:
+
+   if (_itr_init) _eobj_kls_itr_end(obj, op);
+   return ret;
 }
 
 static inline Eina_Bool
-_eobj_ops_internal(Eobj *obj, const Eobj_Class *obj_klass, va_list *p_list)
+_eobj_ops_internal(Eobj *obj, va_list *p_list)
 {
    Eina_Bool ret = EINA_TRUE;
    Eobj_Op op = 0;
@@ -343,7 +370,7 @@ _eobj_ops_internal(Eobj *obj, const Eobj_Class *obj_klass, va_list *p_list)
    op = va_arg(*p_list, Eobj_Op);
    while (op)
      {
-        if (!_eobj_op_internal(obj, obj_klass, op, p_list, EINA_TRUE))
+        if (!_eobj_op_internal(obj, op, p_list))
           {
              const Eobj_Op_Description *desc = _eobj_op_id_desc_get(op);
              const char *_id_name = (desc) ? desc->name : NULL;
@@ -351,7 +378,7 @@ _eobj_ops_internal(Eobj *obj, const Eobj_Class *obj_klass, va_list *p_list)
              const char *_dom_name = (op_klass) ? op_klass->desc->name : NULL;
              ERR("Can't find func for op %x ('%s' of domain '%s') for class '%s'. Aborting.",
                    op, _id_name, _dom_name,
-                   obj_klass->desc->name);
+                   obj->klass->desc->name);
              ret = EINA_FALSE;
              break;
           }
@@ -367,9 +394,7 @@ eobj_do_internal(Eobj *obj, ...)
    Eina_Bool ret;
    va_list p_list;
    va_start(p_list, obj);
-   _eobj_kls_itr_init(obj);
-   ret = _eobj_ops_internal(obj, eobj_class_get(obj), &p_list);
-   _eobj_kls_itr_end(obj);
+   ret = _eobj_ops_internal(obj, &p_list);
    va_end(p_list);
    return ret;
 }
@@ -377,13 +402,15 @@ eobj_do_internal(Eobj *obj, ...)
 EAPI Eina_Bool
 eobj_super_do(Eobj *obj, Eobj_Op op, ...)
 {
-   const Eobj_Class *obj_klass = _eobj_kls_itr_next(obj);
-   if (!obj_klass) return EINA_TRUE;
-
+   const Eobj_Class *obj_klass;
    Eina_Bool ret = EINA_TRUE;
    va_list p_list;
+
    va_start(p_list, op);
-   if (!_eobj_op_internal(obj, obj_klass, op, &p_list, EINA_FALSE))
+
+   /* Advance the kls itr. */
+   obj_klass = _eobj_kls_itr_next(obj);
+   if (!_eobj_op_internal(obj, op, &p_list))
      {
         const Eobj_Op_Description *desc = _eobj_op_id_desc_get(op);
         const char *_id_name = (desc) ? desc->name : NULL;
@@ -391,10 +418,11 @@ eobj_super_do(Eobj *obj, Eobj_Op op, ...)
         const char *_dom_name = (op_klass) ? op_klass->desc->name : NULL;
         ERR("Can't find func for op %x ('%s' of domain '%s') for class '%s'. Aborting.",
               op, _id_name, _dom_name,
-              obj_klass->desc->name);
+              (obj_klass) ? obj_klass->desc->name : NULL);
         ret = EINA_FALSE;
      }
    va_end(p_list);
+
    return ret;
 }
 
@@ -404,12 +432,6 @@ eobj_class_get(Eobj *obj)
    return obj->klass;
 }
 
-EAPI const Eobj_Class *
-eobj_class_parent_get(const Eobj_Class *klass)
-{
-   return klass->parent;
-}
-
 EAPI const char *
 eobj_class_name_get(const Eobj_Class *klass)
 {
@@ -552,14 +574,6 @@ eobj_class_new(const Eobj_Class_Description *desc, const Eobj_Class *parent, ...
 
    klass = calloc(1, sizeof(Eobj_Class));
    klass->parent = parent;
-   klass->class_id = ++_eobj_classes_last_id;
-     {
-        /* FIXME: Handle errors. */
-        Eobj_Class **tmp;
-        tmp = realloc(_eobj_classes, _eobj_classes_last_id * sizeof(*_eobj_classes));
-        _eobj_classes = tmp;
-        _eobj_classes[klass->class_id - 1] = klass;
-     }
 
    /* Handle class extensions */
      {
@@ -591,6 +605,53 @@ eobj_class_new(const Eobj_Class_Description *desc, const Eobj_Class *parent, ...
      }
 
    klass->desc = desc;
+
+   /* Handle the inheritance */
+   if (klass->parent)
+     {
+        /* Verify the inheritance is allowed. */
+        switch (klass->desc->type)
+          {
+           case EOBJ_CLASS_TYPE_REGULAR:
+           case EOBJ_CLASS_TYPE_REGULAR_NO_INSTANT:
+              if ((klass->parent->desc->type != EOBJ_CLASS_TYPE_REGULAR) &&
+                    (klass->parent->desc->type != EOBJ_CLASS_TYPE_REGULAR_NO_INSTANT))
+                {
+                   /* FIXME: Actually handle it. */
+                   ERR("Regular classes ('%s') aren't allowed to inherit from non-regular classes ('%s').", klass->desc->name, klass->parent->desc->name);
+                   goto cleanup;
+                }
+              break;
+           case EOBJ_CLASS_TYPE_INTERFACE:
+           case EOBJ_CLASS_TYPE_MIXIN:
+              if ((klass->parent->desc->type != EOBJ_CLASS_TYPE_REGULAR) &&
+                    (klass->parent->desc->type != EOBJ_CLASS_TYPE_REGULAR_NO_INSTANT))
+                {
+                   /* FIXME: Actually handle it. */
+                   ERR("Non-regular classes ('%s') aren't allowed to inherit from regular classes ('%s').", klass->desc->name, klass->parent->desc->name);
+                   goto cleanup;
+                }
+              break;
+          }
+
+
+        /* Update the current offset. */
+        /* FIXME: Make sure this alignment is enough. */
+        klass->data_offset = klass->parent->data_offset +
+           klass->parent->desc->private_size +
+           (sizeof(void *) -
+                  (klass->parent->desc->private_size % sizeof(void *)));
+     }
+
+   klass->class_id = ++_eobj_classes_last_id;
+     {
+        /* FIXME: Handle errors. */
+        Eobj_Class **tmp;
+        tmp = realloc(_eobj_classes, _eobj_classes_last_id * sizeof(*_eobj_classes));
+        _eobj_classes = tmp;
+        _eobj_classes[klass->class_id - 1] = klass;
+     }
+
    _eobj_class_base_op_init(klass);
 
    /* FIXME: Shouldn't be called here - should be called from eobj_add. */
@@ -599,6 +660,10 @@ eobj_class_new(const Eobj_Class_Description *desc, const Eobj_Class *parent, ...
    va_end(p_list);
 
    return klass;
+
+cleanup:
+   eobj_class_free(klass);
+   return NULL;
 }
 #undef _CLS_NEW_CHECK
 
@@ -627,18 +692,6 @@ eobj_class_free(Eobj_Class *klass)
    free(klass);
 }
 
-/* FIXME: Do I still need count parents? */
-static int
-_eobj_class_count_parents(const Eobj_Class *klass)
-{
-   int count = 0;
-
-   for (count = 0 ; klass->parent ; klass = klass->parent)
-      count++;
-
-   return count;
-}
-
 EAPI Eobj *
 eobj_add(const Eobj_Class *klass, Eobj *parent)
 {
@@ -653,42 +706,10 @@ eobj_add(const Eobj_Class *klass, Eobj *parent)
    obj->parent = parent;
 
    obj->refcount++;
-     {
-        size_t datas_count = 0;
-        intptr_t offset = 0;
-        size_t i;
-        const Eobj_Class *kls_itr;
-        void **pvt_itr;
-        datas_count = _eobj_class_count_parents(klass) + 1;
-
-        obj->datas = calloc(datas_count, sizeof(*(obj->datas)));
-
-        /* Calculate all the offsets and set in the datas array. */
-        pvt_itr = obj->datas + datas_count - 1;
-        for (kls_itr = klass ; kls_itr->parent ; kls_itr = kls_itr->parent)
-           {
-              *pvt_itr = (void *) offset;
-
-              /* FIXME: Make sure this alignment is enough. */
-              offset += kls_itr->desc->private_size +
-                 (sizeof(void *) -
-                  (kls_itr->desc->private_size % sizeof(void *)));
-              pvt_itr--;
-           }
 
-        /* Allocate the datas blob and update the offsets. */
-        obj->data_blob = calloc(1, offset);
+   obj->data_blob = calloc(1, klass->data_offset + klass->desc->private_size);
 
-        pvt_itr = obj->datas;
-        for (i = 0 ; i < datas_count ; i++)
-          {
-             *pvt_itr = ((char *) obj->data_blob) + (intptr_t) *pvt_itr;
-
-              pvt_itr++;
-          }
-     }
-
-   _eobj_kls_itr_init(obj);
+   _eobj_kls_itr_init(obj, EOBJ_NOOP);
    eobj_class_constructor(obj, klass);
    if (eobj_generic_data_get(obj, CONSTRUCT_ERROR_KEY))
      {
@@ -701,7 +722,7 @@ eobj_add(const Eobj_Class *klass, Eobj *parent)
         ERR("Type '%s' - Not all of the object constructors have been executed.", klass->desc->name);
         goto fail;
      }
-   _eobj_kls_itr_end(obj);
+   _eobj_kls_itr_end(obj, EOBJ_NOOP);
 
    return obj;
 
@@ -723,7 +744,7 @@ eobj_unref(Eobj *obj)
    if (--(obj->refcount) == 0)
      {
         const Eobj_Class *klass = eobj_class_get(obj);
-        _eobj_kls_itr_init(obj);
+        _eobj_kls_itr_init(obj, EOBJ_NOOP);
         eobj_class_destructor(obj, klass);
         if (eobj_generic_data_get(obj, CONSTRUCT_ERROR_KEY))
           {
@@ -734,11 +755,16 @@ eobj_unref(Eobj *obj)
           {
              ERR("Type '%s' - Not all of the object destructors have been executed.", klass->desc->name);
           }
-        _eobj_kls_itr_end(obj);
+        _eobj_kls_itr_end(obj, EOBJ_NOOP);
         /*FIXME: add eobj_class_unref(klass) ? - just to clear the caches. */
 
         /* If for some reason it's not empty, clear it. */
-        eina_list_free(obj->kls_itr);
+        while (obj->kls_itr)
+          {
+             Eina_Inlist *nitr = nitr->next;
+             free(EINA_INLIST_CONTAINER_GET(obj->kls_itr, Eobj_Kls_Itr_Node));
+             obj->kls_itr = nitr;
+          }
 
         Eina_List *itr, *itr_n;
         Eobj *emb_obj;
@@ -753,7 +779,6 @@ eobj_unref(Eobj *obj)
 
         if (obj->data_blob)
            free(obj->data_blob);
-        free(obj->datas);
 
         _eobj_generic_data_del_all(obj);
 
@@ -761,6 +786,12 @@ eobj_unref(Eobj *obj)
      }
 }
 
+EAPI int
+eobj_ref_get(const Eobj *obj)
+{
+   return obj->refcount;
+}
+
 EAPI void
 eobj_del(Eobj *obj)
 {
@@ -839,7 +870,7 @@ eobj_data_get(Eobj *obj, const Eobj_Class *klass)
 {
    /* FIXME: Add a check that this is of the right klass and we don't seg.
     * Probably just return NULL. */
-   return obj->datas[_eobj_class_count_parents(klass)];
+   return ((char *) obj->data_blob) + klass->data_offset;
 }
 
 typedef struct
@@ -998,6 +1029,10 @@ eobj_composite_is(Eobj *emb_obj)
    Eobj *obj = eobj_parent_get(emb_obj);
    Eina_List *itr;
    Eobj *tmp;
+
+   if (!obj)
+      return EINA_FALSE;
+
    EINA_LIST_FOREACH(obj->composite_objects, itr, tmp)
      {
         if (tmp == emb_obj)
@@ -1115,11 +1150,13 @@ eobj_event_callback_del(Eobj *obj, const Eobj_Event_Description *desc, Eobj_Even
              cb->delete_me = EINA_TRUE;
              _eobj_callbacks_clear(obj);
              ret = data;
-             goto end;
+             goto found;
           }
      }
 
-end:
+   return NULL;
+
+found:
    eobj_event_callback_call(obj, EOBJ_SIG_CALLBACK_DEL, desc);
    return ret;
 }
@@ -1140,11 +1177,13 @@ eobj_event_callback_del_full(Eobj *obj, const Eobj_Event_Description *desc, Eobj
              cb->delete_me = EINA_TRUE;
              _eobj_callbacks_clear(obj);
              ret = data;
-             goto end;
+             goto found;
           }
      }
 
-end:
+   return NULL;
+
+found:
    eobj_event_callback_call(obj, EOBJ_SIG_CALLBACK_DEL, desc);
    return ret;
 }