01554fb6c94b53d324e58f9954692c51ca1647fa
[profile/ivi/eobj.git] / src / lib / eo.c
1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4
5 #include <Eina.h>
6
7 #include "Eo.h"
8 #include "eo_private.h"
9
10 /* The last id that should be reserved for statically allocated classes. */
11 #define EO_CLASS_IDS_FIRST 1
12 #define EO_OP_IDS_FIRST 1
13
14 /* Used inside the class_get functions of classes, see #EO_DEFINE_CLASS */
15 EAPI Eina_Lock _eo_class_creation_lock;
16 int _eo_log_dom = -1;
17
18 static Eo_Class **_eo_classes;
19 static Eo_Class_Id _eo_classes_last_id;
20 static Eina_Bool _eo_init_count = 0;
21 static Eo_Op _eo_ops_last_id = 0;
22
23 static void _eo_condtor_reset(Eo *obj);
24 static inline void *_eo_data_get(const Eo *obj, const Eo_Class *klass);
25 static inline Eo *_eo_ref(Eo *obj);
26 static inline void _eo_unref(Eo *obj);
27 static const Eo_Class *_eo_op_class_get(Eo_Op op);
28 static const Eo_Op_Description *_eo_op_id_desc_get(Eo_Op op);
29
30 typedef struct
31 {
32    const Eo_Class *kls;
33 } Eo_Kls_Itr;
34
35 struct _Eo {
36      EINA_MAGIC
37      EINA_INLIST;
38      Eo *parent;
39      Eina_Inlist *children;
40      const Eo_Class *klass;
41      int refcount;
42 #ifndef NDEBUG
43      Eina_Inlist *xrefs;
44 #endif
45
46      Eina_List *composite_objects;
47
48      Eo_Kls_Itr mro_itr;
49
50      Eina_Bool do_error:1;
51      Eina_Bool condtor_done:1;
52
53      Eina_Bool composite:1;
54      Eina_Bool del:1;
55      Eina_Bool manual_free:1;
56 };
57
58 /* Start of Dich */
59
60 /* How we search and store the implementations in classes. */
61 #define DICH_CHAIN_LAST_BITS 5
62 #define DICH_CHAIN_LAST_SIZE (1 << DICH_CHAIN_LAST_BITS)
63 #define DICH_CHAIN1(x) ((x) / DICH_CHAIN_LAST_SIZE)
64 #define DICH_CHAIN_LAST(x) ((x) % DICH_CHAIN_LAST_SIZE)
65
66 #define OP_CLASS_OFFSET_GET(x) (((x) >> EO_OP_CLASS_OFFSET) & 0xffff)
67
68 #define ID_CLASS_GET(id) ({ \
69       (Eo_Class *) ((id <= _eo_classes_last_id) && (id > 0)) ? \
70       (_eo_classes[id - 1]) : NULL; \
71       })
72
73 #define EO_ALIGN_SIZE(size) \
74         ((size) + (sizeof(void *) - ((size) % sizeof(void *))))
75
76 typedef struct _Dich_Chain1 Dich_Chain1;
77
78 typedef struct
79 {
80    eo_op_func_type func;
81    const Eo_Class *src;
82 } op_type_funcs;
83
84 struct _Dich_Chain1
85 {
86    op_type_funcs *funcs;
87 };
88
89 typedef struct
90 {
91    const Eo_Class *klass;
92    size_t offset;
93 } Eo_Extension_Data_Offset;
94
95 struct _Eo_Class
96 {
97    EINA_MAGIC
98    Eo_Class_Id class_id;
99    const Eo_Class *parent;
100    const Eo_Class_Description *desc;
101    Dich_Chain1 *chain; /**< The size is chain size */
102    size_t chain_size;
103    size_t base_id;
104
105    const Eo_Class **extensions;
106
107    Eo_Extension_Data_Offset *extn_data_off;
108    size_t extn_data_size;
109
110    const Eo_Class **mro;
111    Eo_Kls_Itr mro_itr;
112
113    size_t data_offset; /* < Offset of the data within object data. */
114
115    Eina_Bool constructed : 1;
116 };
117
118 static inline void
119 _dich_chain_alloc(Dich_Chain1 *chain1)
120 {
121    if (!chain1->funcs)
122      {
123         chain1->funcs = calloc(DICH_CHAIN_LAST_SIZE, sizeof(*(chain1->funcs)));
124      }
125 }
126
127 static inline void
128 _dich_copy_all(Eo_Class *dst, const Eo_Class *src)
129 {
130    Eo_Op i;
131    const Dich_Chain1 *sc1 = src->chain;
132    Dich_Chain1 *dc1 = dst->chain;
133    for (i = 0 ; i < src->chain_size ; i++, sc1++, dc1++)
134      {
135         if (sc1->funcs)
136           {
137              size_t j;
138
139              _dich_chain_alloc(dc1);
140
141              const op_type_funcs *sf = sc1->funcs;
142              op_type_funcs *df = dc1->funcs;
143              for (j = 0 ; j < DICH_CHAIN_LAST_SIZE ; j++, df++, sf++)
144                {
145                   if (sf->func)
146                     {
147                        memcpy(df, sf, sizeof(*df));
148                     }
149                }
150           }
151      }
152 }
153
154 static inline const op_type_funcs *
155 _dich_func_get(const Eo_Class *klass, Eo_Op op)
156 {
157    size_t idx1 = DICH_CHAIN1(op);
158    if (EINA_UNLIKELY(idx1 >= klass->chain_size))
159       return NULL;
160    Dich_Chain1 *chain1 = &klass->chain[idx1];
161    if (EINA_UNLIKELY(!chain1->funcs))
162       return NULL;
163    return &chain1->funcs[DICH_CHAIN_LAST(op)];
164 }
165
166 static inline void
167 _dich_func_set(Eo_Class *klass, Eo_Op op, eo_op_func_type func)
168 {
169    size_t idx1 = DICH_CHAIN1(op);
170    Dich_Chain1 *chain1 = &klass->chain[idx1];
171    _dich_chain_alloc(chain1);
172    if (chain1->funcs[DICH_CHAIN_LAST(op)].src == klass)
173      {
174         const Eo_Class *op_kls = _eo_op_class_get(op);
175         const Eo_Op_Description *op_desc = _eo_op_id_desc_get(op);
176         ERR("Already set function for op %x (%s:%s). Overriding with func %p",
177               op, op_kls->desc->name, op_desc->name, func);
178      }
179
180    chain1->funcs[DICH_CHAIN_LAST(op)].func = func;
181    chain1->funcs[DICH_CHAIN_LAST(op)].src = klass;
182 }
183
184 static inline void
185 _dich_func_clean_all(Eo_Class *klass)
186 {
187    size_t i;
188    Dich_Chain1 *chain1 = klass->chain;
189
190    for (i = 0 ; i < klass->chain_size ; i++, chain1++)
191      {
192         if (chain1->funcs)
193            free(chain1->funcs);
194      }
195    free(klass->chain);
196    klass->chain = NULL;
197 }
198
199 /* END OF DICH */
200
201 static const Eo_Op_Description noop_desc =
202         EO_OP_DESCRIPTION(EO_NOOP, "No operation.");
203
204 static const Eo_Class *
205 _eo_op_class_get(Eo_Op op)
206 {
207    /* FIXME: Make it fast. */
208    Eo_Class **itr = _eo_classes;
209    int mid, max, min;
210
211    min = 0;
212    max = _eo_classes_last_id - 1;
213    while (min <= max)
214      {
215         mid = (min + max) / 2;
216
217         if (itr[mid]->base_id + itr[mid]->desc->ops.count < op)
218            min = mid + 1;
219         else if (itr[mid]->base_id  > op)
220            max = mid - 1;
221         else
222            return itr[mid];
223      }
224
225    return NULL;
226 }
227
228 static const Eo_Op_Description *
229 _eo_op_id_desc_get(Eo_Op op)
230 {
231    const Eo_Class *klass;
232
233    if (op == EO_NOOP)
234       return &noop_desc;
235
236    klass = _eo_op_class_get(op);
237
238    if (klass)
239      {
240         Eo_Op sub_id = op - klass->base_id;
241        if (sub_id < klass->desc->ops.count)
242           return klass->desc->ops.descs + sub_id;
243      }
244
245    return NULL;
246 }
247
248 static const char *
249 _eo_op_id_name_get(Eo_Op op)
250 {
251    const Eo_Op_Description *desc = _eo_op_id_desc_get(op);
252    return (desc) ? desc->name : NULL;
253 }
254
255 static inline void
256 _eo_kls_itr_init(const Eo_Class *obj_klass, Eo_Kls_Itr *cur, Eo_Kls_Itr *prev_state)
257 {
258    memcpy(prev_state, cur, sizeof(*cur));
259    cur->kls = *obj_klass->mro;
260 }
261
262 static inline void
263 _eo_kls_itr_end(Eo_Kls_Itr *cur, Eo_Kls_Itr *prev_state)
264 {
265    memcpy(cur, prev_state, sizeof(*cur));
266 }
267
268 static inline const Eo_Class *
269 _eo_kls_itr_get(Eo_Kls_Itr *cur)
270 {
271    return cur->kls;
272 }
273
274 static inline void
275 _eo_kls_itr_set(Eo_Kls_Itr *cur, const Eo_Class *kls)
276 {
277    cur->kls = kls;
278 }
279
280 static inline const Eo_Class *
281 _eo_kls_itr_next(const Eo_Class *orig_kls, Eo_Kls_Itr *cur, Eo_Kls_Itr *prev_state, Eo_Op op)
282 {
283    const Eo_Class **kls_itr = NULL;
284    memcpy(prev_state, cur, sizeof(*cur));
285
286    /* Find the kls itr. */
287    kls_itr = orig_kls->mro;
288    while (*kls_itr && (*kls_itr != cur->kls))
289       kls_itr++;
290
291    if (*kls_itr)
292      {
293         kls_itr++;
294         while (*kls_itr)
295           {
296              const op_type_funcs *fsrc = _dich_func_get(*kls_itr, op);
297              if (!fsrc || !fsrc->func)
298                {
299                   kls_itr++;
300                   continue;
301                }
302              cur->kls = fsrc->src;
303              return cur->kls;
304           }
305      }
306
307    cur->kls = NULL;
308    return NULL;
309 }
310
311 static inline const op_type_funcs *
312 _eo_kls_itr_func_get(Eo_Kls_Itr *mro_itr, Eo_Op op)
313 {
314    const Eo_Class *klass = _eo_kls_itr_get(mro_itr);
315    if (klass)
316      {
317         const op_type_funcs *func = _dich_func_get(klass, op);
318
319         if (func && func->func)
320           {
321              _eo_kls_itr_set(mro_itr, func->src);
322              return func;
323           }
324      }
325
326    _eo_kls_itr_set(mro_itr, NULL);
327    return NULL;
328 }
329
330 #define _EO_OP_ERR_NO_OP_PRINT(op, klass) \
331    do \
332       { \
333          const Eo_Class *op_klass = _eo_op_class_get(op); \
334          const char *_dom_name = (op_klass) ? op_klass->desc->name : NULL; \
335          ERR("Can't find func for op %x (%s:%s) for class '%s'. Aborting.", \
336                op, _dom_name, _eo_op_id_name_get(op), \
337                (klass) ? klass->desc->name : NULL); \
338       } \
339    while (0)
340
341 static Eina_Bool
342 _eo_op_internal(Eo *obj, Eo_Op_Type op_type, Eo_Op op, va_list *p_list)
343 {
344 #ifndef NDEBUG
345    const Eo_Op_Description *op_desc = _eo_op_id_desc_get(op);
346
347    if (op_desc)
348      {
349         if (op_desc->op_type == EO_OP_TYPE_CLASS)
350           {
351              ERR("Tried calling a class op '%s' (%x) from a non-class context.", (op_desc) ? op_desc->name : NULL, op);
352              return EINA_FALSE;
353           }
354      }
355 #endif
356
357      {
358         const op_type_funcs *func =
359            _eo_kls_itr_func_get(&obj->mro_itr, op);
360         if (func)
361           {
362              void *func_data =_eo_data_get(obj, func->src);
363              func->func(obj, func_data, p_list);
364              return EINA_TRUE;
365           }
366      }
367
368    /* Try composite objects */
369      {
370         Eina_List *itr;
371         Eo *emb_obj;
372         EINA_LIST_FOREACH(obj->composite_objects, itr, emb_obj)
373           {
374              /* FIXME: Clean this up a bit. */
375              Eo_Kls_Itr prev_state;
376              _eo_kls_itr_init(emb_obj->klass, &emb_obj->mro_itr, &prev_state);
377              if (_eo_op_internal(emb_obj, op_type, op, p_list))
378                {
379                   _eo_kls_itr_end(&emb_obj->mro_itr, &prev_state);
380                   return EINA_TRUE;
381                }
382              _eo_kls_itr_end(&emb_obj->mro_itr, &prev_state);
383           }
384      }
385    return EINA_FALSE;
386 }
387
388 static inline Eina_Bool
389 _eo_dov_internal(Eo *obj, Eo_Op_Type op_type, va_list p_list)
390 {
391    Eina_Bool prev_error;
392    Eina_Bool ret = EINA_TRUE;
393    Eo_Op op = EO_NOOP;
394    Eo_Kls_Itr prev_state;
395
396    prev_error = obj->do_error;
397    _eo_ref(obj);
398
399    op = va_arg(p_list, Eo_Op);
400    while (op)
401      {
402         _eo_kls_itr_init(obj->klass, &obj->mro_itr, &prev_state);
403         if (!_eo_op_internal(obj, op_type, op, &p_list))
404           {
405              _EO_OP_ERR_NO_OP_PRINT(op, obj->klass);
406              ret = EINA_FALSE;
407              _eo_kls_itr_end(&obj->mro_itr, &prev_state);
408              break;
409           }
410         op = va_arg(p_list, Eo_Op);
411         _eo_kls_itr_end(&obj->mro_itr, &prev_state);
412      }
413
414    _eo_unref(obj);
415
416    if (obj->do_error)
417       ret = EINA_FALSE;
418
419    obj->do_error = prev_error;
420
421    return ret;
422 }
423
424 EAPI Eina_Bool
425 eo_do_internal(Eo *obj, Eo_Op_Type op_type, ...)
426 {
427    Eina_Bool ret = EINA_TRUE;
428    va_list p_list;
429
430    EO_MAGIC_RETURN_VAL(obj, EO_EINA_MAGIC, EINA_FALSE);
431
432    va_start(p_list, op_type);
433
434    ret = _eo_dov_internal(obj, op_type, p_list);
435
436    va_end(p_list);
437
438    return ret;
439 }
440
441 EAPI Eina_Bool
442 eo_do_super_internal(Eo *obj, Eo_Op_Type op_type, Eo_Op op, ...)
443 {
444    const Eo_Class *nklass;
445    Eina_Bool ret = EINA_TRUE;
446    va_list p_list;
447    Eo_Kls_Itr prev_state;
448    EO_MAGIC_RETURN_VAL(obj, EO_EINA_MAGIC, EINA_FALSE);
449
450    /* Advance the kls itr. */
451    nklass = _eo_kls_itr_next(obj->klass, &obj->mro_itr, &prev_state, op);
452
453    va_start(p_list, op);
454    if (!_eo_op_internal(obj, op_type, op, &p_list))
455      {
456         _EO_OP_ERR_NO_OP_PRINT(op, nklass);
457         ret = EINA_FALSE;
458      }
459    va_end(p_list);
460
461    if (obj->do_error)
462       ret = EINA_FALSE;
463
464    _eo_kls_itr_end(&obj->mro_itr, &prev_state);
465    return ret;
466 }
467
468 static Eina_Bool
469 _eo_class_op_internal(Eo_Class *klass, Eo_Op op, va_list *p_list)
470 {
471 #ifndef NDEBUG
472    const Eo_Op_Description *op_desc = _eo_op_id_desc_get(op);
473
474    if (op_desc)
475      {
476         if (op_desc->op_type != EO_OP_TYPE_CLASS)
477           {
478              ERR("Tried calling an instance op '%s' (%x) from a class context.", (op_desc) ? op_desc->name : NULL, op);
479              return EINA_FALSE;
480           }
481      }
482 #endif
483
484      {
485         const op_type_funcs *func =
486            _eo_kls_itr_func_get(&klass->mro_itr, op);
487         if (func)
488           {
489              ((eo_op_func_type_class) func->func)(klass, p_list);
490              return EINA_TRUE;
491           }
492      }
493
494    return EINA_FALSE;
495 }
496
497 EAPI Eina_Bool
498 eo_class_do_internal(const Eo_Class *klass, ...)
499 {
500    Eina_Bool ret = EINA_TRUE;
501    Eo_Op op = EO_NOOP;
502    Eo_Kls_Itr prev_state;
503    va_list p_list;
504
505    EO_MAGIC_RETURN_VAL(klass, EO_CLASS_EINA_MAGIC, EINA_FALSE);
506
507    va_start(p_list, klass);
508
509    op = va_arg(p_list, Eo_Op);
510    while (op)
511      {
512         _eo_kls_itr_init(klass, &((Eo_Class *) klass)->mro_itr, &prev_state);
513         if (!_eo_class_op_internal((Eo_Class *) klass, op, &p_list))
514           {
515              _EO_OP_ERR_NO_OP_PRINT(op, klass);
516              ret = EINA_FALSE;
517              _eo_kls_itr_end(&((Eo_Class *) klass)->mro_itr, &prev_state);
518              break;
519           }
520         _eo_kls_itr_end(&((Eo_Class *) klass)->mro_itr, &prev_state);
521         op = va_arg(p_list, Eo_Op);
522      }
523
524    va_end(p_list);
525
526    return ret;
527 }
528
529 EAPI Eina_Bool
530 eo_class_do_super_internal(const Eo_Class *klass, Eo_Op op, ...)
531 {
532    const Eo_Class *nklass;
533    Eina_Bool ret = EINA_TRUE;
534    va_list p_list;
535    Eo_Kls_Itr prev_state;
536    EO_MAGIC_RETURN_VAL(klass, EO_CLASS_EINA_MAGIC, EINA_FALSE);
537
538    /* Advance the kls itr. */
539    nklass = _eo_kls_itr_next(klass, &((Eo_Class *) klass)->mro_itr, &prev_state, op);
540
541    va_start(p_list, op);
542    if (!_eo_class_op_internal((Eo_Class *) klass, op, &p_list))
543      {
544         _EO_OP_ERR_NO_OP_PRINT(op, nklass);
545         ret = EINA_FALSE;
546      }
547    va_end(p_list);
548
549    _eo_kls_itr_end(&((Eo_Class *) klass)->mro_itr, &prev_state);
550    return ret;
551 }
552
553 EAPI const Eo_Class *
554 eo_class_get(const Eo *obj)
555 {
556    EO_MAGIC_RETURN_VAL(obj, EO_EINA_MAGIC, EINA_FALSE);
557
558    return obj->klass;
559 }
560
561 EAPI const char *
562 eo_class_name_get(const Eo_Class *klass)
563 {
564    EO_MAGIC_RETURN_VAL(klass, EO_CLASS_EINA_MAGIC, NULL);
565
566    return klass->desc->name;
567 }
568
569 static void
570 _eo_class_base_op_init(Eo_Class *klass)
571 {
572    const Eo_Class_Description *desc = klass->desc;
573
574    klass->base_id = _eo_ops_last_id;
575
576    if (desc && desc->ops.base_op_id)
577       *(desc->ops.base_op_id) = klass->base_id;
578
579    _eo_ops_last_id += desc->ops.count + 1;
580
581    klass->chain_size = DICH_CHAIN1(_eo_ops_last_id) + 1;
582    klass->chain = calloc(klass->chain_size, sizeof(*klass->chain));
583 }
584
585 #ifndef NDEBUG
586 static Eina_Bool
587 _eo_class_mro_has(const Eo_Class *klass, const Eo_Class *find)
588 {
589    const Eo_Class **itr;
590    for (itr = klass->mro ; *itr ; itr++)
591      {
592         if (*itr == find)
593           {
594              return EINA_TRUE;
595           }
596      }
597    return EINA_FALSE;
598 }
599 #endif
600
601 static Eina_List *
602 _eo_class_mro_add(Eina_List *mro, const Eo_Class *klass)
603 {
604    Eina_List *extn_pos = NULL;
605    Eina_Bool check_consistency = !mro;
606    if (!klass)
607       return mro;
608
609    mro = eina_list_append(mro, klass);
610
611    /* ONLY ADD MIXINS! */
612
613    /* Recursively add extenions. */
614      {
615         const Eo_Class **extn_itr;
616
617         for (extn_itr = klass->extensions ; *extn_itr ; extn_itr++)
618           {
619              const Eo_Class *extn = *extn_itr;
620              if (extn->desc->type != EO_CLASS_TYPE_MIXIN)
621                 continue;
622
623              mro = _eo_class_mro_add(mro, extn);
624              /* Not possible: if (!mro) return NULL; */
625
626              if (check_consistency)
627                {
628                   extn_pos = eina_list_append(extn_pos, eina_list_last(mro));
629                }
630           }
631      }
632
633    /* Check if we can create a consistent mro. We only do it for the class
634     * we are working on (i.e no parents). */
635    if (check_consistency)
636      {
637         const Eo_Class **extn_itr;
638
639         Eina_List *itr = extn_pos;
640         for (extn_itr = klass->extensions ; *extn_itr ; extn_itr++)
641           {
642              const Eo_Class *extn = *extn_itr;
643              if (extn->desc->type != EO_CLASS_TYPE_MIXIN)
644                 continue;
645
646              /* Get the first one after the extension. */
647              Eina_List *extn_list = eina_list_next(eina_list_data_get(itr));
648
649              /* If we found the extension again. */
650              if (eina_list_data_find_list(extn_list, extn))
651                {
652                   eina_list_free(mro);
653                   ERR("Cannot create a consistent method resolution order for class '%s' because of '%s'.", klass->desc->name, extn->desc->name);
654                   return NULL;
655                }
656
657              itr = eina_list_next(itr);
658           }
659      }
660
661
662    mro = _eo_class_mro_add(mro, klass->parent);
663
664    return mro;
665 }
666
667 static Eina_Bool
668 _eo_class_mro_init(Eo_Class *klass)
669 {
670    Eina_List *mro = NULL;
671
672    DBG("Started creating MRO for class '%s'", klass->desc->name);
673    mro = _eo_class_mro_add(mro, klass);
674
675    if (!mro)
676       return EINA_FALSE;
677
678    /* Remove duplicates and make them the right order. */
679      {
680         Eina_List *itr1, *itr2, *itr2n;
681
682         itr1 = eina_list_last(mro);
683         while (itr1)
684           {
685              itr2 = eina_list_prev(itr1);
686
687              while (itr2)
688                {
689                   itr2n = eina_list_prev(itr2);
690
691                   if (eina_list_data_get(itr1) == eina_list_data_get(itr2))
692                     {
693                        mro = eina_list_remove_list(mro, itr2);
694                     }
695
696                   itr2 = itr2n;
697                }
698
699              itr1 = eina_list_prev(itr1);
700           }
701      }
702
703    /* Copy the mro and free the list. */
704      {
705         const Eo_Class *kls_itr;
706         const Eo_Class **mro_itr;
707         klass->mro = calloc(sizeof(*klass->mro), eina_list_count(mro) + 1);
708
709         mro_itr = klass->mro;
710
711         EINA_LIST_FREE(mro, kls_itr)
712           {
713              *(mro_itr++) = kls_itr;
714
715              DBG("Added '%s' to MRO", kls_itr->desc->name);
716           }
717         *(mro_itr) = NULL;
718      }
719
720    DBG("Finished creating MRO for class '%s'", klass->desc->name);
721
722    return EINA_TRUE;
723 }
724
725 static void
726 _eo_class_constructor(Eo_Class *klass)
727 {
728    if (klass->constructed)
729       return;
730
731    klass->constructed = EINA_TRUE;
732
733    if (klass->desc->class_constructor)
734       klass->desc->class_constructor(klass);
735 }
736
737 EAPI void
738 eo_class_funcs_set(Eo_Class *klass, const Eo_Op_Func_Description *func_descs)
739 {
740    EO_MAGIC_RETURN(klass, EO_CLASS_EINA_MAGIC);
741
742    const Eo_Op_Func_Description *itr;
743    itr = func_descs;
744    if (itr)
745      {
746         for ( ; itr->op_type != EO_OP_TYPE_INVALID ; itr++)
747           {
748              const Eo_Op_Description *op_desc = _eo_op_id_desc_get(itr->op);
749
750              if (EINA_UNLIKELY(!op_desc || (itr->op == EO_NOOP)))
751                {
752                   ERR("Setting implementation for non-existent op %x for class '%s'. Func index: %d", itr->op, klass->desc->name, itr - func_descs);
753                }
754              else if (EINA_LIKELY(itr->op_type == op_desc->op_type))
755                {
756                   _dich_func_set(klass, itr->op, itr->func);
757                }
758              else
759                {
760                   ERR("Set function's op type (%x) is different than the one in the op description (%d) for op '%s:%s'. Func index: %d",
761                         itr->op_type,
762                         (op_desc) ? op_desc->op_type : EO_OP_TYPE_REGULAR,
763                         klass->desc->name,
764                         (op_desc) ? op_desc->name : NULL,
765                         itr - func_descs);
766                }
767           }
768      }
769 }
770
771 static void
772 eo_class_free(Eo_Class *klass)
773 {
774    if (klass->constructed)
775      {
776         if (klass->desc->class_destructor)
777            klass->desc->class_destructor(klass);
778
779         _dich_func_clean_all(klass);
780      }
781
782    free(klass->extensions);
783
784    if (klass->mro)
785       free(klass->mro);
786
787    if (klass->extn_data_off)
788       free(klass->extn_data_off);
789
790    free(klass);
791 }
792
793 /* DEVCHECK */
794 static Eina_Bool
795 _eo_class_check_op_descs(const Eo_Class *klass)
796 {
797    const Eo_Class_Description *desc = klass->desc;
798    const Eo_Op_Description *itr;
799    size_t i;
800
801    if (desc->ops.count > 0)
802      {
803         if (!desc->ops.base_op_id)
804           {
805              ERR("Class '%s' has a non-zero ops count, but base_id is NULL.",
806                    desc->name);
807              return EINA_FALSE;
808           }
809
810         if (!desc->ops.descs)
811           {
812              ERR("Class '%s' has a non-zero ops count, but there are no descs.",
813                    desc->name);
814              return EINA_FALSE;
815           }
816      }
817
818    itr = desc->ops.descs;
819    for (i = 0 ; i < desc->ops.count ; i++, itr++)
820      {
821         if (itr->sub_op != i)
822           {
823              if (itr->name)
824                {
825                   ERR("Wrong order in Ops description for class '%s'. Expected %x and got %x", desc->name, i, itr->sub_op);
826                }
827              else
828                {
829                   ERR("Found too few Ops description for class '%s'. Expected %x descriptions, but found %x.", desc->name, desc->ops.count, i);
830                }
831              return EINA_FALSE;
832           }
833      }
834
835    if (itr && itr->name)
836      {
837         ERR("Found extra Ops description for class '%s'. Expected %d descriptions, but found more.", desc->name, desc->ops.count);
838         return EINA_FALSE;
839      }
840
841    return EINA_TRUE;
842 }
843
844 /* Not really called, just used for the ptr... */
845 static void
846 _eo_class_isa_func(Eo *obj EINA_UNUSED, void *class_data EINA_UNUSED, va_list *list EINA_UNUSED)
847 {
848    /* Do nonthing. */
849 }
850
851 EAPI const Eo_Class *
852 eo_class_new(const Eo_Class_Description *desc, const Eo_Class *parent, ...)
853 {
854    Eo_Class *klass;
855    va_list p_list;
856
857    if (parent && !EINA_MAGIC_CHECK(parent, EO_CLASS_EINA_MAGIC))
858      {
859         EINA_MAGIC_FAIL(parent, EO_CLASS_EINA_MAGIC);
860         return NULL;
861      }
862
863    va_start(p_list, parent);
864
865    EINA_SAFETY_ON_NULL_RETURN_VAL(desc, NULL);
866    EINA_SAFETY_ON_NULL_RETURN_VAL(desc->name, NULL);
867
868    /* Check restrictions on Interface types. */
869    if (desc->type == EO_CLASS_TYPE_INTERFACE)
870      {
871         EINA_SAFETY_ON_FALSE_RETURN_VAL(!desc->data_size, NULL);
872      }
873
874    klass = calloc(1, sizeof(Eo_Class));
875    klass->parent = parent;
876
877    /* Handle class extensions */
878      {
879         Eina_List *extn_list = NULL;
880         const Eo_Class *extn = NULL;
881         const Eo_Class **extn_itr = NULL;
882
883         extn = va_arg(p_list, Eo_Class *);
884         while (extn)
885           {
886              switch (extn->desc->type)
887                {
888                 case EO_CLASS_TYPE_REGULAR:
889                 case EO_CLASS_TYPE_REGULAR_NO_INSTANT:
890                 case EO_CLASS_TYPE_INTERFACE:
891                 case EO_CLASS_TYPE_MIXIN:
892                    extn_list = eina_list_append(extn_list, extn);
893                    break;
894                }
895
896              extn = va_arg(p_list, Eo_Class *);
897           }
898
899         klass->extensions = calloc(sizeof(*klass->extensions),
900               eina_list_count(extn_list) + 1);
901
902         extn_itr = klass->extensions;
903         EINA_LIST_FREE(extn_list, extn)
904           {
905              *(extn_itr++) = extn;
906           }
907      }
908
909    klass->desc = desc;
910
911    /* Handle the inheritance */
912    if (klass->parent)
913      {
914         /* Verify the inheritance is allowed. */
915         switch (klass->desc->type)
916           {
917            case EO_CLASS_TYPE_REGULAR:
918            case EO_CLASS_TYPE_REGULAR_NO_INSTANT:
919               if ((klass->parent->desc->type != EO_CLASS_TYPE_REGULAR) &&
920                     (klass->parent->desc->type != EO_CLASS_TYPE_REGULAR_NO_INSTANT))
921                 {
922                    ERR("Regular classes ('%s') aren't allowed to inherit from non-regular classes ('%s').", klass->desc->name, klass->parent->desc->name);
923                    goto cleanup;
924                 }
925               break;
926            case EO_CLASS_TYPE_INTERFACE:
927            case EO_CLASS_TYPE_MIXIN:
928               if ((klass->parent->desc->type != EO_CLASS_TYPE_INTERFACE) &&
929                     (klass->parent->desc->type != EO_CLASS_TYPE_MIXIN))
930                 {
931                    ERR("Non-regular classes ('%s') aren't allowed to inherit from regular classes ('%s').", klass->desc->name, klass->parent->desc->name);
932                    goto cleanup;
933                 }
934               break;
935           }
936
937
938         /* Update the current offset. */
939         /* FIXME: Make sure this alignment is enough. */
940         klass->data_offset = klass->parent->data_offset +
941            EO_ALIGN_SIZE(klass->parent->desc->data_size);
942      }
943
944    if (!_eo_class_check_op_descs(klass))
945      {
946         goto cleanup;
947      }
948
949    if (!_eo_class_mro_init(klass))
950      {
951         goto cleanup;
952      }
953
954    /* create MIXIN offset table. */
955      {
956         const Eo_Class **mro_itr = klass->mro;
957         Eo_Extension_Data_Offset *extn_data_itr;
958         size_t extn_num = 0;
959         size_t extn_data_off = klass->data_offset +
960            EO_ALIGN_SIZE(klass->desc->data_size);
961
962         /* FIXME: Make faster... */
963         while (*mro_itr)
964           {
965              if (((*mro_itr)->desc->type == EO_CLASS_TYPE_MIXIN) &&
966                    ((*mro_itr)->desc->data_size > 0))
967                {
968                   extn_num++;
969                }
970              mro_itr++;
971           }
972
973         klass->extn_data_off = calloc(extn_num + 1,
974               sizeof(*klass->extn_data_off));
975
976         extn_data_itr = klass->extn_data_off;
977         mro_itr = klass->mro;
978         while (*mro_itr)
979           {
980              if (((*mro_itr)->desc->type == EO_CLASS_TYPE_MIXIN) &&
981                    ((*mro_itr)->desc->data_size > 0))
982                {
983                   extn_data_itr->klass = *mro_itr;
984                   extn_data_itr->offset = extn_data_off;
985
986                   extn_data_off += EO_ALIGN_SIZE(extn_data_itr->klass->desc->data_size);
987                   extn_data_itr++;
988                }
989              mro_itr++;
990           }
991
992         klass->extn_data_size = extn_data_off;
993      }
994
995    eina_lock_take(&_eo_class_creation_lock);
996
997    klass->class_id = ++_eo_classes_last_id;
998
999      {
1000         /* FIXME: Handle errors. */
1001         size_t arrsize = _eo_classes_last_id * sizeof(*_eo_classes);
1002         Eo_Class **tmp;
1003         tmp = realloc(_eo_classes, arrsize);
1004
1005         /* If it's the first allocation, memset. */
1006         if (!_eo_classes)
1007            memset(tmp, 0, arrsize);
1008
1009         _eo_classes = tmp;
1010         _eo_classes[klass->class_id - 1] = klass;
1011      }
1012    eina_lock_release(&_eo_class_creation_lock);
1013
1014    EINA_MAGIC_SET(klass, EO_CLASS_EINA_MAGIC);
1015
1016    _eo_class_base_op_init(klass);
1017    /* Flatten the function array */
1018      {
1019         const Eo_Class **mro_itr = klass->mro;
1020         for (  ; *mro_itr ; mro_itr++)
1021            ;
1022
1023         /* Skip ourselves. */
1024         for ( mro_itr-- ; mro_itr > klass->mro ; mro_itr--)
1025           {
1026              _dich_copy_all(klass, *mro_itr);
1027           }
1028      }
1029
1030    /* Mark which classes we implement */
1031      {
1032         const Eo_Class **extn_itr;
1033
1034         for (extn_itr = klass->extensions ; *extn_itr ; extn_itr++)
1035           {
1036              const Eo_Class *extn = *extn_itr;
1037              /* Set it in the dich. */
1038              _dich_func_set(klass, extn->base_id +
1039                    extn->desc->ops.count, _eo_class_isa_func);
1040           }
1041
1042         _dich_func_set(klass, klass->base_id + klass->desc->ops.count,
1043               _eo_class_isa_func);
1044
1045         if (klass->parent)
1046           {
1047              _dich_func_set(klass,
1048                    klass->parent->base_id + klass->parent->desc->ops.count,
1049                    _eo_class_isa_func);
1050           }
1051      }
1052
1053    _eo_class_constructor(klass);
1054
1055    va_end(p_list);
1056
1057    return klass;
1058
1059 cleanup:
1060    eo_class_free(klass);
1061    return NULL;
1062 }
1063
1064 EAPI Eina_Bool
1065 eo_isa(const Eo *obj, const Eo_Class *klass)
1066 {
1067    EO_MAGIC_RETURN_VAL(obj, EO_EINA_MAGIC, EINA_FALSE);
1068    EO_MAGIC_RETURN_VAL(klass, EO_CLASS_EINA_MAGIC, EINA_FALSE);
1069    const op_type_funcs *func = _dich_func_get(obj->klass,
1070          klass->base_id + klass->desc->ops.count);
1071
1072    /* Currently implemented by reusing the LAST op id. Just marking it with
1073     * _eo_class_isa_func. */
1074    return (func && (func->func == _eo_class_isa_func));
1075 }
1076
1077 EAPI Eina_Bool
1078 eo_parent_set(Eo *obj, const Eo *parent)
1079 {
1080    EO_MAGIC_RETURN_VAL(obj, EO_EINA_MAGIC, EINA_FALSE);
1081    if (parent)
1082       EO_MAGIC_RETURN_VAL(parent, EO_EINA_MAGIC, EINA_FALSE);
1083
1084    if (obj->parent == parent)
1085       return EINA_TRUE;
1086
1087    _eo_ref(obj);
1088
1089    if (eo_composite_is(obj))
1090      {
1091         eo_composite_detach(obj, obj->parent);
1092      }
1093
1094    if (obj->parent)
1095      {
1096         obj->parent->children =
1097            eina_inlist_remove(obj->parent->children, EINA_INLIST_GET(obj));
1098         eo_xunref(obj, obj->parent);
1099      }
1100
1101    obj->parent = (Eo *) parent;
1102    if (obj->parent)
1103      {
1104         obj->parent->children =
1105            eina_inlist_append(obj->parent->children, EINA_INLIST_GET(obj));
1106         eo_xref(obj, obj->parent);
1107      }
1108
1109    _eo_unref(obj);
1110
1111    return EINA_TRUE;
1112 }
1113
1114 EAPI Eo *
1115 eo_add_internal(const Eo_Class *klass, Eo *parent, ...)
1116 {
1117    Eina_Bool do_err;
1118    EO_MAGIC_RETURN_VAL(klass, EO_CLASS_EINA_MAGIC, NULL);
1119
1120    if (parent) EO_MAGIC_RETURN_VAL(parent, EO_EINA_MAGIC, NULL);
1121
1122    if (EINA_UNLIKELY(klass->desc->type != EO_CLASS_TYPE_REGULAR))
1123      {
1124         ERR("Class '%s' is not instantiate-able. Aborting.", klass->desc->name);
1125         return NULL;
1126      }
1127
1128    Eo *obj = calloc(1, EO_ALIGN_SIZE(sizeof(*obj)) +
1129          (klass->data_offset + EO_ALIGN_SIZE(klass->desc->data_size)) +
1130          klass->extn_data_size);
1131    EINA_MAGIC_SET(obj, EO_EINA_MAGIC);
1132    obj->refcount++;
1133    obj->klass = klass;
1134
1135    eo_parent_set(obj, parent);
1136
1137    _eo_condtor_reset(obj);
1138
1139    _eo_ref(obj);
1140
1141    /* Run the relevant do stuff. */
1142      {
1143         va_list p_list;
1144         va_start(p_list, parent);
1145         do_err = !_eo_dov_internal(obj, EO_OP_TYPE_REGULAR, p_list);
1146         va_end(p_list);
1147      }
1148
1149    if (EINA_UNLIKELY(do_err))
1150      {
1151         ERR("Object of class '%s' - One of the object constructors have failed.", klass->desc->name);
1152         goto fail;
1153      }
1154
1155    if (!obj->condtor_done)
1156      {
1157         ERR("Object of class '%s' - Not all of the object constructors have been executed.", klass->desc->name);
1158         goto fail;
1159      }
1160
1161    _eo_unref(obj);
1162
1163    return obj;
1164
1165 fail:
1166    /* Unref twice, once for the ref above, and once for the basic object ref. */
1167    _eo_unref(obj);
1168    _eo_unref(obj);
1169    return NULL;
1170 }
1171
1172 typedef struct
1173 {
1174    EINA_INLIST;
1175    const Eo *ref_obj;
1176    const char *file;
1177    int line;
1178 } Eo_Xref_Node;
1179
1180 EAPI Eo *
1181 eo_xref_internal(Eo *obj, const Eo *ref_obj, const char *file, int line)
1182 {
1183    EO_MAGIC_RETURN_VAL(obj, EO_EINA_MAGIC, obj);
1184
1185    _eo_ref(obj);
1186
1187 #ifndef NDEBUG
1188    Eo_Xref_Node *xref = calloc(1, sizeof(*xref));
1189    xref->ref_obj = ref_obj;
1190    xref->file = file;
1191    xref->line = line;
1192
1193    obj->xrefs = eina_inlist_prepend(obj->xrefs, EINA_INLIST_GET(xref));
1194 #else
1195    (void) ref_obj;
1196    (void) file;
1197    (void) line;
1198 #endif
1199
1200    return obj;
1201 }
1202
1203 EAPI void
1204 eo_xunref(Eo *obj, const Eo *ref_obj)
1205 {
1206    EO_MAGIC_RETURN(obj, EO_EINA_MAGIC);
1207 #ifndef NDEBUG
1208    Eo_Xref_Node *xref = NULL;
1209    EINA_INLIST_FOREACH(obj->xrefs, xref)
1210      {
1211         if (xref->ref_obj == ref_obj)
1212            break;
1213      }
1214
1215    if (xref)
1216      {
1217         obj->xrefs = eina_inlist_remove(obj->xrefs, EINA_INLIST_GET(xref));
1218         free(xref);
1219      }
1220    else
1221      {
1222         ERR("ref_obj (%p) does not reference obj (%p). Aborting unref.", ref_obj, obj);
1223         return;
1224      }
1225 #else
1226    (void) ref_obj;
1227 #endif
1228    _eo_unref(obj);
1229 }
1230
1231 static inline Eo *
1232 _eo_ref(Eo *obj)
1233 {
1234    obj->refcount++;
1235    return obj;
1236 }
1237
1238 EAPI Eo *
1239 eo_ref(const Eo *_obj)
1240 {
1241    Eo *obj = (Eo *) _obj;
1242    EO_MAGIC_RETURN_VAL(obj, EO_EINA_MAGIC, obj);
1243
1244    return _eo_ref(obj);
1245 }
1246
1247 static inline void
1248 _eo_del_internal(Eo *obj)
1249 {
1250    Eina_Bool do_err;
1251    /* We need that for the event callbacks that may ref/unref. */
1252    obj->refcount++;
1253
1254    eo_do(obj, eo_event_callback_call(EO_EV_DEL, NULL, NULL));
1255
1256    const Eo_Class *klass = eo_class_get(obj);
1257
1258    _eo_condtor_reset(obj);
1259
1260    do_err = eo_do(obj, eo_destructor());
1261    if (EINA_UNLIKELY(!do_err))
1262      {
1263         ERR("Object of class '%s' - One of the object destructors have failed.", klass->desc->name);
1264      }
1265
1266    if (!obj->condtor_done)
1267      {
1268         ERR("Object of class '%s' - Not all of the object destructors have been executed.", klass->desc->name);
1269      }
1270    /*FIXME: add eo_class_unref(klass) ? - just to clear the caches. */
1271
1272      {
1273         Eina_List *itr, *itr_n;
1274         Eo *emb_obj;
1275         EINA_LIST_FOREACH_SAFE(obj->composite_objects, itr, itr_n, emb_obj)
1276           {
1277              eo_composite_detach(emb_obj, obj);
1278           }
1279      }
1280
1281    while (obj->children)
1282      {
1283         eo_parent_set(EINA_INLIST_CONTAINER_GET(obj->children, Eo), NULL);
1284      }
1285
1286    obj->del = EINA_TRUE;
1287    obj->refcount--;
1288 }
1289
1290 static inline void
1291 _eo_free(Eo *obj)
1292 {
1293    EINA_MAGIC_SET(obj, EO_FREED_EINA_MAGIC);
1294    free(obj);
1295 }
1296
1297 static inline void
1298 _eo_unref(Eo *obj)
1299 {
1300    --(obj->refcount);
1301    if (obj->refcount == 0)
1302      {
1303         if (obj->del)
1304           {
1305              ERR("Object %p already deleted.", obj);
1306              return;
1307           }
1308
1309         _eo_del_internal(obj);
1310
1311 #ifndef NDEBUG
1312         /* If for some reason it's not empty, clear it. */
1313         while (obj->xrefs)
1314           {
1315              ERR("obj->xrefs is not empty, possibly a bug, please report. - An error will be reported for each xref in the stack.");
1316              Eina_Inlist *nitr = obj->xrefs->next;
1317              free(EINA_INLIST_CONTAINER_GET(obj->xrefs, Eo_Xref_Node));
1318              obj->xrefs = nitr;
1319           }
1320 #endif
1321
1322         if (!obj->manual_free)
1323            _eo_free(obj);
1324         else
1325            _eo_ref(obj); /* If we manual free, we keep a phantom ref. */
1326      }
1327    else if (obj->refcount < 0)
1328      {
1329         ERR("Obj:%p. Refcount (%d) < 0. Too many unrefs.", obj, obj->refcount);
1330         return;
1331      }
1332 }
1333
1334 EAPI void
1335 eo_unref(const Eo *_obj)
1336 {
1337    Eo *obj = (Eo *) _obj;
1338    EO_MAGIC_RETURN(obj, EO_EINA_MAGIC);
1339
1340    _eo_unref(obj);
1341 }
1342
1343 EAPI void
1344 eo_del(const Eo *obj)
1345 {
1346    eo_parent_set((Eo *) obj, NULL);
1347    eo_unref(obj);
1348 }
1349
1350 EAPI int
1351 eo_ref_get(const Eo *obj)
1352 {
1353    EO_MAGIC_RETURN_VAL(obj, EO_EINA_MAGIC, 0);
1354
1355    return obj->refcount;
1356 }
1357
1358 EAPI Eo *
1359 eo_parent_get(const Eo *obj)
1360 {
1361    EO_MAGIC_RETURN_VAL(obj, EO_EINA_MAGIC, NULL);
1362
1363    return obj->parent;
1364 }
1365
1366 EAPI void
1367 eo_error_set_internal(const Eo *obj, const char *file, int line)
1368 {
1369    EO_MAGIC_RETURN(obj, EO_EINA_MAGIC);
1370
1371    ERR("Error with obj '%p' at %s:%d", obj, file, line);
1372
1373    ((Eo *) obj)->do_error = EINA_TRUE;
1374 }
1375
1376 void
1377 _eo_condtor_done(Eo *obj)
1378 {
1379    if (obj->condtor_done)
1380      {
1381         ERR("Object %p is already constructed at this point.", obj);
1382         return;
1383      }
1384
1385    obj->condtor_done = EINA_TRUE;
1386 }
1387
1388 static void
1389 _eo_condtor_reset(Eo *obj)
1390 {
1391    obj->condtor_done = EINA_FALSE;
1392 }
1393
1394 static inline void *
1395 _eo_data_get(const Eo *obj, const Eo_Class *klass)
1396 {
1397    if (EINA_LIKELY(klass->desc->data_size > 0))
1398      {
1399         if (EINA_UNLIKELY(klass->desc->type == EO_CLASS_TYPE_MIXIN))
1400           {
1401              Eo_Extension_Data_Offset *doff_itr =
1402                 eo_class_get(obj)->extn_data_off;
1403
1404              if (!doff_itr)
1405                 return NULL;
1406
1407              while (doff_itr->klass)
1408                {
1409                   if (doff_itr->klass == klass)
1410                      return ((char *) obj) + EO_ALIGN_SIZE(sizeof(*obj)) +
1411                         doff_itr->offset;
1412                   doff_itr++;
1413                }
1414           }
1415         else
1416           {
1417              return ((char *) obj) + EO_ALIGN_SIZE(sizeof(*obj)) +
1418                 klass->data_offset;
1419           }
1420      }
1421
1422    return NULL;
1423 }
1424
1425 EAPI void *
1426 eo_data_get(const Eo *obj, const Eo_Class *klass)
1427 {
1428    void *ret;
1429    EO_MAGIC_RETURN_VAL(obj, EO_EINA_MAGIC, NULL);
1430    EO_MAGIC_RETURN_VAL(klass, EO_CLASS_EINA_MAGIC, NULL);
1431
1432 #ifndef NDEBUG
1433    if (!_eo_class_mro_has(obj->klass, klass))
1434      {
1435         ERR("Tried getting data of class '%s' from object of class '%s', but the former is not a direct inheritance of the latter.", klass->desc->name, obj->klass->desc->name);
1436         return NULL;
1437      }
1438 #endif
1439
1440    ret = _eo_data_get(obj, klass);
1441
1442 #ifndef NDEBUG
1443    if (!ret && (klass->desc->data_size == 0))
1444      {
1445         ERR("Tried getting data of class '%s', but it has none..", klass->desc->name);
1446      }
1447 #endif
1448
1449    return ret;
1450 }
1451
1452 EAPI Eina_Bool
1453 eo_init(void)
1454 {
1455    const char *log_dom = "eo";
1456    if (_eo_init_count++ > 0)
1457       return EINA_TRUE;
1458
1459    eina_init();
1460
1461    _eo_classes = NULL;
1462    _eo_classes_last_id = EO_CLASS_IDS_FIRST - 1;
1463    _eo_ops_last_id = EO_OP_IDS_FIRST;
1464    _eo_log_dom = eina_log_domain_register(log_dom, EINA_COLOR_LIGHTBLUE);
1465    if (_eo_log_dom < 0)
1466      {
1467         EINA_LOG_ERR("Could not register log domain: %s", log_dom);
1468         return EINA_FALSE;
1469      }
1470
1471    if (!eina_lock_new(&_eo_class_creation_lock))
1472      {
1473         EINA_LOG_ERR("Could not init lock.");
1474         return EINA_FALSE;
1475      }
1476
1477    eina_magic_string_static_set(EO_EINA_MAGIC, EO_EINA_MAGIC_STR);
1478    eina_magic_string_static_set(EO_FREED_EINA_MAGIC,
1479          EO_FREED_EINA_MAGIC_STR);
1480    eina_magic_string_static_set(EO_CLASS_EINA_MAGIC,
1481          EO_CLASS_EINA_MAGIC_STR);
1482
1483 #ifndef NDEBUG
1484    /* Call it just for coverage purposes. Ugly I know, but I like it better than
1485     * casting everywhere else. */
1486    _eo_class_isa_func(NULL, NULL, NULL);
1487 #endif
1488
1489    return EINA_TRUE;
1490 }
1491
1492 EAPI Eina_Bool
1493 eo_shutdown(void)
1494 {
1495    size_t i;
1496    Eo_Class **cls_itr = _eo_classes;
1497
1498    if (--_eo_init_count > 0)
1499       return EINA_TRUE;
1500
1501    for (i = 0 ; i < _eo_classes_last_id ; i++, cls_itr++)
1502      {
1503         if (*cls_itr)
1504            eo_class_free(*cls_itr);
1505      }
1506
1507    if (_eo_classes)
1508       free(_eo_classes);
1509
1510    eina_lock_free(&_eo_class_creation_lock);
1511
1512    eina_log_domain_unregister(_eo_log_dom);
1513    _eo_log_dom = -1;
1514
1515    eina_shutdown();
1516    return EINA_TRUE;
1517 }
1518
1519 EAPI void
1520 eo_composite_attach(Eo *comp_obj, Eo *parent)
1521 {
1522    EO_MAGIC_RETURN(comp_obj, EO_EINA_MAGIC);
1523    EO_MAGIC_RETURN(parent, EO_EINA_MAGIC);
1524
1525    comp_obj->composite = EINA_TRUE;
1526    eo_parent_set(comp_obj, parent);
1527    parent->composite_objects = eina_list_prepend(parent->composite_objects, comp_obj);
1528 }
1529
1530 EAPI void
1531 eo_composite_detach(Eo *comp_obj, Eo *parent)
1532 {
1533    EO_MAGIC_RETURN(comp_obj, EO_EINA_MAGIC);
1534    EO_MAGIC_RETURN(parent, EO_EINA_MAGIC);
1535
1536    comp_obj->composite = EINA_FALSE;
1537    parent->composite_objects = eina_list_remove(parent->composite_objects, comp_obj);
1538    eo_parent_set(comp_obj, NULL);
1539 }
1540
1541 EAPI Eina_Bool
1542 eo_composite_is(const Eo *comp_obj)
1543 {
1544    EO_MAGIC_RETURN_VAL(comp_obj, EO_EINA_MAGIC, EINA_FALSE);
1545
1546    return comp_obj->composite;
1547 }
1548
1549 EAPI Eina_Bool
1550 eo_destructed_is(const Eo *obj)
1551 {
1552    EO_MAGIC_RETURN_VAL(obj, EO_EINA_MAGIC, EINA_FALSE);
1553
1554    return obj->del;
1555 }
1556
1557 EAPI void
1558 eo_manual_free_set(Eo *obj, Eina_Bool manual_free)
1559 {
1560    EO_MAGIC_RETURN(obj, EO_EINA_MAGIC);
1561    obj->manual_free = manual_free;
1562 }
1563
1564 EAPI void
1565 eo_manual_free(Eo *obj)
1566 {
1567    EO_MAGIC_RETURN(obj, EO_EINA_MAGIC);
1568
1569    if (EINA_FALSE == obj->manual_free)
1570      {
1571         ERR("Tried to manually free the object %p while the option has not been set; see eo_manual_free_set for more information.", obj);
1572         return;
1573      }
1574
1575    if (!obj->del)
1576      {
1577         ERR("Tried deleting the object %p while still referenced(%d).", obj, eo_ref_get(obj));
1578         return;
1579      }
1580
1581    _eo_free(obj);
1582 }