Eobj: Added an MRO to classes. Walking the classes tree is not enough.

SVN revision: 70002
This commit is contained in:
Tom Hacohen 2012-04-11 07:05:14 +00:00
parent fc75687bc7
commit 9c4b436c69
1 changed files with 96 additions and 32 deletions

View File

@ -55,7 +55,7 @@ struct _Eobj {
Eina_Inlist *generic_data;
const Eobj_Class *kls_itr;
const Eobj_Class **kls_itr;
Eina_Bool delete:1;
EINA_MAGIC
@ -118,6 +118,9 @@ struct _Eobj_Class
const Eobj_Class_Description *desc;
Dich_Chain1 chain[DICH_CHAIN1_SIZE];
Eina_Inlist *extensions;
const Eobj_Class **mro;
Eina_Bool constructed : 1;
};
@ -372,6 +375,79 @@ _eobj_class_base_op_init(Eobj_Class *klass)
*(desc->ops.base_op_id) = klass->class_id << OP_CLASS_OFFSET;
}
static Eina_List *
_eobj_class_mro_add(Eina_List *mro, const Eobj_Class *klass)
{
if (!klass)
return mro;
mro = eina_list_append(mro, klass);
{
Eobj_Extension_Node *extn;
EINA_INLIST_FOREACH(klass->extensions, extn)
{
mro = _eobj_class_mro_add(mro, extn->klass);
}
}
mro = _eobj_class_mro_add(mro, klass->parent);
return mro;
}
static void
_eobj_class_mro_init(Eobj_Class *klass)
{
Eina_List *mro = NULL;
DBG("Started creating MRO for class '%s'", klass->desc->name);
mro = _eobj_class_mro_add(mro, klass);
{
Eina_List *itr1, *itr2, *itr2n;
itr1 = eina_list_last(mro);
while (itr1)
{
itr2 = eina_list_prev(itr1);
while (itr2)
{
itr2n = eina_list_prev(itr2);
if (eina_list_data_get(itr1) == eina_list_data_get(itr2))
{
mro = eina_list_remove_list(mro, itr2);
}
itr2 = itr2n;
}
itr1 = eina_list_prev(itr1);
}
}
/* Copy the mro and free the list. */
{
const Eobj_Class *kls_itr;
const Eobj_Class **mro_itr;
klass->mro = calloc(sizeof(*klass->mro), eina_list_count(mro) + 1);
mro_itr = klass->mro;
EINA_LIST_FREE(mro, kls_itr)
{
*(mro_itr++) = kls_itr;
DBG("Added '%s' to MRO", kls_itr->desc->name);
}
*(mro_itr) = NULL;
}
DBG("Finished creating MRO for class '%s'", klass->desc->name);
}
static void
_eobj_class_constructor(Eobj_Class *klass)
{
@ -380,10 +456,10 @@ _eobj_class_constructor(Eobj_Class *klass)
klass->constructed = EINA_TRUE;
if (!klass->desc->class_constructor)
return;
if (klass->desc->class_constructor)
klass->desc->class_constructor(klass);
klass->desc->class_constructor(klass);
_eobj_class_mro_init(klass);
}
EAPI void
@ -513,9 +589,12 @@ eobj_class_free(Eobj_Class *klass)
}
}
free(klass->mro);
free(klass);
}
/* FIXME: Do I still need count parents? */
static int
_eobj_class_count_parents(const Eobj_Class *klass)
{
@ -527,6 +606,12 @@ _eobj_class_count_parents(const Eobj_Class *klass)
return count;
}
static void
_eobj_kls_itr_init(Eobj *obj)
{
obj->kls_itr = obj->klass->mro;
}
EAPI Eobj *
eobj_add(const Eobj_Class *klass, Eobj *parent)
{
@ -576,8 +661,9 @@ eobj_add(const Eobj_Class *klass, Eobj *parent)
}
}
_eobj_kls_itr_init(obj);
eobj_class_constructor(obj, klass);
if (obj->kls_itr && obj->kls_itr->parent)
if (*obj->kls_itr && *(obj->kls_itr + 1))
{
ERR("Type '%s' - Not all of the object constructors have been executed.", klass->desc->name);
goto fail;
@ -609,6 +695,7 @@ eobj_unref(Eobj *obj)
if (--(obj->refcount) == 0)
{
const Eobj_Class *klass = eobj_class_get(obj);
_eobj_kls_itr_init(obj);
eobj_class_destructor(obj, klass);
/*FIXME: add eobj_class_unref(klass) ? - just to clear the caches. */
@ -673,20 +760,9 @@ _eobj_destructor_default(Eobj *obj)
static void
eobj_class_constructor(Eobj *obj, const Eobj_Class *klass)
{
const Eobj_Extension_Node *extn;
obj->kls_itr = klass;
if (!klass)
return;
EINA_INLIST_FOREACH(klass->extensions, extn)
{
/* Only call if it's the first one in the class. */
if (!extn->exists && extn->klass->desc->constructor)
extn->klass->desc->constructor(obj);
}
if (klass->desc->constructor)
klass->desc->constructor(obj);
else
@ -696,10 +772,6 @@ eobj_class_constructor(Eobj *obj, const Eobj_Class *klass)
static void
eobj_class_destructor(Eobj *obj, const Eobj_Class *klass)
{
const Eobj_Extension_Node *extn;
obj->kls_itr = klass;
if (!klass)
return;
@ -707,28 +779,20 @@ eobj_class_destructor(Eobj *obj, const Eobj_Class *klass)
klass->desc->destructor(obj);
else
_eobj_destructor_default(obj);
EINA_INLIST_REVERSE_FOREACH(klass->extensions, extn)
{
/* Only call if it's the first one in the class. */
if (!extn->exists && extn->klass->desc->destructor)
extn->klass->desc->destructor(obj);
}
}
EAPI void
eobj_constructor_super(Eobj *obj)
{
if (obj->kls_itr->parent)
eobj_class_constructor(obj, obj->kls_itr->parent);
if (*obj->kls_itr)
eobj_class_constructor(obj, *++(obj->kls_itr));
}
EAPI void
eobj_destructor_super(Eobj *obj)
{
if (obj->kls_itr->parent)
eobj_class_destructor(obj, obj->kls_itr->parent);
if (*obj->kls_itr)
eobj_class_destructor(obj, *++(obj->kls_itr));
}
EAPI void *