eo: Add new API efl_cast

This is similar to efl_super but the specified class is the one
we want to call the function on. This is similar to dynamic_cast<>
in C++.

Note: both efl_super() and efl_cast() need documentation!

This is an experimental feature.

Fixes T5311

@feature

Maniphest Tasks: T5311

Differential Revision: https://phab.enlightenment.org/D4797
This commit is contained in:
Jean-Philippe Andre 2017-04-18 20:41:11 +09:00
parent 85636658e0
commit 19b9234f23
3 changed files with 121 additions and 7 deletions

View File

@ -927,6 +927,7 @@ EAPI void _efl_object_call_end(Efl_Object_Op_Call_Data *call);
EAPI Eo * _efl_add_end(Eo *obj, Eina_Bool is_ref, Eina_Bool is_fallback);
EAPI Eo *efl_super(const Eo *obj, const Efl_Class *cur_klass);
EAPI Eo *efl_cast(const Eo *obj, const Efl_Class *cur_klass);
/*****************************************************************************/

View File

@ -343,7 +343,8 @@ _eo_op_desc_name_get(const Efl_Op_Description *desc)
}
static inline const op_type_funcs *
_eo_kls_itr_next(const _Efl_Class *orig_kls, const _Efl_Class *cur_klass, Efl_Object_Op op)
_eo_kls_itr_next(const _Efl_Class *orig_kls, const _Efl_Class *cur_klass,
Efl_Object_Op op, Eina_Bool super)
{
const _Efl_Class **kls_itr = NULL;
@ -354,7 +355,7 @@ _eo_kls_itr_next(const _Efl_Class *orig_kls, const _Efl_Class *cur_klass, Efl_Ob
if (*kls_itr)
{
kls_itr++;
if (super) kls_itr++;
while (*kls_itr)
{
const op_type_funcs *fsrc = _vtable_func_get(&(*kls_itr)->vtable, op);
@ -374,8 +375,8 @@ _eo_kls_itr_next(const _Efl_Class *orig_kls, const _Efl_Class *cur_klass, Efl_Ob
static EFL_FUNC_TLS _Efl_Class *_super_klass = NULL;
EAPI Eo *
efl_super(const Eo *eo_id, const Efl_Class *cur_klass)
static Eo *
_efl_super_cast(const Eo *eo_id, const Efl_Class *cur_klass, Eina_Bool super)
{
EO_CLASS_POINTER_GOTO(cur_klass, super_klass, err);
@ -389,13 +390,14 @@ efl_super(const Eo *eo_id, const Efl_Class *cur_klass)
EO_OBJ_POINTER_RETURN_VAL(eo_id, obj, NULL);
obj->cur_klass = super_klass;
obj->super = EINA_TRUE;
obj->super = super;
EO_OBJ_DONE(eo_id);
return (Eo *) eo_id;
do_klass:
// efl_super(Class) is extremely rarely used, so TLS write is fine
EINA_SAFETY_ON_FALSE_RETURN_VAL(super, NULL);
_super_klass = super_klass;
return (Eo *) eo_id;
@ -412,6 +414,18 @@ err_obj_hierarchy:
#endif
}
EAPI Eo *
efl_super(const Eo *eo_id, const Efl_Class *cur_klass)
{
return _efl_super_cast(eo_id, cur_klass, EINA_TRUE);
}
EAPI Eo *
efl_cast(const Eo *eo_id, const Efl_Class *cur_klass)
{
return _efl_super_cast(eo_id, cur_klass, EINA_FALSE);
}
EAPI Eina_Bool
_efl_object_call_resolve(Eo *eo_id, const char *func_name, Efl_Object_Op_Call_Data *call, Efl_Object_Call_Cache *cache, const char *file, int line)
{
@ -422,6 +436,7 @@ _efl_object_call_resolve(Eo *eo_id, const char *func_name, Efl_Object_Op_Call_Da
const op_type_funcs *func;
Eina_Bool is_obj;
Eina_Bool is_override = EINA_FALSE;
Eina_Bool super = EINA_TRUE;
if (EINA_UNLIKELY(!eo_id)) return EINA_FALSE;
@ -439,10 +454,11 @@ _efl_object_call_resolve(Eo *eo_id, const char *func_name, Efl_Object_Op_Call_Da
if (_obj->cur_klass)
{
cur_klass = _obj->cur_klass;
super = _obj->super;
_obj->cur_klass = NULL;
}
if (_obj_is_override(obj) && cur_klass &&
if (_obj_is_override(obj) && cur_klass && super &&
(_eo_class_id_get(cur_klass) == EFL_OBJECT_OVERRIDE_CLASS))
{
/* Doing a efl_super(obj, EFL_OBJECT_OVERRIDE_CLASS) should result in calling
@ -603,7 +619,7 @@ err:
// yes - special "move out of hot path" code blobs with goto's for
// speed reasons to have intr prefetches work better and miss less
ok_cur_klass:
func = _eo_kls_itr_next(klass, cur_klass, cache->op);
func = _eo_kls_itr_next(klass, cur_klass, cache->op, super);
if (!func) goto end;
klass = func->src;
goto ok_cur_klass_back;

View File

@ -1584,6 +1584,102 @@ START_TEST(eo_domain)
}
END_TEST
static int
_inherit_value_1(Eo *obj EINA_UNUSED, void *pd EINA_UNUSED)
{
return 1;
}
static int
_inherit_value_2(Eo *obj EINA_UNUSED, void *pd EINA_UNUSED)
{
return 2;
}
EFL_FUNC_BODY(inherit_value, int, 0);
static Eina_Bool
_cast_inherit_class_initializer_1(Efl_Class *klass)
{
EFL_OPS_DEFINE(ops, EFL_OBJECT_OP_FUNC(inherit_value, _inherit_value_1), );
return efl_class_functions_set(klass, &ops, NULL);
}
static Eina_Bool
_cast_inherit_class_initializer_2(Efl_Class *klass)
{
EFL_OPS_DEFINE(ops, EFL_OBJECT_OP_FUNC(inherit_value, _inherit_value_2), );
return efl_class_functions_set(klass, &ops, NULL);
}
START_TEST(efl_cast_test)
{
efl_object_init();
static const Efl_Class_Description class_desc_1 = {
EO_VERSION,
"FirstInherit",
EFL_CLASS_TYPE_REGULAR,
0,
_cast_inherit_class_initializer_1,
NULL,
NULL
};
static const Efl_Class_Description class_desc_2 = {
EO_VERSION,
"SecondInherit",
EFL_CLASS_TYPE_REGULAR,
0,
_cast_inherit_class_initializer_2,
NULL,
NULL
};
const Efl_Class *klass1 = efl_class_new(&class_desc_1, SIMPLE_CLASS, NULL);
fail_if(!klass1);
const Efl_Class *klass2 = efl_class_new(&class_desc_2, klass1, NULL);
fail_if(!klass2);
Eo *obj;
// Testing normal calls
obj = efl_add(SIMPLE_CLASS, NULL);
fail_if(!obj);
ck_assert_int_eq(inherit_value(obj), 0);
efl_unref(obj);
obj = efl_add(klass1, NULL);
fail_if(!obj);
ck_assert_int_eq(inherit_value(obj), 1);
efl_unref(obj);
obj = efl_add(klass2, NULL);
fail_if(!obj);
ck_assert_int_eq(inherit_value(obj), 2);
efl_unref(obj);
// Testing efl_super
obj = efl_add(klass2, NULL);
fail_if(!obj);
ck_assert_int_eq(inherit_value(efl_super(obj, klass2)), 1);
ck_assert_int_eq(inherit_value(efl_super(obj, klass1)), 0);
efl_unref(obj);
// Testing efl_cast
obj = efl_add(klass2, NULL);
fail_if(!obj);
ck_assert_int_eq(inherit_value(efl_cast(obj, klass2)), 2);
ck_assert_int_eq(inherit_value(efl_cast(obj, klass1)), 1);
ck_assert_int_eq(inherit_value(efl_cast(obj, SIMPLE_CLASS)), 0);
efl_unref(obj);
efl_object_shutdown();
}
END_TEST
void eo_test_general(TCase *tc)
{
tcase_add_test(tc, eo_simple);
@ -1607,4 +1703,5 @@ void eo_test_general(TCase *tc)
tcase_add_test(tc, eo_comment);
tcase_add_test(tc, eo_rec_interface);
tcase_add_test(tc, eo_domain);
tcase_add_test(tc, efl_cast_test);
}