Eobj *parent;
const Eobj_Class *klass;
void *data_blob;
- void **datas;
int refcount;
Eina_List *composite_objects;
Eina_Inlist *generic_data;
- const Eobj_Class **kls_itr;
+ Eina_Inlist *kls_itr;
Eina_Bool delete:1;
EINA_MAGIC
{
EINA_INLIST;
const Eobj_Class *klass;
- Eina_Bool exists : 1; /* < True if already exists in class (incl parents). */
} Eobj_Extension_Node;
struct _Eobj_Class
const Eobj_Class **mro;
+ size_t data_offset; /* < Offset of the data within object data. */
+
Eina_Bool constructed : 1;
};
/* END OF DICH */
-static 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)
+{
+ 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_Op op)
+{
+ 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)
+{
+ 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++;
+ node->kls_itr = kls_itr;
+ return *kls_itr;
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+static inline Eina_Bool
+_eobj_kls_itr_reached_end(const Eobj *obj)
{
- obj->kls_itr = obj->klass->mro;
+ 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));
}
/* FIXME: Decide if it should be fast, and if so, add a mapping.
}
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;
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;
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;
}
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);
+ ret = _eobj_ops_internal(obj, &p_list);
va_end(p_list);
return ret;
}
EAPI Eina_Bool
eobj_super_do(Eobj *obj, Eobj_Op op, ...)
{
- const Eobj_Class *obj_klass = *++(obj->kls_itr);
+ 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;
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;
}
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)
{
}
}
-static Eina_Bool
-_eobj_class_extn_exists(const Eobj_Class *klass, const Eobj_Class *extn_cls)
-{
- while (klass)
- {
- Eobj_Extension_Node *extn;
- EINA_INLIST_FOREACH(klass->extensions, extn)
- {
- if (extn->klass == extn_cls)
- return EINA_TRUE;
- }
-
- klass = klass->parent;
- }
-
- return EINA_FALSE;
-}
-
EAPI Eobj_Class *
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 */
{
{
Eobj_Extension_Node *node = calloc(1, sizeof(*node));
node->klass = extn;
- node->exists = _eobj_class_extn_exists(klass, extn);
klass->extensions =
eina_inlist_append(klass->extensions,
EINA_INLIST_GET(node));
}
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. */
va_end(p_list);
return klass;
+
+cleanup:
+ eobj_class_free(klass);
+ return NULL;
}
#undef _CLS_NEW_CHECK
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)
{
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);
-
- pvt_itr = obj->datas;
- for (i = 0 ; i < datas_count ; i++)
- {
- *pvt_itr = ((char *) obj->data_blob) + (intptr_t) *pvt_itr;
- pvt_itr++;
- }
- }
+ obj->data_blob = calloc(1, klass->data_offset + klass->desc->private_size);
- _eobj_kls_itr_init(obj);
+ _eobj_kls_itr_init(obj, EOBJ_NOOP);
eobj_class_constructor(obj, klass);
- if (*obj->kls_itr && *(obj->kls_itr + 1))
+ if (eobj_generic_data_get(obj, CONSTRUCT_ERROR_KEY))
{
- ERR("Type '%s' - Not all of the object constructors have been executed.", klass->desc->name);
+ ERR("Type '%s' - One of the object constructors have failed.", klass->desc->name);
goto fail;
}
- if (eobj_generic_data_get(obj, CONSTRUCT_ERROR_KEY))
+ if (!_eobj_kls_itr_reached_end(obj))
{
- ERR("Type '%s' - One of the object constructors have failed.", klass->desc->name);
+ ERR("Type '%s' - Not all of the object constructors have been executed.", klass->desc->name);
goto fail;
}
+ _eobj_kls_itr_end(obj, EOBJ_NOOP);
return 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))
+ {
+ ERR("Type '%s' - One of the object destructors have failed.", klass->desc->name);
+ }
+
+ if (!_eobj_kls_itr_reached_end(obj))
+ {
+ ERR("Type '%s' - Not all of the object destructors have been executed.", klass->desc->name);
+ }
+ _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. */
+ 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;
EINA_LIST_FOREACH_SAFE(obj->composite_objects, itr, itr_n, emb_obj)
if (obj->data_blob)
free(obj->data_blob);
- free(obj->datas);
_eobj_generic_data_del_all(obj);
}
}
+EAPI int
+eobj_ref_get(const Eobj *obj)
+{
+ return obj->refcount;
+}
+
EAPI void
eobj_del(Eobj *obj)
{
EAPI void
eobj_constructor_super(Eobj *obj)
{
- if (*obj->kls_itr)
- eobj_class_constructor(obj, *++(obj->kls_itr));
+ eobj_class_constructor(obj, _eobj_kls_itr_next(obj));
}
EAPI void
eobj_destructor_super(Eobj *obj)
{
- if (*obj->kls_itr)
- eobj_class_destructor(obj, *++(obj->kls_itr));
+ eobj_class_destructor(obj, _eobj_kls_itr_next(obj));
}
EAPI void *
{
/* 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
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)
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;
}
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;
}