summaryrefslogtreecommitdiff
path: root/src/lib/eina
diff options
context:
space:
mode:
authorCedric BAIL <cedric@osg.samsung.com>2015-04-29 09:47:58 +0200
committerCedric BAIL <cedric@osg.samsung.com>2015-04-29 09:47:58 +0200
commit32d614639fe7fdbc03dc93da185df3ba80c8fdd9 (patch)
tree0881da77715eee2ef49978ec901c4a8c57b09d9b /src/lib/eina
parentc086d505a9f0a311ed6e477117ec0e72502ad5e6 (diff)
eina: in fact this is gone and won't come back.
Eo and Efl.Model are here for that task.
Diffstat (limited to 'src/lib/eina')
-rw-r--r--src/lib/eina/eina_model.c5497
-rw-r--r--src/lib/eina/eina_model.h3146
-rw-r--r--src/lib/eina/eina_object.c852
-rw-r--r--src/lib/eina/eina_object.h80
4 files changed, 0 insertions, 9575 deletions
diff --git a/src/lib/eina/eina_model.c b/src/lib/eina/eina_model.c
deleted file mode 100644
index 99380e2e66..0000000000
--- a/src/lib/eina/eina_model.c
+++ /dev/null
@@ -1,5497 +0,0 @@
1/* EINA - EFL data type library
2 * Copyright (C) 2012 ProFUSION embedded systems
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library;
16 * if not, see <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H
20# include "config.h"
21#endif
22
23#ifdef HAVE_EXECINFO_H
24#include <execinfo.h>
25#endif
26
27#include "eina_config.h"
28#include "eina_private.h"
29#include "eina_alloca.h"
30#include "eina_log.h"
31#include "eina_mempool.h"
32#include "eina_lock.h"
33#include "eina_inlist.h"
34#include "eina_strbuf.h"
35
36/* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
37#include "eina_safety_checks.h"
38#include "eina_value.h" /* eina-safety used in inline.x */
39#include "eina_model.h"
40
41/*============================================================================*
42 * Local *
43 *============================================================================*/
44
45/**
46 * @cond LOCAL
47 */
48
49static Eina_Mempool *_eina_model_mp = NULL;
50static Eina_Hash *_eina_model_inner_mps = NULL;
51static Eina_Lock _eina_model_inner_mps_lock;
52static char *_eina_model_mp_choice = NULL;
53static Eina_Hash *_eina_model_descriptions = NULL;
54static Eina_Lock _eina_model_descriptions_lock;
55static int _eina_model_log_dom = -1;
56static enum {
57 EINA_MODEL_DEBUG_NONE = 0,
58 EINA_MODEL_DEBUG_CHECK = 1,
59 EINA_MODEL_DEBUG_BACKTRACE = 2,
60} _eina_model_debug = EINA_MODEL_DEBUG_NONE;
61static Eina_Lock _eina_model_debug_list_lock;
62static Eina_List *_eina_model_debug_list = NULL;
63
64static const char _eina_model_str_deleted[] = "deleted";
65static const char _eina_model_str_freed[] = "freed";
66static const char _eina_model_str_property_set[] = "property,set";
67static const char _eina_model_str_property_del[] = "property,deleted";
68static const char _eina_model_str_children_changed[] = "children,changed";
69static const char _eina_model_str_child_inserted[] = "child,inserted";
70static const char _eina_model_str_child_set[] = "child,set";
71static const char _eina_model_str_child_del[] = "child,deleted";
72static const char _eina_model_str_loaded[] = "loaded";
73static const char _eina_model_str_unloaded[] = "unloaded";
74static const char _eina_model_str_properties_loaded[] = "properties,loaded";
75static const char _eina_model_str_properties_unloaded[] = "properties,unloaded";
76static const char _eina_model_str_children_loaded[] = "children,loaded";
77static const char _eina_model_str_children_unloaded[] = "children,unloaded";
78
79#ifdef CRI
80#undef CRI
81#endif
82#define CRI(...) EINA_LOG_DOM_CRIT(_eina_model_log_dom, __VA_ARGS__)
83
84#ifdef ERR
85#undef ERR
86#endif
87#define ERR(...) EINA_LOG_DOM_ERR(_eina_model_log_dom, __VA_ARGS__)
88
89#ifdef WRN
90#undef WRN
91#endif
92#define WRN(...) EINA_LOG_DOM_WARN(_eina_model_log_dom, __VA_ARGS__)
93
94#ifdef INF
95#undef INF
96#endif
97#define INF(...) EINA_LOG_DOM_INFO(_eina_model_log_dom, __VA_ARGS__)
98
99#ifdef DBG
100#undef DBG
101#endif
102#define DBG(...) EINA_LOG_DOM_DBG(_eina_model_log_dom, __VA_ARGS__)
103
104
105/* convenience sort array of Eina_Model* giving compare Eina_Model* instead of
106 * Eina_Model**
107 */
108static unsigned int
109_eina_model_array_partition(Eina_Model **array, unsigned int start, unsigned int last, unsigned int pivot, Eina_Compare_Cb compare)
110{
111 Eina_Model **itr, **itr_end, *tmp, *pivot_value;
112
113 pivot_value = tmp = array[pivot];
114 array[pivot] = array[last];
115 array[last] = tmp;
116
117 pivot = start;
118 itr = array + start;
119 itr_end = array + last;
120 for (; itr < itr_end; itr++)
121 {
122 if (compare(*itr, pivot_value) < 0)
123 {
124 tmp = *itr;
125 *itr = array[pivot];
126 array[pivot] = tmp;
127 pivot++;
128 }
129 }
130
131 tmp = array[last];
132 array[last] = array[pivot];
133 array[pivot] = tmp;
134
135 return pivot;
136}
137
138static void
139_eina_model_array_sort(Eina_Model **array, unsigned int start, unsigned int last, Eina_Compare_Cb compare)
140{
141 unsigned int pivot, new_pivot;
142
143 if (last <= start)
144 return;
145
146 pivot = start + (last - start) / 2; /* avoid overflow */
147 new_pivot = _eina_model_array_partition(array, start, last, pivot, compare);
148
149 if (start + 1 < new_pivot)
150 _eina_model_array_sort(array, start, new_pivot - 1, compare);
151
152 if (new_pivot + 1 < last)
153 _eina_model_array_sort(array, new_pivot + 1, last, compare);
154}
155
156/*
157 * Most of inner allocations are made with internal mempools, types
158 * and thus instace private data will repeat and it's good to use them.
159 *
160 * To save on the number of mempools, they are kept per size, not per
161 * type.
162 *
163 * This is done by means of _eina_model_inner_alloc() and
164 * _eina_model_inner_free(), both at thread safe.
165 *
166 */
167typedef struct _Eina_Model_Inner_Mp Eina_Model_Inner_Mp;
168struct _Eina_Model_Inner_Mp
169{
170 Eina_Mempool *mempool;
171 int refcount;
172};
173
174static inline void
175_eina_model_inner_mp_dispose(int size, Eina_Model_Inner_Mp *imp)
176{
177 EINA_SAFETY_ON_FALSE_RETURN(imp->refcount == 0);
178
179 eina_hash_del_by_key(_eina_model_inner_mps, &size);
180 eina_mempool_del(imp->mempool);
181 free(imp);
182}
183
184static inline Eina_Model_Inner_Mp *
185_eina_model_inner_mp_get(int size)
186{
187 Eina_Model_Inner_Mp *imp = eina_hash_find(_eina_model_inner_mps, &size);
188 if (imp) return imp;
189
190 imp = malloc(sizeof(Eina_Model_Inner_Mp));
191 if (!imp)
192 return NULL;
193
194 imp->refcount = 0;
195
196 imp->mempool = eina_mempool_add(_eina_model_mp_choice,
197 "Eina_Model_Inner_Mp", NULL, size, 16);
198 if (!imp->mempool)
199 {
200 free(imp);
201 return NULL;
202 }
203
204 if (!eina_hash_add(_eina_model_inner_mps, &size, imp))
205 {
206 eina_mempool_del(imp->mempool);
207 free(imp);
208 return NULL;
209 }
210
211 return imp;
212}
213
214static inline void *
215_eina_model_inner_alloc_internal(int size)
216{
217 Eina_Model_Inner_Mp *imp;
218 void *mem;
219
220 imp = _eina_model_inner_mp_get(size);
221 if (!imp) return NULL;
222
223 mem = eina_mempool_malloc(imp->mempool, size);
224 if (mem) imp->refcount++;
225 else if (imp->refcount == 0) _eina_model_inner_mp_dispose(size, imp);
226
227 return mem;
228}
229
230static inline void
231_eina_model_inner_free_internal(int size, void *mem)
232{
233 Eina_Model_Inner_Mp *imp = eina_hash_find(_eina_model_inner_mps, &size);
234 EINA_SAFETY_ON_NULL_RETURN(imp);
235
236 eina_mempool_free(imp->mempool, mem);
237
238 imp->refcount--;
239 if (imp->refcount > 0) return;
240 _eina_model_inner_mp_dispose(size, imp);
241}
242
243static void *
244_eina_model_inner_alloc(size_t size)
245{
246 void *mem;
247
248 if (size > 512) return malloc(size);
249
250 eina_lock_take(&_eina_model_inner_mps_lock);
251 mem = _eina_model_inner_alloc_internal(size);
252 eina_lock_release(&_eina_model_inner_mps_lock);
253
254 return mem;
255}
256
257static void
258_eina_model_inner_free(size_t size, void *mem)
259{
260 if (size > 512)
261 {
262 free(mem);
263 return;
264 }
265
266 eina_lock_take(&_eina_model_inner_mps_lock);
267 _eina_model_inner_free_internal(size, mem);
268 eina_lock_release(&_eina_model_inner_mps_lock);
269}
270
271
272typedef union _Eina_Model_Provider Eina_Model_Provider;
273union _Eina_Model_Provider
274{
275 const Eina_Model_Type *type;
276 const Eina_Model_Interface *iface;
277};
278
279/* store event name to aid searching */
280typedef struct _Eina_Model_Event_Description_Cache Eina_Model_Event_Description_Cache;
281struct _Eina_Model_Event_Description_Cache
282{
283 const char *name;
284 const Eina_Model_Event_Description *desc;
285 Eina_Model_Provider provider;
286};
287
288/* description is an optimized structure for type. It's built at runtime
289 * to avoid user input errors and help declaration.
290 *
291 * lookups (ifaces, events) are sorted for binary search.
292 *
293 * recursion is avoided by expansion of every possible value in "cache"
294 * struct.
295 *
296 * the first usable operation is stopred for type at "ops" struct,
297 * avoiding usage of _eina_model_type_find_offset().
298 *
299 * Get a model type description using _eina_model_description_get(),
300 * when it's not used anymore use
301 * _eina_model_description_dispose(). These operations are thread
302 * safe.
303 */
304typedef struct _Eina_Model_Description Eina_Model_Description;
305struct _Eina_Model_Description
306{
307 struct {
308 const Eina_Model_Type **types; /* size = total.types */
309 const Eina_Model_Interface **ifaces; /* sorted, size = total.ifaces */
310 Eina_Model_Provider *privates; /* size = total.privates (types + ifaces) */
311 Eina_Model_Event_Description_Cache *events; /* size = total.events */
312 } cache;
313 struct {
314 /* ops are the topmost operation to use for type/interface */
315 struct {
316 Eina_Bool (*setup)(Eina_Model *model);
317 Eina_Bool (*flush)(Eina_Model *model);
318 Eina_Bool (*constructor)(Eina_Model *model);
319 Eina_Bool (*destructor)(Eina_Model *model);
320 Eina_Bool (*copy)(const Eina_Model *src, Eina_Model *dst);
321 Eina_Bool (*deep_copy)(const Eina_Model *src, Eina_Model *dst);
322 Eina_Bool (*compare)(const Eina_Model *a, const Eina_Model *b, int *cmp);
323 Eina_Bool (*load)(Eina_Model *model);
324 Eina_Bool (*unload)(Eina_Model *model);
325 Eina_Bool (*property_get)(const Eina_Model *model, const char *name, Eina_Value *value);
326 Eina_Bool (*property_set)(Eina_Model *model, const char *name, const Eina_Value *value);
327 Eina_Bool (*property_del)(Eina_Model *model, const char *name);
328 Eina_List *(*properties_names_list_get)(const Eina_Model *model);
329 int (*child_count)(const Eina_Model *model);
330 Eina_Model *(*child_get)(const Eina_Model *model, unsigned int position);
331 Eina_Bool (*child_set)(Eina_Model *model, unsigned int position, Eina_Model *child);
332 Eina_Bool (*child_del)(Eina_Model *model, unsigned int position);
333 Eina_Bool (*child_insert_at)(Eina_Model *model, unsigned int position, Eina_Model *child);
334 int (*child_find)(const Eina_Model *model, unsigned int start_position, const Eina_Model *other);
335 int (*child_criteria_match)(const Eina_Model *model, unsigned int start_position, Eina_Each_Cb match, const void *data);
336 void (*child_sort)(Eina_Model *model, Eina_Compare_Cb compare);
337 Eina_Iterator *(*child_iterator_get)(Eina_Model *model, unsigned int start, unsigned int count);
338 Eina_Iterator *(*child_reversed_iterator_get)(Eina_Model *model, unsigned int start, unsigned int count);
339 Eina_Iterator *(*child_sorted_iterator_get)(Eina_Model *model, unsigned int start, unsigned int count, Eina_Compare_Cb compare);
340 Eina_Iterator *(*child_filtered_iterator_get)(Eina_Model *model, unsigned int start, unsigned int count, Eina_Each_Cb match, const void *data);
341 char *(*to_string)(const Eina_Model *model); /**< used to represent model as string, usually for debug purposes or user convenience */
342 const void **extension;
343 } type;
344 } ops;
345 struct {
346 unsigned int types;
347 unsigned int ifaces;
348 unsigned int privates;
349 unsigned int size; /* sum of all private sizes */
350 unsigned int events;
351 } total;
352 int refcount;
353};
354
355static Eina_Bool
356_eina_model_description_type_fill(Eina_Model_Description *desc, const Eina_Model_Type *type)
357{
358 const Eina_Model_Type *itr, *last_itr = NULL;
359 unsigned int count, child_size = 0;
360
361 for (count = 0, itr = type; itr != NULL; itr = itr->parent, count++)
362 {
363 if (itr->version != EINA_MODEL_TYPE_VERSION)
364 {
365 CRI("Type %p version is %u, expected %u instead.",
366 itr, itr->version, EINA_MODEL_TYPE_VERSION);
367 return EINA_FALSE;
368 }
369 if (!itr->name)
370 {
371 CRI("Type %p provides no name!", itr);
372 return EINA_FALSE;
373 }
374 if (itr->type_size < sizeof(Eina_Model_Type))
375 {
376 CRI("Type %p %s size must be >= sizeof(Eina_Model_Type)!",
377 itr, itr->name);
378 return EINA_FALSE;
379 }
380 if (child_size == 0) child_size = itr->type_size;
381 else if (child_size < itr->type_size)
382 {
383 CRI("Type %p %s size is bigger than its child type %p %s!",
384 itr, itr->name, last_itr, last_itr->name);
385 return EINA_FALSE;
386 }
387 last_itr = itr;
388
389#define DEF_METH(meth) \
390 if (!desc->ops.type.meth) desc->ops.type.meth = itr->meth
391 DEF_METH(setup);
392 DEF_METH(flush);
393 DEF_METH(constructor);
394 DEF_METH(destructor);
395 DEF_METH(copy);
396 DEF_METH(deep_copy);
397 DEF_METH(compare);
398 DEF_METH(load);
399 DEF_METH(unload);
400 DEF_METH(property_get);
401 DEF_METH(property_set);
402 DEF_METH(property_del);
403 DEF_METH(properties_names_list_get);
404 DEF_METH(child_count);
405 DEF_METH(child_get);
406 DEF_METH(child_set);
407 DEF_METH(child_del);
408 DEF_METH(child_insert_at);
409 DEF_METH(child_find);
410 DEF_METH(child_criteria_match);
411 DEF_METH(child_sort);
412 DEF_METH(child_iterator_get);
413 DEF_METH(child_reversed_iterator_get);
414 DEF_METH(child_sorted_iterator_get);
415 DEF_METH(child_filtered_iterator_get);
416 DEF_METH(to_string);
417#undef DEF_METH
418
419 if ((!itr->parent) && (itr != EINA_MODEL_TYPE_BASE))
420 {
421 CRI("Type %p (%s) does not inherit from EINA_MODEL_TYPE_BASE!",
422 type, type->name);
423 return EINA_FALSE;
424 }
425 }
426
427#define CK_METH(meth) \
428 if (!desc->ops.type.meth) \
429 { \
430 CRI("Mandatory method "#meth \
431 "() was not provided by type %p (%s).", \
432 type, type->name); \
433 return EINA_FALSE; \
434 }
435 CK_METH(setup);
436 CK_METH(flush);
437 CK_METH(constructor);
438 CK_METH(destructor);
439 CK_METH(property_get);
440#undef CK_METH
441
442 if (child_size <= sizeof(Eina_Model_Type))
443 desc->ops.type.extension = NULL;
444 else
445 {
446 unsigned ext_size = child_size - sizeof(Eina_Model_Type);
447 unsigned ext_count = ext_size / sizeof(void *);
448
449 if (ext_size % sizeof(void *) != 0)
450 {
451 CRI("Extension size %u is not multiple of sizeof(void*)",
452 ext_size);
453 return EINA_FALSE;
454 }
455
456 desc->ops.type.extension = calloc(ext_count, sizeof(void *));
457 EINA_SAFETY_ON_NULL_RETURN_VAL(desc->ops.type.extension, EINA_FALSE);
458
459 for (itr = type; itr != NULL; itr = itr->parent)
460 {
461 unsigned cur_size = itr->type_size - sizeof(Eina_Model_Type);
462 unsigned i, cur_count = cur_size / sizeof(void *);
463 const void * const *ptr = (const void **)((const char *)itr + sizeof(Eina_Model_Type));
464
465 if (cur_size == 0) break;
466
467 for (i = 0; i < cur_count; i++)
468 {
469 if (desc->ops.type.extension[i]) continue;
470 desc->ops.type.extension[i] = ptr[i];
471 }
472 }
473 }
474
475 desc->cache.types = malloc(count * sizeof(Eina_Model_Type *));
476 EINA_SAFETY_ON_NULL_GOTO(desc->cache.types, cache_types_failed);
477 desc->total.types = count;
478
479 for (count = 0, itr = type; itr != NULL; itr = itr->parent, count++)
480 desc->cache.types[count] = itr;
481
482 return EINA_TRUE;
483
484 cache_types_failed:
485 free(desc->ops.type.extension);
486 return EINA_FALSE;
487}
488
489static inline Eina_Bool
490_eina_model_interface_implements(const Eina_Model_Interface *iface, const Eina_Model_Interface *query)
491{
492 const Eina_Model_Interface **itr;
493
494 if (iface == query)
495 return EINA_TRUE;
496
497 if (!iface->interfaces)
498 return EINA_FALSE;
499
500 for (itr = iface->interfaces; *itr != NULL; itr++)
501 if (_eina_model_interface_implements(*itr, query))
502 return EINA_TRUE;
503
504 return EINA_FALSE;
505}
506
507/* apply topological sort and remove duplicates */
508/*
509 * TODO: Topological sort will only work for linked interfaces, but
510 * will ignore original ordering provided by types. Consider the
511 * following:
512 *
513 * - A_Type -> X_Iface (name: "MyIface")
514 * - B_Type -> Y_Iface (name: "MyIface")
515 *
516 * Both X_Iface and Y_Iface are different implementations of the
517 * "MyIface".
518 *
519 * B_Type inherits from A_Type, then Y_Iface must be looked up
520 * first, even though there is no link between Y_Iface and
521 * X_Iface.
522 *
523 * However, the way the current topological sort behaves, the
524 * roots may come out in any order. We need a stable version
525 * that sorts roots before removing them from graph.
526 *
527 * Thanks to Tasn to report it :-)
528 */
529static Eina_Bool
530_eina_model_description_ifaces_fix(Eina_Model_Description *desc)
531{
532 struct node {
533 const Eina_Model_Interface *iface;
534 unsigned int users;
535 Eina_List *deps;
536 } *nodes, **pending, **roots;
537 unsigned int n_nodes = desc->total.ifaces, n_pending = 0, n_roots = 0, i, j;
538 Eina_Bool ret = EINA_TRUE;
539
540 nodes = alloca(n_nodes * sizeof(struct node));
541 pending = alloca(n_nodes * sizeof(struct node *));
542 roots = alloca(n_nodes * sizeof(struct node *));
543
544 /* populate */
545 for (i = 0, j = 0; i < n_nodes; i++)
546 {
547 unsigned int k;
548 for (k = 0; k < j; k++)
549 {
550 if (nodes[k].iface == desc->cache.ifaces[i])
551 break;
552 }
553 if (k < j)
554 continue; /* already exists */
555
556 nodes[j].iface = desc->cache.ifaces[i];
557 nodes[j].users = 0;
558 nodes[j].deps = NULL;
559 j++;
560 }
561 n_nodes = j;
562
563 for (i = 0; i < n_nodes; i++)
564 {
565 for (j = 0; j < n_nodes; j++)
566 {
567 if (i == j) continue;
568 if (!_eina_model_interface_implements(nodes[j].iface,
569 nodes[i].iface))
570 continue;
571
572 nodes[i].users++;
573 nodes[j].deps = eina_list_append(nodes[j].deps, nodes + i);
574 }
575 }
576 for (i = 0; i < n_nodes; i++)
577 {
578 if (nodes[i].users == 0)
579 {
580 roots[n_roots] = nodes + i;
581 n_roots++;
582 }
583 else
584 {
585 pending[n_pending] = nodes + i;
586 n_pending++;
587 }
588 }
589
590 /* topological sort */
591 desc->total.ifaces = 0;
592 while (n_roots > 0)
593 {
594 struct node *r, *d;
595
596 /* TODO: sort roots using input order? Or at least study if
597 * it's enough to change roots append to prepend.
598 *
599 * See comments above.
600 */
601 n_roots--;
602 r = roots[n_roots];
603
604 desc->cache.ifaces[desc->total.ifaces] = r->iface;
605 desc->total.ifaces++;
606
607 EINA_LIST_FREE(r->deps, d)
608 {
609 d->users--;
610 if (d->users > 0) continue;
611
612 roots[n_roots] = d;
613 n_roots++;
614
615 /* remove node, it became a root */
616 for (j = 0; j < n_pending; j++)
617 {
618 if (pending[j] == d)
619 {
620 n_pending--;
621 if (j < n_pending)
622 pending[j] = pending[n_pending];
623 break;
624 }
625 }
626 }
627 }
628
629 if (n_pending > 0)
630 {
631 ERR("Dependency loop found for interfaces!");
632 for (i = 0; i < n_pending; i++)
633 ERR("%p (%s) is part of dependency loop!",
634 pending[i]->iface, pending[i]->iface->name);
635 CRI("Cannot use type %p (%s) with broken interfaces!",
636 desc->cache.types[0], desc->cache.types[0]->name);
637 free(desc->cache.ifaces);
638 ret = EINA_FALSE;
639 }
640
641 /* likely from still pending (dependency loops) */
642 for (i = 0; i < n_nodes; i++)
643 eina_list_free(nodes[i].deps);
644
645 return ret;
646}
647
648static Eina_Bool
649_eina_model_description_ifaces_validate_and_count(const Eina_Model_Interface *iface, unsigned int *count)
650{
651 if (iface->version != EINA_MODEL_INTERFACE_VERSION)
652 {
653 CRI("Interface %p version is %u, expected %u instead.",
654 iface, iface->version, EINA_MODEL_INTERFACE_VERSION);
655 return EINA_FALSE;
656 }
657
658 if (!iface->name)
659 {
660 CRI("Interface %p provides no name!", iface);
661 return EINA_FALSE;
662 }
663
664 if (iface->interfaces)
665 {
666 const Eina_Model_Interface **itr = iface->interfaces;
667 for (; *itr != NULL; itr++)
668 if (!_eina_model_description_ifaces_validate_and_count(*itr, count))
669 return EINA_FALSE;
670 }
671
672 (*count)++;
673 return EINA_TRUE;
674}
675
676static void
677_eina_model_description_ifaces_populate(Eina_Model_Description *desc, const Eina_Model_Interface *iface)
678{
679 desc->cache.ifaces[desc->total.ifaces] = iface;
680 desc->total.ifaces++;
681
682 if (iface->interfaces)
683 {
684 const Eina_Model_Interface **itr = iface->interfaces;
685 for (; *itr != NULL; itr++)
686 _eina_model_description_ifaces_populate(desc, *itr);
687 }
688}
689
690static Eina_Bool
691_eina_model_description_ifaces_fill(Eina_Model_Description *desc)
692{
693 const Eina_Model_Type **titr, **titr_end;
694 unsigned int count;
695
696 titr = desc->cache.types;
697 titr_end = titr + desc->total.types;
698
699 /* naively count all interfaces, remove duplicates later */
700 for (count = 0; titr < titr_end; titr++)
701 {
702 const Eina_Model_Type *type = *titr;
703 const Eina_Model_Interface **iitr = type->interfaces;
704 if (!type->interfaces) continue;
705
706 for (; *iitr != NULL; iitr++)
707 if (!_eina_model_description_ifaces_validate_and_count(*iitr, &count))
708 return EINA_FALSE;
709 }
710 if (count == 0)
711 {
712 desc->cache.ifaces = NULL;
713 desc->total.ifaces = 0;
714 return EINA_TRUE;
715 }
716
717 desc->cache.ifaces = malloc(count * sizeof(Eina_Model_Interface *));
718 EINA_SAFETY_ON_NULL_RETURN_VAL(desc->cache.ifaces, EINA_FALSE);
719
720 titr = desc->cache.types;
721 desc->total.ifaces = 0;
722 for (; titr < titr_end; titr++)
723 {
724 const Eina_Model_Type *type = *titr;
725 const Eina_Model_Interface **iitr = type->interfaces;
726
727 if (!type->interfaces) continue;
728
729 for (; *iitr != NULL; iitr++)
730 _eina_model_description_ifaces_populate(desc, *iitr);
731 }
732
733 return _eina_model_description_ifaces_fix(desc);
734}
735
736static Eina_Bool
737_eina_model_description_privates_fill(Eina_Model_Description *desc)
738{
739 unsigned int i;
740
741 desc->total.privates = desc->total.types + desc->total.ifaces;
742 desc->cache.privates = malloc(desc->total.privates *
743 sizeof(Eina_Model_Provider));
744 EINA_SAFETY_ON_NULL_RETURN_VAL(desc->cache.privates, EINA_FALSE);
745
746 desc->total.size = 0;
747
748 for (i = 0; i < desc->total.types; i++)
749 {
750 const Eina_Model_Type *type = desc->cache.types[i];
751 desc->cache.privates[i].type = type;
752 if (type->private_size > 0)
753 {
754 unsigned int size = type->private_size;
755 if (size % sizeof(void *) != 0)
756 size += sizeof(void *) - (size % sizeof(void *));
757 desc->total.size += size;
758 }
759 }
760
761 for (i = 0; i < desc->total.ifaces; i++)
762 {
763 const Eina_Model_Interface *iface = desc->cache.ifaces[i];
764 desc->cache.privates[desc->total.types + i].iface = iface;
765 if (iface->private_size > 0)
766 {
767 unsigned int size = iface->private_size;
768 if (size % sizeof(void *) != 0)
769 size += sizeof(void *) - (size % sizeof(void *));
770 desc->total.size += size;
771 }
772 }
773
774 return EINA_TRUE;
775}
776
777static int
778_eina_model_description_events_cmp(const void *pa, const void *pb)
779{
780 const Eina_Model_Event_Description_Cache *a = pa, *b = pb;
781 return strcmp(a->name, b->name);
782}
783
784static int
785_eina_model_description_events_find(const Eina_Model_Description *desc, const Eina_Model_Event_Description *query)
786{
787 unsigned int i;
788 for (i = 0; i < desc->total.events; i++)
789 {
790 const Eina_Model_Event_Description_Cache *itr = desc->cache.events + i;
791 if ((itr->name == query->name) || (strcmp(itr->name, query->name) == 0))
792 return i;
793 }
794
795 return -1;
796}
797
798/* warn and remove duplicates, sort items to speed up lookups */
799static Eina_Bool
800_eina_model_description_events_fill(Eina_Model_Description *desc)
801{
802 unsigned int i, count = 0, type_events;
803
804 for (i = 0; i < desc->total.types; i++)
805 {
806 const Eina_Model_Event_Description *itr = desc->cache.types[i]->events;
807 if (!itr) continue;
808 for (; itr->name != NULL; itr++)
809 {
810 count++;
811 }
812 }
813 type_events = count;
814
815 for (i = 0; i < desc->total.ifaces; i++)
816 {
817 const Eina_Model_Event_Description *itr = desc->cache.ifaces[i]->events;
818 if (!itr) continue;
819 for (; itr->name != NULL; itr++)
820 count++;
821 }
822
823 if (count == 0)
824 {
825 desc->cache.events = NULL;
826 desc->total.events = 0;
827 return EINA_TRUE;
828 }
829
830 desc->cache.events = malloc(count *
831 sizeof(Eina_Model_Event_Description_Cache));
832 EINA_SAFETY_ON_NULL_RETURN_VAL(desc->cache.events, EINA_FALSE);
833 desc->total.events = 0;
834
835 for (i = 0; i < desc->total.types; i++)
836 {
837 const Eina_Model_Type *mtype = desc->cache.types[i];
838 const Eina_Model_Event_Description *itr = mtype->events;
839 if (!itr) continue;
840 for (; itr->name != NULL; itr++)
841 {
842 int j = _eina_model_description_events_find(desc, itr);
843 if (j >= 0)
844 {
845 const Eina_Model_Event_Description_Cache *o = desc->cache.events + j;
846 const Eina_Model_Type *omtype = o->provider.type;
847 WRN("Ignored duplicated event '%s' (type: '%s') from "
848 "model type %p (%s): already exists with type '%s' "
849 "from model type %p (%s)",
850 itr->name,
851 itr->type ? itr->type : "",
852 mtype, mtype->name,
853 o->desc->type ? o->desc->type : "",
854 omtype, omtype->name);
855 continue;
856 }
857
858 desc->cache.events[desc->total.events].name = itr->name;
859 desc->cache.events[desc->total.events].desc = itr;
860 desc->cache.events[desc->total.events].provider.type = mtype;
861 desc->total.events++;
862 }
863 }
864
865 for (i = 0; i < desc->total.ifaces; i++)
866 {
867 const Eina_Model_Interface *miface = desc->cache.ifaces[i];
868 const Eina_Model_Event_Description *itr = desc->cache.ifaces[i]->events;
869 if (!itr) continue;
870 for (; itr->name != NULL; itr++)
871 {
872 int j = _eina_model_description_events_find(desc, itr);
873 if (j >= 0)
874 {
875 const Eina_Model_Event_Description_Cache *o = desc->cache.events + j;
876 if ((unsigned)j < type_events)
877 {
878 const Eina_Model_Type *omtype = o->provider.type;
879 WRN("Ignored duplicated event '%s' (type: '%s') from "
880 "model interface %p (%s): already exists with "
881 "type '%s' from model interface %p (%s)",
882 itr->name,
883 itr->type ? itr->type : "",
884 miface, miface->name,
885 o->desc->type ? o->desc->type : "",
886 omtype, omtype->name);
887 }
888 else
889 {
890 const Eina_Model_Interface *omiface = o->provider.iface;
891 WRN("Ignored duplicated event '%s' (iface: '%s') from "
892 "model interface %p (%s): already exists with "
893 "interface '%s' from model interface %p (%s)",
894 itr->name,
895 itr->type ? itr->type : "",
896 miface, miface->name,
897 o->desc->type ? o->desc->type : "",
898 omiface, omiface->name);
899 }
900 continue;
901 }
902
903 desc->cache.events[desc->total.events].name = itr->name;
904 desc->cache.events[desc->total.events].desc = itr;
905 desc->cache.events[desc->total.events].provider.iface = miface;
906 desc->total.events++;
907 }
908 }
909
910 qsort(desc->cache.events, desc->total.events,
911 sizeof(Eina_Model_Event_Description_Cache),
912 _eina_model_description_events_cmp);
913
914 return EINA_TRUE;
915}
916
917static const Eina_Model_Description *
918_eina_model_description_get_internal(const Eina_Model_Type *type)
919{
920 Eina_Model_Description *desc;
921
922 desc = eina_hash_find(_eina_model_descriptions, &type);
923 if (desc)
924 {
925 desc->refcount++;
926 return desc;
927 }
928
929 desc = calloc(1, sizeof(Eina_Model_Description));
930 EINA_SAFETY_ON_NULL_RETURN_VAL(desc, NULL);
931
932 if (!_eina_model_description_type_fill(desc, type)) goto failed_type;
933 if (!_eina_model_description_ifaces_fill(desc)) goto failed_ifaces;
934 if (!_eina_model_description_privates_fill(desc)) goto failed_privates;
935 if (!_eina_model_description_events_fill(desc)) goto failed_events;
936 if (!eina_hash_add(_eina_model_descriptions, &type, desc)) goto failed_hash;
937
938 desc->refcount = 1;
939 return desc;
940
941 failed_hash:
942 free(desc->cache.events);
943 failed_events:
944 free(desc->cache.privates);
945 failed_privates:
946 free(desc->cache.ifaces);
947 failed_ifaces:
948 free(desc->cache.types);
949 free(desc->ops.type.extension);
950 failed_type:
951 free(desc);
952 return NULL;
953}
954
955static void
956_eina_model_description_dispose_internal(Eina_Model_Description *desc)
957{
958 const Eina_Model_Type *type;
959
960 EINA_SAFETY_ON_FALSE_RETURN(desc->refcount > 0);
961 desc->refcount--;
962 if (desc->refcount > 0) return;
963
964 type = desc->cache.types[0];
965 if (!eina_hash_del_by_key(_eina_model_descriptions, &type))
966 ERR("Cannot find type %p (%s) in descriptions hash!",
967 type, type->name);
968
969 INF("Disposed model description for type %p (%s)", type, type->name);
970
971 free(desc->ops.type.extension);
972 free(desc->cache.types);
973 free(desc->cache.ifaces);
974 free(desc->cache.privates);
975 free(desc->cache.events);
976 free(desc);
977}
978
979static const Eina_Model_Description *
980_eina_model_description_get(const Eina_Model_Type *type)
981{
982 const Eina_Model_Description *desc;
983
984 eina_lock_take(&_eina_model_descriptions_lock);
985 desc = _eina_model_description_get_internal(type);
986 eina_lock_release(&_eina_model_descriptions_lock);
987
988 return desc;
989}
990
991static void
992_eina_model_description_dispose(const Eina_Model_Description *desc)
993{
994 eina_lock_take(&_eina_model_descriptions_lock);
995 _eina_model_description_dispose_internal((Eina_Model_Description *)desc);
996 eina_lock_release(&_eina_model_descriptions_lock);
997}
998
999static inline int
1000_eina_model_description_event_id_find(const Eina_Model_Description *desc, const char *event_name)
1001{
1002 const Eina_Model_Event_Description_Cache *cache;
1003 Eina_Model_Event_Description_Cache criteria_match;
1004
1005 criteria_match.name = event_name;
1006 cache = bsearch(&criteria_match, desc->cache.events, desc->total.events,
1007 sizeof(Eina_Model_Event_Description_Cache),
1008 _eina_model_description_events_cmp);
1009 if (!cache)
1010 {
1011 ERR("No event named %s for type %p (%s)", event_name,
1012 desc->cache.types[0], desc->cache.types[0]->name);
1013 return -1;
1014 }
1015
1016 return cache - desc->cache.events;
1017}
1018
1019/*
1020 * Model management and book keeping
1021 */
1022typedef struct _Eina_Model_Event_Listener Eina_Model_Event_Listener;
1023struct _Eina_Model_Event_Listener
1024{
1025 EINA_INLIST;
1026 Eina_Model_Event_Cb cb;
1027 const void *data;
1028 Eina_Bool deleted:1;
1029};
1030
1031struct _Eina_Model
1032{
1033 const Eina_Model_Description *desc; /**< optimized model description */
1034 struct {
1035 Eina_Inlist **entries; /**< connected/listeners for each event, array of lists of Eina_Model_Event_Listener */
1036 Eina_List **deleted; /**< deleted listeners while was walking. array of lists of Eina_Model_Event_Listener with deleted flag */
1037 int *freeze; /**< freeze count for each event */
1038 int walking; /**< increased while walking entries lists */
1039 } listeners;
1040 void **privates; /**< private data per type and interface, each level gets its own stuff */
1041 Eina_Inlist *xrefs; /**< if EINA_MODEL_DEBUG and eina_model_xref() is used */
1042 int refcount; /**< number of users of this model instance */
1043 Eina_Bool deleted:1; /**< if deleted but still have references */
1044 EINA_MAGIC
1045};
1046
1047static inline Eina_Bool
1048_eina_model_type_check(const Eina_Model_Type *type)
1049{
1050 EINA_SAFETY_ON_NULL_RETURN_VAL(type, EINA_FALSE);
1051 EINA_SAFETY_ON_FALSE_RETURN_VAL(type->version == EINA_MODEL_TYPE_VERSION,
1052 EINA_FALSE);
1053 return EINA_TRUE;
1054}
1055
1056/* find in type hierarchy the first one that the given offset is not a null
1057 * pointer. Use this to discover which method to call on a parent.
1058 */
1059static const void *
1060_eina_model_type_find_offset(const Eina_Model_Type *type, unsigned int offset)
1061{
1062 const unsigned char *ptr = (const unsigned char *)type;
1063 const void **addr = (const void **)(ptr + offset);
1064
1065 if (*addr) return *addr;
1066 if (!type->parent) return NULL;
1067 return _eina_model_type_find_offset(type->parent, offset);
1068}
1069
1070/* find in interface hierarchy the first one that the given offset is
1071 * not a null pointer. Use this to discover which method to call on a
1072 * parent.
1073 *
1074 * TODO: Keep Eina_Model_Interface_Description with topological sorted
1075 * entries for each interface?
1076 * I smell problems with the current code in more complex
1077 * situations (k-s)
1078 *
1079 * iface1
1080 * ^
1081 * |
1082 * .---------+---------.
1083 * | | |
1084 * iface2 iface3 iface4
1085 * ^ ^ ^
1086 * | | |
1087 * `---------+---------'
1088 * |
1089 * iface5
1090 *
1091 * It should look: iface5 -> iface2 -> iface3 -> iface4 -> iface1
1092 * Now it does: iface5 -> iface2 -> iface1 -> iface3 -> iface1 -> iface4 -> iface1
1093 *
1094 *
1095 * iface1
1096 * ^
1097 * |
1098 * iface2
1099 * ^
1100 * |
1101 * .---------+---------.
1102 * | |
1103 * iface3 iface4
1104 * ^ ^
1105 * | |
1106 * `---------+---------'
1107 * |
1108 * iface5
1109 *
1110 * It should look: iface5 -> iface3 -> iface4 -> iface2 -> iface1
1111 * Now it does: iface5 -> iface3 -> iface2 -> iface1 -> iface4 -> iface2 -> iface1
1112 *
1113 *
1114 * iface1 iface2
1115 * ^ ^
1116 * | |
1117 * `---------+---------'
1118 * |
1119 * iface3
1120 *
1121 * It should look: iface3 -> iface1 -> iface2
1122 * Now it does: iface3 -> iface1 -> iface2
1123 *
1124 * For the common case it should work, let's see.
1125 */
1126static const void *
1127_eina_model_interface_find_offset(const Eina_Model_Interface *iface, unsigned int offset)
1128{
1129 const Eina_Model_Interface **itr;
1130 const unsigned char *ptr = (const unsigned char *)iface;
1131 const void **addr = (const void **)(ptr + offset);
1132
1133 if (offset + sizeof(void *) > iface->interface_size) return NULL;
1134
1135 if (*addr) return *addr;
1136 if (!iface->interfaces) return NULL;
1137
1138 for (itr = iface->interfaces; *itr != NULL; itr++)
1139 {
1140 const void *r = _eina_model_interface_find_offset(*itr, offset);
1141 if (r)
1142 return r;
1143 }
1144
1145 return NULL;
1146}
1147
1148static void
1149_eina_model_event_callback_free_deleted(Eina_Model *model)
1150{
1151 unsigned int i;
1152
1153 for (i = 0; i < model->desc->total.events; i++)
1154 {
1155 Eina_Model_Event_Listener *el;
1156 EINA_LIST_FREE(model->listeners.deleted[i], el)
1157 {
1158 model->listeners.entries[i] = eina_inlist_remove
1159 (model->listeners.entries[i], EINA_INLIST_GET(el));
1160 _eina_model_inner_free(sizeof(Eina_Model_Event_Listener), el);
1161 }
1162 }
1163
1164 _eina_model_inner_free(model->desc->total.events * sizeof(Eina_List *),
1165 model->listeners.deleted);
1166 model->listeners.deleted = NULL;
1167}
1168
1169static inline Eina_Bool
1170_eina_model_event_callback_call(Eina_Model *model, const char *name, const void *event_info)
1171{
1172 Eina_Inlist *lst;
1173 Eina_Model_Event_Listener *el;
1174 const Eina_Model_Event_Description *ev_desc;
1175 int event_id = _eina_model_description_event_id_find(model->desc, name);
1176
1177 if (event_id < 0) return EINA_FALSE;
1178 if (!model->listeners.entries) return EINA_TRUE;
1179
1180 if ((model->listeners.freeze) && (model->listeners.freeze[event_id]))
1181 {
1182 DBG("Ignored event callback '%s' of model %p (%s): frozen",
1183 name, model, model->desc->cache.types[0]->name);
1184 return EINA_TRUE;
1185 }
1186
1187 lst = model->listeners.entries[event_id];
1188 if (!lst) return EINA_TRUE;
1189
1190 ev_desc = model->desc->cache.events[event_id].desc;
1191
1192 model->listeners.walking++;
1193 EINA_INLIST_FOREACH(lst, el)
1194 {
1195 if (el->deleted) continue;
1196 el->cb((void *)el->data, model, ev_desc, (void *)event_info);
1197 }
1198 model->listeners.walking--;
1199
1200 if ((model->listeners.walking == 0) && (model->listeners.deleted))
1201 _eina_model_event_callback_free_deleted(model);
1202
1203 return EINA_FALSE;
1204}
1205
1206static void _eina_model_unref(Eina_Model *model);
1207
1208/**
1209 * @endcond
1210 */
1211
1212/* EINA_MODEL_TYPE_BASE: base of all other types **********************/
1213
1214static Eina_Bool
1215_eina_model_type_base_setup(Eina_Model *model)
1216{
1217 DBG("base setup of %p", model);
1218 return EINA_TRUE;
1219}
1220
1221static Eina_Bool
1222_eina_model_type_base_flush(Eina_Model *model)
1223{
1224 DBG("base flush of %p", model);
1225 return EINA_TRUE;
1226}
1227
1228static Eina_Bool
1229_eina_model_type_base_constructor(Eina_Model *model)
1230{
1231 DBG("base constructor of %p", model);
1232 return EINA_TRUE;
1233}
1234
1235static Eina_Bool
1236_eina_model_type_base_destructor(Eina_Model *model)
1237{
1238 DBG("base destructor of %p", model);
1239 return EINA_TRUE;
1240}
1241
1242static Eina_Bool
1243_eina_model_type_base_properties_copy(const Eina_Model *model, Eina_Model *copy)
1244{
1245 Eina_List *l, *props = eina_model_properties_names_list_get(model);
1246 const char *name;
1247 EINA_LIST_FOREACH(props, l, name)
1248 {
1249 Eina_Value tmp;
1250 if (!eina_model_property_get(model, name, &tmp))
1251 {
1252 ERR("Could not get property %s from model %p (%s)",
1253 name, model, model->desc->cache.types[0]->name);
1254 eina_model_properties_names_list_free(props);
1255 return EINA_FALSE;
1256 }
1257 if (!eina_model_property_set(copy, name, &tmp))
1258 {
1259 ERR("Could not set property %s on model %p (%s)",
1260 name, copy, copy->desc->cache.types[0]->name);
1261 eina_value_flush(&tmp);
1262 eina_model_properties_names_list_free(props);
1263 return EINA_FALSE;
1264 }
1265 eina_value_flush(&tmp);
1266 }
1267 eina_model_properties_names_list_free(props);
1268 return EINA_TRUE;
1269}
1270
1271static Eina_Bool
1272_eina_model_type_base_children_copy(const Eina_Model *model, Eina_Model *copy)
1273{
1274 int i, count = eina_model_child_count(model);
1275
1276 if (count < 0)
1277 {
1278 ERR("Could not get children count of model %p (%s)",
1279 model, model->desc->cache.types[0]->name);
1280 return EINA_FALSE;
1281 }
1282
1283 for (i = 0; i < count; i++)
1284 {
1285 Eina_Model *child = eina_model_child_get(model, i);
1286 Eina_Bool ret;
1287
1288 if (!child)
1289 {
1290 ERR("Could not get child #%d from model %p (%s)",
1291 i, model, model->desc->cache.types[0]->name);
1292 return EINA_FALSE;
1293 }
1294
1295 ret = eina_model_child_insert_at(copy, i, child);
1296 _eina_model_unref(child);
1297
1298 if (!ret)
1299 {
1300 ERR("Could not set child #%d on model %p (%s)",
1301 i, copy, copy->desc->cache.types[0]->name);
1302 return EINA_FALSE;
1303 }
1304 }
1305
1306 return EINA_TRUE;
1307}
1308
1309static Eina_Bool
1310_eina_model_type_base_copy(const Eina_Model *model, Eina_Model *copy)
1311{
1312 DBG("base copy of %p to %p", model, copy);
1313
1314 return _eina_model_type_base_properties_copy(model, copy) &&
1315 _eina_model_type_base_children_copy(model, copy);
1316}
1317
1318static Eina_Bool
1319_eina_model_type_base_children_deep_copy(const Eina_Model *model, Eina_Model *copy)
1320{
1321 int i, count = eina_model_child_count(model);
1322
1323 if (count < 0)
1324 {
1325 ERR("Could not get children count of model %p (%s)",
1326 model, model->desc->cache.types[0]->name);
1327 return EINA_FALSE;
1328 }
1329
1330 for (i = 0; i < count; i++)
1331 {
1332 Eina_Model *child_copy, *child = eina_model_child_get(model, i);
1333 Eina_Bool ret;
1334
1335 if (!child)
1336 {
1337 ERR("Could not get child #%d from model %p (%s)",
1338 i, model, model->desc->cache.types[0]->name);
1339 return EINA_FALSE;
1340 }
1341
1342 child_copy = eina_model_deep_copy(child);
1343 if (!child_copy)
1344 {
1345 ERR("Could not deep copy child #%d %p (%s) from model %p (%s)", i,
1346 child, child->desc->cache.types[0]->name,
1347 model, model->desc->cache.types[0]->name);
1348 _eina_model_unref(child);
1349 return EINA_FALSE;
1350 }
1351 _eina_model_unref(child);
1352
1353 ret = eina_model_child_insert_at(copy, i, child_copy);
1354 _eina_model_unref(child_copy);
1355
1356 if (!ret)
1357 {
1358 ERR("Could not set child #%d on model %p (%s)",
1359 i, copy, copy->desc->cache.types[0]->name);
1360 return EINA_FALSE;
1361 }
1362 }
1363
1364 return EINA_TRUE;
1365}
1366
1367static Eina_Bool
1368_eina_model_type_base_deep_copy(const Eina_Model *model, Eina_Model *copy)
1369{
1370 DBG("base deep copy of %p to %p", model, copy);
1371
1372 return _eina_model_type_base_properties_copy(model, copy) &&
1373 _eina_model_type_base_children_deep_copy(model, copy);
1374}
1375
1376static Eina_Bool
1377_eina_model_type_base_properties_compare(const Eina_Model *a, const Eina_Model *b, int *cmp)
1378{
1379 Eina_List *al, *aprops = eina_model_properties_names_list_get(a);
1380 Eina_List *bl, *bprops = eina_model_properties_names_list_get(b);
1381 Eina_List *l, *props = NULL;
1382 const char *aname, *bname, *name;
1383 Eina_Bool ret = EINA_TRUE;
1384
1385 EINA_LIST_FOREACH(aprops, al, aname)
1386 {
1387 EINA_LIST_FOREACH(bprops, bl, bname)
1388 if (strcmp(aname, bname) == 0)
1389 {
1390 props = eina_list_append(props, aname);
1391 break;
1392 }
1393 }
1394
1395 *cmp = 0;
1396 EINA_LIST_FOREACH(props, l, name)
1397 {
1398 Eina_Value atmp, btmp;
1399
1400 if (!eina_model_property_get(a, name, &atmp))
1401 {
1402 ERR("Could not get property %s from model %p (%s)",
1403 name, a, a->desc->cache.types[0]->name);
1404 ret = EINA_FALSE;
1405 *cmp = -1;
1406 break;
1407 }
1408
1409 if (!eina_model_property_get(b, name, &btmp))
1410 {
1411 ERR("Could not get property %s from model %p (%s)",
1412 name, b, b->desc->cache.types[0]->name);
1413 ret = EINA_FALSE;
1414 *cmp = -1;
1415 eina_value_flush(&atmp);
1416 break;
1417 }
1418
1419 *cmp = eina_value_compare(&atmp, &btmp);
1420 if (*cmp == -2)
1421 {
1422 char *astr = eina_value_to_string(&atmp);
1423 char *bstr = eina_value_to_string(&btmp);
1424 ERR("Could not compare property %s: %s=%s, %s=%s", name,
1425 eina_value_type_name_get(eina_value_type_get(&atmp)), astr,
1426 eina_value_type_name_get(eina_value_type_get(&btmp)), bstr);
1427 free(astr);
1428 free(bstr);
1429 ret = EINA_FALSE;
1430 *cmp = -1;
1431 }
1432
1433 eina_value_flush(&atmp);
1434 eina_value_flush(&btmp);
1435
1436 if ((!ret) || (*cmp != 0))
1437 break;
1438 }
1439
1440 if ((ret) && (*cmp == 0))
1441 {
1442 int acount = eina_list_count(aprops);
1443 int bcount = eina_list_count(bprops);
1444
1445 if (acount < bcount)
1446 *cmp = -1;
1447 else if (acount > bcount)
1448 *cmp = 1;
1449 }
1450
1451 eina_model_properties_names_list_free(aprops);
1452 eina_model_properties_names_list_free(bprops);
1453 eina_list_free(props);
1454 return ret;
1455}
1456
1457static Eina_Bool
1458_eina_model_type_base_children_compare(const Eina_Model *a, const Eina_Model *b, int *cmp)
1459{
1460 int acount = eina_model_child_count(a);
1461 int bcount = eina_model_child_count(b);
1462 int i, count;
1463 Eina_Bool ret = EINA_TRUE;
1464
1465 if (acount < 0)
1466 {
1467 ERR("Could not get children count of model %p (%s)",
1468 a, a->desc->cache.types[0]->name);
1469 return EINA_FALSE;
1470 }
1471 if (bcount < 0)
1472 {
1473 ERR("Could not get children count of model %p (%s)",
1474 b, b->desc->cache.types[0]->name);
1475 return EINA_FALSE;
1476 }
1477
1478 if (acount < bcount)
1479 count = acount;
1480 else
1481 count = bcount;
1482
1483 for (i = 0; i < count; i++)
1484 {
1485 Eina_Model *achild, *bchild;
1486
1487 achild = eina_model_child_get(a, i);
1488 if (!achild)
1489 {
1490 ERR("Could not get child #%d from model %p (%s)",
1491 i, a, a->desc->cache.types[0]->name);
1492 *cmp = -1;
1493 return EINA_FALSE;
1494 }
1495
1496 bchild = eina_model_child_get(b, i);
1497 if (!bchild)
1498 {
1499 ERR("Could not get child #%d from model %p (%s)",
1500 i, b, b->desc->cache.types[0]->name);
1501 *cmp = -1;
1502 _eina_model_unref(achild);
1503 return EINA_FALSE;
1504 }
1505
1506 *cmp = eina_model_compare(achild, bchild);
1507 if (*cmp == -2)
1508 {
1509 ERR("Could not compare children #%d %p (%s) and %p (%s) "
1510 "from models %p (%s) and %p (%s)", i,
1511 achild,
1512 eina_model_type_name_get(eina_model_type_get(achild)),
1513 bchild,
1514 eina_model_type_name_get(eina_model_type_get(bchild)),
1515 a, a->desc->cache.types[0]->name,
1516 b, b->desc->cache.types[0]->name);
1517 ret = EINA_FALSE;
1518 }
1519 _eina_model_unref(achild);
1520 _eina_model_unref(bchild);
1521
1522 if ((!ret) || (*cmp != 0))
1523 break;
1524 }
1525
1526 if ((ret) && (*cmp == 0))
1527 {
1528 if (acount < bcount)
1529 *cmp = -1;
1530 else if (acount > bcount)
1531 *cmp = 1;
1532 }
1533
1534 return ret;
1535}
1536
1537static Eina_Bool
1538_eina_model_type_base_compare(const Eina_Model *a, const Eina_Model *b, int *cmp)
1539{
1540 *cmp = 0;
1541 DBG("base compare of %p and %p", a, b);
1542
1543 if (!_eina_model_type_base_properties_compare(a, b, cmp))
1544 return EINA_FALSE;
1545
1546 if (*cmp != 0)
1547 return EINA_TRUE;
1548
1549 return _eina_model_type_base_children_compare(a, b, cmp);
1550}
1551
1552static int
1553_eina_model_type_base_child_count(const Eina_Model *model)
1554{
1555 DBG("base child_count of %p", model);
1556 return 0;
1557}
1558
1559static int
1560_eina_model_type_base_child_find(const Eina_Model *model, unsigned int start_position, const Eina_Model *other)
1561{
1562 int x = eina_model_child_count(model);
1563 unsigned int i, count;
1564
1565 DBG("base child_find of %p, %d children", model, x);
1566
1567 if (x < 0)
1568 return -1;
1569
1570 count = x;
1571 for (i = start_position; i < count; i++)
1572 {
1573 Eina_Model *current = eina_model_child_get(model, i);
1574 if (current)
1575 {
1576 _eina_model_unref(current); /* we'll not use it's value anyway */
1577 if (current == other)
1578 return i;
1579 }
1580 }
1581
1582 return -1;
1583}
1584
1585static int
1586_eina_model_type_base_child_criteria_match(const Eina_Model *model, unsigned int start_position, Eina_Each_Cb match, const void *user_data)
1587{
1588 int x = eina_model_child_count(model);
1589 unsigned int i, count;
1590
1591 DBG("base child_criteria_match of %p, %d children", model, x);
1592
1593 if (x < 0)
1594 return -1;
1595
1596 count = x;
1597 for (i = start_position; i < count; i++)
1598 {
1599 Eina_Model *current = eina_model_child_get(model, i);
1600 if (current)
1601 {
1602 Eina_Bool r = match(model, current, (void *)user_data);
1603 _eina_model_unref(current);
1604 if (r)
1605 return i;
1606 }
1607 }
1608
1609 return -1;
1610}
1611
1612typedef struct _Eina_Iterator_Model_Base Eina_Iterator_Model_Base;
1613struct _Eina_Iterator_Model_Base
1614{
1615 Eina_Iterator base;
1616 Eina_Model *model;
1617 unsigned int current;
1618 unsigned int end;
1619};
1620
1621static Eina_Bool
1622_eina_model_type_base_child_iterator_next(Eina_Iterator *base, void **data)
1623{
1624 Eina_Iterator_Model_Base *it;
1625
1626 it = (Eina_Iterator_Model_Base *)base;
1627 if (it->current >= it->end)
1628 return EINA_FALSE;
1629
1630 *data = eina_model_child_get(it->model, it->current);
1631 if (!*data)
1632 return EINA_FALSE;
1633
1634 it->current++;
1635 return EINA_TRUE;
1636}
1637
1638static void *
1639_eina_model_type_base_child_iterator_get_container(Eina_Iterator *base)
1640{
1641 Eina_Iterator_Model_Base *it;
1642 it = (Eina_Iterator_Model_Base *)base;
1643 return it->model;
1644}
1645
1646static void
1647_eina_model_type_base_child_iterator_free(Eina_Iterator *base)
1648{
1649 Eina_Iterator_Model_Base *it;
1650 it = (Eina_Iterator_Model_Base *)base;
1651 eina_model_xunref(it->model, it);
1652 free(it);
1653}
1654
1655static Eina_Iterator *
1656_eina_model_type_base_child_iterator_get(Eina_Model *model, unsigned int start, unsigned int count)
1657{
1658 Eina_Iterator_Model_Base *it = calloc(1, sizeof(*it));
1659 EINA_SAFETY_ON_NULL_RETURN_VAL(it, NULL);
1660
1661 EINA_MAGIC_SET(&it->base, EINA_MAGIC_ITERATOR);
1662 it->base.version = EINA_ITERATOR_VERSION;
1663 it->base.next = _eina_model_type_base_child_iterator_next;
1664 it->base.get_container = _eina_model_type_base_child_iterator_get_container;
1665 it->base.free = _eina_model_type_base_child_iterator_free;
1666
1667 it->model = eina_model_xref(model, it, "eina_model_child_slice_iterator_get");
1668 it->current = start;
1669 it->end = start + count;
1670
1671 return &it->base;
1672}
1673
1674typedef struct _Eina_Iterator_Model_Base_Reversed Eina_Iterator_Model_Base_Reversed;
1675struct _Eina_Iterator_Model_Base_Reversed
1676{
1677 Eina_Iterator base;
1678 Eina_Model *model;
1679 unsigned int current;
1680 unsigned int end;
1681};
1682
1683static Eina_Bool
1684_eina_model_type_base_child_reversed_iterator_next(Eina_Iterator *base, void **data)
1685{
1686 Eina_Iterator_Model_Base_Reversed *it;
1687
1688 it = (Eina_Iterator_Model_Base_Reversed *)base;
1689 if (it->current == it->end)
1690 return EINA_FALSE;
1691
1692 it->current--;
1693 *data = eina_model_child_get(it->model, it->current);
1694 if (!*data)
1695 return EINA_FALSE;
1696
1697 return EINA_TRUE;
1698}
1699
1700static void *
1701_eina_model_type_base_child_reversed_iterator_get_container(Eina_Iterator *base)
1702{
1703 Eina_Iterator_Model_Base_Reversed *it;
1704 it = (Eina_Iterator_Model_Base_Reversed *)base;
1705 return it->model;
1706}
1707
1708static void
1709_eina_model_type_base_child_reversed_iterator_free(Eina_Iterator *base)
1710{
1711 Eina_Iterator_Model_Base_Reversed *it;
1712 it = (Eina_Iterator_Model_Base_Reversed *)base;
1713 eina_model_xunref(it->model, it);
1714 free(it);
1715}
1716
1717static Eina_Iterator *
1718_eina_model_type_base_child_reversed_iterator_get(Eina_Model *model, unsigned int start, unsigned int count)
1719{
1720 Eina_Iterator_Model_Base_Reversed *it;
1721 int children_count;
1722
1723 children_count = eina_model_child_count(model);
1724 if (children_count < 0)
1725 return NULL;
1726
1727 if (start + count > (unsigned int)children_count)
1728 {
1729 if (start >= (unsigned int)children_count)
1730 count = 0;
1731 else
1732 count = children_count - start;
1733 }
1734
1735 it = calloc(1, sizeof(*it));
1736 EINA_SAFETY_ON_NULL_RETURN_VAL(it, NULL);
1737 EINA_MAGIC_SET(&it->base, EINA_MAGIC_ITERATOR);
1738 it->base.version = EINA_ITERATOR_VERSION;
1739 it->base.next = _eina_model_type_base_child_reversed_iterator_next;
1740 it->base.get_container = _eina_model_type_base_child_reversed_iterator_get_container;
1741 it->base.free = _eina_model_type_base_child_reversed_iterator_free;
1742
1743 it->model = eina_model_xref(model, it, "eina_model_child_slice_reversed_iterator_get");
1744 it->current = start + count;
1745 it->end = start;
1746
1747 return &it->base;
1748}
1749
1750typedef struct _Eina_Iterator_Model_Base_Sorted Eina_Iterator_Model_Base_Sorted;
1751struct _Eina_Iterator_Model_Base_Sorted
1752{
1753 Eina_Iterator base;
1754 Eina_Model *model;
1755 unsigned int current;
1756 unsigned int count;
1757 Eina_Model *elements[];
1758};
1759
1760static Eina_Bool
1761_eina_model_type_base_child_sorted_iterator_next(Eina_Iterator *base, void **data)
1762{
1763 Eina_Iterator_Model_Base_Sorted *it;
1764
1765 it = (Eina_Iterator_Model_Base_Sorted *)base;
1766 if (it->current == it->count)
1767 return EINA_FALSE;
1768
1769 *data = eina_model_ref(it->elements[it->current]);
1770 it->current++;
1771 return EINA_TRUE;
1772}
1773
1774static void *
1775_eina_model_type_base_child_sorted_iterator_get_container(Eina_Iterator *base)
1776{
1777 Eina_Iterator_Model_Base_Sorted *it;
1778 it = (Eina_Iterator_Model_Base_Sorted *)base;
1779 return it->model;
1780}
1781
1782static void
1783_eina_model_type_base_child_sorted_iterator_free(Eina_Iterator *base)
1784{
1785 Eina_Iterator_Model_Base_Sorted *it;
1786 unsigned int i;
1787 it = (Eina_Iterator_Model_Base_Sorted *)base;
1788 eina_model_xunref(it->model, it);
1789
1790 for (i = 0; i < it->count; i++)
1791 _eina_model_unref(it->elements[i]);
1792
1793 free(it);
1794}
1795
1796static Eina_Iterator *
1797_eina_model_type_base_child_sorted_iterator_get(Eina_Model *model, unsigned int start, unsigned int count, Eina_Compare_Cb compare)
1798{
1799 Eina_Iterator_Model_Base_Sorted *it;
1800 int children_count;
1801 unsigned int i;
1802
1803 children_count = eina_model_child_count(model);
1804 if (children_count < 0)
1805 return NULL;
1806
1807 if (start + count > (unsigned int)children_count)
1808 {
1809 if (start >= (unsigned int)children_count)
1810 count = 0;
1811 else
1812 count = children_count - start;
1813 }
1814
1815 it = calloc(1, sizeof(*it) + count * sizeof(Eina_Model *));
1816 EINA_SAFETY_ON_NULL_RETURN_VAL(it, NULL);
1817 EINA_MAGIC_SET(&it->base, EINA_MAGIC_ITERATOR);
1818 it->base.version = EINA_ITERATOR_VERSION;
1819 it->base.next = _eina_model_type_base_child_sorted_iterator_next;
1820 it->base.get_container = _eina_model_type_base_child_sorted_iterator_get_container;
1821 it->base.free = _eina_model_type_base_child_sorted_iterator_free;
1822
1823 it->model = eina_model_xref(model, it, "eina_model_child_slice_sorted_iterator_get");
1824 it->current = 0;
1825 it->count = count;
1826
1827 for (i = 0; i < count; i++)
1828 {
1829 it->elements[i] = eina_model_child_get(model, i + start);
1830 if (!it->elements[i])
1831 {
1832 ERR("Failed to get child %u of model %p (%s)",
1833 i + start, model, model->desc->cache.types[0]->name);
1834 free(it);
1835 return NULL;
1836 }
1837 }
1838
1839 if (count > 1)
1840 _eina_model_array_sort(it->elements, 0, count - 1, compare);
1841
1842 return &it->base;
1843}
1844
1845typedef struct _Eina_Iterator_Model_Base_Filtered Eina_Iterator_Model_Base_Filtered;
1846struct _Eina_Iterator_Model_Base_Filtered
1847{
1848 Eina_Iterator base;
1849 Eina_Model *model;
1850 Eina_Each_Cb match;
1851 const void *data;
1852 unsigned int current;
1853 unsigned int count;
1854};
1855
1856static Eina_Bool
1857_eina_model_type_base_child_filtered_iterator_next(Eina_Iterator *base, void **data)
1858{
1859 Eina_Iterator_Model_Base_Filtered *it;
1860 unsigned int *ret;
1861 int i;
1862
1863 it = (Eina_Iterator_Model_Base_Filtered *)base;
1864 if (it->count == 0) return EINA_FALSE;
1865
1866 i = eina_model_child_criteria_match(it->model, it->current, it->match, it->data);
1867 if (i < 0) return EINA_FALSE;
1868
1869 it->current = i + 1;
1870 it->count--;
1871 ret = (unsigned int *)data;
1872 *ret = i;
1873 return EINA_TRUE;
1874}
1875
1876static void *
1877_eina_model_type_base_child_filtered_iterator_get_container(Eina_Iterator *base)
1878{
1879 Eina_Iterator_Model_Base_Filtered *it;
1880 it = (Eina_Iterator_Model_Base_Filtered *)base;
1881 return it->model;
1882}
1883
1884static void
1885_eina_model_type_base_child_filtered_iterator_free(Eina_Iterator *base)
1886{
1887 Eina_Iterator_Model_Base_Filtered *it;
1888 it = (Eina_Iterator_Model_Base_Filtered *)base;
1889 eina_model_xunref(it->model, it);
1890 free(it);
1891}
1892
1893static Eina_Iterator *
1894_eina_model_type_base_child_filtered_iterator_get(Eina_Model *model, unsigned int start, unsigned int count, Eina_Each_Cb match, const void *data)
1895{
1896 Eina_Iterator_Model_Base_Filtered *it = calloc(1, sizeof(*it));
1897 EINA_SAFETY_ON_NULL_RETURN_VAL(it, NULL);
1898
1899 EINA_MAGIC_SET(&it->base, EINA_MAGIC_ITERATOR);
1900 it->base.version = EINA_ITERATOR_VERSION;
1901 it->base.next = _eina_model_type_base_child_filtered_iterator_next;
1902 it->base.get_container = _eina_model_type_base_child_filtered_iterator_get_container;
1903 it->base.free = _eina_model_type_base_child_filtered_iterator_free;
1904
1905 it->model = eina_model_xref(model, it, "eina_model_child_slice_filtered_iterator_get");
1906 it->match = match;
1907 it->data = data;
1908 it->current = start;
1909 it->count = count;
1910
1911 return &it->base;
1912}
1913
1914static char *
1915_eina_model_type_base_to_string(const Eina_Model *model)
1916{
1917 Eina_List *l, *props;
1918 const char *name;
1919 Eina_Strbuf *str;
1920 Eina_Bool first;
1921 int i, count;
1922 char *ret;
1923
1924 str = eina_strbuf_new();
1925 EINA_SAFETY_ON_NULL_RETURN_VAL(str, NULL);
1926
1927 eina_strbuf_append_printf(str, "%s({", model->desc->cache.types[0]->name);
1928
1929 props = eina_model_properties_names_list_get(model);
1930 props = eina_list_sort(props, 0, EINA_COMPARE_CB(strcmp));
1931
1932 first = EINA_TRUE;
1933 EINA_LIST_FOREACH(props, l, name)
1934 {
1935 Eina_Value val;
1936
1937 if (!first)
1938 eina_strbuf_append_printf(str, ", %s: ", name);
1939 else
1940 {
1941 eina_strbuf_append_printf(str, "%s: ", name);
1942 first = EINA_FALSE;
1943 }
1944
1945 if (!eina_model_property_get(model, name, &val))
1946 eina_strbuf_append_char(str, '?');
1947 else
1948 {
1949 char *tmp = eina_value_to_string(&val);
1950 eina_strbuf_append(str, tmp ? tmp : "?");
1951 free(tmp);
1952 eina_value_flush(&val);
1953 }
1954 }
1955 eina_list_free(props);
1956
1957 eina_strbuf_append(str, "}, [");
1958
1959 count = eina_model_child_count(model);
1960 first = EINA_TRUE;
1961 for (i = 0; i < count; i++)
1962 {
1963 Eina_Model *c = eina_model_child_get(model, i);
1964 if (!c)
1965 {
1966 if (!first)
1967 eina_strbuf_append(str, ", ?");
1968 else
1969 {
1970 eina_strbuf_append_char(str, '?');
1971 first = EINA_FALSE;
1972 }
1973 }
1974 else
1975 {
1976 char *tmp = eina_model_to_string(c);
1977 if (!first)
1978 eina_strbuf_append_printf(str, ", %s", tmp ? tmp : "?");
1979 else
1980 {
1981 eina_strbuf_append(str, tmp ? tmp : "?");
1982 first = EINA_FALSE;
1983 }
1984 free(tmp);
1985 _eina_model_unref(c);
1986 }
1987 }
1988
1989 eina_strbuf_append(str, "])");
1990
1991 ret = eina_strbuf_string_steal(str);
1992 eina_strbuf_free(str);
1993
1994 return ret;
1995}
1996
1997static const Eina_Model_Event_Description _eina_model_type_base_events[] = {
1998 EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_deleted, "", "model was deleted"),
1999 EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_freed, "", "model memory was released"),
2000 EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_property_set, "s", "model data was set, data name given as event information."),
2001 EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_property_del, "s", "model data was deleted, data name given as event information."),
2002 EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_children_changed, "", "model children changed (deleted, inserted)."),
2003 EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_child_inserted, "u", "model child was inserted, child position is given."),
2004 EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_child_set, "u", "model child was set, child position is given."),
2005 EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_child_del, "u", "model child was deleted, child position is given."),
2006 EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_loaded, "", "model was loaded"),
2007 EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_unloaded, "", "model was unloaded"),
2008 EINA_MODEL_EVENT_DESCRIPTION_SENTINEL
2009};
2010
2011static const Eina_Model_Type _EINA_MODEL_TYPE_BASE = {
2012 EINA_MODEL_TYPE_VERSION,
2013 0, /* there is no private data */
2014 sizeof(Eina_Model_Type),
2015 "Eina_Model_Type_Base",
2016 NULL, /* should be the only type with NULL here! */
2017 NULL, /* no interfaces implemented */
2018 _eina_model_type_base_events,
2019 _eina_model_type_base_setup,
2020 _eina_model_type_base_flush,
2021 _eina_model_type_base_constructor,
2022 _eina_model_type_base_destructor,
2023 _eina_model_type_base_copy,
2024 _eina_model_type_base_deep_copy,
2025 _eina_model_type_base_compare,
2026 NULL, /* no load */
2027 NULL, /* no unload */
2028 NULL, /* no property value get */
2029 NULL, /* no property value set */
2030 NULL, /* no property del */
2031 NULL, /* no properties names list */
2032 _eina_model_type_base_child_count,
2033 NULL, /* no child get */
2034 NULL, /* no child set */
2035 NULL, /* no child del */
2036 NULL, /* no child insert */
2037 _eina_model_type_base_child_find,
2038 _eina_model_type_base_child_criteria_match,
2039 NULL, /* no child sort */
2040 _eina_model_type_base_child_iterator_get,
2041 _eina_model_type_base_child_reversed_iterator_get,
2042 _eina_model_type_base_child_sorted_iterator_get,
2043 _eina_model_type_base_child_filtered_iterator_get,
2044 _eina_model_type_base_to_string,
2045 NULL, /* extension pointer */
2046 NULL, /* extension pointer */
2047 NULL, /* extension pointer */
2048 NULL /* extension pointer */
2049};
2050
2051/*
2052 * EINA_MODEL_TYPE_MIXIN:
2053 *
2054 * Mix-in is a type that uses 2 interfaces, one for properties,
2055 * another for children. Users should inherit this model and implement
2056 * at least onf of the interfaces to get an usable model without
2057 * defining the methods.
2058 */
2059
2060static const char _EINA_MODEL_INTERFACE_NAME_PROPERTIES[] = "Eina_Model_Interface_Properties";
2061static const char _EINA_MODEL_INTERFACE_NAME_CHILDREN[] = "Eina_Model_Interface_Children";
2062
2063typedef struct _Eina_Model_Type_Mixin_Data Eina_Model_Type_Mixin_Data;
2064struct _Eina_Model_Type_Mixin_Data
2065{
2066 /* just keep interfaces to avoid lookups */
2067 const Eina_Model_Interface *if_properties;
2068 const Eina_Model_Interface *if_children;
2069};
2070
2071static Eina_Bool
2072_eina_model_type_mixin_setup(Eina_Model *model)
2073{
2074 DBG("mix-in setup of %p", model);
2075 return EINA_TRUE;
2076}
2077
2078static Eina_Bool
2079_eina_model_type_mixin_flush(Eina_Model *model)
2080{
2081 DBG("mix-in flush of %p", model);
2082 return EINA_TRUE;
2083}
2084
2085static Eina_Bool
2086_eina_model_type_mixin_constructor(Eina_Model *model)
2087{
2088 Eina_Model_Type_Mixin_Data *priv = eina_model_type_private_data_get
2089 (model, EINA_MODEL_TYPE_MIXIN);
2090
2091 DBG("mix-in constructor of %p (priv=%p)", model, priv);
2092
2093 priv->if_properties = eina_model_interface_get
2094 (model, EINA_MODEL_INTERFACE_NAME_PROPERTIES);
2095 if (priv->if_properties)
2096 {
2097 if (!eina_model_interface_constructor(priv->if_properties, model))
2098 {
2099 ERR("Could not construct properties interface %p of %p (%s)",
2100 model, priv->if_properties, model->desc->cache.types[0]->name);
2101 return EINA_FALSE;
2102 }
2103 }
2104
2105 priv->if_children = eina_model_interface_get
2106 (model, EINA_MODEL_INTERFACE_NAME_CHILDREN);
2107 if (priv->if_children)
2108 {
2109 if (!eina_model_interface_constructor(priv->if_children, model))
2110 {
2111 ERR("Could not construct children interface %p of %p (%s)",
2112 model, priv->if_children, model->desc->cache.types[0]->name);
2113 return EINA_FALSE;
2114 }
2115 }
2116
2117 if ((!priv->if_properties) && (!priv->if_children))
2118 {
2119 ERR("Mix-in model %p (%s) does not implement properties or children "
2120 "interfaces!",
2121 model, model->desc->cache.types[0]->name);
2122 return EINA_FALSE;
2123 }
2124
2125 return EINA_TRUE;
2126}
2127
2128#define EINA_MODEL_TYPE_MIXIN_GET(model) \
2129 Eina_Model_Type_Mixin_Data *priv = eina_model_type_private_data_get \
2130 (model, EINA_MODEL_TYPE_MIXIN)
2131
2132static Eina_Bool
2133_eina_model_type_mixin_destructor(Eina_Model *model)
2134{
2135 EINA_MODEL_TYPE_MIXIN_GET(model);
2136
2137 DBG("mixin destructor of %p", model);
2138
2139 if (priv->if_properties)
2140 eina_model_interface_destructor(priv->if_properties, model);
2141
2142 if (priv->if_children)
2143 eina_model_interface_destructor(priv->if_children, model);
2144
2145 return EINA_TRUE;
2146}
2147
2148static Eina_Bool
2149_eina_model_type_mixin_compare(const Eina_Model *a, const Eina_Model *b, int *cmp)
2150{
2151 Eina_Bool ret = EINA_TRUE, did_prop = EINA_FALSE, did_child = EINA_FALSE;
2152
2153 *cmp = 0;
2154
2155 EINA_MODEL_TYPE_MIXIN_GET(a);
2156
2157 if (priv->if_properties)
2158 {
2159 Eina_Bool (*compare)(const Eina_Model*, const Eina_Model*, int *) =
2160 _eina_model_interface_find_offset
2161 (priv->if_properties,
2162 offsetof(Eina_Model_Interface_Properties, compare));
2163
2164 if (compare)
2165 {
2166 ret &= compare(a, b, cmp);
2167 did_prop = EINA_TRUE;
2168 }
2169 }
2170
2171 if ((ret) && (*cmp == 0))
2172 {
2173 if (priv->if_children)
2174 {
2175 Eina_Bool (*compare)(const Eina_Model*, const Eina_Model*, int *) =
2176 _eina_model_interface_find_offset
2177 (priv->if_children,
2178 offsetof(Eina_Model_Interface_Children, compare));
2179
2180 if (compare)
2181 {
2182 ret &= compare(a, b, cmp);
2183 did_child = EINA_TRUE;
2184 }
2185 }
2186 }
2187
2188 if ((!did_prop) && (!did_child))
2189 return eina_model_type_compare(EINA_MODEL_TYPE_BASE, a, b, cmp);
2190
2191 return ret;
2192}
2193
2194static Eina_Bool
2195_eina_model_type_mixin_load(Eina_Model *model)
2196{
2197 Eina_Bool ret = EINA_TRUE;
2198
2199 EINA_MODEL_TYPE_MIXIN_GET(model);
2200
2201 if (priv->if_properties)
2202 ret &= eina_model_interface_properties_load(priv->if_properties, model);
2203
2204 if (priv->if_children)
2205 ret &= eina_model_interface_children_load(priv->if_children, model);
2206
2207 return ret;
2208}
2209
2210static Eina_Bool
2211_eina_model_type_mixin_unload(Eina_Model *model)
2212{
2213 Eina_Bool ret = EINA_TRUE;
2214
2215 EINA_MODEL_TYPE_MIXIN_GET(model);
2216
2217 if (priv->if_properties)
2218 ret &= eina_model_interface_properties_unload(priv->if_properties, model);
2219
2220 if (priv->if_children)
2221 ret &= eina_model_interface_children_unload(priv->if_children, model);
2222
2223 return ret;
2224}
2225
2226static Eina_Bool
2227_eina_model_type_mixin_property_get(const Eina_Model *model, const char *name, Eina_Value *value)
2228{
2229 Eina_Bool ret = EINA_FALSE;
2230
2231 EINA_MODEL_TYPE_MIXIN_GET(model);
2232
2233 if (priv->if_properties)
2234 ret = eina_model_interface_properties_get
2235 (priv->if_properties, model, name, value);
2236
2237 return ret;
2238}
2239
2240static Eina_Bool
2241_eina_model_type_mixin_property_set(Eina_Model *model, const char *name, const Eina_Value *value)
2242{
2243 Eina_Bool ret = EINA_FALSE;
2244
2245 EINA_MODEL_TYPE_MIXIN_GET(model);
2246
2247 if (priv->if_properties)
2248 ret = eina_model_interface_properties_set
2249 (priv->if_properties, model, name, value);
2250
2251 return ret;
2252}
2253
2254static Eina_Bool
2255_eina_model_type_mixin_property_del(Eina_Model *model, const char *name)
2256{
2257 Eina_Bool ret = EINA_FALSE;
2258
2259 EINA_MODEL_TYPE_MIXIN_GET(model);
2260
2261 if (priv->if_properties)
2262 ret = eina_model_interface_properties_del
2263 (priv->if_properties, model, name);
2264
2265 return ret;
2266}
2267
2268static Eina_List *
2269_eina_model_type_mixin_properties_names_list_get(const Eina_Model *model)
2270{
2271 Eina_List *ret = NULL;
2272
2273 EINA_MODEL_TYPE_MIXIN_GET(model);
2274
2275 if (priv->if_properties)
2276 ret = eina_model_interface_properties_names_list_get
2277 (priv->if_properties, model);
2278
2279 return ret;
2280}
2281
2282static int
2283_eina_model_type_mixin_child_count(const Eina_Model *model)
2284{
2285 EINA_MODEL_TYPE_MIXIN_GET(model);
2286
2287 if (!priv->if_children)
2288 return 0;
2289
2290 return eina_model_interface_children_count(priv->if_children, model);
2291}
2292
2293static Eina_Model *
2294_eina_model_type_mixin_child_get(const Eina_Model *model, unsigned int position)
2295{
2296 EINA_MODEL_TYPE_MIXIN_GET(model);
2297
2298 if (!priv->if_children)
2299 return 0;
2300
2301 return eina_model_interface_children_get(priv->if_children, model, position);
2302}
2303
2304static Eina_Bool
2305_eina_model_type_mixin_child_set(Eina_Model *model, unsigned int position, Eina_Model *child)
2306{
2307 EINA_MODEL_TYPE_MIXIN_GET(model);
2308
2309 if (!priv->if_children)
2310 return 0;
2311
2312 return eina_model_interface_children_set
2313 (priv->if_children, model, position, child);
2314}
2315
2316static Eina_Bool
2317_eina_model_type_mixin_child_del(Eina_Model *model, unsigned int position)
2318{
2319 EINA_MODEL_TYPE_MIXIN_GET(model);
2320
2321 if (!priv->if_children)
2322 return 0;
2323
2324 return eina_model_interface_children_del
2325 (priv->if_children, model, position);
2326}
2327
2328static Eina_Bool
2329_eina_model_type_mixin_child_insert_at(Eina_Model *model, unsigned int position, Eina_Model *child)
2330{
2331 EINA_MODEL_TYPE_MIXIN_GET(model);
2332
2333 if (!priv->if_children)
2334 return 0;
2335
2336 return eina_model_interface_children_insert_at
2337 (priv->if_children, model, position, child);
2338}
2339
2340static void
2341_eina_model_type_mixin_child_sort(Eina_Model *model, Eina_Compare_Cb compare)
2342{
2343 EINA_MODEL_TYPE_MIXIN_GET(model);
2344
2345 if (!priv->if_children)
2346 return;
2347 eina_model_interface_children_sort(priv->if_children, model, compare);
2348}
2349
2350static const Eina_Model_Type _EINA_MODEL_TYPE_MIXIN = {
2351 EINA_MODEL_TYPE_VERSION,
2352 sizeof(Eina_Model_Type_Mixin_Data),
2353 sizeof(Eina_Model_Type),
2354 "Eina_Model_Type_Mixin",
2355 &_EINA_MODEL_TYPE_BASE,
2356 NULL, /* no interfaces implemented */
2357 NULL, /* no extra events */
2358 _eina_model_type_mixin_setup,
2359 _eina_model_type_mixin_flush,
2360 _eina_model_type_mixin_constructor,
2361 _eina_model_type_mixin_destructor,
2362 NULL, /* no copy, as interface is called automatically */
2363 NULL, /* no deep copy, as interface is called automatically */
2364 _eina_model_type_mixin_compare,
2365 _eina_model_type_mixin_load,
2366 _eina_model_type_mixin_unload,
2367 _eina_model_type_mixin_property_get,
2368 _eina_model_type_mixin_property_set,
2369 _eina_model_type_mixin_property_del,
2370 _eina_model_type_mixin_properties_names_list_get,
2371 _eina_model_type_mixin_child_count,
2372 _eina_model_type_mixin_child_get,
2373 _eina_model_type_mixin_child_set,
2374 _eina_model_type_mixin_child_del,
2375 _eina_model_type_mixin_child_insert_at,
2376 NULL, /* use default find */
2377 NULL, /* use default criteria_match */
2378 _eina_model_type_mixin_child_sort,
2379 NULL, /* use default iterator get */
2380 NULL, /* use default reversed iterator get */
2381 NULL, /* use default sorted iterator get */
2382 NULL, /* use default filtered iterator get */
2383 NULL, /* use default to string */
2384 NULL, /* extension pointer */
2385 NULL, /* extension pointer */
2386 NULL, /* extension pointer */
2387 NULL /* extension pointer */
2388};
2389#undef EINA_MODEL_TYPE_MIXIN_GET
2390
2391/* Events for all Properties interface */
2392static const Eina_Model_Event_Description _eina_model_interface_properties_events[] = {
2393 EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_properties_loaded, "", "model properties were loaded"),
2394 EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_properties_unloaded, "", "model properties were unloaded"),
2395 EINA_MODEL_EVENT_DESCRIPTION_SENTINEL
2396};
2397
2398/* EINA_MODEL_INTERFACE_PROPERTIES_HASH ******************************/
2399
2400#define EINA_MODEL_INTERFACE_PROPERTIES_HASH_GET(model) \
2401 Eina_Hash *priv = *(Eina_Hash **)eina_model_interface_private_data_get \
2402 (model, EINA_MODEL_INTERFACE_PROPERTIES_HASH)
2403
2404static Eina_Bool
2405_eina_model_interface_properties_hash_setup(Eina_Model *model)
2406{
2407 Eina_Hash **p_priv = eina_model_interface_private_data_get
2408 (model, EINA_MODEL_INTERFACE_PROPERTIES_HASH);
2409
2410 DBG("setup interface properties (hash) at %p model %p (%s)",
2411 p_priv, model, model->desc->cache.types[0]->name);
2412
2413 *p_priv = eina_hash_string_small_new(NULL);
2414 return !!*p_priv;
2415}
2416
2417static Eina_Bool
2418_eina_model_interface_properties_hash_flush(Eina_Model *model)
2419{
2420 EINA_MODEL_INTERFACE_PROPERTIES_HASH_GET(model);
2421
2422 DBG("flush interface properties (hash) at %p model %p (%s)",
2423 priv, model, model->desc->cache.types[0]->name);
2424
2425 if (priv)
2426 {
2427 ERR("interface properties flushed with values! priv=%p, model %p (%s)",
2428 priv, model, model->desc->cache.types[0]->name);
2429 eina_hash_free(priv);
2430 }
2431
2432 return EINA_TRUE;
2433}
2434
2435static Eina_Bool
2436_eina_model_interface_properties_hash_constructor(Eina_Model *model)
2437{
2438 EINA_MODEL_INTERFACE_PROPERTIES_HASH_GET(model);
2439
2440 DBG("construct interface properties (hash) at %p model %p (%s)",
2441 priv, model, model->desc->cache.types[0]->name);
2442
2443 return EINA_TRUE;
2444}
2445
2446static Eina_Bool
2447_eina_model_interface_properties_hash_destructor_foreach(const Eina_Hash *hash EINA_UNUSED, const void *key EINA_UNUSED, void *data, void *fdata EINA_UNUSED)
2448{
2449 eina_value_free(data);
2450 return EINA_TRUE;
2451}
2452
2453static Eina_Bool
2454_eina_model_interface_properties_hash_destructor(Eina_Model *model)
2455{
2456 Eina_Hash **p_priv = eina_model_interface_private_data_get
2457 (model, EINA_MODEL_INTERFACE_PROPERTIES_HASH);
2458 int count = eina_hash_population(*p_priv);
2459
2460 DBG("destroy interface properties (hash) at %p model %p (%s). %d values.",
2461 *p_priv, model, model->desc->cache.types[0]->name, count);
2462
2463 eina_hash_foreach
2464 (*p_priv, _eina_model_interface_properties_hash_destructor_foreach, NULL);
2465 eina_hash_free(*p_priv);
2466 *p_priv = NULL;
2467
2468 return EINA_TRUE;
2469}
2470
2471static Eina_Bool
2472_eina_model_interface_properties_hash_get(const Eina_Model *model, const char *name, Eina_Value *value)
2473{
2474 EINA_MODEL_INTERFACE_PROPERTIES_HASH_GET(model);
2475 const Eina_Value *prop = eina_hash_find(priv, name);
2476 EINA_SAFETY_ON_NULL_RETURN_VAL(prop, EINA_FALSE);
2477 return eina_value_copy(prop, value);
2478}
2479
2480static Eina_Bool
2481_eina_model_interface_properties_hash_set(Eina_Model *model, const char *name, const Eina_Value *value)
2482{
2483 EINA_MODEL_INTERFACE_PROPERTIES_HASH_GET(model);
2484 Eina_Value *prop, *old = eina_hash_find(priv, name);
2485
2486 prop = eina_value_new(eina_value_type_get(value));
2487 EINA_SAFETY_ON_NULL_RETURN_VAL(prop, EINA_FALSE);
2488
2489 eina_value_flush(prop);
2490 if (!eina_value_copy(value, prop))
2491 {
2492 ERR("Could not copy value '%s' from %p to %p", name, value, prop);
2493 eina_value_free(prop);
2494 return EINA_FALSE;
2495 }
2496
2497 if (!old)
2498 {
2499 if (!eina_hash_add(priv, name, prop))
2500 {
2501 ERR("Could not add value %p to hash as key '%s'", prop, name);
2502 eina_value_free(prop);
2503 return EINA_FALSE;
2504 }
2505 }
2506 else
2507 {
2508 eina_value_free(old);
2509 if (!eina_hash_modify(priv, name, prop))
2510 {
2511 ERR("Could not modify hash key '%s' value from %p to %p",
2512 name, old, prop);
2513 eina_hash_del_by_key(priv, name);
2514 eina_value_free(prop);
2515 return EINA_FALSE;
2516 }
2517 }
2518
2519 return EINA_TRUE;
2520}
2521
2522static Eina_Bool
2523_eina_model_interface_properties_hash_del(Eina_Model *model, const char *name)
2524{
2525 EINA_MODEL_INTERFACE_PROPERTIES_HASH_GET(model);
2526 Eina_Value *old = eina_hash_find(priv, name);
2527 EINA_SAFETY_ON_NULL_RETURN_VAL(old, EINA_FALSE);
2528 eina_value_free(old);
2529 return eina_hash_del_by_key(priv, name);
2530}
2531
2532static Eina_Bool
2533_eina_model_interface_properties_hash_names_list_foreach(const Eina_Hash *hash EINA_UNUSED, const void *key, void *data EINA_UNUSED, void *fdata)
2534{
2535 Eina_List **p_list = fdata;
2536 *p_list = eina_list_append(*p_list, eina_stringshare_add(key));
2537 return EINA_TRUE;
2538}
2539
2540static Eina_List *
2541_eina_model_interface_properties_hash_names_list(const Eina_Model *model)
2542{
2543 EINA_MODEL_INTERFACE_PROPERTIES_HASH_GET(model);
2544 Eina_List *list = NULL;
2545 eina_hash_foreach
2546 (priv, _eina_model_interface_properties_hash_names_list_foreach, &list);
2547 return list;
2548}
2549#undef EINA_MODEL_INTERFACE_PROPERTIES_HASH_GET
2550
2551static const Eina_Model_Interface_Properties _EINA_MODEL_INTERFACE_PROPERTIES_HASH = {
2552 {
2553 EINA_MODEL_INTERFACE_VERSION,
2554 sizeof(Eina_Hash *),
2555 sizeof(Eina_Model_Interface_Properties),
2556 _EINA_MODEL_INTERFACE_NAME_PROPERTIES,
2557 NULL, /* no parent interfaces */
2558 _eina_model_interface_properties_events,
2559 _eina_model_interface_properties_hash_setup,
2560 _eina_model_interface_properties_hash_flush,
2561 _eina_model_interface_properties_hash_constructor,
2562 _eina_model_interface_properties_hash_destructor,
2563 NULL,
2564 NULL,
2565 NULL,
2566 NULL,
2567 NULL,
2568 NULL
2569 },
2570 EINA_MODEL_INTERFACE_PROPERTIES_VERSION,
2571 NULL, /* no compare */
2572 NULL, /* no load */
2573 NULL, /* no unload */
2574 _eina_model_interface_properties_hash_get,
2575 _eina_model_interface_properties_hash_set,
2576 _eina_model_interface_properties_hash_del,
2577 _eina_model_interface_properties_hash_names_list
2578};
2579
2580/* EINA_MODEL_INTERFACE_PROPERTIES_STRUCT ******************************/
2581
2582static Eina_Value_Struct *
2583_eina_model_interface_properties_struct_private_get(const Eina_Model *model)
2584{
2585 Eina_Value *val = eina_model_interface_private_data_get
2586 (model, EINA_MODEL_INTERFACE_PROPERTIES_STRUCT);
2587 return eina_value_memory_get(val);
2588}
2589
2590#define EINA_MODEL_INTERFACE_PROPERTIES_STRUCT_GET(model) \
2591 Eina_Value_Struct *priv = \
2592 _eina_model_interface_properties_struct_private_get(model)
2593
2594static Eina_Bool
2595_eina_model_interface_properties_struct_setup(Eina_Model *model)
2596{
2597 Eina_Value *val = eina_model_interface_private_data_get
2598 (model, EINA_MODEL_INTERFACE_PROPERTIES_STRUCT);
2599
2600 DBG("setup interface properties (struct) at %p model %p (%s)",
2601 val, model, model->desc->cache.types[0]->name);
2602
2603 return eina_value_setup(val, EINA_VALUE_TYPE_STRUCT);
2604}
2605
2606static Eina_Bool
2607_eina_model_interface_properties_struct_flush(Eina_Model *model)
2608{
2609 Eina_Value *val = eina_model_interface_private_data_get
2610 (model, EINA_MODEL_INTERFACE_PROPERTIES_STRUCT);
2611
2612 DBG("flush interface properties (struct) at %p model %p (%s)",
2613 val, model, model->desc->cache.types[0]->name);
2614
2615 if (val->type)
2616 {
2617 ERR("interface properties flushed with values! val=%p, model %p (%s)",
2618 val, model, model->desc->cache.types[0]->name);
2619 eina_value_flush(val);
2620 }
2621
2622 return EINA_TRUE;
2623}
2624
2625static Eina_Bool
2626_eina_model_interface_properties_struct_constructor(Eina_Model *model)
2627{
2628 EINA_MODEL_INTERFACE_PROPERTIES_STRUCT_GET(model);
2629
2630 DBG("construct interface properties (struct) at %p model %p (%s)",
2631 priv, model, model->desc->cache.types[0]->name);
2632
2633 return EINA_TRUE;
2634}
2635
2636static Eina_Bool
2637_eina_model_interface_properties_struct_destructor(Eina_Model *model)
2638{
2639 Eina_Value *val = eina_model_interface_private_data_get
2640 (model, EINA_MODEL_INTERFACE_PROPERTIES_STRUCT);
2641
2642 DBG("destroy interface properties (struct) at %p model %p (%s)",
2643 val, model, model->desc->cache.types[0]->name);
2644
2645 eina_value_flush(val);
2646 val->type = NULL;
2647
2648 return EINA_TRUE;
2649}
2650
2651static Eina_Bool
2652_eina_model_interface_properties_struct_get(const Eina_Model *model, const char *name, Eina_Value *val)
2653{
2654 const Eina_Value *v = eina_model_interface_private_data_get
2655 (model, EINA_MODEL_INTERFACE_PROPERTIES_STRUCT);
2656 return eina_value_struct_value_get(v, name, val);
2657}
2658
2659static Eina_Bool
2660_eina_model_interface_properties_struct_set(Eina_Model *model, const char *name, const Eina_Value *val)
2661{
2662 Eina_Value *v = eina_model_interface_private_data_get
2663 (model, EINA_MODEL_INTERFACE_PROPERTIES_STRUCT);
2664 return eina_value_struct_value_set(v, name, val);
2665}
2666
2667static Eina_Bool
2668_eina_model_interface_properties_struct_del(Eina_Model *model EINA_UNUSED, const char *name EINA_UNUSED)
2669{
2670 return EINA_FALSE; /* not allowed */
2671}
2672
2673static Eina_List *
2674_eina_model_interface_properties_struct_names_list(const Eina_Model *model)
2675{
2676 EINA_MODEL_INTERFACE_PROPERTIES_STRUCT_GET(model);
2677 const Eina_Value_Struct_Member *itr;
2678 Eina_List *list = NULL;
2679
2680 EINA_SAFETY_ON_NULL_RETURN_VAL(priv, NULL);
2681 EINA_SAFETY_ON_NULL_RETURN_VAL(priv->desc, NULL);
2682 EINA_SAFETY_ON_NULL_RETURN_VAL(priv->desc->members, NULL);
2683
2684 itr = priv->desc->members;
2685 if (priv->desc->member_count)
2686 {
2687 const Eina_Value_Struct_Member *end = itr + priv->desc->member_count;
2688 for (; itr < end; itr++)
2689 list = eina_list_append(list, eina_stringshare_add(itr->name));
2690 }
2691 else
2692 {
2693 for (; itr->name != NULL; itr++)
2694 list = eina_list_append(list, eina_stringshare_add(itr->name));
2695 }
2696
2697 return list;
2698}
2699#undef EINA_MODEL_INTERFACE_PROPERTIES_STRUCT_GET
2700
2701static const Eina_Model_Interface_Properties _EINA_MODEL_INTERFACE_PROPERTIES_STRUCT = {
2702 {
2703 EINA_MODEL_INTERFACE_VERSION,
2704 sizeof(Eina_Value),
2705 sizeof(Eina_Model_Interface_Properties),
2706 _EINA_MODEL_INTERFACE_NAME_PROPERTIES,
2707 NULL, /* no parent interfaces */
2708 _eina_model_interface_properties_events,
2709 _eina_model_interface_properties_struct_setup,
2710 _eina_model_interface_properties_struct_flush,
2711 _eina_model_interface_properties_struct_constructor,
2712 _eina_model_interface_properties_struct_destructor,
2713 NULL,
2714 NULL,
2715 NULL,
2716 NULL,
2717 NULL,
2718 NULL
2719 },
2720 EINA_MODEL_INTERFACE_PROPERTIES_VERSION,
2721 NULL, /* no compare */
2722 NULL, /* no load */
2723 NULL, /* no unload */
2724 _eina_model_interface_properties_struct_get,
2725 _eina_model_interface_properties_struct_set,
2726 _eina_model_interface_properties_struct_del,
2727 _eina_model_interface_properties_struct_names_list
2728};
2729
2730/* Events for all Children interface */
2731static const Eina_Model_Event_Description _eina_model_interface_children_events[] = {
2732 EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_children_loaded, "", "model children were loaded"),
2733 EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_children_unloaded, "", "model children were unloaded"),
2734 EINA_MODEL_EVENT_DESCRIPTION_SENTINEL
2735};
2736
2737/* EINA_MODEL_INTERFACE_CHILDREN_INARRAY ******************************/
2738
2739#define EINA_MODEL_INTERFACE_CHILDREN_INARRAY_GET(model) \
2740 Eina_Inarray *priv = eina_model_interface_private_data_get \
2741 (model, EINA_MODEL_INTERFACE_CHILDREN_INARRAY)
2742
2743static Eina_Bool
2744_eina_model_interface_children_inarray_setup(Eina_Model *model)
2745{
2746 EINA_MODEL_INTERFACE_CHILDREN_INARRAY_GET(model);
2747
2748 DBG("setup interface children (inarray) at %p model %p (%s)",
2749 priv, model, model->desc->cache.types[0]->name);
2750
2751 eina_inarray_step_set(priv, sizeof(Eina_Inarray), sizeof(Eina_Model *), 0);
2752 return EINA_TRUE;
2753}
2754
2755static Eina_Bool
2756_eina_model_interface_children_inarray_flush(Eina_Model *model)
2757{
2758 EINA_MODEL_INTERFACE_CHILDREN_INARRAY_GET(model);
2759 int count;
2760
2761 DBG("flush interface children (inarray) at %p model %p (%s)",
2762 priv, model, model->desc->cache.types[0]->name);
2763
2764 count = eina_inarray_count(priv);
2765 if (count > 0)
2766 ERR("interface children flushed with %d members! priv=%p, model %p (%s)",
2767 count, priv, model, model->desc->cache.types[0]->name);
2768
2769 eina_inarray_flush(priv);
2770 return EINA_TRUE;
2771}
2772
2773static Eina_Bool
2774_eina_model_interface_children_inarray_constructor(Eina_Model *model)
2775{
2776 EINA_MODEL_INTERFACE_CHILDREN_INARRAY_GET(model);
2777
2778 DBG("construct interface children (inarray) at %p model %p (%s)",
2779 priv, model, model->desc->cache.types[0]->name);
2780
2781 return EINA_TRUE;
2782}
2783
2784static Eina_Bool
2785_eina_model_interface_children_inarray_destructor(Eina_Model *model)
2786{
2787 Eina_Model **itr, **itr_end;
2788 int count;
2789
2790 EINA_MODEL_INTERFACE_CHILDREN_INARRAY_GET(model);
2791
2792 count = eina_inarray_count(priv);
2793
2794 DBG("destroy interface children (inarray) at %p model %p (%s). %d members.",
2795 priv, model, model->desc->cache.types[0]->name, count);
2796
2797 itr = priv->members;
2798 itr_end = itr + count;
2799 for (; itr < itr_end; itr++)
2800 eina_model_xunref(*itr, EINA_MODEL_INTERFACE_CHILDREN_INARRAY);
2801 eina_inarray_flush(priv);
2802
2803 return EINA_TRUE;
2804}
2805
2806static int
2807_eina_model_interface_children_inarray_count(const Eina_Model *model)
2808{
2809 EINA_MODEL_INTERFACE_CHILDREN_INARRAY_GET(model);
2810 return eina_inarray_count(priv);
2811}
2812
2813static Eina_Model *
2814_eina_model_interface_children_inarray_get(const Eina_Model *model, unsigned int position)
2815{
2816 EINA_MODEL_INTERFACE_CHILDREN_INARRAY_GET(model);
2817 Eina_Model **child = eina_inarray_nth(priv, position);
2818 if (!child)
2819 return NULL;
2820 return eina_model_ref(*child);
2821}
2822
2823static Eina_Bool
2824_eina_model_interface_children_inarray_set(Eina_Model *model, unsigned int position, Eina_Model *child)
2825{
2826 EINA_MODEL_INTERFACE_CHILDREN_INARRAY_GET(model);
2827 Eina_Model **p_old = eina_inarray_nth(priv, position);
2828 Eina_Model *old;
2829
2830 if (!p_old)
2831 return EINA_FALSE;
2832
2833 old = *p_old;
2834 if (!eina_inarray_replace_at(priv, position, &child))
2835 return EINA_FALSE;
2836
2837 eina_model_xref(child, EINA_MODEL_INTERFACE_CHILDREN_INARRAY,
2838 "eina_model_child_set");
2839 eina_model_xunref(old, EINA_MODEL_INTERFACE_CHILDREN_INARRAY);
2840 return EINA_TRUE;
2841}
2842
2843static Eina_Bool
2844_eina_model_interface_children_inarray_del(Eina_Model *model, unsigned int position)
2845{
2846 EINA_MODEL_INTERFACE_CHILDREN_INARRAY_GET(model);
2847 Eina_Model **p_old = eina_inarray_nth(priv, position);
2848 Eina_Model *old;
2849
2850 if (!p_old)
2851 return EINA_FALSE;
2852
2853 old = *p_old;
2854 if (!eina_inarray_remove_at(priv, position))
2855 return EINA_FALSE;
2856
2857 eina_model_xunref(old, EINA_MODEL_INTERFACE_CHILDREN_INARRAY);
2858 return EINA_TRUE;
2859}
2860
2861static Eina_Bool
2862_eina_model_interface_children_inarray_insert_at(Eina_Model *model, unsigned int position, Eina_Model *child)
2863{
2864 EINA_MODEL_INTERFACE_CHILDREN_INARRAY_GET(model);
2865
2866 if (!eina_inarray_insert_at(priv, position, &child))
2867 return EINA_FALSE;
2868
2869 eina_model_xref(child, EINA_MODEL_INTERFACE_CHILDREN_INARRAY,
2870 "eina_model_child_insert_at");
2871 return EINA_TRUE;
2872}
2873
2874static void
2875_eina_model_interface_children_inarray_sort(Eina_Model *model, Eina_Compare_Cb compare)
2876{
2877 EINA_MODEL_INTERFACE_CHILDREN_INARRAY_GET(model);
2878 int count = eina_inarray_count(priv);
2879 EINA_SAFETY_ON_FALSE_RETURN(count >= 0);
2880
2881 if (count > 1)
2882 _eina_model_array_sort(priv->members, 0, count - 1, compare);
2883}
2884#undef EINA_MODEL_INTERFACE_CHILDREN_INARRAY_GET
2885
2886static const Eina_Model_Interface_Children _EINA_MODEL_INTERFACE_CHILDREN_INARRAY = {
2887 {
2888 EINA_MODEL_INTERFACE_VERSION,
2889 sizeof(Eina_Inarray),
2890 sizeof(Eina_Model_Interface_Children),
2891 _EINA_MODEL_INTERFACE_NAME_CHILDREN,
2892 NULL, /* no parent interfaces */
2893 _eina_model_interface_children_events,
2894 _eina_model_interface_children_inarray_setup,
2895 _eina_model_interface_children_inarray_flush,
2896 _eina_model_interface_children_inarray_constructor,
2897 _eina_model_interface_children_inarray_destructor,
2898 NULL,
2899 NULL,
2900 NULL,
2901 NULL,
2902 NULL,
2903 NULL
2904 },
2905 EINA_MODEL_INTERFACE_CHILDREN_VERSION,
2906 NULL, /* no compare */
2907 NULL, /* no load */
2908 NULL, /* no unload */
2909 _eina_model_interface_children_inarray_count,
2910 _eina_model_interface_children_inarray_get,
2911 _eina_model_interface_children_inarray_set,
2912 _eina_model_interface_children_inarray_del,
2913 _eina_model_interface_children_inarray_insert_at,
2914 _eina_model_interface_children_inarray_sort
2915};
2916
2917/* EINA_MODEL_TYPE_GENERIC ********************************************/
2918
2919static const Eina_Model_Interface *_EINA_MODEL_TYPE_GENERIC_IFACES[] = {
2920 &_EINA_MODEL_INTERFACE_PROPERTIES_HASH.base,
2921 &_EINA_MODEL_INTERFACE_CHILDREN_INARRAY.base,
2922 NULL
2923};
2924
2925static const Eina_Model_Type _EINA_MODEL_TYPE_GENERIC =
2926 EINA_MODEL_TYPE_INIT_NOPRIVATE("Eina_Model_Type_Generic",
2927 Eina_Model_Type,
2928 &_EINA_MODEL_TYPE_MIXIN,
2929 _EINA_MODEL_TYPE_GENERIC_IFACES,
2930 NULL);
2931
2932/* EINA_MODEL_TYPE_STRUCT ********************************************/
2933
2934static const Eina_Model_Interface *_EINA_MODEL_TYPE_STRUCT_IFACES[] = {
2935 &_EINA_MODEL_INTERFACE_PROPERTIES_STRUCT.base,
2936 &_EINA_MODEL_INTERFACE_CHILDREN_INARRAY.base,
2937 NULL
2938};
2939
2940static const Eina_Model_Type _EINA_MODEL_TYPE_STRUCT =
2941 EINA_MODEL_TYPE_INIT_NOPRIVATE("Eina_Model_Type_Struct",
2942 Eina_Model_Type,
2943 &_EINA_MODEL_TYPE_MIXIN,
2944 _EINA_MODEL_TYPE_STRUCT_IFACES,
2945 NULL);
2946
2947/**
2948 */
2949
2950/**
2951 * @internal
2952 * @brief Initialize the model module.
2953 *
2954 * @return #EINA_TRUE on success, #EINA_FALSE on failure.
2955 *
2956 * This function sets up the model module of Eina. It is called
2957 * by eina_init().
2958 *
2959 * @see eina_init()
2960 */
2961Eina_Bool
2962eina_model_init(void)
2963{
2964 const char *choice, *tmp;
2965
2966 _eina_model_log_dom = eina_log_domain_register("eina_model",
2967 EINA_LOG_COLOR_DEFAULT);
2968 if (_eina_model_log_dom < 0)
2969 {
2970 EINA_LOG_ERR("Could not register log domain: eina_model");
2971 return EINA_FALSE;
2972 }
2973
2974 choice = getenv("EINA_MODEL_DEBUG");
2975 if (choice)
2976 {
2977 if (strcmp(choice, "1") == 0)
2978 _eina_model_debug = EINA_MODEL_DEBUG_CHECK;
2979 else if (strcmp(choice, "backtrace") == 0)
2980 _eina_model_debug = EINA_MODEL_DEBUG_BACKTRACE;
2981 }
2982
2983#ifdef EINA_DEFAULT_MEMPOOL
2984 choice = "pass_through";
2985#else
2986 choice = "chained_mempool";
2987#endif
2988 tmp = getenv("EINA_MEMPOOL");
2989 if (tmp && tmp[0])
2990 choice = tmp;
2991
2992 if (choice)
2993 _eina_model_mp_choice = strdup(choice);
2994
2995 _eina_model_mp = eina_mempool_add
2996 (_eina_model_mp_choice, "model", NULL, sizeof(Eina_Model), 32);
2997 if (!_eina_model_mp)
2998 {
2999 ERR("Mempool for model cannot be allocated in model init.");
3000 goto on_init_fail_mp;
3001 }
3002
3003 if (!eina_lock_new(&_eina_model_inner_mps_lock))
3004 {
3005 ERR("Cannot create inner mempools lock in model init.");
3006 goto on_init_fail_lock_mp;
3007 }
3008 _eina_model_inner_mps = eina_hash_int32_new(NULL);
3009 if (!_eina_model_inner_mps)
3010 {
3011 ERR("Cannot create hash for inner mempools in model init.");
3012 goto on_init_fail_hash_mp;
3013 }
3014
3015 if (!eina_lock_new(&_eina_model_descriptions_lock))
3016 {
3017 ERR("Cannot create model descriptions lock in model init.");
3018 goto on_init_fail_lock_desc;
3019 }
3020 _eina_model_descriptions = eina_hash_pointer_new(NULL);
3021 if (!_eina_model_descriptions)
3022 {
3023 ERR("Cannot create model descriptions hash in model init.");
3024 goto on_init_fail_hash_desc;
3025 }
3026
3027 if (!eina_lock_new(&_eina_model_debug_list_lock))
3028 {
3029 ERR("Cannot create model debug list lock in model init.");
3030 goto on_init_fail_lock_debug;
3031 }
3032
3033 EINA_MODEL_TYPE_BASE = &_EINA_MODEL_TYPE_BASE;
3034 EINA_MODEL_TYPE_MIXIN = &_EINA_MODEL_TYPE_MIXIN;
3035 EINA_MODEL_TYPE_GENERIC = &_EINA_MODEL_TYPE_GENERIC;
3036 EINA_MODEL_TYPE_STRUCT = &_EINA_MODEL_TYPE_STRUCT;
3037
3038 EINA_MODEL_INTERFACE_PROPERTIES_HASH = &_EINA_MODEL_INTERFACE_PROPERTIES_HASH.base;
3039 EINA_MODEL_INTERFACE_PROPERTIES_STRUCT = &_EINA_MODEL_INTERFACE_PROPERTIES_STRUCT.base;
3040
3041 EINA_MODEL_INTERFACE_CHILDREN_INARRAY = &_EINA_MODEL_INTERFACE_CHILDREN_INARRAY.base;
3042
3043 EINA_MODEL_INTERFACE_NAME_PROPERTIES = _EINA_MODEL_INTERFACE_NAME_PROPERTIES;
3044 EINA_MODEL_INTERFACE_NAME_CHILDREN = _EINA_MODEL_INTERFACE_NAME_CHILDREN;
3045
3046 eina_magic_string_static_set(EINA_MAGIC_MODEL, EINA_MAGIC_MODEL_STR);
3047
3048 return EINA_TRUE;
3049
3050 on_init_fail_lock_debug:
3051 eina_hash_free(_eina_model_descriptions);
3052 on_init_fail_hash_desc:
3053 eina_lock_free(&_eina_model_descriptions_lock);
3054 on_init_fail_lock_desc:
3055 eina_hash_free(_eina_model_inner_mps);
3056 _eina_model_inner_mps = NULL;
3057 on_init_fail_hash_mp:
3058 eina_lock_free(&_eina_model_inner_mps_lock);
3059 on_init_fail_lock_mp:
3060 eina_mempool_del(_eina_model_mp);
3061 on_init_fail_mp:
3062 free(_eina_model_mp_choice);
3063 _eina_model_mp_choice = NULL;
3064 eina_log_domain_unregister(_eina_model_log_dom);
3065 _eina_model_log_dom = -1;
3066 return EINA_FALSE;
3067}
3068
3069/**
3070 * @internal
3071 * @brief Shut down the model module.
3072 *
3073 * @return #EINA_TRUE on success, #EINA_FALSE on failure.
3074 *
3075 * This function shuts down the model module set up by
3076 * eina_model_init(). It is called by eina_shutdown().
3077 *
3078 * @see eina_shutdown()
3079 */
3080Eina_Bool
3081eina_model_shutdown(void)
3082{
3083 eina_lock_take(&_eina_model_debug_list_lock);
3084 if (eina_list_count(_eina_model_debug_list) > 0)
3085 ERR("%d models are still alive!", eina_list_count(_eina_model_debug_list));
3086 eina_lock_release(&_eina_model_debug_list_lock);
3087 eina_lock_free(&_eina_model_debug_list_lock);
3088
3089 eina_lock_take(&_eina_model_inner_mps_lock);
3090 if (eina_hash_population(_eina_model_inner_mps) != 0)
3091 ERR("Cannot free eina_model internal memory pools -- still in use!");
3092 else
3093 eina_hash_free(_eina_model_inner_mps);
3094 eina_lock_release(&_eina_model_inner_mps_lock);
3095 eina_lock_free(&_eina_model_inner_mps_lock);
3096
3097 eina_lock_take(&_eina_model_descriptions_lock);
3098 if (eina_hash_population(_eina_model_descriptions) != 0)
3099 ERR("Cannot free eina_model internal descriptions -- still in use!");
3100 else
3101 eina_hash_free(_eina_model_descriptions);
3102 eina_lock_release(&_eina_model_descriptions_lock);
3103 eina_lock_free(&_eina_model_descriptions_lock);
3104
3105 free(_eina_model_mp_choice);
3106 _eina_model_mp_choice = NULL;
3107 eina_mempool_del(_eina_model_mp);
3108 eina_log_domain_unregister(_eina_model_log_dom);
3109 _eina_model_log_dom = -1;
3110 return EINA_TRUE;
3111}
3112
3113/*============================================================================*
3114 * Global *
3115 *============================================================================*/
3116
3117/*============================================================================*
3118 * API *
3119 *============================================================================*/
3120
3121
3122EAPI Eina_Error EINA_ERROR_MODEL_FAILED = 0;
3123EAPI Eina_Error EINA_ERROR_MODEL_METHOD_MISSING = 0;
3124
3125EAPI const Eina_Model_Type *EINA_MODEL_TYPE_BASE = NULL;
3126EAPI const Eina_Model_Type *EINA_MODEL_TYPE_MIXIN = NULL;
3127EAPI const Eina_Model_Type *EINA_MODEL_TYPE_GENERIC = NULL;
3128EAPI const Eina_Model_Type *EINA_MODEL_TYPE_STRUCT = NULL;
3129
3130EAPI const Eina_Model_Interface *EINA_MODEL_INTERFACE_PROPERTIES_HASH = NULL;
3131EAPI const Eina_Model_Interface *EINA_MODEL_INTERFACE_PROPERTIES_STRUCT = NULL;
3132EAPI const Eina_Model_Interface *EINA_MODEL_INTERFACE_CHILDREN_INARRAY = NULL;
3133
3134EAPI const char *EINA_MODEL_INTERFACE_NAME_PROPERTIES = "Eina_Model_Interface_Properties";
3135EAPI const char *EINA_MODEL_INTERFACE_NAME_CHILDREN = "Eina_Model_Interface_Children";
3136
3137EAPI Eina_Model *
3138eina_model_new(const Eina_Model_Type *type)
3139{
3140 const Eina_Model_Description *desc;
3141 Eina_Model *model;
3142 unsigned int i;
3143
3144 EINA_SAFETY_ON_NULL_RETURN_VAL(type, NULL);
3145 EINA_SAFETY_ON_FALSE_RETURN_VAL(eina_model_type_check(type), NULL);
3146
3147 desc = _eina_model_description_get(type);
3148 EINA_SAFETY_ON_NULL_RETURN_VAL(desc, NULL);
3149
3150 model = eina_mempool_malloc(_eina_model_mp, sizeof(Eina_Model));
3151 EINA_SAFETY_ON_NULL_GOTO(model, failed_model);
3152
3153 model->desc = desc;
3154 model->listeners.entries = NULL;
3155 model->listeners.deleted = NULL;
3156 model->listeners.freeze = NULL;
3157 model->listeners.walking = 0;
3158
3159 if (desc->total.size == 0)
3160 model->privates = NULL;
3161 else
3162 {
3163 unsigned char *ptr;
3164
3165 model->privates = _eina_model_inner_alloc
3166 (desc->total.privates * sizeof(void *) +
3167 desc->total.size);
3168 EINA_SAFETY_ON_NULL_GOTO(model->privates, failed_privates);
3169
3170 ptr = (unsigned char *)(model->privates + desc->total.privates);
3171 for (i = 0; i < desc->total.privates; i++)
3172 {
3173 unsigned int size;
3174 if (i < desc->total.types)
3175 size = desc->cache.privates[i].type->private_size;
3176 else
3177 size = desc->cache.privates[i].iface->private_size;
3178
3179 if (size == 0)
3180 {
3181 model->privates[i] = NULL;
3182 continue;
3183 }
3184
3185 model->privates[i] = ptr;
3186 memset(ptr, 0, size);
3187
3188 if (size % sizeof(void *) != 0)
3189 size += sizeof(void *) - (size % sizeof(void *));
3190 ptr += size;
3191 }
3192 }
3193
3194 model->refcount = 1;
3195 model->xrefs = NULL;
3196 model->deleted = EINA_FALSE;
3197 EINA_MAGIC_SET(model, EINA_MAGIC_MODEL);
3198
3199 /* call setup of every type in the reverse order,
3200 * they should not call parent's setup.
3201 */
3202 for (i = desc->total.types; i > 0; i--)
3203 {
3204 if (desc->cache.types[i - 1]->setup)
3205 {
3206 if (!desc->cache.types[i - 1]->setup(model))
3207 {
3208 ERR("Failed to setup model %p at type %p (%s)",
3209 model, desc->cache.types[i - 1],
3210 desc->cache.types[i - 1]->name);
3211 goto failed_types;
3212 }
3213 }
3214 }
3215
3216 /* call setup of every interface in the reverse order,
3217 * they should not call parent's setup.
3218 */
3219 for (i = desc->total.ifaces; i > 0; i--)
3220 {
3221 if (desc->cache.ifaces[i - 1]->setup)
3222 {
3223 if (!desc->cache.ifaces[i - 1]->setup(model))
3224 {
3225 ERR("Failed to setup model %p at interface %p (%s)",
3226 model, desc->cache.ifaces[i - 1],
3227 desc->cache.ifaces[i - 1]->name);
3228 goto failed_ifaces;
3229 }
3230 }
3231 }
3232
3233 if (!desc->ops.type.constructor(model))
3234 {
3235 ERR("Failed to construct model %p, type %p (%s)",
3236 model, desc->cache.types[0], desc->cache.types[0]->name);
3237 goto failed_constructor;
3238 }
3239
3240 if (EINA_UNLIKELY(_eina_model_debug))
3241 {
3242 eina_lock_take(&_eina_model_debug_list_lock);
3243 _eina_model_debug_list = eina_list_append
3244 (_eina_model_debug_list, model);
3245 eina_lock_release(&_eina_model_debug_list_lock);
3246 }
3247
3248 return model;
3249
3250 failed_constructor:
3251 i = 0;
3252 failed_ifaces:
3253 /* flush every setup interface, natural order */
3254 for (; i < desc->total.ifaces; i++)
3255 desc->cache.ifaces[i]->flush(model);
3256 i = 0;
3257 failed_types:
3258 /* flush every setup type, natural order */
3259 for (; i < desc->total.types; i++)
3260 desc->cache.types[i]->flush(model);
3261
3262 if (model->privates)
3263 _eina_model_inner_free(desc->total.privates * sizeof(void *) +
3264 desc->total.size,
3265 model->privates);
3266
3267 failed_privates:
3268 EINA_MAGIC_SET(model, EINA_MAGIC_NONE);
3269 eina_mempool_free(_eina_model_mp, model);
3270 failed_model:
3271 _eina_model_description_dispose(desc);
3272 return NULL;
3273}
3274
3275static void
3276_eina_model_free(Eina_Model *model)
3277{
3278 const Eina_Model_Description *desc = model->desc;
3279 unsigned int i;
3280
3281 DBG("model %p (%s) refcount=%d deleted=%hhu",
3282 model, model->desc->cache.types[0]->name,
3283 model->refcount, model->deleted);
3284
3285 if (EINA_UNLIKELY(_eina_model_debug))
3286 {
3287 if (model->xrefs)
3288 {
3289 ERR("Model %p (%s) released with references pending:",
3290 model, model->desc->cache.types[0]->name);
3291 while (model->xrefs)
3292 {
3293 Eina_Model_XRef *ref = (Eina_Model_XRef *)model->xrefs;
3294 model->xrefs = eina_inlist_remove(model->xrefs, model->xrefs);
3295
3296 ERR("xref: %p '%s'", ref->id, ref->label);
3297 free(ref);
3298 }
3299 }
3300
3301 eina_lock_take(&_eina_model_debug_list_lock);
3302 _eina_model_debug_list = eina_list_remove
3303 (_eina_model_debug_list, model);
3304 eina_lock_release(&_eina_model_debug_list_lock);
3305 }
3306
3307 /* flush every interface, natural order */
3308 for (i = 0; i < desc->total.ifaces; i++)
3309 if (desc->cache.ifaces[i]->flush)
3310 desc->cache.ifaces[i]->flush(model);
3311
3312 /* flush every type, natural order */
3313 for (i = 0; i < desc->total.types; i++)
3314 if (desc->cache.types[i]->flush)
3315 desc->cache.types[i]->flush(model);
3316
3317 model->refcount--;
3318 _eina_model_event_callback_call(model, _eina_model_str_freed, NULL);
3319
3320 if (model->privates)
3321 _eina_model_inner_free(desc->total.privates * sizeof(void *) +
3322 desc->total.size,
3323 model->privates);
3324
3325 if (model->listeners.deleted)
3326 _eina_model_event_callback_free_deleted(model);
3327
3328 if (model->listeners.entries)
3329 {
3330 for (i = 0; i < desc->total.events; i++)
3331 {
3332 Eina_Inlist *lst = model->listeners.entries[i];
3333 while (lst)
3334 {
3335 void *tmp = lst;
3336 lst = lst->next;
3337 _eina_model_inner_free(sizeof(Eina_Model_Event_Listener),
3338 tmp);
3339 }
3340 }
3341
3342 _eina_model_inner_free(desc->total.events * sizeof(Eina_Inlist *),
3343 model->listeners.entries);
3344 }
3345
3346 if (model->listeners.freeze)
3347 _eina_model_inner_free(model->desc->total.events * sizeof(int),
3348 model->listeners.freeze);
3349
3350 EINA_MAGIC_SET(model, EINA_MAGIC_NONE);
3351 eina_mempool_free(_eina_model_mp, model);
3352
3353 _eina_model_description_dispose(desc);
3354}
3355
3356static void
3357_eina_model_del(Eina_Model *model)
3358{
3359 const Eina_Model_Description *desc = model->desc;
3360
3361 DBG("model %p (%s) refcount=%d deleted=%hhu",
3362 model, model->desc->cache.types[0]->name,
3363 model->refcount, model->deleted);
3364
3365 EINA_SAFETY_ON_TRUE_RETURN(model->deleted);
3366
3367 model->deleted = EINA_TRUE;
3368 _eina_model_event_callback_call(model, _eina_model_str_deleted, NULL);
3369
3370 if (!desc->ops.type.destructor(model))
3371 ERR("Failed to destroy model %p, type %p (%s)",
3372 model, desc->cache.types[0], desc->cache.types[0]->name);
3373}
3374
3375static void
3376_eina_model_unref(Eina_Model *model)
3377{
3378 DBG("model %p (%s) refcount=%d deleted=%hhu",
3379 model, model->desc->cache.types[0]->name,
3380 model->refcount, model->deleted);
3381
3382 if (model->refcount > 1)
3383 {
3384 model->refcount--;
3385 return;
3386 }
3387
3388 if (!model->deleted) _eina_model_del(model);
3389 _eina_model_free(model);
3390}
3391
3392#define EINA_MODEL_INSTANCE_CHECK_VAL(inst, retval) \
3393 do \
3394 { \
3395 if (!EINA_MAGIC_CHECK(inst, EINA_MAGIC_MODEL)) \
3396 { \
3397 EINA_MAGIC_FAIL(inst, EINA_MAGIC_MODEL); \
3398 return retval; \
3399 } \
3400 EINA_SAFETY_ON_NULL_RETURN_VAL(inst->desc, retval); \
3401 EINA_SAFETY_ON_FALSE_RETURN_VAL(inst->refcount > 0, retval); \
3402 EINA_SAFETY_ON_FALSE_RETURN_VAL(inst->desc->refcount > 0, retval); \
3403 } \
3404 while (0)
3405
3406#define EINA_MODEL_INSTANCE_CHECK(inst) \
3407 do \
3408 { \
3409 if (!EINA_MAGIC_CHECK(inst, EINA_MAGIC_MODEL)) \
3410 { \
3411 EINA_MAGIC_FAIL(inst, EINA_MAGIC_MODEL); \
3412 return; \
3413 } \
3414 EINA_SAFETY_ON_NULL_RETURN(inst->desc); \
3415 EINA_SAFETY_ON_FALSE_RETURN(inst->refcount > 0); \
3416 EINA_SAFETY_ON_FALSE_RETURN(inst->desc->refcount > 0); \
3417 } \
3418 while (0)
3419
3420#define EINA_MODEL_TYPE_CALL_OPTIONAL_RETURN(model, method, def_retval, ...) \
3421 do \
3422 { \
3423 if (model->desc->ops.type.method) \
3424 return model->desc->ops.type.method(model, ## __VA_ARGS__); \
3425 DBG("Optional method" # method "() not implemented for model %p (%s)", \
3426 model, model->desc->cache.types[0]->name); \
3427 return def_retval; \
3428 } \
3429 while (0)
3430
3431#define EINA_MODEL_TYPE_CALL_OPTIONAL(model, method, ...) \
3432 do \
3433 { \
3434 if (model->desc->ops.type.method) \
3435 model->desc->ops.type.method(model, ## __VA_ARGS__); \
3436 else \
3437 DBG("Optional method" # method "() not implemented for model %p (%s)", \
3438 model, model->desc->cache.types[0]->name); \
3439 } \
3440 while (0)
3441
3442#define EINA_MODEL_TYPE_CALL_MANDATORY_RETURN(model, method, def_retval, ...) \
3443 do \
3444 { \
3445 if (model->desc->ops.type.method) \
3446 return model->desc->ops.type.method(model, ## __VA_ARGS__); \
3447 CRI("Mandatory method" # method "() not implemented for model %p (%s)", \
3448 model, model->desc->cache.types[0]->name); \
3449 return def_retval; \
3450 } \
3451 while (0)
3452
3453#define EINA_MODEL_TYPE_CALL_MANDATORY(model, method, ...) \
3454 do \
3455 { \
3456 if (model->desc->ops.type.method) \
3457 model->desc->ops.type.method(model, ## __VA_ARGS__); \
3458 else \
3459 { \
3460 CRI("Mandatory method" # method "() not implemented for model %p (%s)", \
3461 model, model->desc->cache.types[0]->name); \
3462 } \
3463 } \
3464 while (0)
3465
3466
3467#define EINA_MODEL_TYPE_CALL_RETURN(model, method, def_retval, ...) \
3468 do \
3469 { \
3470 if (model->desc->ops.type.method) \
3471 return model->desc->ops.type.method(model, ## __VA_ARGS__); \
3472 ERR("Method" # method "() not implemented for model %p (%s)", \
3473 model, model->desc->cache.types[0]->name); \
3474 return def_retval; \
3475 } \
3476 while (0)
3477
3478#define EINA_MODEL_TYPE_CALL(model, method, ...) \
3479 do \
3480 { \
3481 if (model->desc->ops.type.method) \
3482 model->desc->ops.type.method(model, ## __VA_ARGS__); \
3483 else \
3484 { \
3485 ERR("Method" # method "() not implemented for model %p (%s)", \
3486 model, model->desc->cache.types[0]->name); \
3487 } \
3488 } \
3489 while (0)
3490
3491EAPI void
3492eina_model_del(Eina_Model *model)
3493{
3494 if (!model)
3495 return;
3496
3497 EINA_MODEL_INSTANCE_CHECK(model);
3498 _eina_model_del(model);
3499 _eina_model_unref(model);
3500}
3501
3502EAPI const Eina_Model_Type *
3503eina_model_type_get(const Eina_Model *model)
3504{
3505 EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
3506 return model->desc->cache.types[0];
3507}
3508
3509EAPI const Eina_Model_Interface *
3510eina_model_interface_get(const Eina_Model *model, const char *name)
3511{
3512 const Eina_Model_Description *desc;
3513 const Eina_Model_Interface **itr, **itr_end;
3514
3515 EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
3516 EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL);
3517
3518 desc = model->desc;
3519 itr = desc->cache.ifaces;
3520 itr_end = itr + desc->total.ifaces;
3521
3522 /* fallback to strcmp if user is lazy about speed */
3523 for (; itr < itr_end; itr++)
3524 if (strcmp((*itr)->name, name) == 0)
3525 return *itr;
3526
3527 return NULL;
3528}
3529
3530static Eina_Bool
3531_eina_model_instance_check(const Eina_Model *model, const Eina_Model_Type *type)
3532{
3533 const Eina_Model_Type **itr, **itr_end;
3534
3535 itr = model->desc->cache.types;
3536 itr_end = itr + model->desc->total.types;
3537
3538 for (; itr < itr_end; itr++)
3539 if (*itr == type)
3540 return EINA_TRUE;
3541
3542 return EINA_FALSE;
3543}
3544
3545EAPI Eina_Bool
3546eina_model_instance_check(const Eina_Model *model, const Eina_Model_Type *type)
3547{
3548 EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE);
3549 EINA_SAFETY_ON_NULL_RETURN_VAL(type, EINA_FALSE);
3550 EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_type_check(type), EINA_FALSE);
3551 return _eina_model_instance_check(model, type);
3552}
3553
3554EAPI Eina_Model *
3555eina_model_ref(Eina_Model *model)
3556{
3557 EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
3558 DBG("model %p (%s) refcount=%d deleted=%hhu",
3559 model, model->desc->cache.types[0]->name,
3560 model->refcount, model->deleted);
3561 model->refcount++;
3562 return model;
3563}
3564
3565static Eina_Model *
3566_eina_model_xref_add(Eina_Model *model, const void *id, const char *label)
3567{
3568 Eina_Model_XRef *ref;
3569 void *bt[256];
3570 int btlen, labellen;
3571
3572 labellen = label ? strlen(label): 0;
3573 btlen = 0;
3574
3575#ifdef HAVE_BACKTRACE
3576 if (_eina_model_debug == EINA_MODEL_DEBUG_BACKTRACE)
3577 btlen = backtrace(bt, EINA_C_ARRAY_LENGTH(bt));
3578#endif
3579
3580 ref = calloc(1, sizeof(*ref) + (btlen * sizeof(void *)) + (labellen + 1));
3581 EINA_SAFETY_ON_NULL_RETURN_VAL(ref, NULL);
3582
3583 ref->id = id;
3584 memcpy(ref->label, label, labellen);
3585 ref->label[labellen] = '\0';
3586 ref->backtrace.count = btlen;
3587 if (btlen == 0) ref->backtrace.symbols = NULL;
3588 else
3589 {
3590 void *ptr = (unsigned char *)ref + sizeof(*ref) + (labellen + 1);
3591 ref->backtrace.symbols = ptr;
3592 memcpy(ptr, bt, btlen * sizeof(void *));
3593 }
3594
3595 model->xrefs = eina_inlist_append(model->xrefs, EINA_INLIST_GET(ref));
3596 return model;
3597}
3598
3599EAPI Eina_Model *
3600eina_model_xref(Eina_Model *model, const void *id, const char *label)
3601{
3602 EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
3603 DBG("model %p (%s) refcount=%d deleted=%hhu id=%p label=%s",
3604 model, model->desc->cache.types[0]->name,
3605 model->refcount, model->deleted, id, label ? label : "");
3606
3607 model->refcount++;
3608
3609 if (EINA_LIKELY(!_eina_model_debug))
3610 return model;
3611
3612 return _eina_model_xref_add(model, id, label);
3613}
3614
3615EAPI void
3616eina_model_unref(Eina_Model *model)
3617{
3618 EINA_MODEL_INSTANCE_CHECK(model);
3619 _eina_model_unref(model);
3620}
3621
3622EAPI void
3623eina_model_xunref(Eina_Model *model, const void *id)
3624{
3625 Eina_Model_XRef *ref;
3626 EINA_MODEL_INSTANCE_CHECK(model);
3627
3628 if (EINA_LIKELY(!_eina_model_debug))
3629 {
3630 _eina_model_unref(model);
3631 return;
3632 }
3633
3634 EINA_INLIST_FOREACH(model->xrefs, ref)
3635 {
3636 if (ref->id != id) continue;
3637
3638 model->xrefs = eina_inlist_remove(model->xrefs, EINA_INLIST_GET(ref));
3639 free(ref);
3640 _eina_model_unref(model);
3641 return;
3642 }
3643
3644 ERR("Could not find existing reference %p to model %p", id, model);
3645}
3646
3647EAPI int
3648eina_model_refcount(const Eina_Model *model)
3649{
3650 EINA_MODEL_INSTANCE_CHECK_VAL(model, -1);
3651 return model->refcount;
3652}
3653
3654EAPI const Eina_Inlist *
3655eina_model_xrefs_get(const Eina_Model *model)
3656{
3657 EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
3658 return model->xrefs;
3659}
3660
3661EAPI Eina_Bool
3662eina_model_event_callback_add(Eina_Model *model, const char *event_name, Eina_Model_Event_Cb cb, const void *data)
3663{
3664 const Eina_Model_Description *desc;
3665 Eina_Model_Event_Listener *el;
3666 int event_id;
3667
3668 EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE);
3669 EINA_SAFETY_ON_NULL_RETURN_VAL(event_name, EINA_FALSE);
3670 EINA_SAFETY_ON_NULL_RETURN_VAL(cb, EINA_FALSE);
3671
3672 desc = model->desc;
3673 event_id = _eina_model_description_event_id_find(desc, event_name);
3674 if (event_id < 0)
3675 {
3676 ERR("No event named %s for model %p (%s)",
3677 event_name, model, model->desc->cache.types[0]->name);
3678 return EINA_FALSE;
3679 }
3680
3681 if (!model->listeners.entries)
3682 {
3683 model->listeners.entries = _eina_model_inner_alloc
3684 (desc->total.events * sizeof(Eina_Inlist *));
3685 EINA_SAFETY_ON_NULL_RETURN_VAL(model->listeners.entries, EINA_FALSE);
3686 memset(model->listeners.entries, 0,
3687 desc->total.events * sizeof(Eina_Inlist *));
3688 }
3689
3690 el = _eina_model_inner_alloc(sizeof(Eina_Model_Event_Listener));
3691 EINA_SAFETY_ON_NULL_RETURN_VAL(el, EINA_FALSE);
3692
3693 el->cb = cb;
3694 el->data = data;
3695 el->deleted = EINA_FALSE;
3696 model->listeners.entries[event_id] = eina_inlist_append
3697 (model->listeners.entries[event_id], EINA_INLIST_GET(el));
3698
3699 return EINA_TRUE;
3700}
3701
3702EAPI Eina_Bool
3703eina_model_event_callback_del(Eina_Model *model, const char *event_name, Eina_Model_Event_Cb cb, const void *data)
3704{
3705 int event_id;
3706 Eina_Inlist *lst;
3707 Eina_Model_Event_Listener *el;
3708
3709 EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE);
3710 EINA_SAFETY_ON_NULL_RETURN_VAL(event_name, EINA_FALSE);
3711 EINA_SAFETY_ON_NULL_RETURN_VAL(cb, EINA_FALSE);
3712
3713 if (!model->listeners.entries)
3714 {
3715 ERR("No event callbacks for model %p (%s)",
3716 model, model->desc->cache.types[0]->name);
3717 return EINA_FALSE;
3718 }
3719
3720 event_id = _eina_model_description_event_id_find(model->desc, event_name);
3721 if (event_id < 0)
3722 {
3723 ERR("No event named %s for model %p (%s)",
3724 event_name, model, model->desc->cache.types[0]->name);
3725 return EINA_FALSE;
3726 }
3727
3728 lst = model->listeners.entries[event_id];
3729 EINA_INLIST_FOREACH(lst, el)
3730 {
3731 if (el->cb != cb) continue;
3732 if ((data) && (el->data != data)) continue;
3733
3734 if (model->listeners.walking == 0)
3735 {
3736 model->listeners.entries[event_id] = eina_inlist_remove
3737 (model->listeners.entries[event_id], EINA_INLIST_GET(el));
3738 _eina_model_inner_free(sizeof(Eina_Model_Event_Listener), el);
3739 }
3740 else
3741 {
3742 el->deleted = EINA_TRUE;
3743 if (!model->listeners.deleted)
3744 {
3745 model->listeners.deleted = _eina_model_inner_alloc
3746 (model->desc->total.events * sizeof(Eina_List *));
3747 EINA_SAFETY_ON_NULL_RETURN_VAL(model->listeners.deleted,
3748 EINA_FALSE);
3749
3750 memset(model->listeners.deleted, 0,
3751 model->desc->total.events * sizeof(Eina_List *));
3752
3753 }
3754 model->listeners.deleted[event_id] = eina_list_append
3755 (model->listeners.deleted[event_id], el);
3756 }
3757 return EINA_TRUE;
3758 }
3759
3760 ERR("No callback %p data %p found for event named %s for model %p (%s)",
3761 cb, data, event_name, model, model->desc->cache.types[0]->name);
3762 return EINA_FALSE;
3763}
3764
3765EAPI const Eina_Model_Event_Description *
3766eina_model_event_description_get(const Eina_Model *model, const char *event_name)
3767{
3768 const Eina_Model_Description *desc;
3769 int event_id;
3770
3771 EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
3772 EINA_SAFETY_ON_NULL_RETURN_VAL(event_name, NULL);
3773
3774 desc = model->desc;
3775 event_id = _eina_model_description_event_id_find(desc, event_name);
3776 if (event_id < 0)
3777 return NULL;
3778
3779 return desc->cache.events[event_id].desc;
3780}
3781
3782EAPI Eina_List *
3783eina_model_event_names_list_get(const Eina_Model *model)
3784{
3785 const Eina_Model_Event_Description_Cache *itr, *itr_end;
3786 Eina_List *lst = NULL;
3787
3788 EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
3789
3790 itr = model->desc->cache.events;
3791 itr_end = itr + model->desc->total.events;
3792
3793 for (; itr < itr_end; itr++)
3794 lst = eina_list_append(lst, eina_stringshare_add(itr->name));
3795
3796 return lst;
3797}
3798
3799EAPI void
3800eina_model_event_names_list_free(Eina_List *list)
3801{
3802 const char *str;
3803 EINA_LIST_FREE(list, str)
3804 eina_stringshare_del(str);
3805}
3806
3807EAPI Eina_Bool
3808eina_model_event_callback_call(Eina_Model *model, const char *name, const void *event_info)
3809{
3810 EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE);
3811 EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE);
3812 return _eina_model_event_callback_call(model, name, event_info);
3813}
3814
3815EAPI int
3816eina_model_event_callback_freeze(Eina_Model *model, const char *name)
3817{
3818 int event_id;
3819
3820 EINA_MODEL_INSTANCE_CHECK_VAL(model, -1);
3821 EINA_SAFETY_ON_NULL_RETURN_VAL(name, -1);
3822
3823 event_id = _eina_model_description_event_id_find(model->desc, name);
3824 if (event_id < 0) return -1;
3825
3826 if (!model->listeners.freeze)
3827 {
3828 model->listeners.freeze = _eina_model_inner_alloc
3829 (model->desc->total.events * sizeof(int));
3830 EINA_SAFETY_ON_NULL_RETURN_VAL(model->listeners.freeze, -1);
3831
3832 memset(model->listeners.freeze, 0,
3833 model->desc->total.events * sizeof(int));
3834 }
3835
3836 if (model->listeners.freeze[event_id] == 0)
3837 DBG("model %p (%s) event %s frozen",
3838 model, model->desc->cache.types[0]->name, name);
3839
3840 model->listeners.freeze[event_id]++;
3841 return model->listeners.freeze[event_id];
3842}
3843
3844EAPI int
3845eina_model_event_callback_thaw(Eina_Model *model, const char *name)
3846{
3847 int event_id;
3848
3849 EINA_MODEL_INSTANCE_CHECK_VAL(model, -1);
3850 EINA_SAFETY_ON_NULL_RETURN_VAL(name, -1);
3851 EINA_SAFETY_ON_NULL_RETURN_VAL(model->listeners.freeze, -1);
3852
3853 event_id = _eina_model_description_event_id_find(model->desc, name);
3854 if (event_id < 0) return -1;
3855
3856 model->listeners.freeze[event_id]--;
3857 if (model->listeners.freeze[event_id] == 0)
3858 DBG("model %p (%s) event %s unfrozen",
3859 model, model->desc->cache.types[0]->name, name);
3860 return model->listeners.freeze[event_id];
3861}
3862
3863EAPI Eina_Model *
3864eina_model_copy(const Eina_Model *model)
3865{
3866 const Eina_Model_Description *desc;
3867 Eina_Model *copy;
3868 unsigned int i;
3869
3870 EINA_MODEL_INSTANCE_CHECK_V