summaryrefslogtreecommitdiff
path: root/src/lib/eo
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 /src/lib/eo
parent83a4c3e3e2c1503f32aff81b46cc9c486a35ebd2 (diff)
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 T5580 @feature
Diffstat (limited to 'src/lib/eo')
-rw-r--r--src/lib/eo/Eo.h2
-rw-r--r--src/lib/eo/eo.c120
2 files changed, 78 insertions, 44 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
648 * It is not possible to override a function table of an object when it's 648 * It is not possible to override a function table of an object when it's
649 * already been overridden. Call efl_object_override(obj, NULL) first if you really 649 * already been overridden. Call efl_object_override(obj, NULL) first if you really
650 * need to do that. 650 * need to do that.
651 *
652 * @see EFL_OPS_DEFINE
651 */ 653 */
652EAPI Eina_Bool efl_object_override(Eo *obj, const Efl_Object_Ops *ops); 654EAPI Eina_Bool efl_object_override(Eo *obj, const Efl_Object_Ops *ops);
653 655
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)
231} 231}
232 232
233static inline Eina_Bool 233static inline Eina_Bool
234_vtable_func_set(Eo_Vtable *vtable, const _Efl_Class *klass, Efl_Object_Op op, Eo_Op_Func_Type func, Eina_Bool allow_same_override) 234_vtable_func_set(Eo_Vtable *vtable, const _Efl_Class *klass,
235 const _Efl_Class *hierarchy_klass, Efl_Object_Op op,
236 Eo_Op_Func_Type func, Eina_Bool allow_same_override)
235{ 237{
236 op_type_funcs *fsrc; 238 op_type_funcs *fsrc;
237 size_t idx1 = DICH_CHAIN1(op); 239 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
241 chain1 = &vtable->chain[idx1]; 243 chain1 = &vtable->chain[idx1];
242 _vtable_chain_write_prepare(chain1); 244 _vtable_chain_write_prepare(chain1);
243 fsrc = &chain1->chain2->funcs[DICH_CHAIN_LAST(op)]; 245 fsrc = &chain1->chain2->funcs[DICH_CHAIN_LAST(op)];
244 if (!allow_same_override && (fsrc->src == klass)) 246 if (hierarchy_klass)
245 { 247 {
246 const _Efl_Class *op_kls = _eo_op_class_get(op); 248 if (!func)
247 ERR("Class '%s': Overriding already set func %p for op %d (%s) with %p.", 249 {
248 klass->desc->name, fsrc->func, op, op_kls->desc->name, func); 250 op_type_funcs *fsrc_orig;
249 return EINA_FALSE; 251 Dich_Chain1 *chain1_orig;
252
253 chain1_orig = &hierarchy_klass->vtable.chain[idx1];
254 fsrc_orig = &chain1_orig->chain2->funcs[DICH_CHAIN_LAST(op)];
255 func = fsrc_orig->func;
256 klass = fsrc_orig->src;
257 }
258 }
259 else
260 {
261 if (!allow_same_override && (fsrc->src == klass))
262 {
263 const _Efl_Class *op_kls = _eo_op_class_get(op);
264 ERR("Class '%s': Overriding already set func %p for op %d (%s) with %p.",
265 klass->desc->name, fsrc->func, op, op_kls->desc->name, func);
266 return EINA_FALSE;
267 }
250 } 268 }
251 269
252 fsrc->func = func; 270 fsrc->func = func;
@@ -712,24 +730,32 @@ _efl_object_op_api_id_get(const void *api_func, const Eo *obj, const char *api_f
712static Eina_Bool 730static Eina_Bool
713_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) 731_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)
714{ 732{
715 unsigned int i; 733 unsigned int i, j;
716 Efl_Object_Op op_id; 734 Efl_Object_Op op_id;
717 const void *last_api_func;
718 const Efl_Op_Description *op_desc; 735 const Efl_Op_Description *op_desc;
719 const Efl_Op_Description *op_descs; 736 const Efl_Op_Description *op_descs;
737 const _Efl_Class *override_class;
738 const void **api_funcs;
739 Eina_Bool check_equal;
720 740
721 op_id = hierarchy_klass->base_id + id_offset; 741 op_id = hierarchy_klass->base_id + id_offset;
722 op_descs = ops->descs; 742 op_descs = ops->descs;
743 override_class = override_only ? hierarchy_klass : NULL;
723 744
724 DBG("Set functions for class '%s':%p", klass->desc->name, klass); 745 DBG("Set functions for class '%s':%p", klass->desc->name, klass);
725 746
726 if (!op_descs) return EINA_TRUE; 747 if (!op_descs || !ops->count) return EINA_TRUE;
727 748
728 last_api_func = NULL; 749#ifdef EO_DEBUG
750 check_equal = EINA_TRUE;
751#else
752 check_equal = !override_only;
753#endif
754 api_funcs = alloca(ops->count * sizeof(api_funcs[0]));
755
756 /* sanity checks */
729 for (i = 0, op_desc = op_descs; i < ops->count; i++, op_desc++) 757 for (i = 0, op_desc = op_descs; i < ops->count; i++, op_desc++)
730 { 758 {
731 Efl_Object_Op op = EFL_NOOP;
732
733 if (op_desc->api_func == NULL) 759 if (op_desc->api_func == NULL)
734 { 760 {
735 ERR("Class '%s': NULL API not allowed (NULL->%p '%s').", 761 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
737 return EINA_FALSE; 763 return EINA_FALSE;
738 } 764 }
739 765
740 /* Get the opid for the function. */ 766 if (check_equal)
741 { 767 {
742 if (_eo_api_func_equal(op_desc->api_func, last_api_func)) 768 for (j = 0; j < i; j++)
743 { 769 {
744 ERR("Class '%s': API previously defined (%p->%p '%s').", 770 if (_eo_api_func_equal(op_desc->api_func, api_funcs[j]))
745 klass->desc->name, op_desc->api_func, op_desc->func, _eo_op_desc_name_get(op_desc)); 771 {
746 return EINA_FALSE; 772 ERR("Class '%s': API previously defined (%p->%p '%s').",
773 klass->desc->name, op_desc->api_func, op_desc->func, _eo_op_desc_name_get(op_desc));
774 return EINA_FALSE;
775 }
747 } 776 }
748 777
749 op = _efl_object_api_op_id_get_internal(op_desc->api_func); 778 api_funcs[i] = op_desc->api_func;
779 }
780 }
781
782 for (i = 0, op_desc = op_descs; i < ops->count; i++, op_desc++)
783 {
784 Efl_Object_Op op = EFL_NOOP;
785
786 /* Get the opid for the function. */
787 op = _efl_object_api_op_id_get_internal(op_desc->api_func);
750 788
751 if (op == EFL_NOOP) 789 if (op == EFL_NOOP)
790 {
791 if (override_only)
752 { 792 {
753 if (override_only) 793 ERR("Class '%s': Tried overriding a previously undefined function.", klass->desc->name);
754 { 794 return EINA_FALSE;
755 ERR("Class '%s': Tried overriding a previously undefined function.", klass->desc->name); 795 }
756 return EINA_FALSE;
757 }
758 796
759 op = op_id; 797 op = op_id;
760 eina_spinlock_take(&_ops_storage_lock); 798 eina_spinlock_take(&_ops_storage_lock);
761#ifndef _WIN32 799#ifndef _WIN32
762 eina_hash_add(_ops_storage, &op_desc->api_func, (void *) (uintptr_t) op); 800 eina_hash_add(_ops_storage, &op_desc->api_func, (void *) (uintptr_t) op);
763#else 801#else
764 eina_hash_add(_ops_storage, op_desc->api_func, (void *) (uintptr_t) op); 802 eina_hash_add(_ops_storage, op_desc->api_func, (void *) (uintptr_t) op);
765#endif 803#endif
766 eina_spinlock_release(&_ops_storage_lock); 804 eina_spinlock_release(&_ops_storage_lock);
767 805
768 op_id++; 806 op_id++;
769 }
770 } 807 }
771 808
772 DBG("%p->%p '%s'", op_desc->api_func, op_desc->func, _eo_op_desc_name_get(op_desc)); 809 DBG("%p->%p '%s'", op_desc->api_func, op_desc->func, _eo_op_desc_name_get(op_desc));
773 810
774 if (!_vtable_func_set(vtable, klass, op, op_desc->func, EINA_FALSE)) 811 if (!_vtable_func_set(vtable, klass, override_class, op, op_desc->func, EINA_TRUE))
775 return EINA_FALSE; 812 return EINA_FALSE;
776
777 last_api_func = op_desc->api_func;
778 } 813 }
779 814
780 return EINA_TRUE; 815 return EINA_TRUE;
@@ -1280,8 +1315,8 @@ _eo_class_isa_recursive_set(_Efl_Class *klass, const _Efl_Class *cur)
1280{ 1315{
1281 const _Efl_Class **extn_itr; 1316 const _Efl_Class **extn_itr;
1282 1317
1283 _vtable_func_set(&klass->vtable, klass, cur->base_id + cur->ops_count, 1318 _vtable_func_set(&klass->vtable, klass, NULL, cur->base_id + cur->ops_count,
1284 _eo_class_isa_func, EINA_TRUE); 1319 _eo_class_isa_func, EINA_TRUE);
1285 1320
1286 for (extn_itr = cur->extensions ; *extn_itr ; extn_itr++) 1321 for (extn_itr = cur->extensions ; *extn_itr ; extn_itr++)
1287 { 1322 {
@@ -1594,18 +1629,15 @@ efl_object_override(Eo *eo_id, const Efl_Object_Ops *ops)
1594 1629
1595 if (ops) 1630 if (ops)
1596 { 1631 {
1597 Eo_Vtable *vtable; 1632 Eo_Vtable *vtable = obj->opt->vtable;
1598 1633
1599 if (EINA_UNLIKELY(obj->opt->vtable != NULL)) 1634 if (!vtable)
1600 { 1635 {
1601 ERR("Function table already overridden, not allowed to override again. " 1636 vtable = calloc(1, sizeof(*vtable));
1602 "Call with NULL to reset the function table first."); 1637 _vtable_init(vtable, obj->klass->vtable.size);
1603 goto err; 1638 _vtable_copy_all(vtable, &obj->klass->vtable);
1604 } 1639 }
1605 1640
1606 vtable = calloc(1, sizeof(*vtable));
1607 _vtable_init(vtable, obj->klass->vtable.size);
1608 _vtable_copy_all(vtable, &obj->klass->vtable);
1609 if (!_eo_class_funcs_set(vtable, ops, obj->klass, klass, 0, EINA_TRUE)) 1641 if (!_eo_class_funcs_set(vtable, ops, obj->klass, klass, 0, EINA_TRUE))
1610 { 1642 {
1611 // FIXME: Maybe leaking some chain stuff from copy above? 1643 // FIXME: Maybe leaking some chain stuff from copy above?