summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Hacohen <tom@stosb.com>2016-05-19 11:33:17 +0100
committerTom Hacohen <tom@stosb.com>2016-05-20 10:25:00 +0100
commit06f65ab2b1ad4b6963de4193aeea2f4274ced1fa (patch)
tree971c0676f8088ef4d471346969a17aee34e8ed23
parentc450efdcde1c11b60c9567c70a349134fa9534fc (diff)
Eo: Implement eo_override() to enable overriding functions of objects.
This change lets you override the functions of objects so that those functions will be called instead of the functions of the class. This lets you change objects on the fly and makes using the delegate pattern easier (no need to create a class every time anymore). You can see the newly added tests (in this commit) for usage examples. @feature
-rw-r--r--src/Makefile_Eo.am1
-rw-r--r--src/lib/eo/Eo.h37
-rw-r--r--src/lib/eo/eo.c131
-rw-r--r--src/lib/eo/eo_override.eo4
-rw-r--r--src/lib/eo/eo_private.h16
-rw-r--r--src/tests/eo/suite/eo_test_general.c63
6 files changed, 211 insertions, 41 deletions
diff --git a/src/Makefile_Eo.am b/src/Makefile_Eo.am
index 69c4466d1a..6cf0b3acd4 100644
--- a/src/Makefile_Eo.am
+++ b/src/Makefile_Eo.am
@@ -4,6 +4,7 @@
4eo_eolian_files = \ 4eo_eolian_files = \
5 lib/eo/eo_base.eo \ 5 lib/eo/eo_base.eo \
6 lib/eo/eo_class.eo \ 6 lib/eo/eo_class.eo \
7 lib/eo/eo_override.eo \
7 lib/eo/eo_interface.eo 8 lib/eo/eo_interface.eo
8 9
9eo_eolian_c = $(eo_eolian_files:%.eo=%.eo.c) 10eo_eolian_c = $(eo_eolian_files:%.eo=%.eo.c)
diff --git a/src/lib/eo/Eo.h b/src/lib/eo/Eo.h
index 566720f979..a241d4fe70 100644
--- a/src/lib/eo/Eo.h
+++ b/src/lib/eo/Eo.h
@@ -169,6 +169,7 @@ typedef enum _Eo_Op_Type Eo_Op_Type;
169 */ 169 */
170typedef void (*Eo_Del_Intercept) (Eo *obj_id); 170typedef void (*Eo_Del_Intercept) (Eo *obj_id);
171 171
172#include "eo_override.eo.h"
172#include "eo_base.eo.h" 173#include "eo_base.eo.h"
173#define EO_CLASS EO_BASE_CLASS 174#define EO_CLASS EO_BASE_CLASS
174 175
@@ -386,6 +387,18 @@ typedef struct _Eo_Op_Description
386} Eo_Op_Description; 387} Eo_Op_Description;
387 388
388/** 389/**
390 * @struct _Eo_Ops
391 *
392 * This struct holds the ops and the size of the ops.
393 * Please use the #EO_CLASS_DESCRIPTION_OPS macro when populating it.
394 */
395typedef struct _Eo_Ops
396{
397 const Eo_Op_Description *descs; /**< The op descriptions array of size count. */
398 size_t count; /**< Number of op descriptions. */
399} Eo_Ops;
400
401/**
389 * @struct _Eo_Class_Description 402 * @struct _Eo_Class_Description
390 * This struct holds the description of a class. 403 * This struct holds the description of a class.
391 * This description should be passed to eo_class_new. 404 * This description should be passed to eo_class_new.
@@ -396,10 +409,7 @@ struct _Eo_Class_Description
396 unsigned int version; /**< The current version of eo, use #EO_VERSION */ 409 unsigned int version; /**< The current version of eo, use #EO_VERSION */
397 const char *name; /**< The name of the class. */ 410 const char *name; /**< The name of the class. */
398 Eo_Class_Type type; /**< The type of the class. */ 411 Eo_Class_Type type; /**< The type of the class. */
399 struct { 412 Eo_Ops ops; /**< The ops description, should be filled using #EO_CLASS_DESCRIPTION_OPS (later sorted by Eo). */
400 const Eo_Op_Description *descs; /**< The op descriptions array of size count. */
401 size_t count; /**< Number of op descriptions. */
402 } ops; /**< The ops description, should be filled using #EO_CLASS_DESCRIPTION_OPS (later sorted by Eo). */
403 const Eo_Event_Description **events; /**< The event descriptions for this class. */ 413 const Eo_Event_Description **events; /**< The event descriptions for this class. */
404 size_t data_size; /**< The size of data (private + protected + public) this class needs per object. */ 414 size_t data_size; /**< The size of data (private + protected + public) this class needs per object. */
405 void (*class_constructor)(Eo_Class *klass); /**< The constructor of the class. */ 415 void (*class_constructor)(Eo_Class *klass); /**< The constructor of the class. */
@@ -427,6 +437,21 @@ typedef struct _Eo_Class_Description Eo_Class_Description;
427EAPI const Eo_Class *eo_class_new(const Eo_Class_Description *desc, const Eo_Class *parent, ...); 437EAPI const Eo_Class *eo_class_new(const Eo_Class_Description *desc, const Eo_Class *parent, ...);
428 438
429/** 439/**
440 * @brief Override Eo functions of this object.
441 * @param ops The op description to override with.
442 * @return true on success, false otherwise.
443 *
444 * This lets you override all of the Eo functions of this object (this
445 * one included) and repalce them with ad-hoc implementation.
446 * The contents of the array are copied so they can for example reside
447 * on the stack.
448 *
449 * You are only allowed to override functions that are defined in the
450 * class or any of its interfaces (that is, eo_isa returning true).
451 */
452EAPI Eina_Bool eo_override(Eo *obj, Eo_Ops ops);
453
454/**
430 * @brief Check if an object "is a" klass. 455 * @brief Check if an object "is a" klass.
431 * @param obj The object to check 456 * @param obj The object to check
432 * @param klass The klass to check against. 457 * @param klass The klass to check against.
@@ -466,8 +491,8 @@ EAPI Eina_Bool eo_init(void);
466EAPI Eina_Bool eo_shutdown(void); 491EAPI Eina_Bool eo_shutdown(void);
467 492
468// Helpers macro to help populating #Eo_Class_Description. 493// Helpers macro to help populating #Eo_Class_Description.
469#define EO_CLASS_DESCRIPTION_NOOPS() { NULL, 0} 494#define EO_CLASS_DESCRIPTION_NOOPS() ((Eo_Ops) { NULL, 0})
470#define EO_CLASS_DESCRIPTION_OPS(op_descs) { op_descs, EINA_C_ARRAY_LENGTH(op_descs) } 495#define EO_CLASS_DESCRIPTION_OPS(op_descs) ((Eo_Ops) { op_descs, EINA_C_ARRAY_LENGTH(op_descs) })
471 496
472// to fetch internal function and object data at once 497// to fetch internal function and object data at once
473typedef struct _Eo_Op_Call_Data 498typedef struct _Eo_Op_Call_Data
diff --git a/src/lib/eo/eo.c b/src/lib/eo/eo.c
index 08de539a97..cef7bb797c 100644
--- a/src/lib/eo/eo.c
+++ b/src/lib/eo/eo.c
@@ -15,6 +15,8 @@
15#include "eo_private.h" 15#include "eo_private.h"
16#include "eo_add_fallback.h" 16#include "eo_add_fallback.h"
17 17
18#include "eo_override.eo.c"
19
18#define EO_CLASS_IDS_FIRST 1 20#define EO_CLASS_IDS_FIRST 1
19#define EO_OP_IDS_FIRST 1 21#define EO_OP_IDS_FIRST 1
20 22
@@ -130,11 +132,11 @@ _eo_op_class_get(Eo_Op op)
130} 132}
131 133
132static inline Eina_Bool 134static inline Eina_Bool
133_vtable_func_set(_Eo_Class *klass, Eo_Op op, eo_op_func_type func) 135_vtable_func_set(Eo_Vtable *vtable, const _Eo_Class *klass, Eo_Op op, eo_op_func_type func)
134{ 136{
135 op_type_funcs *fsrc; 137 op_type_funcs *fsrc;
136 size_t idx1 = DICH_CHAIN1(op); 138 size_t idx1 = DICH_CHAIN1(op);
137 Dich_Chain1 *chain1 = &klass->vtable.chain[idx1]; 139 Dich_Chain1 *chain1 = &vtable->chain[idx1];
138 _vtable_chain_alloc(chain1); 140 _vtable_chain_alloc(chain1);
139 fsrc = &chain1->funcs[DICH_CHAIN_LAST(op)]; 141 fsrc = &chain1->funcs[DICH_CHAIN_LAST(op)];
140 if (fsrc->src == klass) 142 if (fsrc->src == klass)
@@ -151,19 +153,19 @@ _vtable_func_set(_Eo_Class *klass, Eo_Op op, eo_op_func_type func)
151 return EINA_TRUE; 153 return EINA_TRUE;
152} 154}
153 155
154static inline void 156void
155_vtable_func_clean_all(_Eo_Class *klass) 157_vtable_func_clean_all(Eo_Vtable *vtable)
156{ 158{
157 size_t i; 159 size_t i;
158 Dich_Chain1 *chain1 = klass->vtable.chain; 160 Dich_Chain1 *chain1 = vtable->chain;
159 161
160 for (i = 0 ; i < klass->vtable.size ; i++, chain1++) 162 for (i = 0 ; i < vtable->size ; i++, chain1++)
161 { 163 {
162 if (chain1->funcs) 164 if (chain1->funcs)
163 free(chain1->funcs); 165 free(chain1->funcs);
164 } 166 }
165 free(klass->vtable.chain); 167 free(vtable->chain);
166 klass->vtable.chain = NULL; 168 vtable->chain = NULL;
167} 169}
168 170
169/* END OF DICH */ 171/* END OF DICH */
@@ -270,8 +272,10 @@ _eo_call_resolve(Eo *eo_id, const char *func_name, Eo_Op_Call_Data *call, Eo_Cal
270 const _Eo_Class *klass, *inputklass, *main_klass; 272 const _Eo_Class *klass, *inputklass, *main_klass;
271 const _Eo_Class *cur_klass = NULL; 273 const _Eo_Class *cur_klass = NULL;
272 _Eo_Object *obj = NULL; 274 _Eo_Object *obj = NULL;
275 const Eo_Vtable *vtable = NULL;
273 const op_type_funcs *func; 276 const op_type_funcs *func;
274 Eina_Bool is_obj; 277 Eina_Bool is_obj;
278 Eina_Bool is_override = EINA_FALSE;
275 279
276 if (((Eo_Id) eo_id) & MASK_SUPER_TAG) 280 if (((Eo_Id) eo_id) & MASK_SUPER_TAG)
277 { 281 {
@@ -301,6 +305,19 @@ _eo_call_resolve(Eo *eo_id, const char *func_name, Eo_Op_Call_Data *call, Eo_Cal
301 EO_OBJ_POINTER_RETURN_VAL(eo_id, _obj, EINA_FALSE); 305 EO_OBJ_POINTER_RETURN_VAL(eo_id, _obj, EINA_FALSE);
302 obj = _obj; 306 obj = _obj;
303 klass = _obj->klass; 307 klass = _obj->klass;
308 vtable = obj->vtable;
309
310 if (_obj_is_override(obj) && cur_klass &&
311 (_eo_class_id_get(cur_klass) == EO_OVERRIDE_CLASS))
312 {
313 /* Doing a eo_super(obj, EO_OVERRIDE_CLASS) should result in calling
314 * as if it's a normal class. */
315 vtable = &klass->vtable;
316 cur_klass = NULL;
317 }
318
319 is_override = _obj_is_override(obj) && (cur_klass == NULL);
320
304 call->obj = obj; 321 call->obj = obj;
305 _eo_ref(_obj); 322 _eo_ref(_obj);
306 } 323 }
@@ -308,6 +325,7 @@ _eo_call_resolve(Eo *eo_id, const char *func_name, Eo_Op_Call_Data *call, Eo_Cal
308 { 325 {
309 EO_CLASS_POINTER_RETURN_VAL(eo_id, _klass, EINA_FALSE); 326 EO_CLASS_POINTER_RETURN_VAL(eo_id, _klass, EINA_FALSE);
310 klass = _klass; 327 klass = _klass;
328 vtable = &klass->vtable;
311 call->obj = NULL; 329 call->obj = NULL;
312 call->data = NULL; 330 call->data = NULL;
313 } 331 }
@@ -337,28 +355,31 @@ _eo_call_resolve(Eo *eo_id, const char *func_name, Eo_Op_Call_Data *call, Eo_Cal
337 else 355 else
338 { 356 {
339# if EO_CALL_CACHE_SIZE > 0 357# if EO_CALL_CACHE_SIZE > 0
358 if (!is_override)
359 {
340# if EO_CALL_CACHE_SIZE > 1 360# if EO_CALL_CACHE_SIZE > 1
341 int i; 361 int i;
342 362
343 for (i = 0; i < EO_CALL_CACHE_SIZE; i++) 363 for (i = 0; i < EO_CALL_CACHE_SIZE; i++)
344# else 364# else
345 const int i = 0; 365 const int i = 0;
346# endif 366# endif
347 {
348 if ((const void *)inputklass == cache->index[i].klass)
349 { 367 {
350 func = (const op_type_funcs *)cache->entry[i].func; 368 if ((const void *)inputklass == cache->index[i].klass)
351 call->func = func->func;
352 if (is_obj)
353 { 369 {
354 call->data = (char *) obj + cache->off[i].off; 370 func = (const op_type_funcs *)cache->entry[i].func;
371 call->func = func->func;
372 if (is_obj)
373 {
374 call->data = (char *) obj + cache->off[i].off;
375 }
376 return EINA_TRUE;
355 } 377 }
356 return EINA_TRUE;
357 } 378 }
358 } 379 }
359#endif 380#endif
360 381
361 func = _vtable_func_get(&klass->vtable, cache->op); 382 func = _vtable_func_get(vtable, cache->op);
362 383
363 if (!func) 384 if (!func)
364 goto end; 385 goto end;
@@ -374,7 +395,7 @@ _eo_call_resolve(Eo *eo_id, const char *func_name, Eo_Op_Call_Data *call, Eo_Cal
374 } 395 }
375 396
376# if EO_CALL_CACHE_SIZE > 0 397# if EO_CALL_CACHE_SIZE > 0
377 if (!cur_klass) 398 if (!cur_klass && !is_override)
378 { 399 {
379# if EO_CALL_CACHE_SIZE > 1 400# if EO_CALL_CACHE_SIZE > 1
380 const int slot = cache->next_slot; 401 const int slot = cache->next_slot;
@@ -535,8 +556,10 @@ _eo_api_op_id_get(const void *api_func)
535 return op; 556 return op;
536} 557}
537 558
559/* klass is the klass we are working on. hierarchy_klass is the class whe should
560 * use when validating. */
538static Eina_Bool 561static Eina_Bool
539_eo_class_funcs_set(_Eo_Class *klass) 562_eo_class_funcs_set(Eo_Vtable *vtable, const Eo_Ops *ops, const _Eo_Class *hierarchy_klass, const _Eo_Class *klass, Eina_Bool override_only)
540{ 563{
541 unsigned int i; 564 unsigned int i;
542 int op_id; 565 int op_id;
@@ -544,15 +567,15 @@ _eo_class_funcs_set(_Eo_Class *klass)
544 const Eo_Op_Description *op_desc; 567 const Eo_Op_Description *op_desc;
545 const Eo_Op_Description *op_descs; 568 const Eo_Op_Description *op_descs;
546 569
547 op_id = klass->base_id; 570 op_id = hierarchy_klass->base_id;
548 op_descs = klass->desc->ops.descs; 571 op_descs = ops->descs;
549 572
550 DBG("Set functions for class '%s':%p", klass->desc->name, klass); 573 DBG("Set functions for class '%s':%p", klass->desc->name, klass);
551 574
552 if (!op_descs) return EINA_TRUE; 575 if (!op_descs) return EINA_TRUE;
553 576
554 last_api_func = NULL; 577 last_api_func = NULL;
555 for (i = 0, op_desc = op_descs; i < klass->desc->ops.count; i++, op_desc++) 578 for (i = 0, op_desc = op_descs; i < ops->count; i++, op_desc++)
556 { 579 {
557 Eo_Op op = EO_NOOP; 580 Eo_Op op = EO_NOOP;
558 581
@@ -565,6 +588,12 @@ _eo_class_funcs_set(_Eo_Class *klass)
565 588
566 if ((op_desc->op_type == EO_OP_TYPE_REGULAR) || (op_desc->op_type == EO_OP_TYPE_CLASS)) 589 if ((op_desc->op_type == EO_OP_TYPE_REGULAR) || (op_desc->op_type == EO_OP_TYPE_CLASS))
567 { 590 {
591 if (override_only)
592 {
593 ERR("Creation of new functions is not allowed when overriding an object's vtable.");
594 return EINA_FALSE;
595 }
596
568 if (_eo_api_func_equal(op_desc->api_func, last_api_func)) 597 if (_eo_api_func_equal(op_desc->api_func, last_api_func))
569 { 598 {
570 ERR("Class '%s': API previously defined (%p->%p '%s').", 599 ERR("Class '%s': API previously defined (%p->%p '%s').",
@@ -586,12 +615,19 @@ _eo_class_funcs_set(_Eo_Class *klass)
586 else if ((op_desc->op_type == EO_OP_TYPE_REGULAR_OVERRIDE) || (op_desc->op_type == EO_OP_TYPE_CLASS_OVERRIDE)) 615 else if ((op_desc->op_type == EO_OP_TYPE_REGULAR_OVERRIDE) || (op_desc->op_type == EO_OP_TYPE_CLASS_OVERRIDE))
587 { 616 {
588 const Eo_Op_Description *api_desc; 617 const Eo_Op_Description *api_desc;
589 api_desc = _eo_api_desc_get(op_desc->api_func, klass->parent, klass->extensions); 618 if (override_only)
619 {
620 api_desc = _eo_api_desc_get(op_desc->api_func, hierarchy_klass, NULL);
621 }
622 else
623 {
624 api_desc = _eo_api_desc_get(op_desc->api_func, hierarchy_klass->parent, hierarchy_klass->extensions);
625 }
590 626
591 if (api_desc == NULL) 627 if (api_desc == NULL)
592 { 628 {
593 ERR("Class '%s': Can't find api func description in class hierarchy (%p->%p) (%s).", 629 ERR("Class '%s': Can't find api func description in class hierarchy (%p->%p) (%s).",
594 klass->desc->name, op_desc->api_func, op_desc->func, _eo_op_desc_name_get(op_desc)); 630 hierarchy_klass->desc->name, op_desc->api_func, op_desc->func, _eo_op_desc_name_get(op_desc));
595 return EINA_FALSE; 631 return EINA_FALSE;
596 } 632 }
597 633
@@ -607,7 +643,7 @@ _eo_class_funcs_set(_Eo_Class *klass)
607 643
608 DBG("%p->%p '%s'", op_desc->api_func, op_desc->func, _eo_op_desc_name_get(op_desc)); 644 DBG("%p->%p '%s'", op_desc->api_func, op_desc->func, _eo_op_desc_name_get(op_desc));
609 645
610 if (!_vtable_func_set(klass, op, op_desc->func)) 646 if (!_vtable_func_set(vtable, klass, op, op_desc->func))
611 return EINA_FALSE; 647 return EINA_FALSE;
612 648
613 last_api_func = op_desc->api_func; 649 last_api_func = op_desc->api_func;
@@ -799,6 +835,13 @@ eo_class_name_get(const Eo_Class *eo_id)
799} 835}
800 836
801static void 837static void
838_vtable_init(Eo_Vtable *vtable, size_t size)
839{
840 vtable->size = size;
841 vtable->chain = calloc(vtable->size, sizeof(vtable->chain));
842}
843
844static void
802_eo_class_base_op_init(_Eo_Class *klass) 845_eo_class_base_op_init(_Eo_Class *klass)
803{ 846{
804 const Eo_Class_Description *desc = klass->desc; 847 const Eo_Class_Description *desc = klass->desc;
@@ -807,8 +850,7 @@ _eo_class_base_op_init(_Eo_Class *klass)
807 850
808 _eo_ops_last_id += desc->ops.count + 1; 851 _eo_ops_last_id += desc->ops.count + 1;
809 852
810 klass->vtable.size = DICH_CHAIN1(_eo_ops_last_id) + 1; 853 _vtable_init(&klass->vtable, DICH_CHAIN1(_eo_ops_last_id) + 1);
811 klass->vtable.chain = calloc(klass->vtable.size, sizeof(*klass->vtable.chain));
812} 854}
813 855
814#ifdef EO_DEBUG 856#ifdef EO_DEBUG
@@ -951,7 +993,7 @@ eo_class_free(_Eo_Class *klass)
951 if (klass->desc->class_destructor) 993 if (klass->desc->class_destructor)
952 klass->desc->class_destructor(_eo_class_id_get(klass)); 994 klass->desc->class_destructor(_eo_class_id_get(klass));
953 995
954 _vtable_func_clean_all(klass); 996 _vtable_func_clean_all(&klass->vtable);
955 } 997 }
956 998
957 EINA_TRASH_CLEAN(&klass->objects.trash, data) 999 EINA_TRASH_CLEAN(&klass->objects.trash, data)
@@ -1258,26 +1300,26 @@ eo_class_new(const Eo_Class_Description *desc, const Eo_Class *parent_id, ...)
1258 { 1300 {
1259 const _Eo_Class *extn = *extn_itr; 1301 const _Eo_Class *extn = *extn_itr;
1260 /* Set it in the dich. */ 1302 /* Set it in the dich. */
1261 _vtable_func_set(klass, extn->base_id + 1303 _vtable_func_set(&klass->vtable, klass, extn->base_id +
1262 extn->desc->ops.count, _eo_class_isa_func); 1304 extn->desc->ops.count, _eo_class_isa_func);
1263 } 1305 }
1264 1306
1265 _vtable_func_set(klass, klass->base_id + klass->desc->ops.count, 1307 _vtable_func_set(&klass->vtable, klass, klass->base_id + klass->desc->ops.count,
1266 _eo_class_isa_func); 1308 _eo_class_isa_func);
1267 1309
1268 if (klass->parent) 1310 if (klass->parent)
1269 { 1311 {
1270 _vtable_func_set(klass, 1312 _vtable_func_set(&klass->vtable, klass,
1271 klass->parent->base_id + klass->parent->desc->ops.count, 1313 klass->parent->base_id + klass->parent->desc->ops.count,
1272 _eo_class_isa_func); 1314 _eo_class_isa_func);
1273 } 1315 }
1274 } 1316 }
1275 1317
1276 if (!_eo_class_funcs_set(klass)) 1318 if (!_eo_class_funcs_set(&klass->vtable, &(klass->desc->ops), klass, klass, EINA_FALSE))
1277 { 1319 {
1278 eina_spinlock_free(&klass->objects.trash_lock); 1320 eina_spinlock_free(&klass->objects.trash_lock);
1279 eina_spinlock_free(&klass->iterators.trash_lock); 1321 eina_spinlock_free(&klass->iterators.trash_lock);
1280 _vtable_func_clean_all(klass); 1322 _vtable_func_clean_all(&klass->vtable);
1281 free(klass); 1323 free(klass);
1282 return NULL; 1324 return NULL;
1283 } 1325 }
@@ -1302,6 +1344,25 @@ eo_class_new(const Eo_Class_Description *desc, const Eo_Class *parent_id, ...)
1302} 1344}
1303 1345
1304EAPI Eina_Bool 1346EAPI Eina_Bool
1347eo_override(Eo *eo_id, Eo_Ops ops)
1348{
1349 EO_OBJ_POINTER_RETURN_VAL(eo_id, obj, EINA_FALSE);
1350 EO_CLASS_POINTER_RETURN_VAL(EO_OVERRIDE_CLASS, klass, EINA_FALSE);
1351 Eo_Vtable *previous = obj->vtable;
1352 obj->vtable = calloc(1, sizeof(*obj->vtable));
1353 _vtable_init(obj->vtable, previous->size);
1354 _vtable_copy_all(obj->vtable, previous);
1355
1356 if (!_eo_class_funcs_set(obj->vtable, &ops, obj->klass, klass, EINA_TRUE))
1357 {
1358 ERR("Failed to override functions for %p", eo_id);
1359 return EINA_FALSE;
1360 }
1361
1362 return EINA_TRUE;
1363}
1364
1365EAPI Eina_Bool
1305eo_isa(const Eo *eo_id, const Eo_Class *klass_id) 1366eo_isa(const Eo *eo_id, const Eo_Class *klass_id)
1306{ 1367{
1307 EO_OBJ_POINTER_RETURN_VAL(eo_id, obj, EINA_FALSE); 1368 EO_OBJ_POINTER_RETURN_VAL(eo_id, obj, EINA_FALSE);
diff --git a/src/lib/eo/eo_override.eo b/src/lib/eo/eo_override.eo
new file mode 100644
index 0000000000..77cc05ff83
--- /dev/null
+++ b/src/lib/eo/eo_override.eo
@@ -0,0 +1,4 @@
1abstract Eo.Override ()
2{
3 data: null;
4}
diff --git a/src/lib/eo/eo_private.h b/src/lib/eo/eo_private.h
index 62f9b73c4c..dd5176cb2e 100644
--- a/src/lib/eo/eo_private.h
+++ b/src/lib/eo/eo_private.h
@@ -85,6 +85,9 @@ typedef struct _Eo_Vtable
85 unsigned int size; 85 unsigned int size;
86} Eo_Vtable; 86} Eo_Vtable;
87 87
88/* Clean the vtable. */
89void _vtable_func_clean_all(Eo_Vtable *vtable);
90
88struct _Eo_Header 91struct _Eo_Header
89{ 92{
90#ifndef HAVE_EO_ID 93#ifndef HAVE_EO_ID
@@ -249,6 +252,12 @@ _eo_del_internal(const char *file, int line, _Eo_Object *obj)
249 obj->refcount--; 252 obj->refcount--;
250} 253}
251 254
255static inline Eina_Bool
256_obj_is_override(_Eo_Object *obj)
257{
258 return (obj->vtable != &obj->klass->vtable);
259}
260
252static inline void 261static inline void
253_eo_free(_Eo_Object *obj) 262_eo_free(_Eo_Object *obj)
254{ 263{
@@ -260,6 +269,13 @@ _eo_free(_Eo_Object *obj)
260 ERR("Object %p data still referenced %d time(s).", obj, obj->datarefcount); 269 ERR("Object %p data still referenced %d time(s).", obj, obj->datarefcount);
261 } 270 }
262#endif 271#endif
272 if (_obj_is_override(obj))
273 {
274 _vtable_func_clean_all(obj->vtable);
275 free(obj->vtable);
276 obj->vtable = &klass->vtable;
277 }
278
263 _eo_id_release((Eo_Id) _eo_obj_id_get(obj)); 279 _eo_id_release((Eo_Id) _eo_obj_id_get(obj));
264 280
265 eina_spinlock_take(&klass->objects.trash_lock); 281 eina_spinlock_take(&klass->objects.trash_lock);
diff --git a/src/tests/eo/suite/eo_test_general.c b/src/tests/eo/suite/eo_test_general.c
index 65d9ae2437..1ae539d2f4 100644
--- a/src/tests/eo/suite/eo_test_general.c
+++ b/src/tests/eo/suite/eo_test_general.c
@@ -50,6 +50,68 @@ START_TEST(eo_singleton)
50} 50}
51END_TEST 51END_TEST
52 52
53#define OVERRIDE_A_SIMPLE 100859
54#define OVERRIDE_A 324000
55static int
56_simple_obj_override_a_get(Eo *obj, void *class_data EINA_UNUSED)
57{
58 return OVERRIDE_A + simple_a_get(eo_super(obj, EO_OVERRIDE_CLASS));
59}
60
61static void
62_simple_obj_override_a_double_set(Eo *obj, void *class_data EINA_UNUSED, int a)
63{
64 simple_a_set(eo_super(obj, EO_OVERRIDE_CLASS), 2 * a);
65}
66
67START_TEST(eo_override_tests)
68{
69 eo_init();
70
71 Eo_Op_Description override_descs[] = {
72 EO_OP_FUNC_OVERRIDE(simple_a_get, _simple_obj_override_a_get),
73 };
74
75 Eo *obj = eo_add(SIMPLE_CLASS, NULL);
76 fail_if(!obj);
77
78 /* First get the value before the override to make sure it works and to
79 * make sure we don't cache. */
80 ck_assert_int_eq(simple_a_get(obj), 0);
81
82 fail_if(!eo_override(obj, EO_CLASS_DESCRIPTION_OPS(override_descs)));
83
84 ck_assert_int_eq(simple_a_get(obj), OVERRIDE_A);
85
86 /* Check super works. */
87 simple_a_set(obj, OVERRIDE_A_SIMPLE);
88 ck_assert_int_eq(simple_a_get(obj), OVERRIDE_A + OVERRIDE_A_SIMPLE);
89
90
91 /* Override again. */
92 Eo_Op_Description override_descs2[] = {
93 EO_OP_FUNC_OVERRIDE(simple_a_set, _simple_obj_override_a_double_set),
94 };
95
96 fail_if(!eo_override(obj, EO_CLASS_DESCRIPTION_OPS(override_descs2)));
97
98 simple_a_set(obj, OVERRIDE_A_SIMPLE);
99 ck_assert_int_eq(simple_a_get(obj), OVERRIDE_A + (OVERRIDE_A_SIMPLE * 2));
100
101
102 /* Try introducing a new function */
103 Eo_Op_Description override_descs3[] = {
104 EO_OP_FUNC(simple2_class_beef_get, _simple_obj_override_a_double_set),
105 };
106
107 fail_if(eo_override(obj, (Eo_Ops) EO_CLASS_DESCRIPTION_OPS(override_descs3)));
108
109 eo_unref(obj);
110
111 eo_shutdown();
112}
113END_TEST
114
53static int _eo_signals_cb_current = 0; 115static int _eo_signals_cb_current = 0;
54static int _eo_signals_cb_flag = 0; 116static int _eo_signals_cb_flag = 0;
55 117
@@ -1178,6 +1240,7 @@ void eo_test_general(TCase *tc)
1178{ 1240{
1179 tcase_add_test(tc, eo_simple); 1241 tcase_add_test(tc, eo_simple);
1180 tcase_add_test(tc, eo_singleton); 1242 tcase_add_test(tc, eo_singleton);
1243 tcase_add_test(tc, eo_override_tests);
1181 tcase_add_test(tc, eo_signals); 1244 tcase_add_test(tc, eo_signals);
1182 tcase_add_test(tc, eo_data_fetch); 1245 tcase_add_test(tc, eo_data_fetch);
1183 tcase_add_test(tc, eo_isa_tests); 1246 tcase_add_test(tc, eo_isa_tests);