forked from enlightenment/efl
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:
parent
85636658e0
commit
19b9234f23
|
@ -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);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue