eo: Change eo_override to avoid struct passing and GCC construct

This is a (minor) API & ABI break in Eo.h!

I say minor as eo_override shouldn't be used yet (EO is unstable
and this patch includes all the use cases in EFL).

I'm not very happy about the new form of the macro, but it avoids
two things:
- passing in a struct (valid in C, but never used in EFL)
- using a GCC construct to create structs on the fly

It was inspired by the event array define, but I don't think
we need the runtime memcpy here.

See also:
https://gcc.gnu.org/onlinedocs/gcc/Compound-Literals.html
This commit is contained in:
Jean-Philippe Andre 2016-07-19 17:21:36 +09:00
parent a9d4d7e836
commit 3029227fa1
4 changed files with 40 additions and 29 deletions

View File

@ -174,20 +174,17 @@ _custom_layout_update(Eo *pack, const void *data EINA_UNUSED)
eina_iterator_free(it);
}
/* Common Eo Class boilerplate. */
static const Eo_Op_Description custom_engine_op_desc[] = {
EO_OP_FUNC_OVERRIDE(efl_pack_layout_update, _custom_layout_update),
};
static void
custom_check_cb(void *data, const Eo_Event *event)
{
EO_OVERRIDE_OPS_DEFINE(custom_layout_ops,
EO_OP_FUNC_OVERRIDE(efl_pack_layout_update, _custom_layout_update));
Eina_Bool chk = elm_check_selected_get(event->object);
Eo *obj = data;
// Overriding just the one function we need
eo_override(obj, chk ? EO_OVERRIDE_OPS(custom_engine_op_desc)
: ((Eo_Ops) { NULL, 0 }));
eo_override(obj, chk ? &custom_layout_ops : NULL);
// Layout request is required as the pack object doesn't know the layout
// function was just overridden.

View File

@ -449,10 +449,29 @@ EAPI const Eo_Class *eo_class_new(const Eo_Class_Description *desc, const Eo_Cla
*
* You are only allowed to override functions that are defined in the
* class or any of its interfaces (that is, eo_isa returning true).
*
* If @p ops is #NULL, this will revert the @p obj to its original class
* without any function overrides.
*/
EAPI Eina_Bool eo_override(Eo *obj, Eo_Ops ops);
EAPI Eina_Bool eo_override(Eo *obj, const Eo_Ops *ops);
#define EO_OVERRIDE_OPS(op_descs) ((Eo_Ops) { op_descs, EINA_C_ARRAY_LENGTH(op_descs) })
/**
* @brief Define an array of override functions for @ref eo_override
* @param ops A name for the Eo_Ops local variable to define
* @param ... A comma separated list of Eo_Op overrides, using
* #EO_OP_FUNC_OVERRIDE or #EO_OP_CLASS_FUNC_OVERRIDE
*
* This can be used as follows:
* @code
* EO_OVERRIDE_OPS_DEFINE(ops, EO_OP_FUNC_OVERRIDE(public_func, _my_func));
* eo_override(obj, &ops);
* @endcode
*
* @see eo_override
*/
#define EO_OVERRIDE_OPS_DEFINE(ops, ...) \
const Eo_Op_Description _##ops##_descs[] = { __VA_ARGS__ }; \
const Eo_Ops ops = { _##ops##_descs, EINA_C_ARRAY_LENGTH(_##ops##_descs) }
/**
* @brief Check if an object "is a" klass.

View File

@ -1338,13 +1338,13 @@ eo_class_new(const Eo_Class_Description *desc, const Eo_Class *parent_id, ...)
}
EAPI Eina_Bool
eo_override(Eo *eo_id, Eo_Ops ops)
eo_override(Eo *eo_id, const Eo_Ops *ops)
{
EO_OBJ_POINTER_RETURN_VAL(eo_id, obj, EINA_FALSE);
EO_CLASS_POINTER_RETURN_VAL(EO_OVERRIDE_CLASS, klass, EINA_FALSE);
Eo_Vtable *previous = obj->vtable;
if (!ops.descs)
if (!ops)
{
if (obj->vtable != &obj->klass->vtable)
{
@ -1361,7 +1361,7 @@ eo_override(Eo *eo_id, Eo_Ops ops)
_vtable_copy_all(obj->vtable, previous);
}
if (!_eo_class_funcs_set(obj->vtable, &ops, obj->klass, klass, EINA_TRUE))
if (!_eo_class_funcs_set(obj->vtable, ops, obj->klass, klass, EINA_TRUE))
{
ERR("Failed to override functions for %p", eo_id);
return EINA_FALSE;

View File

@ -66,10 +66,6 @@ START_TEST(eo_override_tests)
{
eo_init();
Eo_Op_Description override_descs[] = {
EO_OP_FUNC_OVERRIDE(simple_a_get, _simple_obj_override_a_get),
};
Eo *obj = eo_add(SIMPLE_CLASS, NULL);
fail_if(!obj);
@ -77,7 +73,10 @@ START_TEST(eo_override_tests)
* make sure we don't cache. */
ck_assert_int_eq(simple_a_get(obj), 0);
fail_if(!eo_override(obj, EO_OVERRIDE_OPS(override_descs)));
EO_OVERRIDE_OPS_DEFINE(
overrides,
EO_OP_FUNC_OVERRIDE(simple_a_get, _simple_obj_override_a_get));
fail_if(!eo_override(obj, &overrides));
ck_assert_int_eq(simple_a_get(obj), OVERRIDE_A);
@ -85,24 +84,20 @@ START_TEST(eo_override_tests)
simple_a_set(obj, OVERRIDE_A_SIMPLE);
ck_assert_int_eq(simple_a_get(obj), OVERRIDE_A + OVERRIDE_A_SIMPLE);
/* Override again. */
Eo_Op_Description override_descs2[] = {
EO_OP_FUNC_OVERRIDE(simple_a_set, _simple_obj_override_a_double_set),
};
fail_if(!eo_override(obj, EO_OVERRIDE_OPS(override_descs2)));
EO_OVERRIDE_OPS_DEFINE(
overrides2,
EO_OP_FUNC_OVERRIDE(simple_a_set, _simple_obj_override_a_double_set));
fail_if(!eo_override(obj, &overrides2));
simple_a_set(obj, OVERRIDE_A_SIMPLE);
ck_assert_int_eq(simple_a_get(obj), OVERRIDE_A + (OVERRIDE_A_SIMPLE * 2));
/* Try introducing a new function */
Eo_Op_Description override_descs3[] = {
EO_OP_FUNC(simple2_class_beef_get, _simple_obj_override_a_double_set),
};
fail_if(eo_override(obj, EO_OVERRIDE_OPS(override_descs3)));
EO_OVERRIDE_OPS_DEFINE(
overrides3,
EO_OP_FUNC(simple2_class_beef_get, _simple_obj_override_a_double_set));
fail_if(eo_override(obj, &overrides3));
eo_unref(obj);