eo: add eo_childrens_iterator_new().

The goal would be to replace the smart children list and friends. The
problem is that they differ in content. Smart children and Eo children are
the same, but Elm children and them differ. If I put this function as a
virtual, it would be possible to override the list of children and if we
start using it in Evas render loop, that could result in "weird" behavior.

I have added the use of a simplified Eina_Trash mempool kind of feature
to have some fast path for allocation if we start using it in Evas render
loop.
This commit is contained in:
Cedric Bail 2013-09-11 16:08:06 +09:00
parent 766d1d1788
commit cd77853222
3 changed files with 130 additions and 18 deletions

View File

@ -796,6 +796,15 @@ EAPI Eo *eo_add_internal(const char *file, int line, const Eo_Class *klass, Eo *
*/
EAPI Eo *eo_parent_get(const Eo *obj);
/**
* @brief Get an iterator on all childrens
* @param obj the object to get the childrens from.
* @return a pointer to an Eina_Iterator containing all the childrens.
*
* @see eo_parent_set()
*/
EAPI Eina_Iterator *eo_childrens_iterator_new(Eo *obj_id);
/**
* @brief Set the parent of an object
* @param obj the object to get the parent of.

View File

@ -687,7 +687,7 @@ eo_class_funcs_set(Eo_Class *klass_id, const Eo_Op_Func_Description *func_descs)
static void
eo_class_free(_Eo_Class *klass)
{
void *object;
void *data;
if (klass->constructed)
{
@ -697,10 +697,14 @@ eo_class_free(_Eo_Class *klass)
_dich_func_clean_all(klass);
}
EINA_TRASH_CLEAN(&klass->trash, object)
free(object);
EINA_TRASH_CLEAN(&klass->objects.trash, data)
free(data);
eina_lock_free(&klass->trash_lock);
EINA_TRASH_CLEAN(&klass->iterators.trash, data)
free(data);
eina_lock_free(&klass->objects.trash_lock);
eina_lock_free(&klass->iterators.trash_lock);
free(klass);
}
@ -893,7 +897,8 @@ eo_class_new(const Eo_Class_Description *desc, const Eo_Class *parent_id, ...)
klass = calloc(1, _eo_class_sz + extn_sz + mro_sz + mixins_sz);
EINA_MAGIC_SET(klass, EO_CLASS_EINA_MAGIC);
eina_lock_new(&klass->trash_lock);
eina_lock_new(&klass->objects.trash_lock);
eina_lock_new(&klass->iterators.trash_lock);
klass->parent = parent;
klass->desc = desc;
klass->extensions = (const _Eo_Class **) ((char *) klass + _eo_class_sz);
@ -1077,6 +1082,96 @@ eo_parent_set(Eo *obj_id, const Eo *parent_id)
return EINA_TRUE;
}
/* Children accessor */
typedef struct _Eo_Children_Iterator Eo_Children_Iterator;
struct _Eo_Children_Iterator
{
Eina_Iterator iterator;
Eina_List *current;
_Eo *obj;
Eo *obj_id;
};
static Eina_Bool
_eo_children_iterator_next(Eo_Children_Iterator *it, void **data)
{
if (!it->current) return EINA_FALSE;
if (data) *data = eina_list_data_get(it->current);
it->current = eina_list_next(it->current);
return EINA_TRUE;
}
static Eo *
_eo_children_iterator_container(Eo_Children_Iterator *it)
{
return it->obj_id;
}
static void
_eo_children_iterator_free(Eo_Children_Iterator *it)
{
_Eo_Class *klass;
_Eo *obj;
klass = (_Eo_Class*) it->obj->klass;
obj = it->obj;
eina_lock_take(&klass->iterators.trash_lock);
if (klass->iterators.trash_count < 8)
{
klass->iterators.trash_count++;
eina_trash_push(&klass->iterators.trash, it);
}
else
{
free(it);
}
eina_lock_release(&klass->iterators.trash_lock);
_eo_unref(obj);
}
EAPI Eina_Iterator *
eo_childrens_iterator_new(Eo *obj_id)
{
Eo_Children_Iterator *it;
_Eo_Class *klass;
EO_OBJ_POINTER_RETURN_VAL(obj_id, obj, NULL);
if (!obj->children) return NULL;
klass = (_Eo_Class*) obj->klass;
eina_lock_take(&klass->iterators.trash_lock);
it = eina_trash_pop(&klass->iterators.trash);
if (it)
{
klass->iterators.trash_count--;
memset(it, 0, sizeof (Eo_Children_Iterator));
}
else
{
it = calloc(1, sizeof (Eo_Children_Iterator));
}
eina_lock_release(&klass->iterators.trash_lock);
if (!it) return NULL;
EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
it->current = obj->children;
it->obj = _eo_ref(obj);
it->obj_id = obj_id;
it->iterator.next = FUNC_ITERATOR_NEXT(_eo_children_iterator_next);
it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(_eo_children_iterator_container);
it->iterator.free = FUNC_ITERATOR_FREE(_eo_children_iterator_free);
return &it->iterator;
}
EAPI Eo *
eo_add_internal(const char *file, int line, const Eo_Class *klass_id, Eo *parent_id, ...)
{
@ -1096,18 +1191,18 @@ eo_add_internal(const char *file, int line, const Eo_Class *klass_id, Eo *parent
return NULL;
}
eina_lock_take(&klass->trash_lock);
obj = eina_trash_pop(&klass->trash);
eina_lock_take(&klass->objects.trash_lock);
obj = eina_trash_pop(&klass->objects.trash);
if (obj)
{
memset(obj, 0, klass->obj_size);
klass->trash_count--;
klass->objects.trash_count--;
}
else
{
obj = calloc(1, klass->obj_size);
}
eina_lock_release(&klass->trash_lock);
eina_lock_release(&klass->objects.trash_lock);
obj->refcount++;
obj->klass = klass;

View File

@ -140,9 +140,18 @@ struct _Eo_Class
const _Eo_Class **mro;
/* cached object for faster allocation */
Eina_Trash *trash;
Eina_Lock trash_lock;
unsigned int trash_count;
struct {
Eina_Trash *trash;
Eina_Lock trash_lock;
unsigned int trash_count;
} objects;
/* cached iterator for faster allocation cycle */
struct {
Eina_Trash *trash;
Eina_Lock trash_lock;
unsigned int trash_count;
} iterators;
unsigned int obj_size; /**< size of an object of this class */
unsigned int chain_size;
@ -219,18 +228,17 @@ _eo_free(_Eo *obj)
#endif
_eo_id_release(obj->obj_id);
eina_lock_take(&klass->trash_lock);
if (klass->trash_count <= 8)
eina_lock_take(&klass->objects.trash_lock);
if (klass->objects.trash_count <= 8)
{
eina_trash_push(&klass->trash, obj);
klass->trash_count++;
eina_lock_release(&klass->trash_lock);
eina_trash_push(&klass->objects.trash, obj);
klass->objects.trash_count++;
}
else
{
eina_lock_release(&klass->trash_lock);
free(obj);
}
eina_lock_release(&klass->objects.trash_lock);
}
static inline _Eo *