aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJean-Philippe Andre <jp.andre@samsung.com>2017-07-13 17:39:01 +0900
committerJean-Philippe Andre <jp.andre@samsung.com>2017-08-04 10:24:03 +0900
commit0834511067a99faafc2c59f0aabcd58dab1cbc0b (patch)
tree632433d1a9f6aa4c0131100c3a952d19a53329e0
parentelm_test: Remove calls to visible_set for EO objects (diff)
downloadefl-0834511067a99faafc2c59f0aabcd58dab1cbc0b.tar.gz
Eo: Allow multiple functions overrides
This allows two things: - adding new override functions on an object that already has overrides - resetting a specific function (or list of functions) to the parent class implementation by passing NULL as implementation Fixes https://phab.enlightenment.org/T5580 @feature
-rw-r--r--src/lib/eo/Eo.h2
-rw-r--r--src/lib/eo/eo.c120
-rw-r--r--src/tests/eo/suite/eo_test_general.c25
3 files changed, 98 insertions, 49 deletions
diff --git a/src/lib/eo/Eo.h b/src/lib/eo/Eo.h
index 5f97d1b46d..44610e410c 100644
--- a/src/lib/eo/Eo.h
+++ b/src/lib/eo/Eo.h
@@ -648,6 +648,8 @@ EAPI Eina_Bool efl_class_functions_set(const Efl_Class *klass_id, const Efl_Obje
* It is not possible to override a function table of an object when it's
* already been overridden. Call efl_object_override(obj, NULL) first if you really
* need to do that.
+ *
+ * @see EFL_OPS_DEFINE
*/
EAPI Eina_Bool efl_object_override(Eo *obj, const Efl_Object_Ops *ops);
diff --git a/src/lib/eo/eo.c b/src/lib/eo/eo.c
index 5af21f5f74..50ddddd8de 100644
--- a/src/lib/eo/eo.c
+++ b/src/lib/eo/eo.c
@@ -231,7 +231,9 @@ _eo_op_class_get(Efl_Object_Op op)
}
static inline Eina_Bool
-_vtable_func_set(Eo_Vtable *vtable, const _Efl_Class *klass, Efl_Object_Op op, Eo_Op_Func_Type func, Eina_Bool allow_same_override)
+_vtable_func_set(Eo_Vtable *vtable, const _Efl_Class *klass,
+ const _Efl_Class *hierarchy_klass, Efl_Object_Op op,
+ Eo_Op_Func_Type func, Eina_Bool allow_same_override)
{
op_type_funcs *fsrc;
size_t idx1 = DICH_CHAIN1(op);
@@ -241,12 +243,28 @@ _vtable_func_set(Eo_Vtable *vtable, const _Efl_Class *klass, Efl_Object_Op op, E
chain1 = &vtable->chain[idx1];
_vtable_chain_write_prepare(chain1);
fsrc = &chain1->chain2->funcs[DICH_CHAIN_LAST(op)];
- if (!allow_same_override && (fsrc->src == klass))
+ if (hierarchy_klass)
{
- const _Efl_Class *op_kls = _eo_op_class_get(op);
- ERR("Class '%s': Overriding already set func %p for op %d (%s) with %p.",
- klass->desc->name, fsrc->func, op, op_kls->desc->name, func);
- return EINA_FALSE;
+ if (!func)
+ {
+ op_type_funcs *fsrc_orig;
+ Dich_Chain1 *chain1_orig;
+
+ chain1_orig = &hierarchy_klass->vtable.chain[idx1];
+ fsrc_orig = &chain1_orig->chain2->funcs[DICH_CHAIN_LAST(op)];
+ func = fsrc_orig->func;
+ klass = fsrc_orig->src;
+ }
+ }
+ else
+ {
+ if (!allow_same_override && (fsrc->src == klass))
+ {
+ const _Efl_Class *op_kls = _eo_op_class_get(op);
+ ERR("Class '%s': Overriding already set func %p for op %d (%s) with %p.",
+ klass->desc->name, fsrc->func, op, op_kls->desc->name, func);
+ return EINA_FALSE;
+ }
}
fsrc->func = func;
@@ -712,24 +730,32 @@ _efl_object_op_api_id_get(const void *api_func, const Eo *obj, const char *api_f
static Eina_Bool
_eo_class_funcs_set(Eo_Vtable *vtable, const Efl_Object_Ops *ops, const _Efl_Class *hierarchy_klass, const _Efl_Class *klass, Efl_Object_Op id_offset, Eina_Bool override_only)
{
- unsigned int i;
+ unsigned int i, j;
Efl_Object_Op op_id;
- const void *last_api_func;
const Efl_Op_Description *op_desc;
const Efl_Op_Description *op_descs;
+ const _Efl_Class *override_class;
+ const void **api_funcs;
+ Eina_Bool check_equal;
op_id = hierarchy_klass->base_id + id_offset;
op_descs = ops->descs;
+ override_class = override_only ? hierarchy_klass : NULL;
DBG("Set functions for class '%s':%p", klass->desc->name, klass);
- if (!op_descs) return EINA_TRUE;
+ if (!op_descs || !ops->count) return EINA_TRUE;
- last_api_func = NULL;
+#ifdef EO_DEBUG
+ check_equal = EINA_TRUE;
+#else
+ check_equal = !override_only;
+#endif
+ api_funcs = alloca(ops->count * sizeof(api_funcs[0]));
+
+ /* sanity checks */
for (i = 0, op_desc = op_descs; i < ops->count; i++, op_desc++)
{
- Efl_Object_Op op = EFL_NOOP;
-
if (op_desc->api_func == NULL)
{
ERR("Class '%s': NULL API not allowed (NULL->%p '%s').",
@@ -737,44 +763,53 @@ _eo_class_funcs_set(Eo_Vtable *vtable, const Efl_Object_Ops *ops, const _Efl_Cla
return EINA_FALSE;
}
- /* Get the opid for the function. */
+ if (check_equal)
{
- if (_eo_api_func_equal(op_desc->api_func, last_api_func))
+ for (j = 0; j < i; j++)
{
- ERR("Class '%s': API previously defined (%p->%p '%s').",
- klass->desc->name, op_desc->api_func, op_desc->func, _eo_op_desc_name_get(op_desc));
- return EINA_FALSE;
+ if (_eo_api_func_equal(op_desc->api_func, api_funcs[j]))
+ {
+ ERR("Class '%s': API previously defined (%p->%p '%s').",
+ klass->desc->name, op_desc->api_func, op_desc->func, _eo_op_desc_name_get(op_desc));
+ return EINA_FALSE;
+ }
}
- op = _efl_object_api_op_id_get_internal(op_desc->api_func);
+ api_funcs[i] = op_desc->api_func;
+ }
+ }
+
+ for (i = 0, op_desc = op_descs; i < ops->count; i++, op_desc++)
+ {
+ Efl_Object_Op op = EFL_NOOP;
+
+ /* Get the opid for the function. */
+ op = _efl_object_api_op_id_get_internal(op_desc->api_func);
- if (op == EFL_NOOP)
+ if (op == EFL_NOOP)
+ {
+ if (override_only)
{
- if (override_only)
- {
- ERR("Class '%s': Tried overriding a previously undefined function.", klass->desc->name);
- return EINA_FALSE;
- }
+ ERR("Class '%s': Tried overriding a previously undefined function.", klass->desc->name);
+ return EINA_FALSE;
+ }
- op = op_id;
- eina_spinlock_take(&_ops_storage_lock);
+ op = op_id;
+ eina_spinlock_take(&_ops_storage_lock);
#ifndef _WIN32
- eina_hash_add(_ops_storage, &op_desc->api_func, (void *) (uintptr_t) op);
+ eina_hash_add(_ops_storage, &op_desc->api_func, (void *) (uintptr_t) op);
#else
- eina_hash_add(_ops_storage, op_desc->api_func, (void *) (uintptr_t) op);
+ eina_hash_add(_ops_storage, op_desc->api_func, (void *) (uintptr_t) op);
#endif
- eina_spinlock_release(&_ops_storage_lock);
+ eina_spinlock_release(&_ops_storage_lock);
- op_id++;
- }
+ op_id++;
}
DBG("%p->%p '%s'", op_desc->api_func, op_desc->func, _eo_op_desc_name_get(op_desc));
- if (!_vtable_func_set(vtable, klass, op, op_desc->func, EINA_FALSE))
+ if (!_vtable_func_set(vtable, klass, override_class, op, op_desc->func, EINA_TRUE))
return EINA_FALSE;
-
- last_api_func = op_desc->api_func;
}
return EINA_TRUE;
@@ -1280,8 +1315,8 @@ _eo_class_isa_recursive_set(_Efl_Class *klass, const _Efl_Class *cur)
{
const _Efl_Class **extn_itr;
- _vtable_func_set(&klass->vtable, klass, cur->base_id + cur->ops_count,
- _eo_class_isa_func, EINA_TRUE);
+ _vtable_func_set(&klass->vtable, klass, NULL, cur->base_id + cur->ops_count,
+ _eo_class_isa_func, EINA_TRUE);
for (extn_itr = cur->extensions ; *extn_itr ; extn_itr++)
{
@@ -1594,18 +1629,15 @@ efl_object_override(Eo *eo_id, const Efl_Object_Ops *ops)
if (ops)
{
- Eo_Vtable *vtable;
+ Eo_Vtable *vtable = obj->opt->vtable;
- if (EINA_UNLIKELY(obj->opt->vtable != NULL))
+ if (!vtable)
{
- ERR("Function table already overridden, not allowed to override again. "
- "Call with NULL to reset the function table first.");
- goto err;
+ vtable = calloc(1, sizeof(*vtable));
+ _vtable_init(vtable, obj->klass->vtable.size);
+ _vtable_copy_all(vtable, &obj->klass->vtable);
}
- vtable = calloc(1, sizeof(*vtable));
- _vtable_init(vtable, obj->klass->vtable.size);
- _vtable_copy_all(vtable, &obj->klass->vtable);
if (!_eo_class_funcs_set(vtable, ops, obj->klass, klass, 0, EINA_TRUE))
{
// FIXME: Maybe leaking some chain stuff from copy above?
diff --git a/src/tests/eo/suite/eo_test_general.c b/src/tests/eo/suite/eo_test_general.c
index 0d6f322f1f..4ac8f22c54 100644
--- a/src/tests/eo/suite/eo_test_general.c
+++ b/src/tests/eo/suite/eo_test_general.c
@@ -79,6 +79,7 @@ START_TEST(efl_object_override_tests)
* make sure we don't cache. */
ck_assert_int_eq(simple_a_get(obj), 0);
+ /* Test override */
EFL_OPS_DEFINE(
overrides,
EFL_OBJECT_OP_FUNC(simple_a_get, _simple_obj_override_a_get));
@@ -86,7 +87,7 @@ START_TEST(efl_object_override_tests)
ck_assert_int_eq(simple_a_get(obj), OVERRIDE_A);
- /* Check super works. */
+ /* Check non-overriden functions work. */
simple_a_set(obj, OVERRIDE_A_SIMPLE);
ck_assert_int_eq(simple_a_get(obj), OVERRIDE_A + OVERRIDE_A_SIMPLE);
@@ -100,22 +101,36 @@ START_TEST(efl_object_override_tests)
simple_a_set(obj, OVERRIDE_A_SIMPLE);
ck_assert_int_eq(simple_a_get(obj), OVERRIDE_A_SIMPLE * 2);
- /* Try overriding again - not allowed by policy */
- fail_if(efl_object_override(obj, &overrides));
- ck_assert_int_eq(simple_a_get(obj), OVERRIDE_A_SIMPLE * 2);
+ /* Try overriding again, allowed since 1.21. */
+ fail_if(!efl_object_override(obj, &overrides));
+ ck_assert_int_eq(simple_a_get(obj), OVERRIDE_A + OVERRIDE_A_SIMPLE * 2);
/* Try introducing a new function */
EFL_OPS_DEFINE(
overrides3,
EFL_OBJECT_OP_FUNC(simple2_class_beef_get, _simple_obj_override_a_double_set));
+ fail_if(efl_object_override(obj, &overrides3));
fail_if(!efl_object_override(obj, NULL));
fail_if(efl_object_override(obj, &overrides3));
- /* Test override reset */
+ /* Test override reset of all functions */
fail_if(!efl_object_override(obj, NULL));
simple_a_set(obj, 42 * OVERRIDE_A_SIMPLE);
ck_assert_int_eq(simple_a_get(obj), 42 * OVERRIDE_A_SIMPLE);
+ /* Test override reset of a single functions, allowed since 1.21. */
+ EFL_OPS_DEFINE(
+ overrides4,
+ EFL_OBJECT_OP_FUNC(simple_a_get, NULL));
+ fail_if(!efl_object_override(obj, NULL));
+ simple_a_set(obj, 1337);
+ ck_assert_int_eq(simple_a_get(obj), 1337);
+ fail_if(!efl_object_override(obj, &overrides));
+ fail_if(!efl_object_override(obj, &overrides2));
+ ck_assert_int_eq(simple_a_get(obj), OVERRIDE_A + 1337);
+ fail_if(!efl_object_override(obj, &overrides4));
+ ck_assert_int_eq(simple_a_get(obj), 1337);
+
efl_unref(obj);
efl_object_shutdown();