diff options
Diffstat (limited to 'libraries/eina/src/lib/eina_model.c')
-rw-r--r-- | libraries/eina/src/lib/eina_model.c | 5548 |
1 files changed, 5548 insertions, 0 deletions
diff --git a/libraries/eina/src/lib/eina_model.c b/libraries/eina/src/lib/eina_model.c new file mode 100644 index 0000000..ae06c1b --- /dev/null +++ b/libraries/eina/src/lib/eina_model.c | |||
@@ -0,0 +1,5548 @@ | |||
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_ALLOCA_H | ||
24 | # include <alloca.h> | ||
25 | #elif defined __GNUC__ | ||
26 | # define alloca __builtin_alloca | ||
27 | #elif defined _AIX | ||
28 | # define alloca __alloca | ||
29 | #elif defined _MSC_VER | ||
30 | # include <malloc.h> | ||
31 | # define alloca _alloca | ||
32 | #else | ||
33 | # include <stddef.h> | ||
34 | # ifdef __cplusplus | ||
35 | extern "C" | ||
36 | # endif | ||
37 | void *alloca (size_t); | ||
38 | #endif | ||
39 | |||
40 | #ifdef HAVE_EXECINFO_H | ||
41 | #include <execinfo.h> | ||
42 | #endif | ||
43 | |||
44 | #include "eina_config.h" | ||
45 | #include "eina_private.h" | ||
46 | #include "eina_error.h" | ||
47 | #include "eina_log.h" | ||
48 | #include "eina_mempool.h" | ||
49 | #include "eina_lock.h" | ||
50 | #include "eina_inlist.h" | ||
51 | #include "eina_strbuf.h" | ||
52 | |||
53 | /* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */ | ||
54 | #include "eina_safety_checks.h" | ||
55 | #include "eina_value.h" /* eina-safety used in inline.x */ | ||
56 | #include "eina_model.h" | ||
57 | |||
58 | /*============================================================================* | ||
59 | * Local * | ||
60 | *============================================================================*/ | ||
61 | |||
62 | /** | ||
63 | * @cond LOCAL | ||
64 | */ | ||
65 | |||
66 | static Eina_Mempool *_eina_model_mp = NULL; | ||
67 | static Eina_Hash *_eina_model_inner_mps = NULL; | ||
68 | static Eina_Lock _eina_model_inner_mps_lock; | ||
69 | static char *_eina_model_mp_choice = NULL; | ||
70 | static Eina_Hash *_eina_model_descriptions = NULL; | ||
71 | static Eina_Lock _eina_model_descriptions_lock; | ||
72 | static int _eina_model_log_dom = -1; | ||
73 | static enum { | ||
74 | EINA_MODEL_DEBUG_NONE = 0, | ||
75 | EINA_MODEL_DEBUG_CHECK = 1, | ||
76 | EINA_MODEL_DEBUG_BACKTRACE = 2, | ||
77 | } _eina_model_debug = EINA_MODEL_DEBUG_NONE; | ||
78 | static Eina_Lock _eina_model_debug_list_lock; | ||
79 | static Eina_List *_eina_model_debug_list = NULL; | ||
80 | |||
81 | static const char _eina_model_str_deleted[] = "deleted"; | ||
82 | static const char _eina_model_str_freed[] = "freed"; | ||
83 | static const char _eina_model_str_property_set[] = "property,set"; | ||
84 | static const char _eina_model_str_property_del[] = "property,deleted"; | ||
85 | static const char _eina_model_str_children_changed[] = "children,changed"; | ||
86 | static const char _eina_model_str_child_inserted[] = "child,inserted"; | ||
87 | static const char _eina_model_str_child_set[] = "child,set"; | ||
88 | static const char _eina_model_str_child_del[] = "child,deleted"; | ||
89 | static const char _eina_model_str_loaded[] = "loaded"; | ||
90 | static const char _eina_model_str_unloaded[] = "unloaded"; | ||
91 | static const char _eina_model_str_properties_loaded[] = "properties,loaded"; | ||
92 | static const char _eina_model_str_properties_unloaded[] = "properties,unloaded"; | ||
93 | static const char _eina_model_str_children_loaded[] = "children,loaded"; | ||
94 | static const char _eina_model_str_children_unloaded[] = "children,unloaded"; | ||
95 | |||
96 | #ifdef CRITICAL | ||
97 | #undef CRITICAL | ||
98 | #endif | ||
99 | #define CRITICAL(...) EINA_LOG_DOM_CRIT(_eina_model_log_dom, __VA_ARGS__) | ||
100 | |||
101 | #ifdef ERR | ||
102 | #undef ERR | ||
103 | #endif | ||
104 | #define ERR(...) EINA_LOG_DOM_ERR(_eina_model_log_dom, __VA_ARGS__) | ||
105 | |||
106 | #ifdef WRN | ||
107 | #undef WRN | ||
108 | #endif | ||
109 | #define WRN(...) EINA_LOG_DOM_WARN(_eina_model_log_dom, __VA_ARGS__) | ||
110 | |||
111 | #ifdef INF | ||
112 | #undef INF | ||
113 | #endif | ||
114 | #define INF(...) EINA_LOG_DOM_INFO(_eina_model_log_dom, __VA_ARGS__) | ||
115 | |||
116 | #ifdef DBG | ||
117 | #undef DBG | ||
118 | #endif | ||
119 | #define DBG(...) EINA_LOG_DOM_DBG(_eina_model_log_dom, __VA_ARGS__) | ||
120 | |||
121 | |||
122 | /* convenience sort array of Eina_Model* giving compare Eina_Model* instead of | ||
123 | * Eina_Model** | ||
124 | */ | ||
125 | static unsigned int | ||
126 | _eina_model_array_partition(Eina_Model **array, unsigned int start, unsigned int last, unsigned int pivot, Eina_Compare_Cb compare) | ||
127 | { | ||
128 | Eina_Model **itr, **itr_end, *tmp, *pivot_value; | ||
129 | |||
130 | pivot_value = tmp = array[pivot]; | ||
131 | array[pivot] = array[last]; | ||
132 | array[last] = tmp; | ||
133 | |||
134 | pivot = start; | ||
135 | itr = array + start; | ||
136 | itr_end = array + last; | ||
137 | for (; itr < itr_end; itr++) | ||
138 | { | ||
139 | if (compare(*itr, pivot_value) < 0) | ||
140 | { | ||
141 | tmp = *itr; | ||
142 | *itr = array[pivot]; | ||
143 | array[pivot] = tmp; | ||
144 | pivot++; | ||
145 | } | ||
146 | } | ||
147 | |||
148 | tmp = array[last]; | ||
149 | array[last] = array[pivot]; | ||
150 | array[pivot] = tmp; | ||
151 | |||
152 | return pivot; | ||
153 | } | ||
154 | |||
155 | static void | ||
156 | _eina_model_array_sort(Eina_Model **array, unsigned int start, unsigned int last, Eina_Compare_Cb compare) | ||
157 | { | ||
158 | unsigned int pivot, new_pivot; | ||
159 | |||
160 | if (last <= start) | ||
161 | return; | ||
162 | |||
163 | pivot = start + (last - start) / 2; /* avoid overflow */ | ||
164 | new_pivot = _eina_model_array_partition(array, start, last, pivot, compare); | ||
165 | |||
166 | if (start + 1 < new_pivot) | ||
167 | _eina_model_array_sort(array, start, new_pivot - 1, compare); | ||
168 | |||
169 | if (new_pivot + 1 < last) | ||
170 | _eina_model_array_sort(array, new_pivot + 1, last, compare); | ||
171 | } | ||
172 | |||
173 | /* | ||
174 | * Most of inner allocations are made with internal mempools, types | ||
175 | * and thus instace private data will repeat and it's good to use them. | ||
176 | * | ||
177 | * To save on the number of mempools, they are kept per size, not per | ||
178 | * type. | ||
179 | * | ||
180 | * This is done by means of _eina_model_inner_alloc() and | ||
181 | * _eina_model_inner_free(), both at thread safe. | ||
182 | * | ||
183 | */ | ||
184 | typedef struct _Eina_Model_Inner_Mp Eina_Model_Inner_Mp; | ||
185 | struct _Eina_Model_Inner_Mp | ||
186 | { | ||
187 | Eina_Mempool *mempool; | ||
188 | int refcount; | ||
189 | }; | ||
190 | |||
191 | static inline void | ||
192 | _eina_model_inner_mp_dispose(int size, Eina_Model_Inner_Mp *imp) | ||
193 | { | ||
194 | EINA_SAFETY_ON_FALSE_RETURN(imp->refcount == 0); | ||
195 | |||
196 | eina_hash_del_by_key(_eina_model_inner_mps, &size); | ||
197 | eina_mempool_del(imp->mempool); | ||
198 | free(imp); | ||
199 | } | ||
200 | |||
201 | static inline Eina_Model_Inner_Mp * | ||
202 | _eina_model_inner_mp_get(int size) | ||
203 | { | ||
204 | Eina_Model_Inner_Mp *imp = eina_hash_find(_eina_model_inner_mps, &size); | ||
205 | if (imp) return imp; | ||
206 | |||
207 | imp = malloc(sizeof(Eina_Model_Inner_Mp)); | ||
208 | if (!imp) | ||
209 | return NULL; | ||
210 | |||
211 | imp->refcount = 0; | ||
212 | |||
213 | imp->mempool = eina_mempool_add(_eina_model_mp_choice, | ||
214 | "Eina_Model_Inner_Mp", NULL, size, 128); | ||
215 | if (!imp->mempool) | ||
216 | { | ||
217 | free(imp); | ||
218 | return NULL; | ||
219 | } | ||
220 | |||
221 | if (!eina_hash_add(_eina_model_inner_mps, &size, imp)) | ||
222 | { | ||
223 | eina_mempool_del(imp->mempool); | ||
224 | free(imp); | ||
225 | return NULL; | ||
226 | } | ||
227 | |||
228 | return imp; | ||
229 | } | ||
230 | |||
231 | static inline void * | ||
232 | _eina_model_inner_alloc_internal(int size) | ||
233 | { | ||
234 | Eina_Model_Inner_Mp *imp; | ||
235 | void *mem; | ||
236 | |||
237 | imp = _eina_model_inner_mp_get(size); | ||
238 | if (!imp) return NULL; | ||
239 | |||
240 | mem = eina_mempool_malloc(imp->mempool, size); | ||
241 | if (mem) imp->refcount++; | ||
242 | else if (imp->refcount == 0) _eina_model_inner_mp_dispose(size, imp); | ||
243 | |||
244 | return mem; | ||
245 | } | ||
246 | |||
247 | static inline void | ||
248 | _eina_model_inner_free_internal(int size, void *mem) | ||
249 | { | ||
250 | Eina_Model_Inner_Mp *imp = eina_hash_find(_eina_model_inner_mps, &size); | ||
251 | EINA_SAFETY_ON_NULL_RETURN(imp); | ||
252 | |||
253 | eina_mempool_free(imp->mempool, mem); | ||
254 | |||
255 | imp->refcount--; | ||
256 | if (imp->refcount > 0) return; | ||
257 | _eina_model_inner_mp_dispose(size, imp); | ||
258 | } | ||
259 | |||
260 | static void * | ||
261 | _eina_model_inner_alloc(size_t size) | ||
262 | { | ||
263 | void *mem; | ||
264 | |||
265 | if (size > 512) return malloc(size); | ||
266 | |||
267 | eina_lock_take(&_eina_model_inner_mps_lock); | ||
268 | mem = _eina_model_inner_alloc_internal(size); | ||
269 | eina_lock_release(&_eina_model_inner_mps_lock); | ||
270 | |||
271 | return mem; | ||
272 | } | ||
273 | |||
274 | static void | ||
275 | _eina_model_inner_free(size_t size, void *mem) | ||
276 | { | ||
277 | if (size > 512) | ||
278 | { | ||
279 | free(mem); | ||
280 | return; | ||
281 | } | ||
282 | |||
283 | eina_lock_take(&_eina_model_inner_mps_lock); | ||
284 | _eina_model_inner_free_internal(size, mem); | ||
285 | eina_lock_release(&_eina_model_inner_mps_lock); | ||
286 | } | ||
287 | |||
288 | |||
289 | typedef union _Eina_Model_Provider Eina_Model_Provider; | ||
290 | union _Eina_Model_Provider | ||
291 | { | ||
292 | const Eina_Model_Type *type; | ||
293 | const Eina_Model_Interface *iface; | ||
294 | }; | ||
295 | |||
296 | /* store event name to aid searching */ | ||
297 | typedef struct _Eina_Model_Event_Description_Cache Eina_Model_Event_Description_Cache; | ||
298 | struct _Eina_Model_Event_Description_Cache | ||
299 | { | ||
300 | const char *name; | ||
301 | const Eina_Model_Event_Description *desc; | ||
302 | Eina_Model_Provider provider; | ||
303 | }; | ||
304 | |||
305 | /* description is an optimized structure for type. It's built at runtime | ||
306 | * to avoid user input errors and help declaration. | ||
307 | * | ||
308 | * lookups (ifaces, events) are sorted for binary search. | ||
309 | * | ||
310 | * recursion is avoided by expansion of every possible value in "cache" | ||
311 | * struct. | ||
312 | * | ||
313 | * the first usable operation is stopred for type at "ops" struct, | ||
314 | * avoiding usage of _eina_model_type_find_offset(). | ||
315 | * | ||
316 | * Get a model type description using _eina_model_description_get(), | ||
317 | * when it's not used anymore use | ||
318 | * _eina_model_description_dispose(). These operations are thread | ||
319 | * safe. | ||
320 | */ | ||
321 | typedef struct _Eina_Model_Description Eina_Model_Description; | ||
322 | struct _Eina_Model_Description | ||
323 | { | ||
324 | struct { | ||
325 | const Eina_Model_Type **types; /* size = total.types */ | ||
326 | const Eina_Model_Interface **ifaces; /* sorted, size = total.ifaces */ | ||
327 | Eina_Model_Provider *privates; /* size = total.privates (types + ifaces) */ | ||
328 | Eina_Model_Event_Description_Cache *events; /* size = total.events */ | ||
329 | } cache; | ||
330 | struct { | ||
331 | /* ops are the topmost operation to use for type/interface */ | ||
332 | struct { | ||
333 | Eina_Bool (*setup)(Eina_Model *model); | ||
334 | Eina_Bool (*flush)(Eina_Model *model); | ||
335 | Eina_Bool (*constructor)(Eina_Model *model); | ||
336 | Eina_Bool (*destructor)(Eina_Model *model); | ||
337 | Eina_Bool (*copy)(const Eina_Model *src, Eina_Model *dst); | ||
338 | Eina_Bool (*deep_copy)(const Eina_Model *src, Eina_Model *dst); | ||
339 | Eina_Bool (*compare)(const Eina_Model *a, const Eina_Model *b, int *cmp); | ||
340 | Eina_Bool (*load)(Eina_Model *model); | ||
341 | Eina_Bool (*unload)(Eina_Model *model); | ||
342 | Eina_Bool (*property_get)(const Eina_Model *model, const char *name, Eina_Value *value); | ||
343 | Eina_Bool (*property_set)(Eina_Model *model, const char *name, const Eina_Value *value); | ||
344 | Eina_Bool (*property_del)(Eina_Model *model, const char *name); | ||
345 | Eina_List *(*properties_names_list_get)(const Eina_Model *model); | ||
346 | int (*child_count)(const Eina_Model *model); | ||
347 | Eina_Model *(*child_get)(const Eina_Model *model, unsigned int position); | ||
348 | Eina_Bool (*child_set)(Eina_Model *model, unsigned int position, Eina_Model *child); | ||
349 | Eina_Bool (*child_del)(Eina_Model *model, unsigned int position); | ||
350 | Eina_Bool (*child_insert_at)(Eina_Model *model, unsigned int position, Eina_Model *child); | ||
351 | int (*child_find)(const Eina_Model *model, unsigned int start_position, const Eina_Model *other); | ||
352 | int (*child_criteria_match)(const Eina_Model *model, unsigned int start_position, Eina_Each_Cb match, const void *data); | ||
353 | void (*child_sort)(Eina_Model *model, Eina_Compare_Cb compare); | ||
354 | Eina_Iterator *(*child_iterator_get)(Eina_Model *model, unsigned int start, unsigned int count); | ||
355 | Eina_Iterator *(*child_reversed_iterator_get)(Eina_Model *model, unsigned int start, unsigned int count); | ||
356 | Eina_Iterator *(*child_sorted_iterator_get)(Eina_Model *model, unsigned int start, unsigned int count, Eina_Compare_Cb compare); | ||
357 | Eina_Iterator *(*child_filtered_iterator_get)(Eina_Model *model, unsigned int start, unsigned int count, Eina_Each_Cb match, const void *data); | ||
358 | char *(*to_string)(const Eina_Model *model); /**< used to represent model as string, usually for debug purposes or user convenience */ | ||
359 | const void **extension; | ||
360 | } type; | ||
361 | } ops; | ||
362 | struct { | ||
363 | unsigned int types; | ||
364 | unsigned int ifaces; | ||
365 | unsigned int privates; | ||
366 | unsigned int size; /* sum of all private sizes */ | ||
367 | unsigned int events; | ||
368 | } total; | ||
369 | int refcount; | ||
370 | }; | ||
371 | |||
372 | static Eina_Bool | ||
373 | _eina_model_description_type_fill(Eina_Model_Description *desc, const Eina_Model_Type *type) | ||
374 | { | ||
375 | const Eina_Model_Type *itr, *last_itr = NULL; | ||
376 | unsigned int count, child_size = 0; | ||
377 | |||
378 | for (count = 0, itr = type; itr != NULL; itr = itr->parent, count++) | ||
379 | { | ||
380 | if (itr->version != EINA_MODEL_TYPE_VERSION) | ||
381 | { | ||
382 | CRITICAL("Type %p version is %u, expected %u instead.", | ||
383 | itr, itr->version, EINA_MODEL_TYPE_VERSION); | ||
384 | return EINA_FALSE; | ||
385 | } | ||
386 | if (!itr->name) | ||
387 | { | ||
388 | CRITICAL("Type %p provides no name!", itr); | ||
389 | return EINA_FALSE; | ||
390 | } | ||
391 | if (itr->type_size < sizeof(Eina_Model_Type)) | ||
392 | { | ||
393 | CRITICAL("Type %p %s size must be >= sizeof(Eina_Model_Type)!", | ||
394 | itr, itr->name); | ||
395 | return EINA_FALSE; | ||
396 | } | ||
397 | if (child_size == 0) child_size = itr->type_size; | ||
398 | else if (child_size < itr->type_size) | ||
399 | { | ||
400 | CRITICAL("Type %p %s size is bigger than its child type %p %s!", | ||
401 | itr, itr->name, last_itr, last_itr->name); | ||
402 | return EINA_FALSE; | ||
403 | } | ||
404 | last_itr = itr; | ||
405 | |||
406 | #define DEF_METH(meth) \ | ||
407 | if (!desc->ops.type.meth) desc->ops.type.meth = itr->meth | ||
408 | DEF_METH(setup); | ||
409 | DEF_METH(flush); | ||
410 | DEF_METH(constructor); | ||
411 | DEF_METH(destructor); | ||
412 | DEF_METH(copy); | ||
413 | DEF_METH(deep_copy); | ||
414 | DEF_METH(compare); | ||
415 | DEF_METH(load); | ||
416 | DEF_METH(unload); | ||
417 | DEF_METH(property_get); | ||
418 | DEF_METH(property_set); | ||
419 | DEF_METH(property_del); | ||
420 | DEF_METH(properties_names_list_get); | ||
421 | DEF_METH(child_count); | ||
422 | DEF_METH(child_get); | ||
423 | DEF_METH(child_set); | ||
424 | DEF_METH(child_del); | ||
425 | DEF_METH(child_insert_at); | ||
426 | DEF_METH(child_find); | ||
427 | DEF_METH(child_criteria_match); | ||
428 | DEF_METH(child_sort); | ||
429 | DEF_METH(child_iterator_get); | ||
430 | DEF_METH(child_reversed_iterator_get); | ||
431 | DEF_METH(child_sorted_iterator_get); | ||
432 | DEF_METH(child_filtered_iterator_get); | ||
433 | DEF_METH(to_string); | ||
434 | #undef DEF_METH | ||
435 | |||
436 | if ((!itr->parent) && (itr != EINA_MODEL_TYPE_BASE)) | ||
437 | { | ||
438 | CRITICAL("Type %p (%s) does not inherit from EINA_MODEL_TYPE_BASE!", | ||
439 | type, type->name); | ||
440 | return EINA_FALSE; | ||
441 | } | ||
442 | } | ||
443 | |||
444 | #define CK_METH(meth) \ | ||
445 | if (!desc->ops.type.meth) \ | ||
446 | { \ | ||
447 | CRITICAL("Mandatory method "#meth \ | ||
448 | "() was not provided by type %p (%s).", \ | ||
449 | type, type->name); \ | ||
450 | return EINA_FALSE; \ | ||
451 | } | ||
452 | CK_METH(setup); | ||
453 | CK_METH(flush); | ||
454 | CK_METH(constructor); | ||
455 | CK_METH(destructor); | ||
456 | CK_METH(property_get); | ||
457 | #undef CK_METH | ||
458 | |||
459 | if (child_size <= sizeof(Eina_Model_Type)) | ||
460 | desc->ops.type.extension = NULL; | ||
461 | else | ||
462 | { | ||
463 | unsigned ext_size = child_size - sizeof(Eina_Model_Type); | ||
464 | unsigned ext_count = ext_size / sizeof(void *); | ||
465 | |||
466 | if (ext_size % sizeof(void *) != 0) | ||
467 | { | ||
468 | CRITICAL("Extension size %u is not multiple of sizeof(void*)", | ||
469 | ext_size); | ||
470 | return EINA_FALSE; | ||
471 | } | ||
472 | |||
473 | desc->ops.type.extension = calloc(ext_count, sizeof(void *)); | ||
474 | EINA_SAFETY_ON_NULL_RETURN_VAL(desc->ops.type.extension, EINA_FALSE); | ||
475 | |||
476 | for (itr = type; itr != NULL; itr = itr->parent) | ||
477 | { | ||
478 | unsigned cur_size = itr->type_size - sizeof(Eina_Model_Type); | ||
479 | unsigned i, cur_count = cur_size / sizeof(void *); | ||
480 | const void * const *ptr = (const void **)((const char *)itr + sizeof(Eina_Model_Type)); | ||
481 | |||
482 | if (cur_size == 0) break; | ||
483 | |||
484 | for (i = 0; i < cur_count; i++) | ||
485 | { | ||
486 | if (desc->ops.type.extension[i]) continue; | ||
487 | desc->ops.type.extension[i] = ptr[i]; | ||
488 | } | ||
489 | } | ||
490 | } | ||
491 | |||
492 | desc->cache.types = malloc(count * sizeof(Eina_Model_Type *)); | ||
493 | EINA_SAFETY_ON_NULL_GOTO(desc->cache.types, cache_types_failed); | ||
494 | desc->total.types = count; | ||
495 | |||
496 | for (count = 0, itr = type; itr != NULL; itr = itr->parent, count++) | ||
497 | desc->cache.types[count] = itr; | ||
498 | |||
499 | return EINA_TRUE; | ||
500 | |||
501 | cache_types_failed: | ||
502 | free(desc->ops.type.extension); | ||
503 | return EINA_FALSE; | ||
504 | } | ||
505 | |||
506 | static inline Eina_Bool | ||
507 | _eina_model_interface_implements(const Eina_Model_Interface *iface, const Eina_Model_Interface *query) | ||
508 | { | ||
509 | const Eina_Model_Interface **itr; | ||
510 | |||
511 | if (iface == query) | ||
512 | return EINA_TRUE; | ||
513 | |||
514 | if (!iface->interfaces) | ||
515 | return EINA_FALSE; | ||
516 | |||
517 | for (itr = iface->interfaces; *itr != NULL; itr++) | ||
518 | if (_eina_model_interface_implements(*itr, query)) | ||
519 | return EINA_TRUE; | ||
520 | |||
521 | return EINA_FALSE; | ||
522 | } | ||
523 | |||
524 | /* apply topological sort and remove duplicates */ | ||
525 | /* | ||
526 | * TODO: Topological sort will only work for linked interfaces, but | ||
527 | * will ignore original ordering provided by types. Consider the | ||
528 | * following: | ||
529 | * | ||
530 | * - A_Type -> X_Iface (name: "MyIface") | ||
531 | * - B_Type -> Y_Iface (name: "MyIface") | ||
532 | * | ||
533 | * Both X_Iface and Y_Iface are different implementations of the | ||
534 | * "MyIface". | ||
535 | * | ||
536 | * B_Type inherits from A_Type, then Y_Iface must be looked up | ||
537 | * first, even though there is no link between Y_Iface and | ||
538 | * X_Iface. | ||
539 | * | ||
540 | * However, the way the current topological sort behaves, the | ||
541 | * roots may come out in any order. We need a stable version | ||
542 | * that sorts roots before removing them from graph. | ||
543 | * | ||
544 | * Thanks to Tasn to report it :-) | ||
545 | */ | ||
546 | static Eina_Bool | ||
547 | _eina_model_description_ifaces_fix(Eina_Model_Description *desc) | ||
548 | { | ||
549 | struct node { | ||
550 | const Eina_Model_Interface *iface; | ||
551 | unsigned int users; | ||
552 | Eina_List *deps; | ||
553 | } *nodes, **pending, **roots; | ||
554 | unsigned int n_nodes = desc->total.ifaces, n_pending = 0, n_roots = 0, i, j; | ||
555 | Eina_Bool ret = EINA_TRUE; | ||
556 | |||
557 | nodes = alloca(n_nodes * sizeof(struct node)); | ||
558 | pending = alloca(n_nodes * sizeof(struct node *)); | ||
559 | roots = alloca(n_nodes * sizeof(struct node *)); | ||
560 | |||
561 | /* populate */ | ||
562 | for (i = 0, j = 0; i < n_nodes; i++) | ||
563 | { | ||
564 | unsigned int k; | ||
565 | for (k = 0; k < j; k++) | ||
566 | { | ||
567 | if (nodes[k].iface == desc->cache.ifaces[i]) | ||
568 | break; | ||
569 | } | ||
570 | if (k < j) | ||
571 | continue; /* already exists */ | ||
572 | |||
573 | nodes[j].iface = desc->cache.ifaces[i]; | ||
574 | nodes[j].users = 0; | ||
575 | nodes[j].deps = NULL; | ||
576 | j++; | ||
577 | } | ||
578 | n_nodes = j; | ||
579 | |||
580 | for (i = 0; i < n_nodes; i++) | ||
581 | { | ||
582 | for (j = 0; j < n_nodes; j++) | ||
583 | { | ||
584 | if (i == j) continue; | ||
585 | if (!_eina_model_interface_implements(nodes[j].iface, | ||
586 | nodes[i].iface)) | ||
587 | continue; | ||
588 | |||
589 | nodes[i].users++; | ||
590 | nodes[j].deps = eina_list_append(nodes[j].deps, nodes + i); | ||
591 | } | ||
592 | } | ||
593 | for (i = 0; i < n_nodes; i++) | ||
594 | { | ||
595 | if (nodes[i].users == 0) | ||
596 | { | ||
597 | roots[n_roots] = nodes + i; | ||
598 | n_roots++; | ||
599 | } | ||
600 | else | ||
601 | { | ||
602 | pending[n_pending] = nodes + i; | ||
603 | n_pending++; | ||
604 | } | ||
605 | } | ||
606 | |||
607 | /* topological sort */ | ||
608 | desc->total.ifaces = 0; | ||
609 | while (n_roots > 0) | ||
610 | { | ||
611 | struct node *r, *d; | ||
612 | |||
613 | /* TODO: sort roots using input order? Or at least study if | ||
614 | * it's enough to change roots append to prepend. | ||
615 | * | ||
616 | * See comments above. | ||
617 | */ | ||
618 | n_roots--; | ||
619 | r = roots[n_roots]; | ||
620 | |||
621 | desc->cache.ifaces[desc->total.ifaces] = r->iface; | ||
622 | desc->total.ifaces++; | ||
623 | |||
624 | EINA_LIST_FREE(r->deps, d) | ||
625 | { | ||
626 | d->users--; | ||
627 | if (d->users > 0) continue; | ||
628 | |||
629 | roots[n_roots] = d; | ||
630 | n_roots++; | ||
631 | |||
632 | /* remove node, it became a root */ | ||
633 | for (j = 0; j < n_pending; j++) | ||
634 | { | ||
635 | if (pending[j] == d) | ||
636 | { | ||
637 | n_pending--; | ||
638 | if (j < n_pending) | ||
639 | pending[j] = pending[n_pending]; | ||
640 | break; | ||
641 | } | ||
642 | } | ||
643 | } | ||
644 | } | ||
645 | |||
646 | if (n_pending > 0) | ||
647 | { | ||
648 | ERR("Dependency loop found for interfaces!"); | ||
649 | for (i = 0; i < n_pending; i++) | ||
650 | ERR("%p (%s) is part of dependency loop!", | ||
651 | pending[i]->iface, pending[i]->iface->name); | ||
652 | CRITICAL("Cannot use type %p (%s) with broken interfaces!", | ||
653 | desc->cache.types[0], desc->cache.types[0]->name); | ||
654 | free(desc->cache.ifaces); | ||
655 | ret = EINA_FALSE; | ||
656 | } | ||
657 | |||
658 | /* likely from still pending (dependency loops) */ | ||
659 | for (i = 0; i < n_nodes; i++) | ||
660 | eina_list_free(nodes[i].deps); | ||
661 | |||
662 | return ret; | ||
663 | } | ||
664 | |||
665 | static Eina_Bool | ||
666 | _eina_model_description_ifaces_validate_and_count(const Eina_Model_Interface *iface, unsigned int *count) | ||
667 | { | ||
668 | if (iface->version != EINA_MODEL_INTERFACE_VERSION) | ||
669 | { | ||
670 | CRITICAL("Interface %p version is %u, expected %u instead.", | ||
671 | iface, iface->version, EINA_MODEL_INTERFACE_VERSION); | ||
672 | return EINA_FALSE; | ||
673 | } | ||
674 | |||
675 | if (!iface->name) | ||
676 | { | ||
677 | CRITICAL("Interface %p provides no name!", iface); | ||
678 | return EINA_FALSE; | ||
679 | } | ||
680 | |||
681 | if (iface->interfaces) | ||
682 | { | ||
683 | const Eina_Model_Interface **itr = iface->interfaces; | ||
684 | for (; *itr != NULL; itr++) | ||
685 | if (!_eina_model_description_ifaces_validate_and_count(*itr, count)) | ||
686 | return EINA_FALSE; | ||
687 | } | ||
688 | |||
689 | (*count)++; | ||
690 | return EINA_TRUE; | ||
691 | } | ||
692 | |||
693 | static void | ||
694 | _eina_model_description_ifaces_populate(Eina_Model_Description *desc, const Eina_Model_Interface *iface) | ||
695 | { | ||
696 | desc->cache.ifaces[desc->total.ifaces] = iface; | ||
697 | desc->total.ifaces++; | ||
698 | |||
699 | if (iface->interfaces) | ||
700 | { | ||
701 | const Eina_Model_Interface **itr = iface->interfaces; | ||
702 | for (; *itr != NULL; itr++) | ||
703 | _eina_model_description_ifaces_populate(desc, *itr); | ||
704 | } | ||
705 | } | ||
706 | |||
707 | static Eina_Bool | ||
708 | _eina_model_description_ifaces_fill(Eina_Model_Description *desc) | ||
709 | { | ||
710 | const Eina_Model_Type **titr, **titr_end; | ||
711 | unsigned int count; | ||
712 | |||
713 | titr = desc->cache.types; | ||
714 | titr_end = titr + desc->total.types; | ||
715 | |||
716 | /* naively count all interfaces, remove duplicates later */ | ||
717 | for (count = 0; titr < titr_end; titr++) | ||
718 | { | ||
719 | const Eina_Model_Type *type = *titr; | ||
720 | const Eina_Model_Interface **iitr = type->interfaces; | ||
721 | if (!type->interfaces) continue; | ||
722 | |||
723 | for (; *iitr != NULL; iitr++) | ||
724 | if (!_eina_model_description_ifaces_validate_and_count(*iitr, &count)) | ||
725 | return EINA_FALSE; | ||
726 | } | ||
727 | if (count == 0) | ||
728 | { | ||
729 | desc->cache.ifaces = NULL; | ||
730 | desc->total.ifaces = 0; | ||
731 | return EINA_TRUE; | ||
732 | } | ||
733 | |||
734 | desc->cache.ifaces = malloc(count * sizeof(Eina_Model_Interface *)); | ||
735 | EINA_SAFETY_ON_NULL_RETURN_VAL(desc->cache.ifaces, EINA_FALSE); | ||
736 | |||
737 | titr = desc->cache.types; | ||
738 | desc->total.ifaces = 0; | ||
739 | for (; titr < titr_end; titr++) | ||
740 | { | ||
741 | const Eina_Model_Type *type = *titr; | ||
742 | const Eina_Model_Interface **iitr = type->interfaces; | ||
743 | |||
744 | if (!type->interfaces) continue; | ||
745 | |||
746 | for (; *iitr != NULL; iitr++) | ||
747 | _eina_model_description_ifaces_populate(desc, *iitr); | ||
748 | } | ||
749 | |||
750 | return _eina_model_description_ifaces_fix(desc); | ||
751 | } | ||
752 | |||
753 | static Eina_Bool | ||
754 | _eina_model_description_privates_fill(Eina_Model_Description *desc) | ||
755 | { | ||
756 | unsigned int i; | ||
757 | |||
758 | desc->total.privates = desc->total.types + desc->total.ifaces; | ||
759 | desc->cache.privates = malloc(desc->total.privates * | ||
760 | sizeof(Eina_Model_Provider)); | ||
761 | EINA_SAFETY_ON_NULL_RETURN_VAL(desc->cache.privates, EINA_FALSE); | ||
762 | |||
763 | desc->total.size = 0; | ||
764 | |||
765 | for (i = 0; i < desc->total.types; i++) | ||
766 | { | ||
767 | const Eina_Model_Type *type = desc->cache.types[i]; | ||
768 | desc->cache.privates[i].type = type; | ||
769 | if (type->private_size > 0) | ||
770 | { | ||
771 | unsigned int size = type->private_size; | ||
772 | if (size % sizeof(void *) != 0) | ||
773 | size += sizeof(void *) - (size % sizeof(void *)); | ||
774 | desc->total.size += size; | ||
775 | } | ||
776 | } | ||
777 | |||
778 | for (i = 0; i < desc->total.ifaces; i++) | ||
779 | { | ||
780 | const Eina_Model_Interface *iface = desc->cache.ifaces[i]; | ||
781 | desc->cache.privates[desc->total.types + i].iface = iface; | ||
782 | if (iface->private_size > 0) | ||
783 | { | ||
784 | unsigned int size = iface->private_size; | ||
785 | if (size % sizeof(void *) != 0) | ||
786 | size += sizeof(void *) - (size % sizeof(void *)); | ||
787 | desc->total.size += size; | ||
788 | } | ||
789 | } | ||
790 | |||
791 | return EINA_TRUE; | ||
792 | } | ||
793 | |||
794 | static int | ||
795 | _eina_model_description_events_cmp(const void *pa, const void *pb) | ||
796 | { | ||
797 | const Eina_Model_Event_Description_Cache *a = pa, *b = pb; | ||
798 | return strcmp(a->name, b->name); | ||
799 | } | ||
800 | |||
801 | static int | ||
802 | _eina_model_description_events_find(const Eina_Model_Description *desc, const Eina_Model_Event_Description *query) | ||
803 | { | ||
804 | unsigned int i; | ||
805 | for (i = 0; i < desc->total.events; i++) | ||
806 | { | ||
807 | const Eina_Model_Event_Description_Cache *itr = desc->cache.events + i; | ||
808 | if ((itr->name == query->name) || (strcmp(itr->name, query->name) == 0)) | ||
809 | return i; | ||
810 | } | ||
811 | |||
812 | return -1; | ||
813 | } | ||
814 | |||
815 | /* warn and remove duplicates, sort items to speed up lookups */ | ||
816 | static Eina_Bool | ||
817 | _eina_model_description_events_fill(Eina_Model_Description *desc) | ||
818 | { | ||
819 | unsigned int i, count = 0, type_events; | ||
820 | |||
821 | for (i = 0; i < desc->total.types; i++) | ||
822 | { | ||
823 | const Eina_Model_Event_Description *itr = desc->cache.types[i]->events; | ||
824 | if (!itr) continue; | ||
825 | for (; itr->name != NULL; itr++) | ||
826 | { | ||
827 | count++; | ||
828 | } | ||
829 | } | ||
830 | type_events = count; | ||
831 | |||
832 | for (i = 0; i < desc->total.ifaces; i++) | ||
833 | { | ||
834 | const Eina_Model_Event_Description *itr = desc->cache.ifaces[i]->events; | ||
835 | if (!itr) continue; | ||
836 | for (; itr->name != NULL; itr++) | ||
837 | count++; | ||
838 | } | ||
839 | |||
840 | if (count == 0) | ||
841 | { | ||
842 | desc->cache.events = NULL; | ||
843 | desc->total.events = 0; | ||
844 | return EINA_TRUE; | ||
845 | } | ||
846 | |||
847 | desc->cache.events = malloc(count * | ||
848 | sizeof(Eina_Model_Event_Description_Cache)); | ||
849 | EINA_SAFETY_ON_NULL_RETURN_VAL(desc->cache.events, EINA_FALSE); | ||
850 | desc->total.events = 0; | ||
851 | |||
852 | for (i = 0; i < desc->total.types; i++) | ||
853 | { | ||
854 | const Eina_Model_Type *mtype = desc->cache.types[i]; | ||
855 | const Eina_Model_Event_Description *itr = mtype->events; | ||
856 | if (!itr) continue; | ||
857 | for (; itr->name != NULL; itr++) | ||
858 | { | ||
859 | int j = _eina_model_description_events_find(desc, itr); | ||
860 | if (j >= 0) | ||
861 | { | ||
862 | const Eina_Model_Event_Description_Cache *o = desc->cache.events + j; | ||
863 | const Eina_Model_Type *omtype = o->provider.type; | ||
864 | WRN("Ignored duplicated event '%s' (type: '%s') from " | ||
865 | "model type %p (%s): already exists with type '%s' " | ||
866 | "from model type %p (%s)", | ||
867 | itr->name, | ||
868 | itr->type ? itr->type : "", | ||
869 | mtype, mtype->name, | ||
870 | o->desc->type ? o->desc->type : "", | ||
871 | omtype, omtype->name); | ||
872 | continue; | ||
873 | } | ||
874 | |||
875 | desc->cache.events[desc->total.events].name = itr->name; | ||
876 | desc->cache.events[desc->total.events].desc = itr; | ||
877 | desc->cache.events[desc->total.events].provider.type = mtype; | ||
878 | desc->total.events++; | ||
879 | } | ||
880 | } | ||
881 | |||
882 | for (i = 0; i < desc->total.ifaces; i++) | ||
883 | { | ||
884 | const Eina_Model_Interface *miface = desc->cache.ifaces[i]; | ||
885 | const Eina_Model_Event_Description *itr = desc->cache.ifaces[i]->events; | ||
886 | if (!itr) continue; | ||
887 | for (; itr->name != NULL; itr++) | ||
888 | { | ||
889 | int j = _eina_model_description_events_find(desc, itr); | ||
890 | if (j >= 0) | ||
891 | { | ||
892 | const Eina_Model_Event_Description_Cache *o = desc->cache.events + j; | ||
893 | if ((unsigned)j < type_events) | ||
894 | { | ||
895 | const Eina_Model_Type *omtype = o->provider.type; | ||
896 | WRN("Ignored duplicated event '%s' (type: '%s') from " | ||
897 | "model interface %p (%s): already exists with " | ||
898 | "type '%s' from model interface %p (%s)", | ||
899 | itr->name, | ||
900 | itr->type ? itr->type : "", | ||
901 | miface, miface->name, | ||
902 | o->desc->type ? o->desc->type : "", | ||
903 | omtype, omtype->name); | ||
904 | } | ||
905 | else | ||
906 | { | ||
907 | const Eina_Model_Interface *omiface = o->provider.iface; | ||
908 | WRN("Ignored duplicated event '%s' (iface: '%s') from " | ||
909 | "model interface %p (%s): already exists with " | ||
910 | "interface '%s' from model interface %p (%s)", | ||
911 | itr->name, | ||
912 | itr->type ? itr->type : "", | ||
913 | miface, miface->name, | ||
914 | o->desc->type ? o->desc->type : "", | ||
915 | omiface, omiface->name); | ||
916 | } | ||
917 | continue; | ||
918 | } | ||
919 | |||
920 | desc->cache.events[desc->total.events].name = itr->name; | ||
921 | desc->cache.events[desc->total.events].desc = itr; | ||
922 | desc->cache.events[desc->total.events].provider.iface = miface; | ||
923 | desc->total.events++; | ||
924 | } | ||
925 | } | ||
926 | |||
927 | qsort(desc->cache.events, desc->total.events, | ||
928 | sizeof(Eina_Model_Event_Description_Cache), | ||
929 | _eina_model_description_events_cmp); | ||
930 | |||
931 | return EINA_TRUE; | ||
932 | } | ||
933 | |||
934 | static const Eina_Model_Description * | ||
935 | _eina_model_description_get_internal(const Eina_Model_Type *type) | ||
936 | { | ||
937 | Eina_Model_Description *desc; | ||
938 | |||
939 | desc = eina_hash_find(_eina_model_descriptions, &type); | ||
940 | if (desc) | ||
941 | { | ||
942 | desc->refcount++; | ||
943 | return desc; | ||
944 | } | ||
945 | |||
946 | desc = calloc(1, sizeof(Eina_Model_Description)); | ||
947 | EINA_SAFETY_ON_NULL_RETURN_VAL(desc, NULL); | ||
948 | |||
949 | if (!_eina_model_description_type_fill(desc, type)) goto failed_type; | ||
950 | if (!_eina_model_description_ifaces_fill(desc)) goto failed_ifaces; | ||
951 | if (!_eina_model_description_privates_fill(desc)) goto failed_privates; | ||
952 | if (!_eina_model_description_events_fill(desc)) goto failed_events; | ||
953 | if (!eina_hash_add(_eina_model_descriptions, &type, desc)) goto failed_hash; | ||
954 | |||
955 | desc->refcount = 1; | ||
956 | return desc; | ||
957 | |||
958 | failed_hash: | ||
959 | free(desc->cache.events); | ||
960 | failed_events: | ||
961 | free(desc->cache.privates); | ||
962 | failed_privates: | ||
963 | free(desc->cache.ifaces); | ||
964 | failed_ifaces: | ||
965 | free(desc->cache.types); | ||
966 | free(desc->ops.type.extension); | ||
967 | failed_type: | ||
968 | free(desc); | ||
969 | return NULL; | ||
970 | } | ||
971 | |||
972 | static void | ||
973 | _eina_model_description_dispose_internal(Eina_Model_Description *desc) | ||
974 | { | ||
975 | const Eina_Model_Type *type; | ||
976 | |||
977 | EINA_SAFETY_ON_FALSE_RETURN(desc->refcount > 0); | ||
978 | desc->refcount--; | ||
979 | if (desc->refcount > 0) return; | ||
980 | |||
981 | type = desc->cache.types[0]; | ||
982 | if (!eina_hash_del_by_key(_eina_model_descriptions, &type)) | ||
983 | ERR("Cannot find type %p (%s) in descriptions hash!", | ||
984 | type, type->name); | ||
985 | |||
986 | INF("Disposed model description for type %p (%s)", type, type->name); | ||
987 | |||
988 | free(desc->ops.type.extension); | ||
989 | free(desc->cache.types); | ||
990 | free(desc->cache.ifaces); | ||
991 | free(desc->cache.privates); | ||
992 | free(desc->cache.events); | ||
993 | free(desc); | ||
994 | } | ||
995 | |||
996 | static const Eina_Model_Description * | ||
997 | _eina_model_description_get(const Eina_Model_Type *type) | ||
998 | { | ||
999 | const Eina_Model_Description *desc; | ||
1000 | |||
1001 | eina_lock_take(&_eina_model_descriptions_lock); | ||
1002 | desc = _eina_model_description_get_internal(type); | ||
1003 | eina_lock_release(&_eina_model_descriptions_lock); | ||
1004 | |||
1005 | return desc; | ||
1006 | } | ||
1007 | |||
1008 | static void | ||
1009 | _eina_model_description_dispose(const Eina_Model_Description *desc) | ||
1010 | { | ||
1011 | eina_lock_take(&_eina_model_descriptions_lock); | ||
1012 | _eina_model_description_dispose_internal((Eina_Model_Description *)desc); | ||
1013 | eina_lock_release(&_eina_model_descriptions_lock); | ||
1014 | } | ||
1015 | |||
1016 | static inline int | ||
1017 | _eina_model_description_event_id_find(const Eina_Model_Description *desc, const char *event_name) | ||
1018 | { | ||
1019 | const Eina_Model_Event_Description_Cache *cache; | ||
1020 | Eina_Model_Event_Description_Cache criteria_match; | ||
1021 | |||
1022 | criteria_match.name = event_name; | ||
1023 | cache = bsearch(&criteria_match, desc->cache.events, desc->total.events, | ||
1024 | sizeof(Eina_Model_Event_Description_Cache), | ||
1025 | _eina_model_description_events_cmp); | ||
1026 | if (!cache) | ||
1027 | { | ||
1028 | ERR("No event named %s for type %p (%s)", event_name, | ||
1029 | desc->cache.types[0], desc->cache.types[0]->name); | ||
1030 | return -1; | ||
1031 | } | ||
1032 | |||
1033 | return cache - desc->cache.events; | ||
1034 | } | ||
1035 | |||
1036 | /* | ||
1037 | * Model management and book keeping | ||
1038 | */ | ||
1039 | typedef struct _Eina_Model_Event_Listener Eina_Model_Event_Listener; | ||
1040 | struct _Eina_Model_Event_Listener | ||
1041 | { | ||
1042 | EINA_INLIST; | ||
1043 | Eina_Model_Event_Cb cb; | ||
1044 | const void *data; | ||
1045 | Eina_Bool deleted:1; | ||
1046 | }; | ||
1047 | |||
1048 | struct _Eina_Model | ||
1049 | { | ||
1050 | const Eina_Model_Description *desc; /**< optimized model description */ | ||
1051 | struct { | ||
1052 | Eina_Inlist **entries; /**< connected/listeners for each event, array of lists of Eina_Model_Event_Listener */ | ||
1053 | Eina_List **deleted; /**< deleted listeners while was walking. array of lists of Eina_Model_Event_Listener with deleted flag */ | ||
1054 | int *freeze; /**< freeze count for each event */ | ||
1055 | int walking; /**< increased while walking entries lists */ | ||
1056 | } listeners; | ||
1057 | void **privates; /**< private data per type and interface, each level gets its own stuff */ | ||
1058 | Eina_Inlist *xrefs; /**< if EINA_MODEL_DEBUG and eina_model_xref() is used */ | ||
1059 | int refcount; /**< number of users of this model instance */ | ||
1060 | Eina_Bool deleted:1; /**< if deleted but still have references */ | ||
1061 | EINA_MAGIC | ||
1062 | }; | ||
1063 | |||
1064 | static inline Eina_Bool | ||
1065 | _eina_model_type_check(const Eina_Model_Type *type) | ||
1066 | { | ||
1067 | EINA_SAFETY_ON_NULL_RETURN_VAL(type, EINA_FALSE); | ||
1068 | EINA_SAFETY_ON_FALSE_RETURN_VAL(type->version == EINA_MODEL_TYPE_VERSION, | ||
1069 | EINA_FALSE); | ||
1070 | return EINA_TRUE; | ||
1071 | } | ||
1072 | |||
1073 | /* find in type hierarchy the first one that the given offset is not a null | ||
1074 | * pointer. Use this to discover which method to call on a parent. | ||
1075 | */ | ||
1076 | static const void * | ||
1077 | _eina_model_type_find_offset(const Eina_Model_Type *type, unsigned int offset) | ||
1078 | { | ||
1079 | const unsigned char *ptr = (const unsigned char *)type; | ||
1080 | const void **addr = (const void **)(ptr + offset); | ||
1081 | |||
1082 | if (*addr) return *addr; | ||
1083 | if (!type->parent) return NULL; | ||
1084 | return _eina_model_type_find_offset(type->parent, offset); | ||
1085 | } | ||
1086 | |||
1087 | /* find in interface hierarchy the first one that the given offset is | ||
1088 | * not a null pointer. Use this to discover which method to call on a | ||
1089 | * parent. | ||
1090 | * | ||
1091 | * TODO: Keep Eina_Model_Interface_Description with topological sorted | ||
1092 | * entries for each interface? | ||
1093 | * I smell problems with the current code in more complex | ||
1094 | * situations (k-s) | ||
1095 | * | ||
1096 | * iface1 | ||
1097 | * ^ | ||
1098 | * | | ||
1099 | * .---------+---------. | ||
1100 | * | | | | ||
1101 | * iface2 iface3 iface4 | ||
1102 | * ^ ^ ^ | ||
1103 | * | | | | ||
1104 | * `---------+---------' | ||
1105 | * | | ||
1106 | * iface5 | ||
1107 | * | ||
1108 | * It should look: iface5 -> iface2 -> iface3 -> iface4 -> iface1 | ||
1109 | * Now it does: iface5 -> iface2 -> iface1 -> iface3 -> iface1 -> iface4 -> iface1 | ||
1110 | * | ||
1111 | * | ||
1112 | * iface1 | ||
1113 | * ^ | ||
1114 | * | | ||
1115 | * iface2 | ||
1116 | * ^ | ||
1117 | * | | ||
1118 | * .---------+---------. | ||
1119 | * | | | ||
1120 | * iface3 iface4 | ||
1121 | * ^ ^ | ||
1122 | * | | | ||
1123 | * `---------+---------' | ||
1124 | * | | ||
1125 | * iface5 | ||
1126 | * | ||
1127 | * It should look: iface5 -> iface3 -> iface4 -> iface2 -> iface1 | ||
1128 | * Now it does: iface5 -> iface3 -> iface2 -> iface1 -> iface4 -> iface2 -> iface1 | ||
1129 | * | ||
1130 | * | ||
1131 | * iface1 iface2 | ||
1132 | * ^ ^ | ||
1133 | * | | | ||
1134 | * `---------+---------' | ||
1135 | * | | ||
1136 | * iface3 | ||
1137 | * | ||
1138 | * It should look: iface3 -> iface1 -> iface2 | ||
1139 | * Now it does: iface3 -> iface1 -> iface2 | ||
1140 | * | ||
1141 | * For the common case it should work, let's see. | ||
1142 | */ | ||
1143 | static const void * | ||
1144 | _eina_model_interface_find_offset(const Eina_Model_Interface *iface, unsigned int offset) | ||
1145 | { | ||
1146 | const Eina_Model_Interface **itr; | ||
1147 | const unsigned char *ptr = (const unsigned char *)iface; | ||
1148 | const void **addr = (const void **)(ptr + offset); | ||
1149 | |||
1150 | if (offset + sizeof(void *) > iface->interface_size) return NULL; | ||
1151 | |||
1152 | if (*addr) return *addr; | ||
1153 | if (!iface->interfaces) return NULL; | ||
1154 | |||
1155 | for (itr = iface->interfaces; *itr != NULL; itr++) | ||
1156 | { | ||
1157 | const void *r = _eina_model_interface_find_offset(*itr, offset); | ||
1158 | if (r) | ||
1159 | return r; | ||
1160 | } | ||
1161 | |||
1162 | return NULL; | ||
1163 | } | ||
1164 | |||
1165 | static void | ||
1166 | _eina_model_event_callback_free_deleted(Eina_Model *model) | ||
1167 | { | ||
1168 | unsigned int i; | ||
1169 | |||
1170 | for (i = 0; i < model->desc->total.events; i++) | ||
1171 | { | ||
1172 | Eina_Model_Event_Listener *el; | ||
1173 | EINA_LIST_FREE(model->listeners.deleted[i], el) | ||
1174 | { | ||
1175 | model->listeners.entries[i] = eina_inlist_remove | ||
1176 | (model->listeners.entries[i], EINA_INLIST_GET(el)); | ||
1177 | _eina_model_inner_free(sizeof(Eina_Model_Event_Listener), el); | ||
1178 | } | ||
1179 | } | ||
1180 | |||
1181 | _eina_model_inner_free(model->desc->total.events * sizeof(Eina_List *), | ||
1182 | model->listeners.deleted); | ||
1183 | model->listeners.deleted = NULL; | ||
1184 | } | ||
1185 | |||
1186 | static inline Eina_Bool | ||
1187 | _eina_model_event_callback_call(Eina_Model *model, const char *name, const void *event_info) | ||
1188 | { | ||
1189 | Eina_Inlist *lst; | ||
1190 | Eina_Model_Event_Listener *el; | ||
1191 | const Eina_Model_Event_Description *ev_desc; | ||
1192 | int event_id = _eina_model_description_event_id_find(model->desc, name); | ||
1193 | |||
1194 | if (event_id < 0) return EINA_FALSE; | ||
1195 | if (!model->listeners.entries) return EINA_TRUE; | ||
1196 | |||
1197 | if ((model->listeners.freeze) && (model->listeners.freeze[event_id])) | ||
1198 | { | ||
1199 | DBG("Ignored event callback '%s' of model %p (%s): frozen", | ||
1200 | name, model, model->desc->cache.types[0]->name); | ||
1201 | return EINA_TRUE; | ||
1202 | } | ||
1203 | |||
1204 | lst = model->listeners.entries[event_id]; | ||
1205 | if (!lst) return EINA_TRUE; | ||
1206 | |||
1207 | ev_desc = model->desc->cache.events[event_id].desc; | ||
1208 | |||
1209 | model->listeners.walking++; | ||
1210 | EINA_INLIST_FOREACH(lst, el) | ||
1211 | { | ||
1212 | if (el->deleted) continue; | ||
1213 | el->cb((void *)el->data, model, ev_desc, (void *)event_info); | ||
1214 | } | ||
1215 | model->listeners.walking--; | ||
1216 | |||
1217 | if ((model->listeners.walking == 0) && (model->listeners.deleted)) | ||
1218 | _eina_model_event_callback_free_deleted(model); | ||
1219 | |||
1220 | return EINA_FALSE; | ||
1221 | } | ||
1222 | |||
1223 | static const char EINA_ERROR_MODEL_FAILED_STR[] = "Model check failed."; | ||
1224 | static const char EINA_ERROR_MODEL_METHOD_MISSING_STR[] = "Model method is missing."; | ||
1225 | static const char EINA_MAGIC_MODEL_STR[] = "Eina Model"; | ||
1226 | |||
1227 | static void _eina_model_unref(Eina_Model *model); | ||
1228 | |||
1229 | /** | ||
1230 | * @endcond | ||
1231 | */ | ||
1232 | |||
1233 | /* EINA_MODEL_TYPE_BASE: base of all other types **********************/ | ||
1234 | |||
1235 | static Eina_Bool | ||
1236 | _eina_model_type_base_setup(Eina_Model *model) | ||
1237 | { | ||
1238 | DBG("base setup of %p", model); | ||
1239 | return EINA_TRUE; | ||
1240 | } | ||
1241 | |||
1242 | static Eina_Bool | ||
1243 | _eina_model_type_base_flush(Eina_Model *model) | ||
1244 | { | ||
1245 | DBG("base flush of %p", model); | ||
1246 | return EINA_TRUE; | ||
1247 | } | ||
1248 | |||
1249 | static Eina_Bool | ||
1250 | _eina_model_type_base_constructor(Eina_Model *model) | ||
1251 | { | ||
1252 | DBG("base constructor of %p", model); | ||
1253 | return EINA_TRUE; | ||
1254 | } | ||
1255 | |||
1256 | static Eina_Bool | ||
1257 | _eina_model_type_base_destructor(Eina_Model *model) | ||
1258 | { | ||
1259 | DBG("base destructor of %p", model); | ||
1260 | return EINA_TRUE; | ||
1261 | } | ||
1262 | |||
1263 | static Eina_Bool | ||
1264 | _eina_model_type_base_properties_copy(const Eina_Model *model, Eina_Model *copy) | ||
1265 | { | ||
1266 | Eina_List *l, *props = eina_model_properties_names_list_get(model); | ||
1267 | const char *name; | ||
1268 | EINA_LIST_FOREACH(props, l, name) | ||
1269 | { | ||
1270 | Eina_Value tmp; | ||
1271 | if (!eina_model_property_get(model, name, &tmp)) | ||
1272 | { | ||
1273 | ERR("Could not get property %s from model %p (%s)", | ||
1274 | name, model, model->desc->cache.types[0]->name); | ||
1275 | eina_model_properties_names_list_free(props); | ||
1276 | return EINA_FALSE; | ||
1277 | } | ||
1278 | if (!eina_model_property_set(copy, name, &tmp)) | ||
1279 | { | ||
1280 | ERR("Could not set property %s on model %p (%s)", | ||
1281 | name, copy, copy->desc->cache.types[0]->name); | ||
1282 | eina_value_flush(&tmp); | ||
1283 | eina_model_properties_names_list_free(props); | ||
1284 | return EINA_FALSE; | ||
1285 | } | ||
1286 | eina_value_flush(&tmp); | ||
1287 | } | ||
1288 | eina_model_properties_names_list_free(props); | ||
1289 | return EINA_TRUE; | ||
1290 | } | ||
1291 | |||
1292 | static Eina_Bool | ||
1293 | _eina_model_type_base_children_copy(const Eina_Model *model, Eina_Model *copy) | ||
1294 | { | ||
1295 | int i, count = eina_model_child_count(model); | ||
1296 | |||
1297 | if (count < 0) | ||
1298 | { | ||
1299 | ERR("Could not get children count of model %p (%s)", | ||
1300 | model, model->desc->cache.types[0]->name); | ||
1301 | return EINA_FALSE; | ||
1302 | } | ||
1303 | |||
1304 | for (i = 0; i < count; i++) | ||
1305 | { | ||
1306 | Eina_Model *child = eina_model_child_get(model, i); | ||
1307 | Eina_Bool ret; | ||
1308 | |||
1309 | if (!child) | ||
1310 | { | ||
1311 | ERR("Could not get child #%d from model %p (%s)", | ||
1312 | i, model, model->desc->cache.types[0]->name); | ||
1313 | return EINA_FALSE; | ||
1314 | } | ||
1315 | |||
1316 | ret = eina_model_child_insert_at(copy, i, child); | ||
1317 | _eina_model_unref(child); | ||
1318 | |||
1319 | if (!ret) | ||
1320 | { | ||
1321 | ERR("Could not set child #%d on model %p (%s)", | ||
1322 | i, copy, copy->desc->cache.types[0]->name); | ||
1323 | return EINA_FALSE; | ||
1324 | } | ||
1325 | } | ||
1326 | |||
1327 | return EINA_TRUE; | ||
1328 | } | ||
1329 | |||
1330 | static Eina_Bool | ||
1331 | _eina_model_type_base_copy(const Eina_Model *model, Eina_Model *copy) | ||
1332 | { | ||
1333 | DBG("base copy of %p to %p", model, copy); | ||
1334 | |||
1335 | return _eina_model_type_base_properties_copy(model, copy) && | ||
1336 | _eina_model_type_base_children_copy(model, copy); | ||
1337 | } | ||
1338 | |||
1339 | static Eina_Bool | ||
1340 | _eina_model_type_base_children_deep_copy(const Eina_Model *model, Eina_Model *copy) | ||
1341 | { | ||
1342 | int i, count = eina_model_child_count(model); | ||
1343 | |||
1344 | if (count < 0) | ||
1345 | { | ||
1346 | ERR("Could not get children count of model %p (%s)", | ||
1347 | model, model->desc->cache.types[0]->name); | ||
1348 | return EINA_FALSE; | ||
1349 | } | ||
1350 | |||
1351 | for (i = 0; i < count; i++) | ||
1352 | { | ||
1353 | Eina_Model *child_copy, *child = eina_model_child_get(model, i); | ||
1354 | Eina_Bool ret; | ||
1355 | |||
1356 | if (!child) | ||
1357 | { | ||
1358 | ERR("Could not get child #%d from model %p (%s)", | ||
1359 | i, model, model->desc->cache.types[0]->name); | ||
1360 | return EINA_FALSE; | ||
1361 | } | ||
1362 | |||
1363 | child_copy = eina_model_deep_copy(child); | ||
1364 | if (!child_copy) | ||
1365 | { | ||
1366 | ERR("Could not deep copy child #%d %p (%s) from model %p (%s)", i, | ||
1367 | child, child->desc->cache.types[0]->name, | ||
1368 | model, model->desc->cache.types[0]->name); | ||
1369 | _eina_model_unref(child); | ||
1370 | return EINA_FALSE; | ||
1371 | } | ||
1372 | _eina_model_unref(child); | ||
1373 | |||
1374 | ret = eina_model_child_insert_at(copy, i, child_copy); | ||
1375 | _eina_model_unref(child_copy); | ||
1376 | |||
1377 | if (!ret) | ||
1378 | { | ||
1379 | ERR("Could not set child #%d on model %p (%s)", | ||
1380 | i, copy, copy->desc->cache.types[0]->name); | ||
1381 | return EINA_FALSE; | ||
1382 | } | ||
1383 | } | ||
1384 | |||
1385 | return EINA_TRUE; | ||
1386 | } | ||
1387 | |||
1388 | static Eina_Bool | ||
1389 | _eina_model_type_base_deep_copy(const Eina_Model *model, Eina_Model *copy) | ||
1390 | { | ||
1391 | DBG("base deep copy of %p to %p", model, copy); | ||
1392 | |||
1393 | return _eina_model_type_base_properties_copy(model, copy) && | ||
1394 | _eina_model_type_base_children_deep_copy(model, copy); | ||
1395 | } | ||
1396 | |||
1397 | static Eina_Bool | ||
1398 | _eina_model_type_base_properties_compare(const Eina_Model *a, const Eina_Model *b, int *cmp) | ||
1399 | { | ||
1400 | Eina_List *al, *aprops = eina_model_properties_names_list_get(a); | ||
1401 | Eina_List *bl, *bprops = eina_model_properties_names_list_get(b); | ||
1402 | Eina_List *l, *props = NULL; | ||
1403 | const char *aname, *bname, *name; | ||
1404 | Eina_Bool ret = EINA_TRUE; | ||
1405 | |||
1406 | EINA_LIST_FOREACH(aprops, al, aname) | ||
1407 | { | ||
1408 | EINA_LIST_FOREACH(bprops, bl, bname) | ||
1409 | if (strcmp(aname, bname) == 0) | ||
1410 | { | ||
1411 | props = eina_list_append(props, aname); | ||
1412 | break; | ||
1413 | } | ||
1414 | } | ||
1415 | |||
1416 | *cmp = 0; | ||
1417 | EINA_LIST_FOREACH(props, l, name) | ||
1418 | { | ||
1419 | Eina_Value atmp, btmp; | ||
1420 | |||
1421 | if (!eina_model_property_get(a, name, &atmp)) | ||
1422 | { | ||
1423 | ERR("Could not get property %s from model %p (%s)", | ||
1424 | name, a, a->desc->cache.types[0]->name); | ||
1425 | ret = EINA_FALSE; | ||
1426 | *cmp = -1; | ||
1427 | break; | ||
1428 | } | ||
1429 | |||
1430 | if (!eina_model_property_get(b, name, &btmp)) | ||
1431 | { | ||
1432 | ERR("Could not get property %s from model %p (%s)", | ||
1433 | name, b, b->desc->cache.types[0]->name); | ||
1434 | ret = EINA_FALSE; | ||
1435 | *cmp = -1; | ||
1436 | eina_value_flush(&atmp); | ||
1437 | break; | ||
1438 | } | ||
1439 | |||
1440 | *cmp = eina_value_compare(&atmp, &btmp); | ||
1441 | if (eina_error_get() != 0) | ||
1442 | { | ||
1443 | char *astr = eina_value_to_string(&atmp); | ||
1444 | char *bstr = eina_value_to_string(&btmp); | ||
1445 | ERR("Could not compare property %s: %s=%s, %s=%s", name, | ||
1446 | eina_value_type_name_get(eina_value_type_get(&atmp)), astr, | ||
1447 | eina_value_type_name_get(eina_value_type_get(&btmp)), bstr); | ||
1448 | free(astr); | ||
1449 | free(bstr); | ||
1450 | ret = EINA_FALSE; | ||
1451 | *cmp = -1; | ||
1452 | } | ||
1453 | |||
1454 | eina_value_flush(&atmp); | ||
1455 | eina_value_flush(&btmp); | ||
1456 | |||
1457 | if ((!ret) || (*cmp != 0)) | ||
1458 | break; | ||
1459 | } | ||
1460 | |||
1461 | if ((ret) && (*cmp == 0)) | ||
1462 | { | ||
1463 | int acount = eina_list_count(aprops); | ||
1464 | int bcount = eina_list_count(bprops); | ||
1465 | |||
1466 | if (acount < bcount) | ||
1467 | *cmp = -1; | ||
1468 | else if (acount > bcount) | ||
1469 | *cmp = 1; | ||
1470 | } | ||
1471 | |||
1472 | eina_model_properties_names_list_free(aprops); | ||
1473 | eina_model_properties_names_list_free(bprops); | ||
1474 | eina_list_free(props); | ||
1475 | return ret; | ||
1476 | } | ||
1477 | |||
1478 | static Eina_Bool | ||
1479 | _eina_model_type_base_children_compare(const Eina_Model *a, const Eina_Model *b, int *cmp) | ||
1480 | { | ||
1481 | int acount = eina_model_child_count(a); | ||
1482 | int bcount = eina_model_child_count(b); | ||
1483 | int i, count; | ||
1484 | Eina_Bool ret = EINA_TRUE; | ||
1485 | |||
1486 | if (acount < 0) | ||
1487 | { | ||
1488 | ERR("Could not get children count of model %p (%s)", | ||
1489 | a, a->desc->cache.types[0]->name); | ||
1490 | return EINA_FALSE; | ||
1491 | } | ||
1492 | if (bcount < 0) | ||
1493 | { | ||
1494 | ERR("Could not get children count of model %p (%s)", | ||
1495 | b, b->desc->cache.types[0]->name); | ||
1496 | return EINA_FALSE; | ||
1497 | } | ||
1498 | |||
1499 | if (acount < bcount) | ||
1500 | count = acount; | ||
1501 | else | ||
1502 | count = bcount; | ||
1503 | |||
1504 | for (i = 0; i < count; i++) | ||
1505 | { | ||
1506 | Eina_Model *achild, *bchild; | ||
1507 | |||
1508 | achild = eina_model_child_get(a, i); | ||
1509 | if (!achild) | ||
1510 | { | ||
1511 | ERR("Could not get child #%d from model %p (%s)", | ||
1512 | i, a, a->desc->cache.types[0]->name); | ||
1513 | *cmp = -1; | ||
1514 | return EINA_FALSE; | ||
1515 | } | ||
1516 | |||
1517 | bchild = eina_model_child_get(b, i); | ||
1518 | if (!bchild) | ||
1519 | { | ||
1520 | ERR("Could not get child #%d from model %p (%s)", | ||
1521 | i, b, b->desc->cache.types[0]->name); | ||
1522 | *cmp = -1; | ||
1523 | _eina_model_unref(achild); | ||
1524 | return EINA_FALSE; | ||
1525 | } | ||
1526 | |||
1527 | *cmp = eina_model_compare(achild, bchild); | ||
1528 | if (eina_error_get()) | ||
1529 | { | ||
1530 | ERR("Could not compare children #%d %p (%s) and %p (%s) " | ||
1531 | "from models %p (%s) and %p (%s)", i, | ||
1532 | achild, | ||
1533 | eina_model_type_name_get(eina_model_type_get(achild)), | ||
1534 | bchild, | ||
1535 | eina_model_type_name_get(eina_model_type_get(bchild)), | ||
1536 | a, a->desc->cache.types[0]->name, | ||
1537 | b, b->desc->cache.types[0]->name); | ||
1538 | ret = EINA_FALSE; | ||
1539 | } | ||
1540 | _eina_model_unref(achild); | ||
1541 | _eina_model_unref(bchild); | ||
1542 | |||
1543 | if ((!ret) || (*cmp != 0)) | ||
1544 | break; | ||
1545 | } | ||
1546 | |||
1547 | if ((ret) && (*cmp == 0)) | ||
1548 | { | ||
1549 | if (acount < bcount) | ||
1550 | *cmp = -1; | ||
1551 | else if (acount > bcount) | ||
1552 | *cmp = 1; | ||
1553 | } | ||
1554 | |||
1555 | return ret; | ||
1556 | } | ||
1557 | |||
1558 | static Eina_Bool | ||
1559 | _eina_model_type_base_compare(const Eina_Model *a, const Eina_Model *b, int *cmp) | ||
1560 | { | ||
1561 | *cmp = 0; | ||
1562 | DBG("base compare of %p and %p", a, b); | ||
1563 | |||
1564 | if (!_eina_model_type_base_properties_compare(a, b, cmp)) | ||
1565 | return EINA_FALSE; | ||
1566 | |||
1567 | if (*cmp != 0) | ||
1568 | return EINA_TRUE; | ||
1569 | |||
1570 | return _eina_model_type_base_children_compare(a, b, cmp); | ||
1571 | } | ||
1572 | |||
1573 | static int | ||
1574 | _eina_model_type_base_child_count(const Eina_Model *model) | ||
1575 | { | ||
1576 | DBG("base child_count of %p", model); | ||
1577 | return 0; | ||
1578 | } | ||
1579 | |||
1580 | static int | ||
1581 | _eina_model_type_base_child_find(const Eina_Model *model, unsigned int start_position, const Eina_Model *other) | ||
1582 | { | ||
1583 | int x = eina_model_child_count(model); | ||
1584 | unsigned int i, count; | ||
1585 | |||
1586 | DBG("base child_find of %p, %d children", model, x); | ||
1587 | |||
1588 | if (x < 0) | ||
1589 | return -1; | ||
1590 | |||
1591 | count = x; | ||
1592 | for (i = start_position; i < count; i++) | ||
1593 | { | ||
1594 | Eina_Model *current = eina_model_child_get(model, i); | ||
1595 | if (current) | ||
1596 | { | ||
1597 | _eina_model_unref(current); /* we'll not use it's value anyway */ | ||
1598 | if (current == other) | ||
1599 | return i; | ||
1600 | } | ||
1601 | } | ||
1602 | |||
1603 | return -1; | ||
1604 | } | ||
1605 | |||
1606 | static int | ||
1607 | _eina_model_type_base_child_criteria_match(const Eina_Model *model, unsigned int start_position, Eina_Each_Cb match, const void *user_data) | ||
1608 | { | ||
1609 | int x = eina_model_child_count(model); | ||
1610 | unsigned int i, count; | ||
1611 | |||
1612 | DBG("base child_criteria_match of %p, %d children", model, x); | ||
1613 | |||
1614 | if (x < 0) | ||
1615 | return -1; | ||
1616 | |||
1617 | count = x; | ||
1618 | for (i = start_position; i < count; i++) | ||
1619 | { | ||
1620 | Eina_Model *current = eina_model_child_get(model, i); | ||
1621 | if (current) | ||
1622 | { | ||
1623 | Eina_Bool r = match(model, current, (void *)user_data); | ||
1624 | _eina_model_unref(current); | ||
1625 | if (r) | ||
1626 | return i; | ||
1627 | } | ||
1628 | } | ||
1629 | |||
1630 | return -1; | ||
1631 | } | ||
1632 | |||
1633 | typedef struct _Eina_Iterator_Model_Base Eina_Iterator_Model_Base; | ||
1634 | struct _Eina_Iterator_Model_Base | ||
1635 | { | ||
1636 | Eina_Iterator base; | ||
1637 | Eina_Model *model; | ||
1638 | unsigned int current; | ||
1639 | unsigned int end; | ||
1640 | }; | ||
1641 | |||
1642 | static Eina_Bool | ||
1643 | _eina_model_type_base_child_iterator_next(Eina_Iterator *base, void **data) | ||
1644 | { | ||
1645 | Eina_Iterator_Model_Base *it; | ||
1646 | |||
1647 | it = (Eina_Iterator_Model_Base *)base; | ||
1648 | if (it->current >= it->end) | ||
1649 | return EINA_FALSE; | ||
1650 | |||
1651 | *data = eina_model_child_get(it->model, it->current); | ||
1652 | if (!*data) | ||
1653 | return EINA_FALSE; | ||
1654 | |||
1655 | it->current++; | ||
1656 | return EINA_TRUE; | ||
1657 | } | ||
1658 | |||
1659 | static void * | ||
1660 | _eina_model_type_base_child_iterator_get_container(Eina_Iterator *base) | ||
1661 | { | ||
1662 | Eina_Iterator_Model_Base *it; | ||
1663 | it = (Eina_Iterator_Model_Base *)base; | ||
1664 | return it->model; | ||
1665 | } | ||
1666 | |||
1667 | static void | ||
1668 | _eina_model_type_base_child_iterator_free(Eina_Iterator *base) | ||
1669 | { | ||
1670 | Eina_Iterator_Model_Base *it; | ||
1671 | it = (Eina_Iterator_Model_Base *)base; | ||
1672 | eina_model_xunref(it->model, it); | ||
1673 | free(it); | ||
1674 | } | ||
1675 | |||
1676 | static Eina_Iterator * | ||
1677 | _eina_model_type_base_child_iterator_get(Eina_Model *model, unsigned int start, unsigned int count) | ||
1678 | { | ||
1679 | Eina_Iterator_Model_Base *it = calloc(1, sizeof(*it)); | ||
1680 | EINA_SAFETY_ON_NULL_RETURN_VAL(it, NULL); | ||
1681 | |||
1682 | EINA_MAGIC_SET(&it->base, EINA_MAGIC_ITERATOR); | ||
1683 | it->base.version = EINA_ITERATOR_VERSION; | ||
1684 | it->base.next = _eina_model_type_base_child_iterator_next; | ||
1685 | it->base.get_container = _eina_model_type_base_child_iterator_get_container; | ||
1686 | it->base.free = _eina_model_type_base_child_iterator_free; | ||
1687 | |||
1688 | it->model = eina_model_xref(model, it, "eina_model_child_slice_iterator_get"); | ||
1689 | it->current = start; | ||
1690 | it->end = start + count; | ||
1691 | |||
1692 | return &it->base; | ||
1693 | } | ||
1694 | |||
1695 | typedef struct _Eina_Iterator_Model_Base_Reversed Eina_Iterator_Model_Base_Reversed; | ||
1696 | struct _Eina_Iterator_Model_Base_Reversed | ||
1697 | { | ||
1698 | Eina_Iterator base; | ||
1699 | Eina_Model *model; | ||
1700 | unsigned int current; | ||
1701 | unsigned int end; | ||
1702 | }; | ||
1703 | |||
1704 | static Eina_Bool | ||
1705 | _eina_model_type_base_child_reversed_iterator_next(Eina_Iterator *base, void **data) | ||
1706 | { | ||
1707 | Eina_Iterator_Model_Base_Reversed *it; | ||
1708 | |||
1709 | it = (Eina_Iterator_Model_Base_Reversed *)base; | ||
1710 | if (it->current == it->end) | ||
1711 | return EINA_FALSE; | ||
1712 | |||
1713 | it->current--; | ||
1714 | *data = eina_model_child_get(it->model, it->current); | ||
1715 | if (!*data) | ||
1716 | return EINA_FALSE; | ||
1717 | |||
1718 | return EINA_TRUE; | ||
1719 | } | ||
1720 | |||
1721 | static void * | ||
1722 | _eina_model_type_base_child_reversed_iterator_get_container(Eina_Iterator *base) | ||
1723 | { | ||
1724 | Eina_Iterator_Model_Base_Reversed *it; | ||
1725 | it = (Eina_Iterator_Model_Base_Reversed *)base; | ||
1726 | return it->model; | ||
1727 | } | ||
1728 | |||
1729 | static void | ||
1730 | _eina_model_type_base_child_reversed_iterator_free(Eina_Iterator *base) | ||
1731 | { | ||
1732 | Eina_Iterator_Model_Base_Reversed *it; | ||
1733 | it = (Eina_Iterator_Model_Base_Reversed *)base; | ||
1734 | eina_model_xunref(it->model, it); | ||
1735 | free(it); | ||
1736 | } | ||
1737 | |||
1738 | static Eina_Iterator * | ||
1739 | _eina_model_type_base_child_reversed_iterator_get(Eina_Model *model, unsigned int start, unsigned int count) | ||
1740 | { | ||
1741 | Eina_Iterator_Model_Base_Reversed *it; | ||
1742 | int children_count; | ||
1743 | |||
1744 | children_count = eina_model_child_count(model); | ||
1745 | if (children_count < 0) | ||
1746 | return NULL; | ||
1747 | |||
1748 | if (start + count > (unsigned int)children_count) | ||
1749 | { | ||
1750 | if (start >= (unsigned int)children_count) | ||
1751 | count = 0; | ||
1752 | else | ||
1753 | count = children_count - start; | ||
1754 | } | ||
1755 | |||
1756 | it = calloc(1, sizeof(*it)); | ||
1757 | EINA_SAFETY_ON_NULL_RETURN_VAL(it, NULL); | ||
1758 | EINA_MAGIC_SET(&it->base, EINA_MAGIC_ITERATOR); | ||
1759 | it->base.version = EINA_ITERATOR_VERSION; | ||
1760 | it->base.next = _eina_model_type_base_child_reversed_iterator_next; | ||
1761 | it->base.get_container = _eina_model_type_base_child_reversed_iterator_get_container; | ||
1762 | it->base.free = _eina_model_type_base_child_reversed_iterator_free; | ||
1763 | |||
1764 | it->model = eina_model_xref(model, it, "eina_model_child_slice_reversed_iterator_get"); | ||
1765 | it->current = start + count; | ||
1766 | it->end = start; | ||
1767 | |||
1768 | return &it->base; | ||
1769 | } | ||
1770 | |||
1771 | typedef struct _Eina_Iterator_Model_Base_Sorted Eina_Iterator_Model_Base_Sorted; | ||
1772 | struct _Eina_Iterator_Model_Base_Sorted | ||
1773 | { | ||
1774 | Eina_Iterator base; | ||
1775 | Eina_Model *model; | ||
1776 | unsigned int current; | ||
1777 | unsigned int count; | ||
1778 | Eina_Model *elements[]; | ||
1779 | }; | ||
1780 | |||
1781 | static Eina_Bool | ||
1782 | _eina_model_type_base_child_sorted_iterator_next(Eina_Iterator *base, void **data) | ||
1783 | { | ||
1784 | Eina_Iterator_Model_Base_Sorted *it; | ||
1785 | |||
1786 | it = (Eina_Iterator_Model_Base_Sorted *)base; | ||
1787 | if (it->current == it->count) | ||
1788 | return EINA_FALSE; | ||
1789 | |||
1790 | *data = eina_model_ref(it->elements[it->current]); | ||
1791 | it->current++; | ||
1792 | return EINA_TRUE; | ||
1793 | } | ||
1794 | |||
1795 | static void * | ||
1796 | _eina_model_type_base_child_sorted_iterator_get_container(Eina_Iterator *base) | ||
1797 | { | ||
1798 | Eina_Iterator_Model_Base_Sorted *it; | ||
1799 | it = (Eina_Iterator_Model_Base_Sorted *)base; | ||
1800 | return it->model; | ||
1801 | } | ||
1802 | |||
1803 | static void | ||
1804 | _eina_model_type_base_child_sorted_iterator_free(Eina_Iterator *base) | ||
1805 | { | ||
1806 | Eina_Iterator_Model_Base_Sorted *it; | ||
1807 | unsigned int i; | ||
1808 | it = (Eina_Iterator_Model_Base_Sorted *)base; | ||
1809 | eina_model_xunref(it->model, it); | ||
1810 | |||
1811 | for (i = 0; i < it->count; i++) | ||
1812 | _eina_model_unref(it->elements[i]); | ||
1813 | |||
1814 | free(it); | ||
1815 | } | ||
1816 | |||
1817 | static Eina_Iterator * | ||
1818 | _eina_model_type_base_child_sorted_iterator_get(Eina_Model *model, unsigned int start, unsigned int count, Eina_Compare_Cb compare) | ||
1819 | { | ||
1820 | Eina_Iterator_Model_Base_Sorted *it; | ||
1821 | int children_count; | ||
1822 | unsigned int i; | ||
1823 | |||
1824 | children_count = eina_model_child_count(model); | ||
1825 | if (children_count < 0) | ||
1826 | return NULL; | ||
1827 | |||
1828 | if (start + count > (unsigned int)children_count) | ||
1829 | { | ||
1830 | if (start >= (unsigned int)children_count) | ||
1831 | count = 0; | ||
1832 | else | ||
1833 | count = children_count - start; | ||
1834 | } | ||
1835 | |||
1836 | it = calloc(1, sizeof(*it) + count * sizeof(Eina_Model *)); | ||
1837 | EINA_SAFETY_ON_NULL_RETURN_VAL(it, NULL); | ||
1838 | EINA_MAGIC_SET(&it->base, EINA_MAGIC_ITERATOR); | ||
1839 | it->base.version = EINA_ITERATOR_VERSION; | ||
1840 | it->base.next = _eina_model_type_base_child_sorted_iterator_next; | ||
1841 | it->base.get_container = _eina_model_type_base_child_sorted_iterator_get_container; | ||
1842 | it->base.free = _eina_model_type_base_child_sorted_iterator_free; | ||
1843 | |||
1844 | it->model = eina_model_xref(model, it, "eina_model_child_slice_sorted_iterator_get"); | ||
1845 | it->current = 0; | ||
1846 | it->count = count; | ||
1847 | |||
1848 | for (i = 0; i < count; i++) | ||
1849 | { | ||
1850 | it->elements[i] = eina_model_child_get(model, i + start); | ||
1851 | if (!it->elements[i]) | ||
1852 | { | ||
1853 | ERR("Failed to get child %u of model %p (%s)", | ||
1854 | i + start, model, model->desc->cache.types[0]->name); | ||
1855 | free(it); | ||
1856 | return NULL; | ||
1857 | } | ||
1858 | } | ||
1859 | |||
1860 | if (count > 1) | ||
1861 | _eina_model_array_sort(it->elements, 0, count - 1, compare); | ||
1862 | |||
1863 | return &it->base; | ||
1864 | } | ||
1865 | |||
1866 | typedef struct _Eina_Iterator_Model_Base_Filtered Eina_Iterator_Model_Base_Filtered; | ||
1867 | struct _Eina_Iterator_Model_Base_Filtered | ||
1868 | { | ||
1869 | Eina_Iterator base; | ||
1870 | Eina_Model *model; | ||
1871 | Eina_Each_Cb match; | ||
1872 | const void *data; | ||
1873 | unsigned int current; | ||
1874 | unsigned int count; | ||
1875 | }; | ||
1876 | |||
1877 | static Eina_Bool | ||
1878 | _eina_model_type_base_child_filtered_iterator_next(Eina_Iterator *base, void **data) | ||
1879 | { | ||
1880 | Eina_Iterator_Model_Base_Filtered *it; | ||
1881 | unsigned int *ret; | ||
1882 | int i; | ||
1883 | |||
1884 | it = (Eina_Iterator_Model_Base_Filtered *)base; | ||
1885 | if (it->count == 0) return EINA_FALSE; | ||
1886 | |||
1887 | i = eina_model_child_criteria_match(it->model, it->current, it->match, it->data); | ||
1888 | if (i < 0) return EINA_FALSE; | ||
1889 | |||
1890 | it->current = i + 1; | ||
1891 | it->count--; | ||
1892 | ret = (unsigned int *)data; | ||
1893 | *ret = i; | ||
1894 | return EINA_TRUE; | ||
1895 | } | ||
1896 | |||
1897 | static void * | ||
1898 | _eina_model_type_base_child_filtered_iterator_get_container(Eina_Iterator *base) | ||
1899 | { | ||
1900 | Eina_Iterator_Model_Base_Filtered *it; | ||
1901 | it = (Eina_Iterator_Model_Base_Filtered *)base; | ||
1902 | return it->model; | ||
1903 | } | ||
1904 | |||
1905 | static void | ||
1906 | _eina_model_type_base_child_filtered_iterator_free(Eina_Iterator *base) | ||
1907 | { | ||
1908 | Eina_Iterator_Model_Base_Filtered *it; | ||
1909 | it = (Eina_Iterator_Model_Base_Filtered *)base; | ||
1910 | eina_model_xunref(it->model, it); | ||
1911 | free(it); | ||
1912 | } | ||
1913 | |||
1914 | static Eina_Iterator * | ||
1915 | _eina_model_type_base_child_filtered_iterator_get(Eina_Model *model, unsigned int start, unsigned int count, Eina_Each_Cb match, const void *data) | ||
1916 | { | ||
1917 | Eina_Iterator_Model_Base_Filtered *it = calloc(1, sizeof(*it)); | ||
1918 | EINA_SAFETY_ON_NULL_RETURN_VAL(it, NULL); | ||
1919 | |||
1920 | EINA_MAGIC_SET(&it->base, EINA_MAGIC_ITERATOR); | ||
1921 | it->base.version = EINA_ITERATOR_VERSION; | ||
1922 | it->base.next = _eina_model_type_base_child_filtered_iterator_next; | ||
1923 | it->base.get_container = _eina_model_type_base_child_filtered_iterator_get_container; | ||
1924 | it->base.free = _eina_model_type_base_child_filtered_iterator_free; | ||
1925 | |||
1926 | it->model = eina_model_xref(model, it, "eina_model_child_slice_filtered_iterator_get"); | ||
1927 | it->match = match; | ||
1928 | it->data = data; | ||
1929 | it->current = start; | ||
1930 | it->count = count; | ||
1931 | |||
1932 | return &it->base; | ||
1933 | } | ||
1934 | |||
1935 | static char * | ||
1936 | _eina_model_type_base_to_string(const Eina_Model *model) | ||
1937 | { | ||
1938 | Eina_List *l, *props; | ||
1939 | const char *name; | ||
1940 | Eina_Strbuf *str; | ||
1941 | Eina_Bool first; | ||
1942 | int i, count; | ||
1943 | char *ret; | ||
1944 | |||
1945 | str = eina_strbuf_new(); | ||
1946 | EINA_SAFETY_ON_NULL_RETURN_VAL(str, NULL); | ||
1947 | |||
1948 | eina_strbuf_append_printf(str, "%s({", model->desc->cache.types[0]->name); | ||
1949 | |||
1950 | props = eina_model_properties_names_list_get(model); | ||
1951 | props = eina_list_sort(props, 0, EINA_COMPARE_CB(strcmp)); | ||
1952 | |||
1953 | first = EINA_TRUE; | ||
1954 | EINA_LIST_FOREACH(props, l, name) | ||
1955 | { | ||
1956 | Eina_Value val; | ||
1957 | |||
1958 | if (!first) | ||
1959 | eina_strbuf_append_printf(str, ", %s: ", name); | ||
1960 | else | ||
1961 | { | ||
1962 | eina_strbuf_append_printf(str, "%s: ", name); | ||
1963 | first = EINA_FALSE; | ||
1964 | } | ||
1965 | |||
1966 | if (!eina_model_property_get(model, name, &val)) | ||
1967 | eina_strbuf_append_char(str, '?'); | ||
1968 | else | ||
1969 | { | ||
1970 | char *tmp = eina_value_to_string(&val); | ||
1971 | eina_strbuf_append(str, tmp ? tmp : "?"); | ||
1972 | free(tmp); | ||
1973 | eina_value_flush(&val); | ||
1974 | } | ||
1975 | } | ||
1976 | eina_list_free(props); | ||
1977 | |||
1978 | eina_strbuf_append(str, "}, ["); | ||
1979 | |||
1980 | count = eina_model_child_count(model); | ||
1981 | first = EINA_TRUE; | ||
1982 | for (i = 0; i < count; i++) | ||
1983 | { | ||
1984 | Eina_Model *c = eina_model_child_get(model, i); | ||
1985 | if (!c) | ||
1986 | { | ||
1987 | if (!first) | ||
1988 | eina_strbuf_append(str, ", ?"); | ||
1989 | else | ||
1990 | { | ||
1991 | eina_strbuf_append_char(str, '?'); | ||
1992 | first = EINA_FALSE; | ||
1993 | } | ||
1994 | } | ||
1995 | else | ||
1996 | { | ||
1997 | char *tmp = eina_model_to_string(c); | ||
1998 | if (!first) | ||
1999 | eina_strbuf_append_printf(str, ", %s", tmp ? tmp : "?"); | ||
2000 | else | ||
2001 | { | ||
2002 | eina_strbuf_append(str, tmp ? tmp : "?"); | ||
2003 | first = EINA_FALSE; | ||
2004 | } | ||
2005 | free(tmp); | ||
2006 | _eina_model_unref(c); | ||
2007 | } | ||
2008 | } | ||
2009 | |||
2010 | eina_strbuf_append(str, "])"); | ||
2011 | |||
2012 | ret = eina_strbuf_string_steal(str); | ||
2013 | eina_strbuf_free(str); | ||
2014 | |||
2015 | return ret; | ||
2016 | } | ||
2017 | |||
2018 | static const Eina_Model_Event_Description _eina_model_type_base_events[] = { | ||
2019 | EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_deleted, "", "model was deleted"), | ||
2020 | EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_freed, "", "model memory was released"), | ||
2021 | EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_property_set, "s", "model data was set, data name given as event information."), | ||
2022 | EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_property_del, "s", "model data was deleted, data name given as event information."), | ||
2023 | EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_children_changed, "", "model children changed (deleted, inserted)."), | ||
2024 | EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_child_inserted, "u", "model child was inserted, child position is given."), | ||
2025 | EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_child_set, "u", "model child was set, child position is given."), | ||
2026 | EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_child_del, "u", "model child was deleted, child position is given."), | ||
2027 | EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_loaded, "", "model was loaded"), | ||
2028 | EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_unloaded, "", "model was unloaded"), | ||
2029 | EINA_MODEL_EVENT_DESCRIPTION_SENTINEL | ||
2030 | }; | ||
2031 | |||
2032 | static const Eina_Model_Type _EINA_MODEL_TYPE_BASE = { | ||
2033 | EINA_MODEL_TYPE_VERSION, | ||
2034 | 0, /* there is no private data */ | ||
2035 | sizeof(Eina_Model_Type), | ||
2036 | "Eina_Model_Type_Base", | ||
2037 | NULL, /* should be the only type with NULL here! */ | ||
2038 | NULL, /* no interfaces implemented */ | ||
2039 | _eina_model_type_base_events, | ||
2040 | _eina_model_type_base_setup, | ||
2041 | _eina_model_type_base_flush, | ||
2042 | _eina_model_type_base_constructor, | ||
2043 | _eina_model_type_base_destructor, | ||
2044 | _eina_model_type_base_copy, | ||
2045 | _eina_model_type_base_deep_copy, | ||
2046 | _eina_model_type_base_compare, | ||
2047 | NULL, /* no load */ | ||
2048 | NULL, /* no unload */ | ||
2049 | NULL, /* no property value get */ | ||
2050 | NULL, /* no property value set */ | ||
2051 | NULL, /* no property del */ | ||
2052 | NULL, /* no properties names list */ | ||
2053 | _eina_model_type_base_child_count, | ||
2054 | NULL, /* no child get */ | ||
2055 | NULL, /* no child set */ | ||
2056 | NULL, /* no child del */ | ||
2057 | NULL, /* no child insert */ | ||
2058 | _eina_model_type_base_child_find, | ||
2059 | _eina_model_type_base_child_criteria_match, | ||
2060 | NULL, /* no child sort */ | ||
2061 | _eina_model_type_base_child_iterator_get, | ||
2062 | _eina_model_type_base_child_reversed_iterator_get, | ||
2063 | _eina_model_type_base_child_sorted_iterator_get, | ||
2064 | _eina_model_type_base_child_filtered_iterator_get, | ||
2065 | _eina_model_type_base_to_string, | ||
2066 | NULL, /* extension pointer */ | ||
2067 | NULL, /* extension pointer */ | ||
2068 | NULL, /* extension pointer */ | ||
2069 | NULL /* extension pointer */ | ||
2070 | }; | ||
2071 | |||
2072 | /* | ||
2073 | * EINA_MODEL_TYPE_MIXIN: | ||
2074 | * | ||
2075 | * Mix-in is a type that uses 2 interfaces, one for properties, | ||
2076 | * another for children. Users should inherit this model and implement | ||
2077 | * at least onf of the interfaces to get an usable model without | ||
2078 | * defining the methods. | ||
2079 | */ | ||
2080 | |||
2081 | static const char _EINA_MODEL_INTERFACE_NAME_PROPERTIES[] = "Eina_Model_Interface_Properties"; | ||
2082 | static const char _EINA_MODEL_INTERFACE_NAME_CHILDREN[] = "Eina_Model_Interface_Children"; | ||
2083 | |||
2084 | typedef struct _Eina_Model_Type_Mixin_Data Eina_Model_Type_Mixin_Data; | ||
2085 | struct _Eina_Model_Type_Mixin_Data | ||
2086 | { | ||
2087 | /* just keep interfaces to avoid lookups */ | ||
2088 | const Eina_Model_Interface *if_properties; | ||
2089 | const Eina_Model_Interface *if_children; | ||
2090 | }; | ||
2091 | |||
2092 | static Eina_Bool | ||
2093 | _eina_model_type_mixin_setup(Eina_Model *model) | ||
2094 | { | ||
2095 | DBG("mix-in setup of %p", model); | ||
2096 | return EINA_TRUE; | ||
2097 | } | ||
2098 | |||
2099 | static Eina_Bool | ||
2100 | _eina_model_type_mixin_flush(Eina_Model *model) | ||
2101 | { | ||
2102 | DBG("mix-in flush of %p", model); | ||
2103 | return EINA_TRUE; | ||
2104 | } | ||
2105 | |||
2106 | static Eina_Bool | ||
2107 | _eina_model_type_mixin_constructor(Eina_Model *model) | ||
2108 | { | ||
2109 | Eina_Model_Type_Mixin_Data *priv = eina_model_type_private_data_get | ||
2110 | (model, EINA_MODEL_TYPE_MIXIN); | ||
2111 | |||
2112 | DBG("mix-in constructor of %p (priv=%p)", model, priv); | ||
2113 | |||
2114 | priv->if_properties = eina_model_interface_get | ||
2115 | (model, EINA_MODEL_INTERFACE_NAME_PROPERTIES); | ||
2116 | if (priv->if_properties) | ||
2117 | { | ||
2118 | if (!eina_model_interface_constructor(priv->if_properties, model)) | ||
2119 | { | ||
2120 | ERR("Could not construct properties interface %p of %p (%s)", | ||
2121 | model, priv->if_properties, model->desc->cache.types[0]->name); | ||
2122 | return EINA_FALSE; | ||
2123 | } | ||
2124 | } | ||
2125 | |||
2126 | priv->if_children = eina_model_interface_get | ||
2127 | (model, EINA_MODEL_INTERFACE_NAME_CHILDREN); | ||
2128 | if (priv->if_children) | ||
2129 | { | ||
2130 | if (!eina_model_interface_constructor(priv->if_children, model)) | ||
2131 | { | ||
2132 | ERR("Could not construct children interface %p of %p (%s)", | ||
2133 | model, priv->if_children, model->desc->cache.types[0]->name); | ||
2134 | return EINA_FALSE; | ||
2135 | } | ||
2136 | } | ||
2137 | |||
2138 | if ((!priv->if_properties) && (!priv->if_children)) | ||
2139 | { | ||
2140 | ERR("Mix-in model %p (%s) does not implement properties or children " | ||
2141 | "interfaces!", | ||
2142 | model, model->desc->cache.types[0]->name); | ||
2143 | return EINA_FALSE; | ||
2144 | } | ||
2145 | |||
2146 | return EINA_TRUE; | ||
2147 | } | ||
2148 | |||
2149 | #define EINA_MODEL_TYPE_MIXIN_GET(model) \ | ||
2150 | Eina_Model_Type_Mixin_Data *priv = eina_model_type_private_data_get \ | ||
2151 | (model, EINA_MODEL_TYPE_MIXIN) | ||
2152 | |||
2153 | static Eina_Bool | ||
2154 | _eina_model_type_mixin_destructor(Eina_Model *model) | ||
2155 | { | ||
2156 | EINA_MODEL_TYPE_MIXIN_GET(model); | ||
2157 | |||
2158 | DBG("mixin destructor of %p", model); | ||
2159 | |||
2160 | if (priv->if_properties) | ||
2161 | eina_model_interface_destructor(priv->if_properties, model); | ||
2162 | |||
2163 | if (priv->if_children) | ||
2164 | eina_model_interface_destructor(priv->if_children, model); | ||
2165 | |||
2166 | return EINA_TRUE; | ||
2167 | } | ||
2168 | |||
2169 | static Eina_Bool | ||
2170 | _eina_model_type_mixin_compare(const Eina_Model *a, const Eina_Model *b, int *cmp) | ||
2171 | { | ||
2172 | Eina_Bool ret = EINA_TRUE, did_prop = EINA_FALSE, did_child = EINA_FALSE; | ||
2173 | |||
2174 | *cmp = 0; | ||
2175 | |||
2176 | EINA_MODEL_TYPE_MIXIN_GET(a); | ||
2177 | |||
2178 | if (priv->if_properties) | ||
2179 | { | ||
2180 | Eina_Bool (*compare)(const Eina_Model*, const Eina_Model*, int *) = | ||
2181 | _eina_model_interface_find_offset | ||
2182 | (priv->if_properties, | ||
2183 | offsetof(Eina_Model_Interface_Properties, compare)); | ||
2184 | |||
2185 | if (compare) | ||
2186 | { | ||
2187 | ret &= compare(a, b, cmp); | ||
2188 | did_prop = EINA_TRUE; | ||
2189 | } | ||
2190 | } | ||
2191 | |||
2192 | if ((ret) && (*cmp == 0)) | ||
2193 | { | ||
2194 | if (priv->if_children) | ||
2195 | { | ||
2196 | Eina_Bool (*compare)(const Eina_Model*, const Eina_Model*, int *) = | ||
2197 | _eina_model_interface_find_offset | ||
2198 | (priv->if_children, | ||
2199 | offsetof(Eina_Model_Interface_Children, compare)); | ||
2200 | |||
2201 | if (compare) | ||
2202 | { | ||
2203 | ret &= compare(a, b, cmp); | ||
2204 | did_child = EINA_TRUE; | ||
2205 | } | ||
2206 | } | ||
2207 | } | ||
2208 | |||
2209 | if ((!did_prop) && (!did_child)) | ||
2210 | return eina_model_type_compare(EINA_MODEL_TYPE_BASE, a, b, cmp); | ||
2211 | |||
2212 | return ret; | ||
2213 | } | ||
2214 | |||
2215 | static Eina_Bool | ||
2216 | _eina_model_type_mixin_load(Eina_Model *model) | ||
2217 | { | ||
2218 | Eina_Bool ret = EINA_TRUE; | ||
2219 | |||
2220 | EINA_MODEL_TYPE_MIXIN_GET(model); | ||
2221 | |||
2222 | if (priv->if_properties) | ||
2223 | ret &= eina_model_interface_properties_load(priv->if_properties, model); | ||
2224 | |||
2225 | if (priv->if_children) | ||
2226 | ret &= eina_model_interface_children_load(priv->if_children, model); | ||
2227 | |||
2228 | return ret; | ||
2229 | } | ||
2230 | |||
2231 | static Eina_Bool | ||
2232 | _eina_model_type_mixin_unload(Eina_Model *model) | ||
2233 | { | ||
2234 | Eina_Bool ret = EINA_TRUE; | ||
2235 | |||
2236 | EINA_MODEL_TYPE_MIXIN_GET(model); | ||
2237 | |||
2238 | if (priv->if_properties) | ||
2239 | ret &= eina_model_interface_properties_unload(priv->if_properties, model); | ||
2240 | |||
2241 | if (priv->if_children) | ||
2242 | ret &= eina_model_interface_children_unload(priv->if_children, model); | ||
2243 | |||
2244 | return ret; | ||
2245 | } | ||
2246 | |||
2247 | static Eina_Bool | ||
2248 | _eina_model_type_mixin_property_get(const Eina_Model *model, const char *name, Eina_Value *value) | ||
2249 | { | ||
2250 | Eina_Bool ret = EINA_FALSE; | ||
2251 | |||
2252 | EINA_MODEL_TYPE_MIXIN_GET(model); | ||
2253 | |||
2254 | if (priv->if_properties) | ||
2255 | ret = eina_model_interface_properties_get | ||
2256 | (priv->if_properties, model, name, value); | ||
2257 | |||
2258 | return ret; | ||
2259 | } | ||
2260 | |||
2261 | static Eina_Bool | ||
2262 | _eina_model_type_mixin_property_set(Eina_Model *model, const char *name, const Eina_Value *value) | ||
2263 | { | ||
2264 | Eina_Bool ret = EINA_FALSE; | ||
2265 | |||
2266 | EINA_MODEL_TYPE_MIXIN_GET(model); | ||
2267 | |||
2268 | if (priv->if_properties) | ||
2269 | ret = eina_model_interface_properties_set | ||
2270 | (priv->if_properties, model, name, value); | ||
2271 | |||
2272 | return ret; | ||
2273 | } | ||
2274 | |||
2275 | static Eina_Bool | ||
2276 | _eina_model_type_mixin_property_del(Eina_Model *model, const char *name) | ||
2277 | { | ||
2278 | Eina_Bool ret = EINA_FALSE; | ||
2279 | |||
2280 | EINA_MODEL_TYPE_MIXIN_GET(model); | ||
2281 | |||
2282 | if (priv->if_properties) | ||
2283 | ret = eina_model_interface_properties_del | ||
2284 | (priv->if_properties, model, name); | ||
2285 | |||
2286 | return ret; | ||
2287 | } | ||
2288 | |||
2289 | static Eina_List * | ||
2290 | _eina_model_type_mixin_properties_names_list_get(const Eina_Model *model) | ||
2291 | { | ||
2292 | Eina_List *ret = NULL; | ||
2293 | |||
2294 | EINA_MODEL_TYPE_MIXIN_GET(model); | ||
2295 | |||
2296 | if (priv->if_properties) | ||
2297 | ret = eina_model_interface_properties_names_list_get | ||
2298 | (priv->if_properties, model); | ||
2299 | |||
2300 | return ret; | ||
2301 | } | ||
2302 | |||
2303 | static int | ||
2304 | _eina_model_type_mixin_child_count(const Eina_Model *model) | ||
2305 | { | ||
2306 | EINA_MODEL_TYPE_MIXIN_GET(model); | ||
2307 | |||
2308 | if (!priv->if_children) | ||
2309 | return 0; | ||
2310 | |||
2311 | return eina_model_interface_children_count(priv->if_children, model); | ||
2312 | } | ||
2313 | |||
2314 | static Eina_Model * | ||
2315 | _eina_model_type_mixin_child_get(const Eina_Model *model, unsigned int position) | ||
2316 | { | ||
2317 | EINA_MODEL_TYPE_MIXIN_GET(model); | ||
2318 | |||
2319 | if (!priv->if_children) | ||
2320 | return 0; | ||
2321 | |||
2322 | return eina_model_interface_children_get(priv->if_children, model, position); | ||
2323 | } | ||
2324 | |||
2325 | static Eina_Bool | ||
2326 | _eina_model_type_mixin_child_set(Eina_Model *model, unsigned int position, Eina_Model *child) | ||
2327 | { | ||
2328 | EINA_MODEL_TYPE_MIXIN_GET(model); | ||
2329 | |||
2330 | if (!priv->if_children) | ||
2331 | return 0; | ||
2332 | |||
2333 | return eina_model_interface_children_set | ||
2334 | (priv->if_children, model, position, child); | ||
2335 | } | ||
2336 | |||
2337 | static Eina_Bool | ||
2338 | _eina_model_type_mixin_child_del(Eina_Model *model, unsigned int position) | ||
2339 | { | ||
2340 | EINA_MODEL_TYPE_MIXIN_GET(model); | ||
2341 | |||
2342 | if (!priv->if_children) | ||
2343 | return 0; | ||
2344 | |||
2345 | return eina_model_interface_children_del | ||
2346 | (priv->if_children, model, position); | ||
2347 | } | ||
2348 | |||
2349 | static Eina_Bool | ||
2350 | _eina_model_type_mixin_child_insert_at(Eina_Model *model, unsigned int position, Eina_Model *child) | ||
2351 | { | ||
2352 | EINA_MODEL_TYPE_MIXIN_GET(model); | ||
2353 | |||
2354 | if (!priv->if_children) | ||
2355 | return 0; | ||
2356 | |||
2357 | return eina_model_interface_children_insert_at | ||
2358 | (priv->if_children, model, position, child); | ||
2359 | } | ||
2360 | |||
2361 | static void | ||
2362 | _eina_model_type_mixin_child_sort(Eina_Model *model, Eina_Compare_Cb compare) | ||
2363 | { | ||
2364 | EINA_MODEL_TYPE_MIXIN_GET(model); | ||
2365 | |||
2366 | if (!priv->if_children) | ||
2367 | return; | ||
2368 | eina_model_interface_children_sort(priv->if_children, model, compare); | ||
2369 | } | ||
2370 | |||
2371 | static const Eina_Model_Type _EINA_MODEL_TYPE_MIXIN = { | ||
2372 | EINA_MODEL_TYPE_VERSION, | ||
2373 | sizeof(Eina_Model_Type_Mixin_Data), | ||
2374 | sizeof(Eina_Model_Type), | ||
2375 | "Eina_Model_Type_Mixin", | ||
2376 | &_EINA_MODEL_TYPE_BASE, | ||
2377 | NULL, /* no interfaces implemented */ | ||
2378 | NULL, /* no extra events */ | ||
2379 | _eina_model_type_mixin_setup, | ||
2380 | _eina_model_type_mixin_flush, | ||
2381 | _eina_model_type_mixin_constructor, | ||
2382 | _eina_model_type_mixin_destructor, | ||
2383 | NULL, /* no copy, as interface is called automatically */ | ||
2384 | NULL, /* no deep copy, as interface is called automatically */ | ||
2385 | _eina_model_type_mixin_compare, | ||
2386 | _eina_model_type_mixin_load, | ||
2387 | _eina_model_type_mixin_unload, | ||
2388 | _eina_model_type_mixin_property_get, | ||
2389 | _eina_model_type_mixin_property_set, | ||
2390 | _eina_model_type_mixin_property_del, | ||
2391 | _eina_model_type_mixin_properties_names_list_get, | ||
2392 | _eina_model_type_mixin_child_count, | ||
2393 | _eina_model_type_mixin_child_get, | ||
2394 | _eina_model_type_mixin_child_set, | ||
2395 | _eina_model_type_mixin_child_del, | ||
2396 | _eina_model_type_mixin_child_insert_at, | ||
2397 | NULL, /* use default find */ | ||
2398 | NULL, /* use default criteria_match */ | ||
2399 | _eina_model_type_mixin_child_sort, | ||
2400 | NULL, /* use default iterator get */ | ||
2401 | NULL, /* use default reversed iterator get */ | ||
2402 | NULL, /* use default sorted iterator get */ | ||
2403 | NULL, /* use default filtered iterator get */ | ||
2404 | NULL, /* use default to string */ | ||
2405 | NULL, /* extension pointer */ | ||
2406 | NULL, /* extension pointer */ | ||
2407 | NULL, /* extension pointer */ | ||
2408 | NULL /* extension pointer */ | ||
2409 | }; | ||
2410 | #undef EINA_MODEL_TYPE_MIXIN_GET | ||
2411 | |||
2412 | /* Events for all Properties interface */ | ||
2413 | static const Eina_Model_Event_Description _eina_model_interface_properties_events[] = { | ||
2414 | EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_properties_loaded, "", "model properties were loaded"), | ||
2415 | EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_properties_unloaded, "", "model properties were unloaded"), | ||
2416 | EINA_MODEL_EVENT_DESCRIPTION_SENTINEL | ||
2417 | }; | ||
2418 | |||
2419 | /* EINA_MODEL_INTERFACE_PROPERTIES_HASH ******************************/ | ||
2420 | |||
2421 | #define EINA_MODEL_INTERFACE_PROPERTIES_HASH_GET(model) \ | ||
2422 | Eina_Hash *priv = *(Eina_Hash **)eina_model_interface_private_data_get \ | ||
2423 | (model, EINA_MODEL_INTERFACE_PROPERTIES_HASH) | ||
2424 | |||
2425 | static Eina_Bool | ||
2426 | _eina_model_interface_properties_hash_setup(Eina_Model *model) | ||
2427 | { | ||
2428 | Eina_Hash **p_priv = eina_model_interface_private_data_get | ||
2429 | (model, EINA_MODEL_INTERFACE_PROPERTIES_HASH); | ||
2430 | |||
2431 | DBG("setup interface properties (hash) at %p model %p (%s)", | ||
2432 | p_priv, model, model->desc->cache.types[0]->name); | ||
2433 | |||
2434 | *p_priv = eina_hash_string_small_new(NULL); | ||
2435 | return !!*p_priv; | ||
2436 | } | ||
2437 | |||
2438 | static Eina_Bool | ||
2439 | _eina_model_interface_properties_hash_flush(Eina_Model *model) | ||
2440 | { | ||
2441 | EINA_MODEL_INTERFACE_PROPERTIES_HASH_GET(model); | ||
2442 | |||
2443 | DBG("flush interface properties (hash) at %p model %p (%s)", | ||
2444 | priv, model, model->desc->cache.types[0]->name); | ||
2445 | |||
2446 | if (priv) | ||
2447 | { | ||
2448 | ERR("interface properties flushed with values! priv=%p, model %p (%s)", | ||
2449 | priv, model, model->desc->cache.types[0]->name); | ||
2450 | eina_hash_free(priv); | ||
2451 | } | ||
2452 | |||
2453 | return EINA_TRUE; | ||
2454 | } | ||
2455 | |||
2456 | static Eina_Bool | ||
2457 | _eina_model_interface_properties_hash_constructor(Eina_Model *model) | ||
2458 | { | ||
2459 | EINA_MODEL_INTERFACE_PROPERTIES_HASH_GET(model); | ||
2460 | |||
2461 | DBG("construct interface properties (hash) at %p model %p (%s)", | ||
2462 | priv, model, model->desc->cache.types[0]->name); | ||
2463 | |||
2464 | return EINA_TRUE; | ||
2465 | } | ||
2466 | |||
2467 | static Eina_Bool | ||
2468 | _eina_model_interface_properties_hash_destructor_foreach(const Eina_Hash *hash __UNUSED__, const void *key __UNUSED__, void *data, void *fdata __UNUSED__) | ||
2469 | { | ||
2470 | eina_value_free(data); | ||
2471 | return EINA_TRUE; | ||
2472 | } | ||
2473 | |||
2474 | static Eina_Bool | ||
2475 | _eina_model_interface_properties_hash_destructor(Eina_Model *model) | ||
2476 | { | ||
2477 | Eina_Hash **p_priv = eina_model_interface_private_data_get | ||
2478 | (model, EINA_MODEL_INTERFACE_PROPERTIES_HASH); | ||
2479 | int count = eina_hash_population(*p_priv); | ||
2480 | |||
2481 | DBG("destroy interface properties (hash) at %p model %p (%s). %d values.", | ||
2482 | *p_priv, model, model->desc->cache.types[0]->name, count); | ||
2483 | |||
2484 | eina_hash_foreach | ||
2485 | (*p_priv, _eina_model_interface_properties_hash_destructor_foreach, NULL); | ||
2486 | eina_hash_free(*p_priv); | ||
2487 | *p_priv = NULL; | ||
2488 | |||
2489 | return EINA_TRUE; | ||
2490 | } | ||
2491 | |||
2492 | static Eina_Bool | ||
2493 | _eina_model_interface_properties_hash_get(const Eina_Model *model, const char *name, Eina_Value *value) | ||
2494 | { | ||
2495 | EINA_MODEL_INTERFACE_PROPERTIES_HASH_GET(model); | ||
2496 | const Eina_Value *prop = eina_hash_find(priv, name); | ||
2497 | EINA_SAFETY_ON_NULL_RETURN_VAL(prop, EINA_FALSE); | ||
2498 | return eina_value_copy(prop, value); | ||
2499 | } | ||
2500 | |||
2501 | static Eina_Bool | ||
2502 | _eina_model_interface_properties_hash_set(Eina_Model *model, const char *name, const Eina_Value *value) | ||
2503 | { | ||
2504 | EINA_MODEL_INTERFACE_PROPERTIES_HASH_GET(model); | ||
2505 | Eina_Value *prop, *old = eina_hash_find(priv, name); | ||
2506 | |||
2507 | prop = eina_value_new(eina_value_type_get(value)); | ||
2508 | EINA_SAFETY_ON_NULL_RETURN_VAL(prop, EINA_FALSE); | ||
2509 | |||
2510 | eina_value_flush(prop); | ||
2511 | if (!eina_value_copy(value, prop)) | ||
2512 | { | ||
2513 | ERR("Could not copy value '%s' from %p to %p", name, value, prop); | ||
2514 | eina_value_free(prop); | ||
2515 | return EINA_FALSE; | ||
2516 | } | ||
2517 | |||
2518 | if (!old) | ||
2519 | { | ||
2520 | if (!eina_hash_add(priv, name, prop)) | ||
2521 | { | ||
2522 | ERR("Could not add value %p to hash as key '%s'", prop, name); | ||
2523 | eina_value_free(prop); | ||
2524 | return EINA_FALSE; | ||
2525 | } | ||
2526 | } | ||
2527 | else | ||
2528 | { | ||
2529 | eina_value_free(old); | ||
2530 | if (!eina_hash_modify(priv, name, prop)) | ||
2531 | { | ||
2532 | ERR("Could not modify hash key '%s' value from %p to %p", | ||
2533 | name, old, prop); | ||
2534 | eina_hash_del_by_key(priv, name); | ||
2535 | eina_value_free(prop); | ||
2536 | return EINA_FALSE; | ||
2537 | } | ||
2538 | } | ||
2539 | |||
2540 | return EINA_TRUE; | ||
2541 | } | ||
2542 | |||
2543 | static Eina_Bool | ||
2544 | _eina_model_interface_properties_hash_del(Eina_Model *model, const char *name) | ||
2545 | { | ||
2546 | EINA_MODEL_INTERFACE_PROPERTIES_HASH_GET(model); | ||
2547 | Eina_Value *old = eina_hash_find(priv, name); | ||
2548 | EINA_SAFETY_ON_NULL_RETURN_VAL(old, EINA_FALSE); | ||
2549 | eina_value_free(old); | ||
2550 | return eina_hash_del_by_key(priv, name); | ||
2551 | } | ||
2552 | |||
2553 | static Eina_Bool | ||
2554 | _eina_model_interface_properties_hash_names_list_foreach(const Eina_Hash *hash __UNUSED__, const void *key, void *data __UNUSED__, void *fdata) | ||
2555 | { | ||
2556 | Eina_List **p_list = fdata; | ||
2557 | *p_list = eina_list_append(*p_list, eina_stringshare_add(key)); | ||
2558 | return EINA_TRUE; | ||
2559 | } | ||
2560 | |||
2561 | static Eina_List * | ||
2562 | _eina_model_interface_properties_hash_names_list(const Eina_Model *model) | ||
2563 | { | ||
2564 | EINA_MODEL_INTERFACE_PROPERTIES_HASH_GET(model); | ||
2565 | Eina_List *list = NULL; | ||
2566 | eina_hash_foreach | ||
2567 | (priv, _eina_model_interface_properties_hash_names_list_foreach, &list); | ||
2568 | return list; | ||
2569 | } | ||
2570 | #undef EINA_MODEL_INTERFACE_PROPERTIES_HASH_GET | ||
2571 | |||
2572 | static const Eina_Model_Interface_Properties _EINA_MODEL_INTERFACE_PROPERTIES_HASH = { | ||
2573 | { | ||
2574 | EINA_MODEL_INTERFACE_VERSION, | ||
2575 | sizeof(Eina_Hash *), | ||
2576 | sizeof(Eina_Model_Interface_Properties), | ||
2577 | _EINA_MODEL_INTERFACE_NAME_PROPERTIES, | ||
2578 | NULL, /* no parent interfaces */ | ||
2579 | _eina_model_interface_properties_events, | ||
2580 | _eina_model_interface_properties_hash_setup, | ||
2581 | _eina_model_interface_properties_hash_flush, | ||
2582 | _eina_model_interface_properties_hash_constructor, | ||
2583 | _eina_model_interface_properties_hash_destructor, | ||
2584 | NULL, | ||
2585 | NULL, | ||
2586 | NULL, | ||
2587 | NULL, | ||
2588 | NULL, | ||
2589 | NULL | ||
2590 | }, | ||
2591 | EINA_MODEL_INTERFACE_PROPERTIES_VERSION, | ||
2592 | NULL, /* no compare */ | ||
2593 | NULL, /* no load */ | ||
2594 | NULL, /* no unload */ | ||
2595 | _eina_model_interface_properties_hash_get, | ||
2596 | _eina_model_interface_properties_hash_set, | ||
2597 | _eina_model_interface_properties_hash_del, | ||
2598 | _eina_model_interface_properties_hash_names_list | ||
2599 | }; | ||
2600 | |||
2601 | /* EINA_MODEL_INTERFACE_PROPERTIES_STRUCT ******************************/ | ||
2602 | |||
2603 | static Eina_Value_Struct * | ||
2604 | _eina_model_interface_properties_struct_private_get(const Eina_Model *model) | ||
2605 | { | ||
2606 | Eina_Value *val = eina_model_interface_private_data_get | ||
2607 | (model, EINA_MODEL_INTERFACE_PROPERTIES_STRUCT); | ||
2608 | return eina_value_memory_get(val); | ||
2609 | } | ||
2610 | |||
2611 | #define EINA_MODEL_INTERFACE_PROPERTIES_STRUCT_GET(model) \ | ||
2612 | Eina_Value_Struct *priv = \ | ||
2613 | _eina_model_interface_properties_struct_private_get(model) | ||
2614 | |||
2615 | static Eina_Bool | ||
2616 | _eina_model_interface_properties_struct_setup(Eina_Model *model) | ||
2617 | { | ||
2618 | Eina_Value *val = eina_model_interface_private_data_get | ||
2619 | (model, EINA_MODEL_INTERFACE_PROPERTIES_STRUCT); | ||
2620 | |||
2621 | DBG("setup interface properties (struct) at %p model %p (%s)", | ||
2622 | val, model, model->desc->cache.types[0]->name); | ||
2623 | |||
2624 | return eina_value_setup(val, EINA_VALUE_TYPE_STRUCT); | ||
2625 | } | ||
2626 | |||
2627 | static Eina_Bool | ||
2628 | _eina_model_interface_properties_struct_flush(Eina_Model *model) | ||
2629 | { | ||
2630 | Eina_Value *val = eina_model_interface_private_data_get | ||
2631 | (model, EINA_MODEL_INTERFACE_PROPERTIES_STRUCT); | ||
2632 | |||
2633 | DBG("flush interface properties (struct) at %p model %p (%s)", | ||
2634 | val, model, model->desc->cache.types[0]->name); | ||
2635 | |||
2636 | if (val->type) | ||
2637 | { | ||
2638 | ERR("interface properties flushed with values! val=%p, model %p (%s)", | ||
2639 | val, model, model->desc->cache.types[0]->name); | ||
2640 | eina_value_flush(val); | ||
2641 | } | ||
2642 | |||
2643 | return EINA_TRUE; | ||
2644 | } | ||
2645 | |||
2646 | static Eina_Bool | ||
2647 | _eina_model_interface_properties_struct_constructor(Eina_Model *model) | ||
2648 | { | ||
2649 | EINA_MODEL_INTERFACE_PROPERTIES_STRUCT_GET(model); | ||
2650 | |||
2651 | DBG("construct interface properties (struct) at %p model %p (%s)", | ||
2652 | priv, model, model->desc->cache.types[0]->name); | ||
2653 | |||
2654 | return EINA_TRUE; | ||
2655 | } | ||
2656 | |||
2657 | static Eina_Bool | ||
2658 | _eina_model_interface_properties_struct_destructor(Eina_Model *model) | ||
2659 | { | ||
2660 | Eina_Value *val = eina_model_interface_private_data_get | ||
2661 | (model, EINA_MODEL_INTERFACE_PROPERTIES_STRUCT); | ||
2662 | |||
2663 | DBG("destroy interface properties (struct) at %p model %p (%s)", | ||
2664 | val, model, model->desc->cache.types[0]->name); | ||
2665 | |||
2666 | eina_value_flush(val); | ||
2667 | val->type = NULL; | ||
2668 | |||
2669 | return EINA_TRUE; | ||
2670 | } | ||
2671 | |||
2672 | static Eina_Bool | ||
2673 | _eina_model_interface_properties_struct_get(const Eina_Model *model, const char *name, Eina_Value *val) | ||
2674 | { | ||
2675 | const Eina_Value *v = eina_model_interface_private_data_get | ||
2676 | (model, EINA_MODEL_INTERFACE_PROPERTIES_STRUCT); | ||
2677 | return eina_value_struct_value_get(v, name, val); | ||
2678 | } | ||
2679 | |||
2680 | static Eina_Bool | ||
2681 | _eina_model_interface_properties_struct_set(Eina_Model *model, const char *name, const Eina_Value *val) | ||
2682 | { | ||
2683 | Eina_Value *v = eina_model_interface_private_data_get | ||
2684 | (model, EINA_MODEL_INTERFACE_PROPERTIES_STRUCT); | ||
2685 | return eina_value_struct_value_set(v, name, val); | ||
2686 | } | ||
2687 | |||
2688 | static Eina_Bool | ||
2689 | _eina_model_interface_properties_struct_del(Eina_Model *model __UNUSED__, const char *name __UNUSED__) | ||
2690 | { | ||
2691 | return EINA_FALSE; /* not allowed */ | ||
2692 | } | ||
2693 | |||
2694 | static Eina_List * | ||
2695 | _eina_model_interface_properties_struct_names_list(const Eina_Model *model) | ||
2696 | { | ||
2697 | EINA_MODEL_INTERFACE_PROPERTIES_STRUCT_GET(model); | ||
2698 | const Eina_Value_Struct_Member *itr; | ||
2699 | Eina_List *list = NULL; | ||
2700 | |||
2701 | EINA_SAFETY_ON_NULL_RETURN_VAL(priv, NULL); | ||
2702 | EINA_SAFETY_ON_NULL_RETURN_VAL(priv->desc, NULL); | ||
2703 | EINA_SAFETY_ON_NULL_RETURN_VAL(priv->desc->members, NULL); | ||
2704 | |||
2705 | itr = priv->desc->members; | ||
2706 | if (priv->desc->member_count) | ||
2707 | { | ||
2708 | const Eina_Value_Struct_Member *end = itr + priv->desc->member_count; | ||
2709 | for (; itr < end; itr++) | ||
2710 | list = eina_list_append(list, eina_stringshare_add(itr->name)); | ||
2711 | } | ||
2712 | else | ||
2713 | { | ||
2714 | for (; itr->name != NULL; itr++) | ||
2715 | list = eina_list_append(list, eina_stringshare_add(itr->name)); | ||
2716 | } | ||
2717 | |||
2718 | return list; | ||
2719 | } | ||
2720 | #undef EINA_MODEL_INTERFACE_PROPERTIES_STRUCT_GET | ||
2721 | |||
2722 | static const Eina_Model_Interface_Properties _EINA_MODEL_INTERFACE_PROPERTIES_STRUCT = { | ||
2723 | { | ||
2724 | EINA_MODEL_INTERFACE_VERSION, | ||
2725 | sizeof(Eina_Value), | ||
2726 | sizeof(Eina_Model_Interface_Properties), | ||
2727 | _EINA_MODEL_INTERFACE_NAME_PROPERTIES, | ||
2728 | NULL, /* no parent interfaces */ | ||
2729 | _eina_model_interface_properties_events, | ||
2730 | _eina_model_interface_properties_struct_setup, | ||
2731 | _eina_model_interface_properties_struct_flush, | ||
2732 | _eina_model_interface_properties_struct_constructor, | ||
2733 | _eina_model_interface_properties_struct_destructor, | ||
2734 | NULL, | ||
2735 | NULL, | ||
2736 | NULL, | ||
2737 | NULL, | ||
2738 | NULL, | ||
2739 | NULL | ||
2740 | }, | ||
2741 | EINA_MODEL_INTERFACE_PROPERTIES_VERSION, | ||
2742 | NULL, /* no compare */ | ||
2743 | NULL, /* no load */ | ||
2744 | NULL, /* no unload */ | ||
2745 | _eina_model_interface_properties_struct_get, | ||
2746 | _eina_model_interface_properties_struct_set, | ||
2747 | _eina_model_interface_properties_struct_del, | ||
2748 | _eina_model_interface_properties_struct_names_list | ||
2749 | }; | ||
2750 | |||
2751 | /* Events for all Children interface */ | ||
2752 | static const Eina_Model_Event_Description _eina_model_interface_children_events[] = { | ||
2753 | EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_children_loaded, "", "model children were loaded"), | ||
2754 | EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_children_unloaded, "", "model children were unloaded"), | ||
2755 | EINA_MODEL_EVENT_DESCRIPTION_SENTINEL | ||
2756 | }; | ||
2757 | |||
2758 | /* EINA_MODEL_INTERFACE_CHILDREN_INARRAY ******************************/ | ||
2759 | |||
2760 | #define EINA_MODEL_INTERFACE_CHILDREN_INARRAY_GET(model) \ | ||
2761 | Eina_Inarray *priv = eina_model_interface_private_data_get \ | ||
2762 | (model, EINA_MODEL_INTERFACE_CHILDREN_INARRAY) | ||
2763 | |||
2764 | static Eina_Bool | ||
2765 | _eina_model_interface_children_inarray_setup(Eina_Model *model) | ||
2766 | { | ||
2767 | EINA_MODEL_INTERFACE_CHILDREN_INARRAY_GET(model); | ||
2768 | |||
2769 | DBG("setup interface children (inarray) at %p model %p (%s)", | ||
2770 | priv, model, model->desc->cache.types[0]->name); | ||
2771 | |||
2772 | eina_inarray_setup(priv, sizeof(Eina_Model *), 0); | ||
2773 | return EINA_TRUE; | ||
2774 | } | ||
2775 | |||
2776 | static Eina_Bool | ||
2777 | _eina_model_interface_children_inarray_flush(Eina_Model *model) | ||
2778 | { | ||
2779 | EINA_MODEL_INTERFACE_CHILDREN_INARRAY_GET(model); | ||
2780 | int count; | ||
2781 | |||
2782 | DBG("flush interface children (inarray) at %p model %p (%s)", | ||
2783 | priv, model, model->desc->cache.types[0]->name); | ||
2784 | |||
2785 | count = eina_inarray_count(priv); | ||
2786 | if (count > 0) | ||
2787 | ERR("interface children flushed with %d members! priv=%p, model %p (%s)", | ||
2788 | count, priv, model, model->desc->cache.types[0]->name); | ||
2789 | |||
2790 | eina_inarray_flush(priv); | ||
2791 | return EINA_TRUE; | ||
2792 | } | ||
2793 | |||
2794 | static Eina_Bool | ||
2795 | _eina_model_interface_children_inarray_constructor(Eina_Model *model) | ||
2796 | { | ||
2797 | EINA_MODEL_INTERFACE_CHILDREN_INARRAY_GET(model); | ||
2798 | |||
2799 | DBG("construct interface children (inarray) at %p model %p (%s)", | ||
2800 | priv, model, model->desc->cache.types[0]->name); | ||
2801 | |||
2802 | return EINA_TRUE; | ||
2803 | } | ||
2804 | |||
2805 | static Eina_Bool | ||
2806 | _eina_model_interface_children_inarray_destructor(Eina_Model *model) | ||
2807 | { | ||
2808 | Eina_Model **itr, **itr_end; | ||
2809 | int count; | ||
2810 | |||
2811 | EINA_MODEL_INTERFACE_CHILDREN_INARRAY_GET(model); | ||
2812 | |||
2813 | count = eina_inarray_count(priv); | ||
2814 | |||
2815 | DBG("destroy interface children (inarray) at %p model %p (%s). %d members.", | ||
2816 | priv, model, model->desc->cache.types[0]->name, count); | ||
2817 | |||
2818 | itr = priv->members; | ||
2819 | itr_end = itr + count; | ||
2820 | for (; itr < itr_end; itr++) | ||
2821 | eina_model_xunref(*itr, EINA_MODEL_INTERFACE_CHILDREN_INARRAY); | ||
2822 | eina_inarray_flush(priv); | ||
2823 | |||
2824 | return EINA_TRUE; | ||
2825 | } | ||
2826 | |||
2827 | static int | ||
2828 | _eina_model_interface_children_inarray_count(const Eina_Model *model) | ||
2829 | { | ||
2830 | EINA_MODEL_INTERFACE_CHILDREN_INARRAY_GET(model); | ||
2831 | return eina_inarray_count(priv); | ||
2832 | } | ||
2833 | |||
2834 | static Eina_Model * | ||
2835 | _eina_model_interface_children_inarray_get(const Eina_Model *model, unsigned int position) | ||
2836 | { | ||
2837 | EINA_MODEL_INTERFACE_CHILDREN_INARRAY_GET(model); | ||
2838 | Eina_Model **child = eina_inarray_nth(priv, position); | ||
2839 | if (!child) | ||
2840 | return NULL; | ||
2841 | return eina_model_ref(*child); | ||
2842 | } | ||
2843 | |||
2844 | static Eina_Bool | ||
2845 | _eina_model_interface_children_inarray_set(Eina_Model *model, unsigned int position, Eina_Model *child) | ||
2846 | { | ||
2847 | EINA_MODEL_INTERFACE_CHILDREN_INARRAY_GET(model); | ||
2848 | Eina_Model **p_old = eina_inarray_nth(priv, position); | ||
2849 | Eina_Model *old; | ||
2850 | |||
2851 | if (!p_old) | ||
2852 | return EINA_FALSE; | ||
2853 | |||
2854 | old = *p_old; | ||
2855 | if (!eina_inarray_replace_at(priv, position, &child)) | ||
2856 | return EINA_FALSE; | ||
2857 | |||
2858 | eina_model_xref(child, EINA_MODEL_INTERFACE_CHILDREN_INARRAY, | ||
2859 | "eina_model_child_set"); | ||
2860 | eina_model_xunref(old, EINA_MODEL_INTERFACE_CHILDREN_INARRAY); | ||
2861 | return EINA_TRUE; | ||
2862 | } | ||
2863 | |||
2864 | static Eina_Bool | ||
2865 | _eina_model_interface_children_inarray_del(Eina_Model *model, unsigned int position) | ||
2866 | { | ||
2867 | EINA_MODEL_INTERFACE_CHILDREN_INARRAY_GET(model); | ||
2868 | Eina_Model **p_old = eina_inarray_nth(priv, position); | ||
2869 | Eina_Model *old; | ||
2870 | |||
2871 | if (!p_old) | ||
2872 | return EINA_FALSE; | ||
2873 | |||
2874 | old = *p_old; | ||
2875 | if (!eina_inarray_remove_at(priv, position)) | ||
2876 | return EINA_FALSE; | ||
2877 | |||
2878 | eina_model_xunref(old, EINA_MODEL_INTERFACE_CHILDREN_INARRAY); | ||
2879 | return EINA_TRUE; | ||
2880 | } | ||
2881 | |||
2882 | static Eina_Bool | ||
2883 | _eina_model_interface_children_inarray_insert_at(Eina_Model *model, unsigned int position, Eina_Model *child) | ||
2884 | { | ||
2885 | EINA_MODEL_INTERFACE_CHILDREN_INARRAY_GET(model); | ||
2886 | |||
2887 | if (!eina_inarray_insert_at(priv, position, &child)) | ||
2888 | return EINA_FALSE; | ||
2889 | |||
2890 | eina_model_xref(child, EINA_MODEL_INTERFACE_CHILDREN_INARRAY, | ||
2891 | "eina_model_child_insert_at"); | ||
2892 | return EINA_TRUE; | ||
2893 | } | ||
2894 | |||
2895 | static void | ||
2896 | _eina_model_interface_children_inarray_sort(Eina_Model *model, Eina_Compare_Cb compare) | ||
2897 | { | ||
2898 | EINA_MODEL_INTERFACE_CHILDREN_INARRAY_GET(model); | ||
2899 | int count = eina_inarray_count(priv); | ||
2900 | EINA_SAFETY_ON_FALSE_RETURN(count >= 0); | ||
2901 | |||
2902 | if (count > 1) | ||
2903 | _eina_model_array_sort(priv->members, 0, count - 1, compare); | ||
2904 | } | ||
2905 | #undef EINA_MODEL_INTERFACE_CHILDREN_INARRAY_GET | ||
2906 | |||
2907 | static const Eina_Model_Interface_Children _EINA_MODEL_INTERFACE_CHILDREN_INARRAY = { | ||
2908 | { | ||
2909 | EINA_MODEL_INTERFACE_VERSION, | ||
2910 | sizeof(Eina_Inarray), | ||
2911 | sizeof(Eina_Model_Interface_Children), | ||
2912 | _EINA_MODEL_INTERFACE_NAME_CHILDREN, | ||
2913 | NULL, /* no parent interfaces */ | ||
2914 | _eina_model_interface_children_events, | ||
2915 | _eina_model_interface_children_inarray_setup, | ||
2916 | _eina_model_interface_children_inarray_flush, | ||
2917 | _eina_model_interface_children_inarray_constructor, | ||
2918 | _eina_model_interface_children_inarray_destructor, | ||
2919 | NULL, | ||
2920 | NULL, | ||
2921 | NULL, | ||
2922 | NULL, | ||
2923 | NULL, | ||
2924 | NULL | ||
2925 | }, | ||
2926 | EINA_MODEL_INTERFACE_CHILDREN_VERSION, | ||
2927 | NULL, /* no compare */ | ||
2928 | NULL, /* no load */ | ||
2929 | NULL, /* no unload */ | ||
2930 | _eina_model_interface_children_inarray_count, | ||
2931 | _eina_model_interface_children_inarray_get, | ||
2932 | _eina_model_interface_children_inarray_set, | ||
2933 | _eina_model_interface_children_inarray_del, | ||
2934 | _eina_model_interface_children_inarray_insert_at, | ||
2935 | _eina_model_interface_children_inarray_sort | ||
2936 | }; | ||
2937 | |||
2938 | /* EINA_MODEL_TYPE_GENERIC ********************************************/ | ||
2939 | |||
2940 | static const Eina_Model_Interface *_EINA_MODEL_TYPE_GENERIC_IFACES[] = { | ||
2941 | &_EINA_MODEL_INTERFACE_PROPERTIES_HASH.base, | ||
2942 | &_EINA_MODEL_INTERFACE_CHILDREN_INARRAY.base, | ||
2943 | NULL | ||
2944 | }; | ||
2945 | |||
2946 | static const Eina_Model_Type _EINA_MODEL_TYPE_GENERIC = | ||
2947 | EINA_MODEL_TYPE_INIT_NOPRIVATE("Eina_Model_Type_Generic", | ||
2948 | Eina_Model_Type, | ||
2949 | &_EINA_MODEL_TYPE_MIXIN, | ||
2950 | _EINA_MODEL_TYPE_GENERIC_IFACES, | ||
2951 | NULL); | ||
2952 | |||
2953 | /* EINA_MODEL_TYPE_STRUCT ********************************************/ | ||
2954 | |||
2955 | static const Eina_Model_Interface *_EINA_MODEL_TYPE_STRUCT_IFACES[] = { | ||
2956 | &_EINA_MODEL_INTERFACE_PROPERTIES_STRUCT.base, | ||
2957 | &_EINA_MODEL_INTERFACE_CHILDREN_INARRAY.base, | ||
2958 | NULL | ||
2959 | }; | ||
2960 | |||
2961 | static const Eina_Model_Type _EINA_MODEL_TYPE_STRUCT = | ||
2962 | EINA_MODEL_TYPE_INIT_NOPRIVATE("Eina_Model_Type_Struct", | ||
2963 | Eina_Model_Type, | ||
2964 | &_EINA_MODEL_TYPE_MIXIN, | ||
2965 | _EINA_MODEL_TYPE_STRUCT_IFACES, | ||
2966 | NULL); | ||
2967 | |||
2968 | /** | ||
2969 | */ | ||
2970 | |||
2971 | /** | ||
2972 | * @internal | ||
2973 | * @brief Initialize the model module. | ||
2974 | * | ||
2975 | * @return #EINA_TRUE on success, #EINA_FALSE on failure. | ||
2976 | * | ||
2977 | * This function sets up the model module of Eina. It is called | ||
2978 | * by eina_init(). | ||
2979 | * | ||
2980 | * @see eina_init() | ||
2981 | */ | ||
2982 | Eina_Bool | ||
2983 | eina_model_init(void) | ||
2984 | { | ||
2985 | const char *choice, *tmp; | ||
2986 | |||
2987 | _eina_model_log_dom = eina_log_domain_register("eina_model", | ||
2988 | EINA_LOG_COLOR_DEFAULT); | ||
2989 | if (_eina_model_log_dom < 0) | ||
2990 | { | ||
2991 | EINA_LOG_ERR("Could not register log domain: eina_model"); | ||
2992 | return EINA_FALSE; | ||
2993 | } | ||
2994 | |||
2995 | choice = getenv("EINA_MODEL_DEBUG"); | ||
2996 | if (choice) | ||
2997 | { | ||
2998 | if (strcmp(choice, "1") == 0) | ||
2999 | _eina_model_debug = EINA_MODEL_DEBUG_CHECK; | ||
3000 | else if (strcmp(choice, "backtrace") == 0) | ||
3001 | _eina_model_debug = EINA_MODEL_DEBUG_BACKTRACE; | ||
3002 | } | ||
3003 | |||
3004 | #ifdef EINA_DEFAULT_MEMPOOL | ||
3005 | choice = "pass_through"; | ||
3006 | #else | ||
3007 | choice = "chained_mempool"; | ||
3008 | #endif | ||
3009 | tmp = getenv("EINA_MEMPOOL"); | ||
3010 | if (tmp && tmp[0]) | ||
3011 | choice = tmp; | ||
3012 | |||
3013 | if (choice) | ||
3014 | _eina_model_mp_choice = strdup(choice); | ||
3015 | |||
3016 | _eina_model_mp = eina_mempool_add | ||
3017 | (_eina_model_mp_choice, "model", NULL, sizeof(Eina_Model), 320); | ||
3018 | if (!_eina_model_mp) | ||
3019 | { | ||
3020 | ERR("Mempool for model cannot be allocated in model init."); | ||
3021 | goto on_init_fail_mp; | ||
3022 | } | ||
3023 | |||
3024 | if (!eina_lock_new(&_eina_model_inner_mps_lock)) | ||
3025 | { | ||
3026 | ERR("Cannot create inner mempools lock in model init."); | ||
3027 | goto on_init_fail_lock_mp; | ||
3028 | } | ||
3029 | _eina_model_inner_mps = eina_hash_int32_new(NULL); | ||
3030 | if (!_eina_model_inner_mps) | ||
3031 | { | ||
3032 | ERR("Cannot create hash for inner mempools in model init."); | ||
3033 | goto on_init_fail_hash_mp; | ||
3034 | } | ||
3035 | |||
3036 | if (!eina_lock_new(&_eina_model_descriptions_lock)) | ||
3037 | { | ||
3038 | ERR("Cannot create model descriptions lock in model init."); | ||
3039 | goto on_init_fail_lock_desc; | ||
3040 | } | ||
3041 | _eina_model_descriptions = eina_hash_pointer_new(NULL); | ||
3042 | if (!_eina_model_descriptions) | ||
3043 | { | ||
3044 | ERR("Cannot create model descriptions hash in model init."); | ||
3045 | goto on_init_fail_hash_desc; | ||
3046 | } | ||
3047 | |||
3048 | if (!eina_lock_new(&_eina_model_debug_list_lock)) | ||
3049 | { | ||
3050 | ERR("Cannot create model debug list lock in model init."); | ||
3051 | goto on_init_fail_lock_debug; | ||
3052 | } | ||
3053 | |||
3054 | EINA_ERROR_MODEL_FAILED = eina_error_msg_static_register( | ||
3055 | EINA_ERROR_MODEL_FAILED_STR); | ||
3056 | EINA_ERROR_MODEL_METHOD_MISSING = eina_error_msg_static_register( | ||
3057 | EINA_ERROR_MODEL_METHOD_MISSING_STR); | ||
3058 | |||
3059 | EINA_MODEL_TYPE_BASE = &_EINA_MODEL_TYPE_BASE; | ||
3060 | EINA_MODEL_TYPE_MIXIN = &_EINA_MODEL_TYPE_MIXIN; | ||
3061 | EINA_MODEL_TYPE_GENERIC = &_EINA_MODEL_TYPE_GENERIC; | ||
3062 | EINA_MODEL_TYPE_STRUCT = &_EINA_MODEL_TYPE_STRUCT; | ||
3063 | |||
3064 | EINA_MODEL_INTERFACE_PROPERTIES_HASH = &_EINA_MODEL_INTERFACE_PROPERTIES_HASH.base; | ||
3065 | EINA_MODEL_INTERFACE_PROPERTIES_STRUCT = &_EINA_MODEL_INTERFACE_PROPERTIES_STRUCT.base; | ||
3066 | |||
3067 | EINA_MODEL_INTERFACE_CHILDREN_INARRAY = &_EINA_MODEL_INTERFACE_CHILDREN_INARRAY.base; | ||
3068 | |||
3069 | EINA_MODEL_INTERFACE_NAME_PROPERTIES = _EINA_MODEL_INTERFACE_NAME_PROPERTIES; | ||
3070 | EINA_MODEL_INTERFACE_NAME_CHILDREN = _EINA_MODEL_INTERFACE_NAME_CHILDREN; | ||
3071 | |||
3072 | eina_magic_string_static_set(EINA_MAGIC_MODEL, EINA_MAGIC_MODEL_STR); | ||
3073 | |||
3074 | return EINA_TRUE; | ||
3075 | |||
3076 | on_init_fail_lock_debug: | ||
3077 | eina_hash_free(_eina_model_descriptions); | ||
3078 | on_init_fail_hash_desc: | ||
3079 | eina_lock_free(&_eina_model_descriptions_lock); | ||
3080 | on_init_fail_lock_desc: | ||
3081 | eina_hash_free(_eina_model_inner_mps); | ||
3082 | _eina_model_inner_mps = NULL; | ||
3083 | on_init_fail_hash_mp: | ||
3084 | eina_lock_free(&_eina_model_inner_mps_lock); | ||
3085 | on_init_fail_lock_mp: | ||
3086 | eina_mempool_del(_eina_model_mp); | ||
3087 | on_init_fail_mp: | ||
3088 | free(_eina_model_mp_choice); | ||
3089 | _eina_model_mp_choice = NULL; | ||
3090 | eina_log_domain_unregister(_eina_model_log_dom); | ||
3091 | _eina_model_log_dom = -1; | ||
3092 | return EINA_FALSE; | ||
3093 | } | ||
3094 | |||
3095 | /** | ||
3096 | * @internal | ||
3097 | * @brief Shut down the model module. | ||
3098 | * | ||
3099 | * @return #EINA_TRUE on success, #EINA_FALSE on failure. | ||
3100 | * | ||
3101 | * This function shuts down the model module set up by | ||
3102 | * eina_model_init(). It is called by eina_shutdown(). | ||
3103 | * | ||
3104 | * @see eina_shutdown() | ||
3105 | */ | ||
3106 | Eina_Bool | ||
3107 | eina_model_shutdown(void) | ||
3108 | { | ||
3109 | eina_lock_take(&_eina_model_debug_list_lock); | ||
3110 | if (eina_list_count(_eina_model_debug_list) > 0) | ||
3111 | ERR("%d models are still alive!", eina_list_count(_eina_model_debug_list)); | ||
3112 | eina_lock_release(&_eina_model_debug_list_lock); | ||
3113 | eina_lock_free(&_eina_model_debug_list_lock); | ||
3114 | |||
3115 | eina_lock_take(&_eina_model_inner_mps_lock); | ||
3116 | if (eina_hash_population(_eina_model_inner_mps) != 0) | ||
3117 | ERR("Cannot free eina_model internal memory pools -- still in use!"); | ||
3118 | else | ||
3119 | eina_hash_free(_eina_model_inner_mps); | ||
3120 | eina_lock_release(&_eina_model_inner_mps_lock); | ||
3121 | eina_lock_free(&_eina_model_inner_mps_lock); | ||
3122 | |||
3123 | eina_lock_take(&_eina_model_descriptions_lock); | ||
3124 | if (eina_hash_population(_eina_model_descriptions) != 0) | ||
3125 | ERR("Cannot free eina_model internal descriptions -- still in use!"); | ||
3126 | else | ||
3127 | eina_hash_free(_eina_model_descriptions); | ||
3128 | eina_lock_release(&_eina_model_descriptions_lock); | ||
3129 | eina_lock_free(&_eina_model_descriptions_lock); | ||
3130 | |||
3131 | free(_eina_model_mp_choice); | ||
3132 | _eina_model_mp_choice = NULL; | ||
3133 | eina_mempool_del(_eina_model_mp); | ||
3134 | eina_log_domain_unregister(_eina_model_log_dom); | ||
3135 | _eina_model_log_dom = -1; | ||
3136 | return EINA_TRUE; | ||
3137 | } | ||
3138 | |||
3139 | /*============================================================================* | ||
3140 | * Global * | ||
3141 | *============================================================================*/ | ||
3142 | |||
3143 | /*============================================================================* | ||
3144 | * API * | ||
3145 | *============================================================================*/ | ||
3146 | |||
3147 | |||
3148 | EAPI Eina_Error EINA_ERROR_MODEL_FAILED = 0; | ||
3149 | EAPI Eina_Error EINA_ERROR_MODEL_METHOD_MISSING = 0; | ||
3150 | |||
3151 | EAPI const Eina_Model_Type *EINA_MODEL_TYPE_BASE = NULL; | ||
3152 | EAPI const Eina_Model_Type *EINA_MODEL_TYPE_MIXIN = NULL; | ||
3153 | EAPI const Eina_Model_Type *EINA_MODEL_TYPE_GENERIC = NULL; | ||
3154 | EAPI const Eina_Model_Type *EINA_MODEL_TYPE_STRUCT = NULL; | ||
3155 | |||
3156 | EAPI const Eina_Model_Interface *EINA_MODEL_INTERFACE_PROPERTIES_HASH = NULL; | ||
3157 | EAPI const Eina_Model_Interface *EINA_MODEL_INTERFACE_PROPERTIES_STRUCT = NULL; | ||
3158 | EAPI const Eina_Model_Interface *EINA_MODEL_INTERFACE_CHILDREN_INARRAY = NULL; | ||
3159 | |||
3160 | EAPI const char *EINA_MODEL_INTERFACE_NAME_PROPERTIES = "Eina_Model_Interface_Properties"; | ||
3161 | EAPI const char *EINA_MODEL_INTERFACE_NAME_CHILDREN = "Eina_Model_Interface_Children"; | ||
3162 | |||
3163 | EAPI Eina_Model * | ||
3164 | eina_model_new(const Eina_Model_Type *type) | ||
3165 | { | ||
3166 | const Eina_Model_Description *desc; | ||
3167 | Eina_Model *model; | ||
3168 | unsigned int i; | ||
3169 | |||
3170 | EINA_SAFETY_ON_NULL_RETURN_VAL(type, NULL); | ||
3171 | EINA_SAFETY_ON_FALSE_RETURN_VAL(eina_model_type_check(type), NULL); | ||
3172 | |||
3173 | desc = _eina_model_description_get(type); | ||
3174 | EINA_SAFETY_ON_NULL_RETURN_VAL(desc, NULL); | ||
3175 | |||
3176 | model = eina_mempool_malloc(_eina_model_mp, sizeof(Eina_Model)); | ||
3177 | EINA_SAFETY_ON_NULL_GOTO(model, failed_model); | ||
3178 | |||
3179 | model->desc = desc; | ||
3180 | model->listeners.entries = NULL; | ||
3181 | model->listeners.deleted = NULL; | ||
3182 | model->listeners.freeze = NULL; | ||
3183 | model->listeners.walking = 0; | ||
3184 | |||
3185 | if (desc->total.size == 0) | ||
3186 | model->privates = NULL; | ||
3187 | else | ||
3188 | { | ||
3189 | unsigned char *ptr; | ||
3190 | |||
3191 | model->privates = _eina_model_inner_alloc | ||
3192 | (desc->total.privates * sizeof(void *) + | ||
3193 | desc->total.size); | ||
3194 | EINA_SAFETY_ON_NULL_GOTO(model->privates, failed_privates); | ||
3195 | |||
3196 | ptr = (unsigned char *)(model->privates + desc->total.privates); | ||
3197 | for (i = 0; i < desc->total.privates; i++) | ||
3198 | { | ||
3199 | unsigned int size; | ||
3200 | if (i < desc->total.types) | ||
3201 | size = desc->cache.privates[i].type->private_size; | ||
3202 | else | ||
3203 | size = desc->cache.privates[i].iface->private_size; | ||
3204 | |||
3205 | if (size == 0) | ||
3206 | { | ||
3207 | model->privates[i] = NULL; | ||
3208 | continue; | ||
3209 | } | ||
3210 | |||
3211 | model->privates[i] = ptr; | ||
3212 | memset(ptr, 0, size); | ||
3213 | |||
3214 | if (size % sizeof(void *) != 0) | ||
3215 | size += sizeof(void *) - (size % sizeof(void *)); | ||
3216 | ptr += size; | ||
3217 | } | ||
3218 | } | ||
3219 | |||
3220 | model->refcount = 1; | ||
3221 | model->xrefs = NULL; | ||
3222 | model->deleted = EINA_FALSE; | ||
3223 | EINA_MAGIC_SET(model, EINA_MAGIC_MODEL); | ||
3224 | |||
3225 | /* call setup of every type in the reverse order, | ||
3226 | * they should not call parent's setup. | ||
3227 | */ | ||
3228 | for (i = desc->total.types; i > 0; i--) | ||
3229 | { | ||
3230 | if (desc->cache.types[i - 1]->setup) | ||
3231 | { | ||
3232 | if (!desc->cache.types[i - 1]->setup(model)) | ||
3233 | { | ||
3234 | ERR("Failed to setup model %p at type %p (%s)", | ||
3235 | model, desc->cache.types[i - 1], | ||
3236 | desc->cache.types[i - 1]->name); | ||
3237 | goto failed_types; | ||
3238 | } | ||
3239 | } | ||
3240 | } | ||
3241 | |||
3242 | /* call setup of every interface in the reverse order, | ||
3243 | * they should not call parent's setup. | ||
3244 | */ | ||
3245 | for (i = desc->total.ifaces; i > 0; i--) | ||
3246 | { | ||
3247 | if (desc->cache.ifaces[i - 1]->setup) | ||
3248 | { | ||
3249 | if (!desc->cache.ifaces[i - 1]->setup(model)) | ||
3250 | { | ||
3251 | ERR("Failed to setup model %p at interface %p (%s)", | ||
3252 | model, desc->cache.ifaces[i - 1], | ||
3253 | desc->cache.ifaces[i - 1]->name); | ||
3254 | goto failed_ifaces; | ||
3255 | } | ||
3256 | } | ||
3257 | } | ||
3258 | |||
3259 | if (!desc->ops.type.constructor(model)) | ||
3260 | { | ||
3261 | ERR("Failed to construct model %p, type %p (%s)", | ||
3262 | model, desc->cache.types[0], desc->cache.types[0]->name); | ||
3263 | goto failed_constructor; | ||
3264 | } | ||
3265 | |||
3266 | if (EINA_UNLIKELY(_eina_model_debug)) | ||
3267 | { | ||
3268 | eina_lock_take(&_eina_model_debug_list_lock); | ||
3269 | _eina_model_debug_list = eina_list_append | ||
3270 | (_eina_model_debug_list, model); | ||
3271 | eina_lock_release(&_eina_model_debug_list_lock); | ||
3272 | } | ||
3273 | |||
3274 | return model; | ||
3275 | |||
3276 | failed_constructor: | ||
3277 | i = 0; | ||
3278 | failed_ifaces: | ||
3279 | /* flush every setup interface, natural order */ | ||
3280 | for (; i < desc->total.ifaces; i++) | ||
3281 | desc->cache.ifaces[i]->flush(model); | ||
3282 | i = 0; | ||
3283 | failed_types: | ||
3284 | /* flush every setup type, natural order */ | ||
3285 | for (; i < desc->total.types; i++) | ||
3286 | desc->cache.types[i]->flush(model); | ||
3287 | |||
3288 | if (model->privates) | ||
3289 | _eina_model_inner_free(desc->total.privates * sizeof(void *) + | ||
3290 | desc->total.size, | ||
3291 | model->privates); | ||
3292 | |||
3293 | failed_privates: | ||
3294 | EINA_MAGIC_SET(model, EINA_MAGIC_NONE); | ||
3295 | eina_mempool_free(_eina_model_mp, model); | ||
3296 | failed_model: | ||
3297 | _eina_model_description_dispose(desc); | ||
3298 | return NULL; | ||
3299 | } | ||
3300 | |||
3301 | static void | ||
3302 | _eina_model_free(Eina_Model *model) | ||
3303 | { | ||
3304 | const Eina_Model_Description *desc = model->desc; | ||
3305 | unsigned int i; | ||
3306 | |||
3307 | DBG("model %p (%s) refcount=%d deleted=%hhu", | ||
3308 | model, model->desc->cache.types[0]->name, | ||
3309 | model->refcount, model->deleted); | ||
3310 | |||
3311 | if (EINA_UNLIKELY(_eina_model_debug)) | ||
3312 | { | ||
3313 | if (model->xrefs) | ||
3314 | { | ||
3315 | ERR("Model %p (%s) released with references pending:", | ||
3316 | model, model->desc->cache.types[0]->name); | ||
3317 | while (model->xrefs) | ||
3318 | { | ||
3319 | Eina_Model_XRef *ref = (Eina_Model_XRef *)model->xrefs; | ||
3320 | model->xrefs = eina_inlist_remove(model->xrefs, model->xrefs); | ||
3321 | |||
3322 | ERR("xref: %p '%s'", ref->id, ref->label); | ||
3323 | free(ref); | ||
3324 | } | ||
3325 | } | ||
3326 | |||
3327 | eina_lock_take(&_eina_model_debug_list_lock); | ||
3328 | _eina_model_debug_list = eina_list_remove | ||
3329 | (_eina_model_debug_list, model); | ||
3330 | eina_lock_release(&_eina_model_debug_list_lock); | ||
3331 | } | ||
3332 | |||
3333 | /* flush every interface, natural order */ | ||
3334 | for (i = 0; i < desc->total.ifaces; i++) | ||
3335 | if (desc->cache.ifaces[i]->flush) | ||
3336 | desc->cache.ifaces[i]->flush(model); | ||
3337 | |||
3338 | /* flush every type, natural order */ | ||
3339 | for (i = 0; i < desc->total.types; i++) | ||
3340 | if (desc->cache.types[i]->flush) | ||
3341 | desc->cache.types[i]->flush(model); | ||
3342 | |||
3343 | model->refcount--; | ||
3344 | _eina_model_event_callback_call(model, _eina_model_str_freed, NULL); | ||
3345 | |||
3346 | if (model->privates) | ||
3347 | _eina_model_inner_free(desc->total.privates * sizeof(void *) + | ||
3348 | desc->total.size, | ||
3349 | model->privates); | ||
3350 | |||
3351 | if (model->listeners.deleted) | ||
3352 | _eina_model_event_callback_free_deleted(model); | ||
3353 | |||
3354 | if (model->listeners.entries) | ||
3355 | { | ||
3356 | for (i = 0; i < desc->total.events; i++) | ||
3357 | { | ||
3358 | Eina_Inlist *lst = model->listeners.entries[i]; | ||
3359 | while (lst) | ||
3360 | { | ||
3361 | void *tmp = lst; | ||
3362 | lst = lst->next; | ||
3363 | _eina_model_inner_free(sizeof(Eina_Model_Event_Listener), | ||
3364 | tmp); | ||
3365 | } | ||
3366 | } | ||
3367 | |||
3368 | _eina_model_inner_free(desc->total.events * sizeof(Eina_Inlist *), | ||
3369 | model->listeners.entries); | ||
3370 | } | ||
3371 | |||
3372 | if (model->listeners.freeze) | ||
3373 | _eina_model_inner_free(model->desc->total.events * sizeof(int), | ||
3374 | model->listeners.freeze); | ||
3375 | |||
3376 | EINA_MAGIC_SET(model, EINA_MAGIC_NONE); | ||
3377 | eina_mempool_free(_eina_model_mp, model); | ||
3378 | |||
3379 | _eina_model_description_dispose(desc); | ||
3380 | } | ||
3381 | |||
3382 | static void | ||
3383 | _eina_model_del(Eina_Model *model) | ||
3384 | { | ||
3385 | const Eina_Model_Description *desc = model->desc; | ||
3386 | |||
3387 | DBG("model %p (%s) refcount=%d deleted=%hhu", | ||
3388 | model, model->desc->cache.types[0]->name, | ||
3389 | model->refcount, model->deleted); | ||
3390 | |||
3391 | EINA_SAFETY_ON_TRUE_RETURN(model->deleted); | ||
3392 | |||
3393 | model->deleted = EINA_TRUE; | ||
3394 | _eina_model_event_callback_call(model, _eina_model_str_deleted, NULL); | ||
3395 | |||
3396 | if (!desc->ops.type.destructor(model)) | ||
3397 | ERR("Failed to destroy model %p, type %p (%s)", | ||
3398 | model, desc->cache.types[0], desc->cache.types[0]->name); | ||
3399 | } | ||
3400 | |||
3401 | static void | ||
3402 | _eina_model_unref(Eina_Model *model) | ||
3403 | { | ||
3404 | DBG("model %p (%s) refcount=%d deleted=%hhu", | ||
3405 | model, model->desc->cache.types[0]->name, | ||
3406 | model->refcount, model->deleted); | ||
3407 | |||
3408 | if (model->refcount > 1) | ||
3409 | { | ||
3410 | model->refcount--; | ||
3411 | return; | ||
3412 | } | ||
3413 | |||
3414 | if (!model->deleted) _eina_model_del(model); | ||
3415 | _eina_model_free(model); | ||
3416 | } | ||
3417 | |||
3418 | #define EINA_MODEL_INSTANCE_CHECK_VAL(inst, retval) \ | ||
3419 | do \ | ||
3420 | { \ | ||
3421 | if (!EINA_MAGIC_CHECK(inst, EINA_MAGIC_MODEL)) \ | ||
3422 | { \ | ||
3423 | EINA_MAGIC_FAIL(inst, EINA_MAGIC_MODEL); \ | ||
3424 | return retval; \ | ||
3425 | } \ | ||
3426 | EINA_SAFETY_ON_NULL_RETURN_VAL(inst->desc, retval); \ | ||
3427 | EINA_SAFETY_ON_FALSE_RETURN_VAL(inst->refcount > 0, retval); \ | ||
3428 | EINA_SAFETY_ON_FALSE_RETURN_VAL(inst->desc->refcount > 0, retval); \ | ||
3429 | } \ | ||
3430 | while (0) | ||
3431 | |||
3432 | #define EINA_MODEL_INSTANCE_CHECK(inst) \ | ||
3433 | do \ | ||
3434 | { \ | ||
3435 | if (!EINA_MAGIC_CHECK(inst, EINA_MAGIC_MODEL)) \ | ||
3436 | { \ | ||
3437 | EINA_MAGIC_FAIL(inst, EINA_MAGIC_MODEL); \ | ||
3438 | return; \ | ||
3439 | } \ | ||
3440 | EINA_SAFETY_ON_NULL_RETURN(inst->desc); \ | ||
3441 | EINA_SAFETY_ON_FALSE_RETURN(inst->refcount > 0); \ | ||
3442 | EINA_SAFETY_ON_FALSE_RETURN(inst->desc->refcount > 0); \ | ||
3443 | } \ | ||
3444 | while (0) | ||
3445 | |||
3446 | #define EINA_MODEL_TYPE_CALL_OPTIONAL_RETURN(model, method, def_retval, ...) \ | ||
3447 | do \ | ||
3448 | { \ | ||
3449 | eina_error_set(0); \ | ||
3450 | if (model->desc->ops.type.method) \ | ||
3451 | return model->desc->ops.type.method(model, ## __VA_ARGS__); \ | ||
3452 | DBG("Optional method" # method "() not implemented for model %p (%s)", \ | ||
3453 | model, model->desc->cache.types[0]->name); \ | ||
3454 | return def_retval; \ | ||
3455 | } \ | ||
3456 | while (0) | ||
3457 | |||
3458 | #define EINA_MODEL_TYPE_CALL_OPTIONAL(model, method, ...) \ | ||
3459 | do \ | ||
3460 | { \ | ||
3461 | eina_error_set(0); \ | ||
3462 | if (model->desc->ops.type.method) \ | ||
3463 | model->desc->ops.type.method(model, ## __VA_ARGS__); \ | ||
3464 | else \ | ||
3465 | DBG("Optional method" # method "() not implemented for model %p (%s)", \ | ||
3466 | model, model->desc->cache.types[0]->name); \ | ||
3467 | } \ | ||
3468 | while (0) | ||
3469 | |||
3470 | #define EINA_MODEL_TYPE_CALL_MANDATORY_RETURN(model, method, def_retval, ...) \ | ||
3471 | do \ | ||
3472 | { \ | ||
3473 | eina_error_set(0); \ | ||
3474 | if (model->desc->ops.type.method) \ | ||
3475 | return model->desc->ops.type.method(model, ## __VA_ARGS__); \ | ||
3476 | eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING); \ | ||
3477 | CRITICAL("Mandatory method" # method "() not implemented for model %p (%s)", \ | ||
3478 | model, model->desc->cache.types[0]->name); \ | ||
3479 | return def_retval; \ | ||
3480 | } \ | ||
3481 | while (0) | ||
3482 | |||
3483 | #define EINA_MODEL_TYPE_CALL_MANDATORY(model, method, ...) \ | ||
3484 | do \ | ||
3485 | { \ | ||
3486 | eina_error_set(0); \ | ||
3487 | if (model->desc->ops.type.method) \ | ||
3488 | model->desc->ops.type.method(model, ## __VA_ARGS__); \ | ||
3489 | else \ | ||
3490 | { \ | ||
3491 | eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING); \ | ||
3492 | CRITICAL("Mandatory method" # method "() not implemented for model %p (%s)", \ | ||
3493 | model, model->desc->cache.types[0]->name); \ | ||
3494 | } \ | ||
3495 | } \ | ||
3496 | while (0) | ||
3497 | |||
3498 | |||
3499 | #define EINA_MODEL_TYPE_CALL_RETURN(model, method, def_retval, ...) \ | ||
3500 | do \ | ||
3501 | { \ | ||
3502 | eina_error_set(0); \ | ||
3503 | if (model->desc->ops.type.method) \ | ||
3504 | return model->desc->ops.type.method(model, ## __VA_ARGS__); \ | ||
3505 | eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING); \ | ||
3506 | ERR("Method" # method "() not implemented for model %p (%s)", \ | ||
3507 | model, model->desc->cache.types[0]->name); \ | ||
3508 | return def_retval; \ | ||
3509 | } \ | ||
3510 | while (0) | ||
3511 | |||
3512 | #define EINA_MODEL_TYPE_CALL(model, method, ...) \ | ||
3513 | do \ | ||
3514 | { \ | ||
3515 | eina_error_set(0); \ | ||
3516 | if (model->desc->ops.type.method) \ | ||
3517 | model->desc->ops.type.method(model, ## __VA_ARGS__); \ | ||
3518 | else \ | ||
3519 | { \ | ||
3520 | eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING); \ | ||
3521 | ERR("Method" # method "() not implemented for model %p (%s)", \ | ||
3522 | model, model->desc->cache.types[0]->name); \ | ||
3523 | } \ | ||
3524 | } \ | ||
3525 | while (0) | ||
3526 | |||
3527 | EAPI void | ||
3528 | eina_model_del(Eina_Model *model) | ||
3529 | { | ||
3530 | EINA_MODEL_INSTANCE_CHECK(model); | ||
3531 | _eina_model_del(model); | ||
3532 | _eina_model_unref(model); | ||
3533 | } | ||
3534 | |||
3535 | EAPI const Eina_Model_Type * | ||
3536 | eina_model_type_get(const Eina_Model *model) | ||
3537 | { | ||
3538 | EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL); | ||
3539 | return model->desc->cache.types[0]; | ||
3540 | } | ||
3541 | |||
3542 | EAPI const Eina_Model_Interface * | ||
3543 | eina_model_interface_get(const Eina_Model *model, const char *name) | ||
3544 | { | ||
3545 | const Eina_Model_Description *desc; | ||
3546 | const Eina_Model_Interface **itr, **itr_end; | ||
3547 | |||
3548 | EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL); | ||
3549 | EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL); | ||
3550 | |||
3551 | desc = model->desc; | ||
3552 | itr = desc->cache.ifaces; | ||
3553 | itr_end = itr + desc->total.ifaces; | ||
3554 | |||
3555 | /* fallback to strcmp if user is lazy about speed */ | ||
3556 | for (; itr < itr_end; itr++) | ||
3557 | if (strcmp((*itr)->name, name) == 0) | ||
3558 | return *itr; | ||
3559 | |||
3560 | return NULL; | ||
3561 | } | ||
3562 | |||
3563 | static Eina_Bool | ||
3564 | _eina_model_instance_check(const Eina_Model *model, const Eina_Model_Type *type) | ||
3565 | { | ||
3566 | const Eina_Model_Type **itr, **itr_end; | ||
3567 | |||
3568 | itr = model->desc->cache.types; | ||
3569 | itr_end = itr + model->desc->total.types; | ||
3570 | |||
3571 | for (; itr < itr_end; itr++) | ||
3572 | if (*itr == type) | ||
3573 | return EINA_TRUE; | ||
3574 | |||
3575 | return EINA_FALSE; | ||
3576 | } | ||
3577 | |||
3578 | EAPI Eina_Bool | ||
3579 | eina_model_instance_check(const Eina_Model *model, const Eina_Model_Type *type) | ||
3580 | { | ||
3581 | EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE); | ||
3582 | EINA_SAFETY_ON_NULL_RETURN_VAL(type, EINA_FALSE); | ||
3583 | EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_type_check(type), EINA_FALSE); | ||
3584 | return _eina_model_instance_check(model, type); | ||
3585 | } | ||
3586 | |||
3587 | EAPI Eina_Model * | ||
3588 | eina_model_ref(Eina_Model *model) | ||
3589 | { | ||
3590 | EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL); | ||
3591 | DBG("model %p (%s) refcount=%d deleted=%hhu", | ||
3592 | model, model->desc->cache.types[0]->name, | ||
3593 | model->refcount, model->deleted); | ||
3594 | model->refcount++; | ||
3595 | return model; | ||
3596 | } | ||
3597 | |||
3598 | static Eina_Model * | ||
3599 | _eina_model_xref_add(Eina_Model *model, const void *id, const char *label) | ||
3600 | { | ||
3601 | Eina_Model_XRef *ref; | ||
3602 | void *bt[256]; | ||
3603 | int btlen, labellen; | ||
3604 | |||
3605 | labellen = label ? strlen(label): 0; | ||
3606 | btlen = 0; | ||
3607 | |||
3608 | #ifdef HAVE_BACKTRACE | ||
3609 | if (_eina_model_debug == EINA_MODEL_DEBUG_BACKTRACE) | ||
3610 | btlen = backtrace(bt, EINA_C_ARRAY_LENGTH(bt)); | ||
3611 | #endif | ||
3612 | |||
3613 | ref = calloc(1, sizeof(*ref) + (btlen * sizeof(void *)) + (labellen + 1)); | ||
3614 | EINA_SAFETY_ON_NULL_RETURN_VAL(ref, NULL); | ||
3615 | |||
3616 | ref->id = id; | ||
3617 | memcpy(ref->label, label, labellen); | ||
3618 | ref->label[labellen] = '\0'; | ||
3619 | ref->backtrace.count = btlen; | ||
3620 | if (btlen == 0) ref->backtrace.symbols = NULL; | ||
3621 | else | ||
3622 | { | ||
3623 | void *ptr = (unsigned char *)ref + sizeof(*ref) + (labellen + 1); | ||
3624 | ref->backtrace.symbols = ptr; | ||
3625 | memcpy(ptr, bt, btlen * sizeof(void *)); | ||
3626 | } | ||
3627 | |||
3628 | model->xrefs = eina_inlist_append(model->xrefs, EINA_INLIST_GET(ref)); | ||
3629 | return model; | ||
3630 | } | ||
3631 | |||
3632 | EAPI Eina_Model * | ||
3633 | eina_model_xref(Eina_Model *model, const void *id, const char *label) | ||
3634 | { | ||
3635 | EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL); | ||
3636 | DBG("model %p (%s) refcount=%d deleted=%hhu id=%p label=%s", | ||
3637 | model, model->desc->cache.types[0]->name, | ||
3638 | model->refcount, model->deleted, id, label ? label : ""); | ||
3639 | |||
3640 | model->refcount++; | ||
3641 | |||
3642 | if (EINA_LIKELY(!_eina_model_debug)) | ||
3643 | return model; | ||
3644 | |||
3645 | return _eina_model_xref_add(model, id, label); | ||
3646 | } | ||
3647 | |||
3648 | EAPI void | ||
3649 | eina_model_unref(Eina_Model *model) | ||
3650 | { | ||
3651 | EINA_MODEL_INSTANCE_CHECK(model); | ||
3652 | _eina_model_unref(model); | ||
3653 | } | ||
3654 | |||
3655 | EAPI void | ||
3656 | eina_model_xunref(Eina_Model *model, const void *id) | ||
3657 | { | ||
3658 | Eina_Model_XRef *ref; | ||
3659 | EINA_MODEL_INSTANCE_CHECK(model); | ||
3660 | |||
3661 | if (EINA_LIKELY(!_eina_model_debug)) | ||
3662 | { | ||
3663 | _eina_model_unref(model); | ||
3664 | return; | ||
3665 | } | ||
3666 | |||
3667 | EINA_INLIST_FOREACH(model->xrefs, ref) | ||
3668 | { | ||
3669 | if (ref->id != id) continue; | ||
3670 | |||
3671 | model->xrefs = eina_inlist_remove(model->xrefs, EINA_INLIST_GET(ref)); | ||
3672 | free(ref); | ||
3673 | _eina_model_unref(model); | ||
3674 | return; | ||
3675 | } | ||
3676 | |||
3677 | ERR("Could not find existing reference %p to model %p", id, model); | ||
3678 | } | ||
3679 | |||
3680 | EAPI int | ||
3681 | eina_model_refcount(const Eina_Model *model) | ||
3682 | { | ||
3683 | EINA_MODEL_INSTANCE_CHECK_VAL(model, -1); | ||
3684 | return model->refcount; | ||
3685 | } | ||
3686 | |||
3687 | EAPI const Eina_Inlist * | ||
3688 | eina_model_xrefs_get(const Eina_Model *model) | ||
3689 | { | ||
3690 | EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL); | ||
3691 | return model->xrefs; | ||
3692 | } | ||
3693 | |||
3694 | EAPI Eina_Bool | ||
3695 | eina_model_event_callback_add(Eina_Model *model, const char *event_name, Eina_Model_Event_Cb cb, const void *data) | ||
3696 | { | ||
3697 | const Eina_Model_Description *desc; | ||
3698 | Eina_Model_Event_Listener *el; | ||
3699 | int event_id; | ||
3700 | |||
3701 | EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE); | ||
3702 | EINA_SAFETY_ON_NULL_RETURN_VAL(event_name, EINA_FALSE); | ||
3703 | EINA_SAFETY_ON_NULL_RETURN_VAL(cb, EINA_FALSE); | ||
3704 | |||
3705 | desc = model->desc; | ||
3706 | event_id = _eina_model_description_event_id_find(desc, event_name); | ||
3707 | if (event_id < 0) | ||
3708 | { | ||
3709 | ERR("No event named %s for model %p (%s)", | ||
3710 | event_name, model, model->desc->cache.types[0]->name); | ||
3711 | return EINA_FALSE; | ||
3712 | } | ||
3713 | |||
3714 | if (!model->listeners.entries) | ||
3715 | { | ||
3716 | model->listeners.entries = _eina_model_inner_alloc | ||
3717 | (desc->total.events * sizeof(Eina_Inlist *)); | ||
3718 | EINA_SAFETY_ON_NULL_RETURN_VAL(model->listeners.entries, EINA_FALSE); | ||
3719 | memset(model->listeners.entries, 0, | ||
3720 | desc->total.events * sizeof(Eina_Inlist *)); | ||
3721 | } | ||
3722 | |||
3723 | el = _eina_model_inner_alloc(sizeof(Eina_Model_Event_Listener)); | ||
3724 | EINA_SAFETY_ON_NULL_RETURN_VAL(el, EINA_FALSE); | ||
3725 | |||
3726 | el->cb = cb; | ||
3727 | el->data = data; | ||
3728 | el->deleted = EINA_FALSE; | ||
3729 | model->listeners.entries[event_id] = eina_inlist_append | ||
3730 | (model->listeners.entries[event_id], EINA_INLIST_GET(el)); | ||
3731 | |||
3732 | return EINA_TRUE; | ||
3733 | } | ||
3734 | |||
3735 | EAPI Eina_Bool | ||
3736 | eina_model_event_callback_del(Eina_Model *model, const char *event_name, Eina_Model_Event_Cb cb, const void *data) | ||
3737 | { | ||
3738 | int event_id; | ||
3739 | Eina_Inlist *lst; | ||
3740 | Eina_Model_Event_Listener *el; | ||
3741 | |||
3742 | EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE); | ||
3743 | EINA_SAFETY_ON_NULL_RETURN_VAL(event_name, EINA_FALSE); | ||
3744 | EINA_SAFETY_ON_NULL_RETURN_VAL(cb, EINA_FALSE); | ||
3745 | |||
3746 | if (!model->listeners.entries) | ||
3747 | { | ||
3748 | ERR("No event callbacks for model %p (%s)", | ||
3749 | model, model->desc->cache.types[0]->name); | ||
3750 | return EINA_FALSE; | ||
3751 | } | ||
3752 | |||
3753 | event_id = _eina_model_description_event_id_find(model->desc, event_name); | ||
3754 | if (event_id < 0) | ||
3755 | { | ||
3756 | ERR("No event named %s for model %p (%s)", | ||
3757 | event_name, model, model->desc->cache.types[0]->name); | ||
3758 | return EINA_FALSE; | ||
3759 | } | ||
3760 | |||
3761 | lst = model->listeners.entries[event_id]; | ||
3762 | EINA_INLIST_FOREACH(lst, el) | ||
3763 | { | ||
3764 | if (el->cb != cb) continue; | ||
3765 | if ((data) && (el->data != data)) continue; | ||
3766 | |||
3767 | if (model->listeners.walking == 0) | ||
3768 | { | ||
3769 | model->listeners.entries[event_id] = eina_inlist_remove | ||
3770 | (model->listeners.entries[event_id], EINA_INLIST_GET(el)); | ||
3771 | _eina_model_inner_free(sizeof(Eina_Model_Event_Listener), el); | ||
3772 | } | ||
3773 | else | ||
3774 | { | ||
3775 | el->deleted = EINA_TRUE; | ||
3776 | if (!model->listeners.deleted) | ||
3777 | { | ||
3778 | model->listeners.deleted = _eina_model_inner_alloc | ||
3779 | (model->desc->total.events * sizeof(Eina_List *)); | ||
3780 | EINA_SAFETY_ON_NULL_RETURN_VAL(model->listeners.deleted, | ||
3781 | EINA_FALSE); | ||
3782 | |||
3783 | memset(model->listeners.deleted, 0, | ||
3784 | model->desc->total.events * sizeof(Eina_List *)); | ||
3785 | |||
3786 | } | ||
3787 | model->listeners.deleted[event_id] = eina_list_append | ||
3788 | (model->listeners.deleted[event_id], el); | ||
3789 | } | ||
3790 | return EINA_TRUE; | ||
3791 | } | ||
3792 | |||
3793 | ERR("No callback %p data %p found for event named %s for model %p (%s)", | ||
3794 | cb, data, event_name, model, model->desc->cache.types[0]->name); | ||
3795 | return EINA_FALSE; | ||
3796 | } | ||
3797 | |||
3798 | EAPI const Eina_Model_Event_Description * | ||
3799 | eina_model_event_description_get(const Eina_Model *model, const char *event_name) | ||
3800 | { | ||
3801 | const Eina_Model_Description *desc; | ||
3802 | int event_id; | ||
3803 | |||
3804 | EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL); | ||
3805 | EINA_SAFETY_ON_NULL_RETURN_VAL(event_name, NULL); | ||
3806 | |||
3807 | desc = model->desc; | ||
3808 | event_id = _eina_model_description_event_id_find(desc, event_name); | ||
3809 | if (event_id < 0) | ||
3810 | return NULL; | ||
3811 | |||
3812 | return desc->cache.events[event_id].desc; | ||
3813 | } | ||
3814 | |||
3815 | EAPI Eina_List * | ||
3816 | eina_model_event_names_list_get(const Eina_Model *model) | ||
3817 | { | ||
3818 | const Eina_Model_Event_Description_Cache *itr, *itr_end; | ||
3819 | Eina_List *lst = NULL; | ||
3820 | |||
3821 | EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL); | ||
3822 | |||
3823 | itr = model->desc->cache.events; | ||
3824 | itr_end = itr + model->desc->total.events; | ||
3825 | |||
3826 | for (; itr < itr_end; itr++) | ||
3827 | lst = eina_list_append(lst, eina_stringshare_add(itr->name)); | ||
3828 | |||
3829 | return lst; | ||
3830 | } | ||
3831 | |||
3832 | EAPI void | ||
3833 | eina_model_event_names_list_free(Eina_List *list) | ||
3834 | { | ||
3835 | const char *str; | ||
3836 | EINA_LIST_FREE(list, str) | ||
3837 | eina_stringshare_del(str); | ||
3838 | } | ||
3839 | |||
3840 | EAPI Eina_Bool | ||
3841 | eina_model_event_callback_call(Eina_Model *model, const char *name, const void *event_info) | ||
3842 | { | ||
3843 | EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE); | ||
3844 | EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE); | ||
3845 | return _eina_model_event_callback_call(model, name, event_info); | ||
3846 | } | ||
3847 | |||
3848 | EAPI int | ||
3849 | eina_model_event_callback_freeze(Eina_Model *model, const char *name) | ||
3850 | { | ||
3851 | int event_id; | ||
3852 | |||
3853 | EINA_MODEL_INSTANCE_CHECK_VAL(model, -1); | ||
3854 | EINA_SAFETY_ON_NULL_RETURN_VAL(name, -1); | ||
3855 | |||
3856 | event_id = _eina_model_description_event_id_find(model->desc, name); | ||
3857 | if (event_id < 0) return -1; | ||
3858 | |||
3859 | if (!model->listeners.freeze) | ||
3860 | { | ||
3861 | model->listeners.freeze = _eina_model_inner_alloc | ||
3862 | (model->desc->total.events * sizeof(int)); | ||
3863 | EINA_SAFETY_ON_NULL_RETURN_VAL(model->listeners.freeze, -1); | ||
3864 | |||
3865 | memset(model->listeners.freeze, 0, | ||
3866 | model->desc->total.events * sizeof(int)); | ||
3867 | } | ||
3868 | |||
3869 | if (model->listeners.freeze[event_id] == 0) | ||
3870 | DBG("model %p (%s) event %s frozen", | ||
3871 | model, model->desc->cache.types[0]->name, name); | ||
3872 | |||
3873 | model->listeners.freeze[event_id]++; | ||
3874 | return model->listeners.freeze[event_id]; | ||
3875 | } | ||
3876 | |||
3877 | EAPI int | ||
3878 | eina_model_event_callback_thaw(Eina_Model *model, const char *name) | ||
3879 | { | ||
3880 | int event_id; | ||
3881 | |||
3882 | EINA_MODEL_INSTANCE_CHECK_VAL(model, -1); | ||
3883 | EINA_SAFETY_ON_NULL_RETURN_VAL(name, -1); | ||
3884 | EINA_SAFETY_ON_NULL_RETURN_VAL(model->listeners.freeze, -1); | ||
3885 | |||
3886 | event_id = _eina_model_description_event_id_find(model->desc, name); | ||
3887 | if (event_id < 0) return -1; | ||
3888 | |||
3889 | model->listeners.freeze[event_id]--; | ||
3890 | if (model->listeners.freeze[event_id] == 0) | ||
3891 | DBG("model %p (%s) event %s unfrozen", | ||
3892 | model, model->desc->cache.types[0]->name, name); | ||
3893 | return model->listeners.freeze[event_id]; | ||
3894 | } | ||
3895 | |||
3896 | EAPI Eina_Model * | ||
3897 | eina_model_copy(const Eina_Model *model) | ||
3898 | { | ||
3899 | const Eina_Model_Description *desc; | ||
3900 | Eina_Model *copy; | ||
3901 | unsigned int i; | ||
3902 | |||
3903 | EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL); | ||
3904 | desc = model->desc; | ||
3905 | copy = eina_model_new(desc->cache.types[0]); | ||
3906 | EINA_SAFETY_ON_NULL_RETURN_VAL(copy, NULL); | ||
3907 | |||
3908 | /* call copy of every type in the reverse order, | ||
3909 | * they should not call parent's copy. | ||
3910 | */ | ||
3911 | for (i = desc->total.types; i > 0; i--) | ||
3912 | { | ||
3913 | if (desc->cache.types[i - 1]->copy) | ||
3914 | { | ||
3915 | if (!desc->cache.types[i - 1]->copy(model, copy)) | ||
3916 | goto failed; | ||
3917 | } | ||
3918 | } | ||
3919 | |||
3920 | /* call copy of every interface in the reverse order, | ||
3921 | * they should not call parent's copy. | ||
3922 | */ | ||
3923 | for (i = desc->total.ifaces; i > 0; i--) | ||
3924 | { | ||
3925 | if (desc->cache.ifaces[i - 1]->copy) | ||
3926 | { | ||
3927 | if (!desc->cache.ifaces[i - 1]->copy(model, copy)) | ||
3928 | goto failed; | ||
3929 | } | ||
3930 | } | ||
3931 | |||
3932 | return copy; | ||
3933 | |||
3934 | failed: | ||
3935 | ERR("Failed to copy model %p %s", model, desc->cache.types[0]->name); | ||
3936 | eina_model_del(copy); | ||
3937 | return NULL; | ||
3938 | } | ||
3939 | |||
3940 | EAPI Eina_Model * | ||
3941 | eina_model_deep_copy(const Eina_Model *model) | ||
3942 | { | ||
3943 | const Eina_Model_Description *desc; | ||
3944 | Eina_Model *deep_copy; | ||
3945 | unsigned int i; | ||
3946 | |||
3947 | EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL); | ||
3948 | desc = model->desc; | ||
3949 | deep_copy = eina_model_new(desc->cache.types[0]); | ||
3950 | EINA_SAFETY_ON_NULL_RETURN_VAL(deep_copy, NULL); | ||
3951 | |||
3952 | /* call deep_copy of every type in the reverse order, | ||
3953 | * they should not call parent's deep_copy. | ||
3954 | */ | ||
3955 | for (i = desc->total.types; i > 0; i--) | ||
3956 | { | ||
3957 | if (desc->cache.types[i - 1]->deep_copy) | ||
3958 | { | ||
3959 | if (!desc->cache.types[i - 1]->deep_copy(model, deep_copy)) | ||
3960 | goto failed; | ||
3961 | } | ||
3962 | } | ||
3963 | |||
3964 | /* call deep_copy of every interface in the reverse order, | ||
3965 | * they should not call parent's deep_copy. | ||
3966 | */ | ||
3967 | for (i = desc->total.ifaces; i > 0; i--) | ||
3968 | { | ||
3969 | if (desc->cache.ifaces[i - 1]->deep_copy) | ||
3970 | { | ||
3971 | if (!desc->cache.ifaces[i - 1]->deep_copy(model, deep_copy)) | ||
3972 | goto failed; | ||
3973 | } | ||
3974 | } | ||
3975 | |||
3976 | return deep_copy; | ||
3977 | |||
3978 | failed: | ||
3979 | ERR("Failed to deep copy model %p %s", model, desc->cache.types[0]->name); | ||
3980 | eina_model_del(deep_copy); | ||
3981 | return NULL; | ||
3982 | } | ||
3983 | |||
3984 | EAPI int | ||
3985 | eina_model_compare(const Eina_Model *a, const Eina_Model *b) | ||
3986 | { | ||
3987 | const Eina_Model_Description *desc_a, *desc_b; | ||
3988 | Eina_Bool ok; | ||
3989 | int cmp = -1; | ||
3990 | |||
3991 | EINA_MODEL_INSTANCE_CHECK_VAL(a, -1); | ||
3992 | EINA_MODEL_INSTANCE_CHECK_VAL(b, -1); | ||
3993 | desc_a = a->desc; | ||
3994 | desc_b = b->desc; | ||
3995 | |||
3996 | if ((!desc_a->ops.type.compare) && (!desc_b->ops.type.compare)) | ||
3997 | { | ||
3998 | ERR("Models %p (%s) and %p (%s) can't compare", | ||
3999 | a, desc_a->cache.types[0]->name, | ||
4000 | b, desc_b->cache.types[0]->name); | ||
4001 | eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING); | ||
4002 | return -1; | ||
4003 | } | ||
4004 | else if ((desc_a->ops.type.compare) && (desc_b->ops.type.compare)) | ||
4005 | { | ||
4006 | ok = desc_a->ops.type.compare(a, b, &cmp); | ||
4007 | if (!ok) | ||
4008 | { | ||
4009 | ok = desc_b->ops.type.compare(b, a, &cmp); | ||
4010 | if (ok) | ||
4011 | cmp = -cmp; /* swapped sides! */ | ||
4012 | } | ||
4013 | } | ||
4014 | else if (desc_a->ops.type.compare) | ||
4015 | ok = desc_a->ops.type.compare(a, b, &cmp); | ||
4016 | else | ||
4017 | { | ||
4018 | ok = desc_b->ops.type.compare(b, a, &cmp); | ||
4019 | if (ok) | ||
4020 | cmp = -cmp; /* swapped sides! */ | ||
4021 | } | ||
4022 | |||
4023 | if (!ok) | ||
4024 | { | ||
4025 | ERR("Could not compare models %p (%s) and %p (%s)", | ||
4026 | a, desc_a->cache.types[0]->name, | ||
4027 | b, desc_b->cache.types[0]->name); | ||
4028 | eina_error_set(EINA_ERROR_MODEL_FAILED); | ||
4029 | return -1; | ||
4030 | } | ||
4031 | |||
4032 | return cmp; | ||
4033 | } | ||
4034 | |||
4035 | EAPI Eina_Bool | ||
4036 | eina_model_load(Eina_Model *model) | ||
4037 | { | ||
4038 | Eina_Bool ret; | ||
4039 | |||
4040 | EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE); | ||
4041 | |||
4042 | eina_error_set(0); | ||
4043 | if (model->desc->ops.type.load) | ||
4044 | { | ||
4045 | ret = model->desc->ops.type.load(model); | ||
4046 | if (ret) | ||
4047 | _eina_model_event_callback_call(model, _eina_model_str_loaded, NULL); | ||
4048 | } | ||
4049 | else | ||
4050 | { | ||
4051 | eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING); | ||
4052 | ret = EINA_FALSE; | ||
4053 | ERR("Method load() not implemented for model %p (%s)", | ||
4054 | model, model->desc->cache.types[0]->name); | ||
4055 | } | ||
4056 | |||
4057 | return ret; | ||
4058 | } | ||
4059 | |||
4060 | EAPI Eina_Bool | ||
4061 | eina_model_unload(Eina_Model *model) | ||
4062 | { | ||
4063 | Eina_Bool ret; | ||
4064 | |||
4065 | EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE); | ||
4066 | |||
4067 | eina_error_set(0); | ||
4068 | if (model->desc->ops.type.unload) | ||
4069 | { | ||
4070 | ret = model->desc->ops.type.unload(model); | ||
4071 | if (ret) | ||
4072 | _eina_model_event_callback_call | ||
4073 | (model, _eina_model_str_unloaded, NULL); | ||
4074 | } | ||
4075 | else | ||
4076 | { | ||
4077 | eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING); | ||
4078 | ret = EINA_FALSE; | ||
4079 | ERR("Method unload() not implemented for model %p (%s)", | ||
4080 | model, model->desc->cache.types[0]->name); | ||
4081 | } | ||
4082 | |||
4083 | return ret; | ||
4084 | } | ||
4085 | |||
4086 | EAPI Eina_Bool | ||
4087 | eina_model_property_get(const Eina_Model *model, const char *name, Eina_Value *value) | ||
4088 | { | ||
4089 | EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE); | ||
4090 | EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE); | ||
4091 | EINA_SAFETY_ON_NULL_RETURN_VAL(value, EINA_FALSE); | ||
4092 | EINA_MODEL_TYPE_CALL_MANDATORY_RETURN(model, property_get, EINA_FALSE, | ||
4093 | name, value); | ||
4094 | } | ||
4095 | |||
4096 | EAPI Eina_Bool | ||
4097 | eina_model_property_set(Eina_Model *model, const const char *name, const Eina_Value *value) | ||
4098 | { | ||
4099 | Eina_Bool ret; | ||
4100 | |||
4101 | EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE); | ||
4102 | EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE); | ||
4103 | EINA_SAFETY_ON_NULL_RETURN_VAL(value, EINA_FALSE); | ||
4104 | EINA_SAFETY_ON_FALSE_RETURN_VAL(eina_value_type_check(value->type), EINA_FALSE); | ||
4105 | |||
4106 | eina_error_set(0); | ||
4107 | if (model->desc->ops.type.property_set) | ||
4108 | { | ||
4109 | ret = model->desc->ops.type.property_set(model, name, value); | ||
4110 | if (ret) | ||
4111 | _eina_model_event_callback_call | ||
4112 | (model, _eina_model_str_property_set, name); | ||
4113 | } | ||
4114 | else | ||
4115 | { | ||
4116 | eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING); | ||
4117 | ret = EINA_FALSE; | ||
4118 | ERR("Method property_set() not implemented for model %p (%s)", | ||
4119 | model, model->desc->cache.types[0]->name); | ||
4120 | } | ||
4121 | |||
4122 | return ret; | ||
4123 | } | ||
4124 | |||
4125 | EAPI Eina_Bool | ||
4126 | eina_model_property_del(Eina_Model *model, const char *name) | ||
4127 | { | ||
4128 | Eina_Bool ret; | ||
4129 | |||
4130 | EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE); | ||
4131 | EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE); | ||
4132 | |||
4133 | eina_error_set(0); | ||
4134 | if (model->desc->ops.type.property_del) | ||
4135 | { | ||
4136 | ret = model->desc->ops.type.property_del(model, name); | ||
4137 | if (ret) | ||
4138 | _eina_model_event_callback_call | ||
4139 | (model, _eina_model_str_property_del, name); | ||
4140 | } | ||
4141 | else | ||
4142 | { | ||
4143 | eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING); | ||
4144 | ret = EINA_FALSE; | ||
4145 | ERR("Method property_del() not implemented for model %p (%s)", | ||
4146 | model, model->desc->cache.types[0]->name); | ||
4147 | } | ||
4148 | |||
4149 | return ret; | ||
4150 | } | ||
4151 | |||
4152 | EAPI Eina_List * | ||
4153 | eina_model_properties_names_list_get(const Eina_Model *model) | ||
4154 | { | ||
4155 | EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL); | ||
4156 | EINA_MODEL_TYPE_CALL_OPTIONAL_RETURN(model, properties_names_list_get, NULL); | ||
4157 | } | ||
4158 | |||
4159 | EAPI void | ||
4160 | eina_model_properties_names_list_free(Eina_List *list) | ||
4161 | { | ||
4162 | const char *str; | ||
4163 | EINA_LIST_FREE(list, str) | ||
4164 | eina_stringshare_del(str); | ||
4165 | } | ||
4166 | |||
4167 | EAPI int | ||
4168 | eina_model_child_count(const Eina_Model *model) | ||
4169 | { | ||
4170 | EINA_MODEL_INSTANCE_CHECK_VAL(model, -1); | ||
4171 | EINA_MODEL_TYPE_CALL_OPTIONAL_RETURN(model, child_count, 0); | ||
4172 | } | ||
4173 | |||
4174 | EAPI Eina_Model * | ||
4175 | eina_model_child_get(const Eina_Model *model, unsigned int position) | ||
4176 | { | ||
4177 | EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL); | ||
4178 | EINA_MODEL_TYPE_CALL_RETURN(model, child_get, NULL, position); | ||
4179 | } | ||
4180 | |||
4181 | EAPI Eina_Bool | ||
4182 | eina_model_child_set(Eina_Model *model, unsigned int position, Eina_Model *child) | ||
4183 | { | ||
4184 | Eina_Bool ret; | ||
4185 | |||
4186 | EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE); | ||
4187 | EINA_MODEL_INSTANCE_CHECK_VAL(child, EINA_FALSE); | ||
4188 | |||
4189 | eina_error_set(0); | ||
4190 | if (model->desc->ops.type.child_set) | ||
4191 | { | ||
4192 | ret = model->desc->ops.type.child_set(model, position, child); | ||
4193 | if (ret) | ||
4194 | _eina_model_event_callback_call | ||
4195 | (model, _eina_model_str_child_set, &position); | ||
4196 | } | ||
4197 | else | ||
4198 | { | ||
4199 | eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING); | ||
4200 | ret = EINA_FALSE; | ||
4201 | ERR("Method child_set() not implemented for model %p (%s)", | ||
4202 | model, model->desc->cache.types[0]->name); | ||
4203 | } | ||
4204 | |||
4205 | return ret; | ||
4206 | } | ||
4207 | |||
4208 | EAPI Eina_Bool | ||
4209 | eina_model_child_del(Eina_Model *model, unsigned int position) | ||
4210 | { | ||
4211 | Eina_Bool ret; | ||
4212 | |||
4213 | EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE); | ||
4214 | |||
4215 | eina_error_set(0); | ||
4216 | if (model->desc->ops.type.child_del) | ||
4217 | { | ||
4218 | ret = model->desc->ops.type.child_del(model, position); | ||
4219 | if (ret) | ||
4220 | { | ||
4221 | _eina_model_event_callback_call | ||
4222 | (model, _eina_model_str_child_del, &position); | ||
4223 | _eina_model_event_callback_call | ||
4224 | (model, _eina_model_str_children_changed, NULL); | ||
4225 | } | ||
4226 | } | ||
4227 | else | ||
4228 | { | ||
4229 | eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING); | ||
4230 | ret = EINA_FALSE; | ||
4231 | ERR("Method child_del() not implemented for model %p (%s)", | ||
4232 | model, model->desc->cache.types[0]->name); | ||
4233 | } | ||
4234 | |||
4235 | return ret; | ||
4236 | } | ||
4237 | |||
4238 | EAPI Eina_Bool | ||
4239 | eina_model_child_insert_at(Eina_Model *model, unsigned int position, Eina_Model *child) | ||
4240 | { | ||
4241 | Eina_Bool ret; | ||
4242 | |||
4243 | EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE); | ||
4244 | EINA_SAFETY_ON_NULL_RETURN_VAL(child, EINA_FALSE); | ||
4245 | |||
4246 | eina_error_set(0); | ||
4247 | if (model->desc->ops.type.child_insert_at) | ||
4248 | { | ||
4249 | ret = model->desc->ops.type.child_insert_at(model, position, child); | ||
4250 | if (ret) | ||
4251 | { | ||
4252 | _eina_model_event_callback_call | ||
4253 | (model, _eina_model_str_child_inserted, &position); | ||
4254 | _eina_model_event_callback_call | ||
4255 | (model, _eina_model_str_children_changed, NULL); | ||
4256 | } | ||
4257 | } | ||
4258 | else | ||
4259 | { | ||
4260 | eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING); | ||
4261 | ret = EINA_FALSE; | ||
4262 | ERR("Method child_insert_at() not implemented for model %p (%s)", | ||
4263 | model, model->desc->cache.types[0]->name); | ||
4264 | } | ||
4265 | |||
4266 | return ret; | ||
4267 | } | ||
4268 | |||
4269 | EAPI int | ||
4270 | eina_model_child_append(Eina_Model *model, Eina_Model *child) | ||
4271 | { | ||
4272 | Eina_Bool ret; | ||
4273 | int position; | ||
4274 | |||
4275 | EINA_MODEL_INSTANCE_CHECK_VAL(model, -1); | ||
4276 | EINA_SAFETY_ON_NULL_RETURN_VAL(child, -1); | ||
4277 | |||
4278 | position = eina_model_child_count(model); | ||
4279 | if (position < 0) | ||
4280 | return -1; | ||
4281 | |||
4282 | eina_error_set(0); | ||
4283 | if (model->desc->ops.type.child_insert_at) | ||
4284 | { | ||
4285 | ret = model->desc->ops.type.child_insert_at(model, position, child); | ||
4286 | if (ret) | ||
4287 | { | ||
4288 | _eina_model_event_callback_call | ||
4289 | (model, _eina_model_str_child_inserted, &position); | ||
4290 | _eina_model_event_callback_call | ||
4291 | (model, _eina_model_str_children_changed, NULL); | ||
4292 | } | ||
4293 | } | ||
4294 | else | ||
4295 | { | ||
4296 | eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING); | ||
4297 | ret = EINA_FALSE; | ||
4298 | ERR("Method child_insert_at() not implemented for model %p (%s)", | ||
4299 | model, model->desc->cache.types[0]->name); | ||
4300 | } | ||
4301 | |||
4302 | return ret ? position : -1; | ||
4303 | } | ||
4304 | |||
4305 | EAPI int | ||
4306 | eina_model_child_find(const Eina_Model *model, unsigned int start_position, const Eina_Model *other) | ||
4307 | { | ||
4308 | EINA_MODEL_INSTANCE_CHECK_VAL(model, -1); | ||
4309 | EINA_SAFETY_ON_NULL_RETURN_VAL(other, -1); | ||
4310 | EINA_MODEL_TYPE_CALL_RETURN(model, child_find, -1, start_position, other); | ||
4311 | } | ||
4312 | |||
4313 | EAPI int | ||
4314 | eina_model_child_criteria_match(const Eina_Model *model, unsigned int start_position, Eina_Each_Cb match, const void *data) | ||
4315 | { | ||
4316 | EINA_MODEL_INSTANCE_CHECK_VAL(model, -1); | ||
4317 | EINA_SAFETY_ON_NULL_RETURN_VAL(match, -1); | ||
4318 | EINA_MODEL_TYPE_CALL_RETURN(model, child_criteria_match, -1, | ||
4319 | start_position, match, data); | ||
4320 | } | ||
4321 | |||
4322 | EAPI Eina_Bool | ||
4323 | eina_model_child_sort(Eina_Model *model, Eina_Compare_Cb compare) | ||
4324 | { | ||
4325 | EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE); | ||
4326 | EINA_SAFETY_ON_NULL_RETURN_VAL(compare, EINA_FALSE); | ||
4327 | EINA_MODEL_TYPE_CALL(model, child_sort, compare); | ||
4328 | _eina_model_event_callback_call | ||
4329 | (model, _eina_model_str_children_changed, NULL); | ||
4330 | return EINA_TRUE; | ||
4331 | } | ||
4332 | |||
4333 | EAPI Eina_Iterator * | ||
4334 | eina_model_child_iterator_get(Eina_Model *model) | ||
4335 | { | ||
4336 | int count; | ||
4337 | EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL); | ||
4338 | count = eina_model_child_count(model); | ||
4339 | if (count < 0) | ||
4340 | return NULL; | ||
4341 | EINA_MODEL_TYPE_CALL_RETURN(model, child_iterator_get, NULL, 0, count); | ||
4342 | } | ||
4343 | |||
4344 | EAPI Eina_Iterator * | ||
4345 | eina_model_child_slice_iterator_get(Eina_Model *model, unsigned int start, unsigned int count) | ||
4346 | { | ||
4347 | EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL); | ||
4348 | EINA_MODEL_TYPE_CALL_RETURN(model, child_iterator_get, NULL, start, count); | ||
4349 | } | ||
4350 | |||
4351 | EAPI Eina_Iterator * | ||
4352 | eina_model_child_reversed_iterator_get(Eina_Model *model) | ||
4353 | { | ||
4354 | int count; | ||
4355 | EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL); | ||
4356 | count = eina_model_child_count(model); | ||
4357 | if (count < 0) | ||
4358 | return NULL; | ||
4359 | EINA_MODEL_TYPE_CALL_RETURN(model, child_reversed_iterator_get, NULL, | ||
4360 | 0, count); | ||
4361 | } | ||
4362 | |||
4363 | EAPI Eina_Iterator * | ||
4364 | eina_model_child_slice_reversed_iterator_get(Eina_Model *model, unsigned int start, unsigned int count) | ||
4365 | { | ||
4366 | EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL); | ||
4367 | EINA_MODEL_TYPE_CALL_RETURN(model, child_reversed_iterator_get, NULL, | ||
4368 | start, count); | ||
4369 | } | ||
4370 | |||
4371 | EAPI Eina_Iterator * | ||
4372 | eina_model_child_sorted_iterator_get(Eina_Model *model, Eina_Compare_Cb compare) | ||
4373 | { | ||
4374 | int count; | ||
4375 | EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL); | ||
4376 | EINA_SAFETY_ON_NULL_RETURN_VAL(compare, NULL); | ||
4377 | count = eina_model_child_count(model); | ||
4378 | if (count < 0) | ||
4379 | return NULL; | ||
4380 | EINA_MODEL_TYPE_CALL_RETURN(model, child_sorted_iterator_get, NULL, | ||
4381 | 0, count, compare); | ||
4382 | } | ||
4383 | |||
4384 | EAPI Eina_Iterator * | ||
4385 | eina_model_child_slice_sorted_iterator_get(Eina_Model *model, unsigned int start, unsigned int count, Eina_Compare_Cb compare) | ||
4386 | { | ||
4387 | EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL); | ||
4388 | EINA_SAFETY_ON_NULL_RETURN_VAL(compare, NULL); | ||
4389 | EINA_MODEL_TYPE_CALL_RETURN(model, child_sorted_iterator_get, NULL, | ||
4390 | start, count, compare); | ||
4391 | } | ||
4392 | |||
4393 | EAPI Eina_Iterator * | ||
4394 | eina_model_child_filtered_iterator_get(Eina_Model *model, Eina_Each_Cb match, const void *data) | ||
4395 | { | ||
4396 | int count; | ||
4397 | EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL); | ||
4398 | EINA_SAFETY_ON_NULL_RETURN_VAL(match, NULL); | ||
4399 | count = eina_model_child_count(model); | ||
4400 | if (count < 0) | ||
4401 | return NULL; | ||
4402 | EINA_MODEL_TYPE_CALL_RETURN(model, child_filtered_iterator_get, NULL, | ||
4403 | 0, count, match, data); | ||
4404 | } | ||
4405 | |||
4406 | EAPI Eina_Iterator * | ||
4407 | eina_model_child_slice_filtered_iterator_get(Eina_Model *model, unsigned int start, unsigned int count, Eina_Each_Cb match, const void *data) | ||
4408 | { | ||
4409 | EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL); | ||
4410 | EINA_SAFETY_ON_NULL_RETURN_VAL(match, NULL); | ||
4411 | EINA_MODEL_TYPE_CALL_RETURN(model, child_filtered_iterator_get, NULL, | ||
4412 | start, count, match, data); | ||
4413 | } | ||
4414 | |||
4415 | EAPI char * | ||
4416 | eina_model_to_string(const Eina_Model *model) | ||
4417 | { | ||
4418 | EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL); | ||
4419 | EINA_MODEL_TYPE_CALL_RETURN(model, to_string, NULL); | ||
4420 | } | ||
4421 | |||
4422 | /* type functions *****************************************************/ | ||
4423 | |||
4424 | EAPI Eina_Bool | ||
4425 | eina_model_type_check(const Eina_Model_Type *type) | ||
4426 | { | ||
4427 | EINA_SAFETY_ON_NULL_RETURN_VAL(type, EINA_FALSE); | ||
4428 | return _eina_model_type_check(type); | ||
4429 | } | ||
4430 | |||
4431 | EAPI const char * | ||
4432 | eina_model_type_name_get(const Eina_Model_Type *type) | ||
4433 | { | ||
4434 | EINA_SAFETY_ON_NULL_RETURN_VAL(type, NULL); | ||
4435 | EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_type_check(type), NULL); | ||
4436 | return type->name; | ||
4437 | } | ||
4438 | |||
4439 | EAPI const Eina_Model_Type * | ||
4440 | eina_model_type_parent_get(const Eina_Model_Type *type) | ||
4441 | { | ||
4442 | EINA_SAFETY_ON_NULL_RETURN_VAL(type, NULL); | ||
4443 | EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_type_check(type), NULL); | ||
4444 | return type->parent; | ||
4445 | } | ||
4446 | |||
4447 | #define EINA_MODEL_TYPE_INSTANCE_CHECK(type, model) \ | ||
4448 | EINA_SAFETY_ON_NULL_RETURN(type); \ | ||
4449 | EINA_SAFETY_ON_FALSE_RETURN(_eina_model_type_check(type)); \ | ||
4450 | EINA_MODEL_INSTANCE_CHECK(model); \ | ||
4451 | EINA_SAFETY_ON_FALSE_RETURN(_eina_model_instance_check(model, type)); | ||
4452 | |||
4453 | #define EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, retval) \ | ||
4454 | EINA_SAFETY_ON_NULL_RETURN_VAL(type, retval); \ | ||
4455 | EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_type_check(type), retval); \ | ||
4456 | EINA_MODEL_INSTANCE_CHECK_VAL(model, retval); \ | ||
4457 | EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_instance_check(model, type), retval); | ||
4458 | |||
4459 | EAPI Eina_Bool | ||
4460 | eina_model_type_constructor(const Eina_Model_Type *type, Eina_Model *model) | ||
4461 | { | ||
4462 | Eina_Bool (*constructor)(Eina_Model *); | ||
4463 | |||
4464 | EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, EINA_FALSE); | ||
4465 | |||
4466 | constructor = _eina_model_type_find_offset | ||
4467 | (type, offsetof(Eina_Model_Type, constructor)); | ||
4468 | EINA_SAFETY_ON_NULL_RETURN_VAL(constructor, EINA_FALSE); | ||
4469 | |||
4470 | return constructor(model); | ||
4471 | } | ||
4472 | |||
4473 | EAPI Eina_Bool | ||
4474 | eina_model_type_destructor(const Eina_Model_Type *type, Eina_Model *model) | ||
4475 | { | ||
4476 | Eina_Bool (*destructor)(Eina_Model *); | ||
4477 | |||
4478 | EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, EINA_FALSE); | ||
4479 | |||
4480 | destructor = _eina_model_type_find_offset | ||
4481 | (type, offsetof(Eina_Model_Type, destructor)); | ||
4482 | EINA_SAFETY_ON_NULL_RETURN_VAL(destructor, EINA_FALSE); | ||
4483 | |||
4484 | return destructor(model); | ||
4485 | } | ||
4486 | |||
4487 | EAPI Eina_Bool | ||
4488 | eina_model_type_copy(const Eina_Model_Type *type, const Eina_Model *src, Eina_Model *dst) | ||
4489 | { | ||
4490 | Eina_Bool (*copy)(const Eina_Model *, Eina_Model *); | ||
4491 | |||
4492 | EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, src, EINA_FALSE); | ||
4493 | EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, dst, EINA_FALSE); | ||
4494 | |||
4495 | copy = _eina_model_type_find_offset | ||
4496 | (type, offsetof(Eina_Model_Type, copy)); | ||
4497 | EINA_SAFETY_ON_NULL_RETURN_VAL(copy, EINA_FALSE); | ||
4498 | |||
4499 | return copy(src, dst); | ||
4500 | } | ||
4501 | |||
4502 | EAPI Eina_Bool | ||
4503 | eina_model_type_deep_copy(const Eina_Model_Type *type, const Eina_Model *src, Eina_Model *dst) | ||
4504 | { | ||
4505 | Eina_Bool (*deep_copy)(const Eina_Model *, Eina_Model *); | ||
4506 | |||
4507 | EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, src, EINA_FALSE); | ||
4508 | EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, dst, EINA_FALSE); | ||
4509 | |||
4510 | deep_copy = _eina_model_type_find_offset | ||
4511 | (type, offsetof(Eina_Model_Type, deep_copy)); | ||
4512 | EINA_SAFETY_ON_NULL_RETURN_VAL(deep_copy, EINA_FALSE); | ||
4513 | |||
4514 | return deep_copy(src, dst); | ||
4515 | } | ||
4516 | |||
4517 | EAPI Eina_Bool | ||
4518 | eina_model_type_compare(const Eina_Model_Type *type, const Eina_Model *a, const Eina_Model *b, int *cmp) | ||
4519 | { | ||
4520 | Eina_Bool (*compare)(const Eina_Model *, const Eina_Model *, int *); | ||
4521 | |||
4522 | EINA_SAFETY_ON_NULL_RETURN_VAL(cmp, EINA_FALSE); | ||
4523 | *cmp = 0; | ||
4524 | |||
4525 | EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, a, EINA_FALSE); | ||
4526 | EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, b, EINA_FALSE); | ||
4527 | |||
4528 | compare = _eina_model_type_find_offset | ||
4529 | (type, offsetof(Eina_Model_Type, compare)); | ||
4530 | EINA_SAFETY_ON_NULL_RETURN_VAL(compare, EINA_FALSE); | ||
4531 | |||
4532 | return compare(a, b, cmp); | ||
4533 | } | ||
4534 | |||
4535 | EAPI Eina_Bool | ||
4536 | eina_model_type_load(const Eina_Model_Type *type, Eina_Model *model) | ||
4537 | { | ||
4538 | Eina_Bool (*load)(Eina_Model *); | ||
4539 | |||
4540 | EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, EINA_FALSE); | ||
4541 | |||
4542 | load = _eina_model_type_find_offset | ||
4543 | (type, offsetof(Eina_Model_Type, load)); | ||
4544 | EINA_SAFETY_ON_NULL_RETURN_VAL(load, EINA_FALSE); | ||
4545 | |||
4546 | return load(model); | ||
4547 | } | ||
4548 | |||
4549 | EAPI Eina_Bool | ||
4550 | eina_model_type_unload(const Eina_Model_Type *type, Eina_Model *model) | ||
4551 | { | ||
4552 | Eina_Bool (*unload)(Eina_Model *); | ||
4553 | |||
4554 | EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, EINA_FALSE); | ||
4555 | |||
4556 | unload = _eina_model_type_find_offset | ||
4557 | (type, offsetof(Eina_Model_Type, unload)); | ||
4558 | EINA_SAFETY_ON_NULL_RETURN_VAL(unload, EINA_FALSE); | ||
4559 | |||
4560 | return unload(model); | ||
4561 | } | ||
4562 | |||
4563 | EAPI Eina_Bool | ||
4564 | eina_model_type_property_get(const Eina_Model_Type *type, const Eina_Model *model, const char *name, Eina_Value *value) | ||
4565 | { | ||
4566 | Eina_Bool (*property_get)(const Eina_Model *, const char *, Eina_Value *); | ||
4567 | |||
4568 | EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE); | ||
4569 | EINA_SAFETY_ON_NULL_RETURN_VAL(value, EINA_FALSE); | ||
4570 | |||
4571 | EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, EINA_FALSE); | ||
4572 | |||
4573 | property_get = _eina_model_type_find_offset | ||
4574 | (type, offsetof(Eina_Model_Type, property_get)); | ||
4575 | EINA_SAFETY_ON_NULL_RETURN_VAL(property_get, EINA_FALSE); | ||
4576 | |||
4577 | return property_get(model, name, value); | ||
4578 | } | ||
4579 | |||
4580 | EAPI Eina_Bool | ||
4581 | eina_model_type_property_set(const Eina_Model_Type *type, Eina_Model *model, const char *name, const Eina_Value *value) | ||
4582 | { | ||
4583 | Eina_Bool (*property_set)(Eina_Model *, const char *, const Eina_Value *); | ||
4584 | |||
4585 | EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE); | ||
4586 | EINA_SAFETY_ON_NULL_RETURN_VAL(value, EINA_FALSE); | ||
4587 | EINA_SAFETY_ON_FALSE_RETURN_VAL(eina_value_type_check(value->type), EINA_FALSE); | ||
4588 | |||
4589 | EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, EINA_FALSE); | ||
4590 | |||
4591 | property_set = _eina_model_type_find_offset | ||
4592 | (type, offsetof(Eina_Model_Type, property_set)); | ||
4593 | EINA_SAFETY_ON_NULL_RETURN_VAL(property_set, EINA_FALSE); | ||
4594 | |||
4595 | return property_set(model, name, value); | ||
4596 | } | ||
4597 | |||
4598 | EAPI Eina_Bool | ||
4599 | eina_model_type_property_del(const Eina_Model_Type *type, Eina_Model *model, const char *name) | ||
4600 | { | ||
4601 | Eina_Bool (*property_del)(const Eina_Model *, const char *); | ||
4602 | |||
4603 | EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE); | ||
4604 | EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, EINA_FALSE); | ||
4605 | |||
4606 | property_del = _eina_model_type_find_offset | ||
4607 | (type, offsetof(Eina_Model_Type, property_del)); | ||
4608 | EINA_SAFETY_ON_NULL_RETURN_VAL(property_del, EINA_FALSE); | ||
4609 | |||
4610 | return property_del(model, name); | ||
4611 | } | ||
4612 | |||
4613 | EAPI Eina_List * | ||
4614 | eina_model_type_properties_names_list_get(const Eina_Model_Type *type, const Eina_Model *model) | ||
4615 | { | ||
4616 | Eina_List *(*properties_names_list_get)(const Eina_Model *); | ||
4617 | |||
4618 | EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, NULL); | ||
4619 | |||
4620 | properties_names_list_get = _eina_model_type_find_offset | ||
4621 | (type, offsetof(Eina_Model_Type, properties_names_list_get)); | ||
4622 | EINA_SAFETY_ON_NULL_RETURN_VAL(properties_names_list_get, NULL); | ||
4623 | |||
4624 | return properties_names_list_get(model); | ||
4625 | } | ||
4626 | |||
4627 | EAPI int | ||
4628 | eina_model_type_child_count(const Eina_Model_Type *type, const Eina_Model *model) | ||
4629 | { | ||
4630 | int (*child_count)(const Eina_Model *); | ||
4631 | |||
4632 | EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, -1); | ||
4633 | |||
4634 | child_count = _eina_model_type_find_offset | ||
4635 | (type, offsetof(Eina_Model_Type, child_count)); | ||
4636 | EINA_SAFETY_ON_NULL_RETURN_VAL(child_count, -1); | ||
4637 | |||
4638 | return child_count(model); | ||
4639 | } | ||
4640 | |||
4641 | EAPI Eina_Model * | ||
4642 | eina_model_type_child_get(const Eina_Model_Type *type, const Eina_Model *model, unsigned int position) | ||
4643 | { | ||
4644 | Eina_Model *(*child_get)(const Eina_Model *, unsigned int); | ||
4645 | |||
4646 | EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, NULL); | ||
4647 | |||
4648 | child_get = _eina_model_type_find_offset | ||
4649 | (type, offsetof(Eina_Model_Type, child_get)); | ||
4650 | EINA_SAFETY_ON_NULL_RETURN_VAL(child_get, NULL); | ||
4651 | |||
4652 | return child_get(model, position); | ||
4653 | } | ||
4654 | |||
4655 | EAPI Eina_Bool | ||
4656 | eina_model_type_child_set(const Eina_Model_Type *type, Eina_Model *model, unsigned int position, Eina_Model *child) | ||
4657 | { | ||
4658 | Eina_Bool (*child_set)(Eina_Model *, unsigned int, Eina_Model *); | ||
4659 | |||
4660 | EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, EINA_FALSE); | ||
4661 | EINA_MODEL_INSTANCE_CHECK_VAL(child, EINA_FALSE); | ||
4662 | |||
4663 | child_set = _eina_model_type_find_offset | ||
4664 | (type, offsetof(Eina_Model_Type, child_set)); | ||
4665 | EINA_SAFETY_ON_NULL_RETURN_VAL(child_set, EINA_FALSE); | ||
4666 | |||
4667 | return child_set(model, position, child); | ||
4668 | } | ||
4669 | |||
4670 | EAPI Eina_Bool | ||
4671 | eina_model_type_child_del(const Eina_Model_Type *type, Eina_Model *model, unsigned int position) | ||
4672 | { | ||
4673 | Eina_Bool (*child_del)(Eina_Model *, unsigned int); | ||
4674 | |||
4675 | EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, EINA_FALSE); | ||
4676 | |||
4677 | child_del = _eina_model_type_find_offset | ||
4678 | (type, offsetof(Eina_Model_Type, child_del)); | ||
4679 | EINA_SAFETY_ON_NULL_RETURN_VAL(child_del, EINA_FALSE); | ||
4680 | |||
4681 | return child_del(model, position); | ||
4682 | } | ||
4683 | |||
4684 | EAPI Eina_Bool | ||
4685 | eina_model_type_child_insert_at(const Eina_Model_Type *type, Eina_Model *model, unsigned int position, Eina_Model *child) | ||
4686 | { | ||
4687 | Eina_Bool (*child_insert_at)(Eina_Model *, unsigned int, Eina_Model *); | ||
4688 | |||
4689 | EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, EINA_FALSE); | ||
4690 | EINA_MODEL_INSTANCE_CHECK_VAL(child, EINA_FALSE); | ||
4691 | |||
4692 | child_insert_at = _eina_model_type_find_offset | ||
4693 | (type, offsetof(Eina_Model_Type, child_insert_at)); | ||
4694 | EINA_SAFETY_ON_NULL_RETURN_VAL(child_insert_at, EINA_FALSE); | ||
4695 | |||
4696 | return child_insert_at(model, position, child); | ||
4697 | } | ||
4698 | |||
4699 | EAPI int | ||
4700 | eina_model_type_child_find(const Eina_Model_Type *type, const Eina_Model *model, unsigned int start_position, const Eina_Model *other) | ||
4701 | { | ||
4702 | int (*child_find)(const Eina_Model *, unsigned int, const Eina_Model *); | ||
4703 | |||
4704 | EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, -1); | ||
4705 | EINA_MODEL_INSTANCE_CHECK_VAL(other, -1); | ||
4706 | |||
4707 | child_find = _eina_model_type_find_offset | ||
4708 | (type, offsetof(Eina_Model_Type, child_find)); | ||
4709 | EINA_SAFETY_ON_NULL_RETURN_VAL(child_find, -1); | ||
4710 | |||
4711 | return child_find(model, start_position, other); | ||
4712 | } | ||
4713 | |||
4714 | EAPI int | ||
4715 | eina_model_type_child_criteria_match(const Eina_Model_Type *type, const Eina_Model *model, unsigned int start_position, Eina_Each_Cb match, const void *data) | ||
4716 | { | ||
4717 | int (*child_criteria_match)(const Eina_Model *, unsigned int, Eina_Each_Cb, const void *); | ||
4718 | |||
4719 | EINA_SAFETY_ON_NULL_RETURN_VAL(match, -1); | ||
4720 | EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, -1); | ||
4721 | |||
4722 | child_criteria_match = _eina_model_type_find_offset | ||
4723 | (type, offsetof(Eina_Model_Type, child_criteria_match)); | ||
4724 | EINA_SAFETY_ON_NULL_RETURN_VAL(child_criteria_match, -1); | ||
4725 | |||
4726 | return child_criteria_match(model, start_position, match, data); | ||
4727 | } | ||
4728 | |||
4729 | EAPI void | ||
4730 | eina_model_type_child_sort(const Eina_Model_Type *type, Eina_Model *model, Eina_Compare_Cb compare) | ||
4731 | { | ||
4732 | void (*child_sort)(Eina_Model *, Eina_Compare_Cb); | ||
4733 | |||
4734 | EINA_SAFETY_ON_NULL_RETURN(compare); | ||
4735 | EINA_MODEL_TYPE_INSTANCE_CHECK(type, model); | ||
4736 | |||
4737 | child_sort = _eina_model_type_find_offset | ||
4738 | (type, offsetof(Eina_Model_Type, child_sort)); | ||
4739 | EINA_SAFETY_ON_NULL_RETURN(child_sort); | ||
4740 | |||
4741 | return child_sort(model, compare); | ||
4742 | } | ||
4743 | |||
4744 | EAPI Eina_Iterator * | ||
4745 | eina_model_type_child_iterator_get(const Eina_Model_Type *type, Eina_Model *model, unsigned int start, unsigned int count) | ||
4746 | { | ||
4747 | Eina_Iterator *(*child_iterator_get)(const Eina_Model *, unsigned int, unsigned int); | ||
4748 | |||
4749 | EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, NULL); | ||
4750 | |||
4751 | child_iterator_get = _eina_model_type_find_offset | ||
4752 | (type, offsetof(Eina_Model_Type, child_iterator_get)); | ||
4753 | EINA_SAFETY_ON_NULL_RETURN_VAL(child_iterator_get, NULL); | ||
4754 | |||
4755 | return child_iterator_get(model, start, count); | ||
4756 | } | ||
4757 | |||
4758 | EAPI Eina_Iterator * | ||
4759 | eina_model_type_child_reversed_iterator_get(const Eina_Model_Type *type, Eina_Model *model, unsigned int start, unsigned int count) | ||
4760 | { | ||
4761 | Eina_Iterator *(*child_reversed_iterator_get)(const Eina_Model *, unsigned int, unsigned int); | ||
4762 | |||
4763 | EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, NULL); | ||
4764 | |||
4765 | child_reversed_iterator_get = _eina_model_type_find_offset | ||
4766 | (type, offsetof(Eina_Model_Type, child_reversed_iterator_get)); | ||
4767 | EINA_SAFETY_ON_NULL_RETURN_VAL(child_reversed_iterator_get, NULL); | ||
4768 | |||
4769 | return child_reversed_iterator_get(model, start, count); | ||
4770 | } | ||
4771 | |||
4772 | EAPI Eina_Iterator * | ||
4773 | eina_model_type_child_sorted_iterator_get(const Eina_Model_Type *type, Eina_Model *model, unsigned int start, unsigned int count, Eina_Compare_Cb compare) | ||
4774 | { | ||
4775 | Eina_Iterator *(*child_sorted_iterator_get)(const Eina_Model *, unsigned int, unsigned int, Eina_Compare_Cb); | ||
4776 | |||
4777 | EINA_SAFETY_ON_NULL_RETURN_VAL(compare, NULL); | ||
4778 | EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, NULL); | ||
4779 | |||
4780 | child_sorted_iterator_get = _eina_model_type_find_offset | ||
4781 | (type, offsetof(Eina_Model_Type, child_sorted_iterator_get)); | ||
4782 | EINA_SAFETY_ON_NULL_RETURN_VAL(child_sorted_iterator_get, NULL); | ||
4783 | |||
4784 | return child_sorted_iterator_get(model, start, count, compare); | ||
4785 | } | ||
4786 | |||
4787 | EAPI Eina_Iterator * | ||
4788 | eina_model_type_child_filtered_iterator_get(const Eina_Model_Type *type, Eina_Model *model, unsigned int start, unsigned int count, Eina_Each_Cb match, const void *data) | ||
4789 | { | ||
4790 | Eina_Iterator *(*child_filtered_iterator_get)(const Eina_Model *, unsigned int, unsigned int, Eina_Each_Cb, const void *); | ||
4791 | |||
4792 | EINA_SAFETY_ON_NULL_RETURN_VAL(match, NULL); | ||
4793 | EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, NULL); | ||
4794 | |||
4795 | child_filtered_iterator_get = _eina_model_type_find_offset | ||
4796 | (type, offsetof(Eina_Model_Type, child_filtered_iterator_get)); | ||
4797 | EINA_SAFETY_ON_NULL_RETURN_VAL(child_filtered_iterator_get, NULL); | ||
4798 | |||
4799 | return child_filtered_iterator_get(model, start, count, match, data); | ||
4800 | } | ||
4801 | |||
4802 | EAPI char * | ||
4803 | eina_model_type_to_string(const Eina_Model_Type *type, const Eina_Model *model) | ||
4804 | { | ||
4805 | char *(*to_string)(const Eina_Model *); | ||
4806 | |||
4807 | EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, NULL); | ||
4808 | |||
4809 | to_string = _eina_model_type_find_offset | ||
4810 | (type, offsetof(Eina_Model_Type, to_string)); | ||
4811 | EINA_SAFETY_ON_NULL_RETURN_VAL(to_string, NULL); | ||
4812 | |||
4813 | return to_string(model); | ||
4814 | } | ||
4815 | |||
4816 | EAPI Eina_Bool | ||
4817 | eina_model_type_subclass_setup(Eina_Model_Type *type, const Eina_Model_Type *parent) | ||
4818 | { | ||
4819 | EINA_SAFETY_ON_NULL_RETURN_VAL(type, EINA_FALSE); | ||
4820 | EINA_SAFETY_ON_NULL_RETURN_VAL(parent, EINA_FALSE); | ||
4821 | EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_type_check(parent), EINA_FALSE); | ||
4822 | EINA_SAFETY_ON_FALSE_RETURN_VAL(type->version == EINA_MODEL_TYPE_VERSION, | ||
4823 | EINA_FALSE); | ||
4824 | |||
4825 | type->parent = parent; | ||
4826 | type->type_size = parent->type_size; | ||
4827 | type->interfaces = NULL; | ||
4828 | type->events = NULL; | ||
4829 | |||
4830 | type->setup = NULL; | ||
4831 | type->flush = NULL; | ||
4832 | type->constructor = NULL; | ||
4833 | type->destructor = NULL; | ||
4834 | type->copy = NULL; | ||
4835 | type->deep_copy = NULL; | ||
4836 | type->compare = NULL; | ||
4837 | type->load = NULL; | ||
4838 | type->unload = NULL; | ||
4839 | type->property_get = NULL; | ||
4840 | type->property_set = NULL; | ||
4841 | type->property_del = NULL; | ||
4842 | type->properties_names_list_get = NULL; | ||
4843 | type->child_count = NULL; | ||
4844 | type->child_get = NULL; | ||
4845 | type->child_set = NULL; | ||
4846 | type->child_del = NULL; | ||
4847 | type->child_insert_at = NULL; | ||
4848 | type->child_find = NULL; | ||
4849 | type->child_criteria_match = NULL; | ||
4850 | type->child_sort = NULL; | ||
4851 | type->child_iterator_get = NULL; | ||
4852 | type->child_reversed_iterator_get = NULL; | ||
4853 | type->child_sorted_iterator_get = NULL; | ||
4854 | type->child_filtered_iterator_get = NULL; | ||
4855 | type->to_string = NULL; | ||
4856 | type->__extension_ptr0 = NULL; | ||
4857 | type->__extension_ptr1 = NULL; | ||
4858 | type->__extension_ptr2 = NULL; | ||
4859 | type->__extension_ptr3 = NULL; | ||
4860 | |||
4861 | if (type->type_size > sizeof(Eina_Model_Type)) | ||
4862 | { | ||
4863 | unsigned char *p = (unsigned char *)type; | ||
4864 | p += sizeof(Eina_Model_Type); | ||
4865 | memset(p, 0, type->type_size - sizeof(Eina_Model_Type)); | ||
4866 | } | ||
4867 | |||
4868 | return EINA_TRUE; | ||
4869 | } | ||
4870 | |||
4871 | EAPI Eina_Bool | ||
4872 | eina_model_type_subclass_check(const Eina_Model_Type *type, const Eina_Model_Type *self_or_parent) | ||
4873 | { | ||
4874 | EINA_SAFETY_ON_NULL_RETURN_VAL(type, EINA_FALSE); | ||
4875 | EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_type_check(type), EINA_FALSE); | ||
4876 | EINA_SAFETY_ON_NULL_RETURN_VAL(self_or_parent, EINA_FALSE); | ||
4877 | |||
4878 | for (; type != NULL; type = type->parent) | ||
4879 | { | ||
4880 | if (type == self_or_parent) | ||
4881 | return EINA_TRUE; | ||
4882 | } | ||
4883 | |||
4884 | return EINA_FALSE; | ||
4885 | } | ||
4886 | |||
4887 | static inline const Eina_Model_Interface * | ||
4888 | _eina_model_type_interface_get(const Eina_Model_Type *type, const char *name, Eina_Bool ptr_cmp __UNUSED__) | ||
4889 | { | ||
4890 | const Eina_Model_Interface **itr; | ||
4891 | |||
4892 | if (!type) | ||
4893 | return NULL; | ||
4894 | |||
4895 | if (!type->interfaces) | ||
4896 | return _eina_model_type_interface_get(type->parent, name, ptr_cmp); | ||
4897 | |||
4898 | { | ||
4899 | for (itr = type->interfaces ; itr != NULL ; itr++) | ||
4900 | if (strcmp((*itr)->name, name) == 0) | ||
4901 | return *itr; | ||
4902 | } | ||
4903 | |||
4904 | return NULL; | ||
4905 | } | ||
4906 | |||
4907 | static inline Eina_Bool | ||
4908 | _eina_model_interface_check(const Eina_Model_Interface *iface) | ||
4909 | { | ||
4910 | EINA_SAFETY_ON_FALSE_RETURN_VAL | ||
4911 | (iface->version == EINA_MODEL_INTERFACE_VERSION, EINA_FALSE); | ||
4912 | return EINA_TRUE; | ||
4913 | } | ||
4914 | |||
4915 | EAPI const Eina_Model_Interface * | ||
4916 | eina_model_type_interface_get(const Eina_Model_Type *type, const char *name) | ||
4917 | { | ||
4918 | const Eina_Model_Interface *iface; | ||
4919 | |||
4920 | EINA_SAFETY_ON_NULL_RETURN_VAL(type, NULL); | ||
4921 | EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_type_check(type), NULL); | ||
4922 | |||
4923 | /* search for pointer, make speed-aware users fast */ | ||
4924 | iface = _eina_model_type_interface_get(type, name, EINA_TRUE); | ||
4925 | |||
4926 | if (!iface) | ||
4927 | { | ||
4928 | /* search using strcmp(), slow users don't care */ | ||
4929 | iface = _eina_model_type_interface_get(type, name, EINA_FALSE); | ||
4930 | } | ||
4931 | else if (!_eina_model_interface_check(iface)) | ||
4932 | iface = NULL; | ||
4933 | |||
4934 | return iface; | ||
4935 | } | ||
4936 | |||
4937 | EAPI void * | ||
4938 | eina_model_type_private_data_get(const Eina_Model *model, const Eina_Model_Type *type) | ||
4939 | { | ||
4940 | const Eina_Model_Description *desc; | ||
4941 | unsigned int i; | ||
4942 | |||
4943 | EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL); | ||
4944 | EINA_SAFETY_ON_NULL_RETURN_VAL(type, NULL); | ||
4945 | EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_type_check(type), NULL); | ||
4946 | |||
4947 | desc = model->desc; | ||
4948 | |||
4949 | for (i = 0; i < desc->total.types; i++) | ||
4950 | if (desc->cache.types[i] == type) | ||
4951 | return model->privates[i]; | ||
4952 | |||
4953 | CRITICAL("Model %p (%s) is not an instance of type %p (%s)", | ||
4954 | model, desc->cache.types[0]->name, | ||
4955 | type, type->name); | ||
4956 | return NULL; | ||
4957 | } | ||
4958 | |||
4959 | EAPI const void * | ||
4960 | eina_model_method_offset_resolve(const Eina_Model *model, unsigned int offset) | ||
4961 | { | ||
4962 | const Eina_Model_Description *desc; | ||
4963 | |||
4964 | EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL); | ||
4965 | EINA_SAFETY_ON_FALSE_RETURN_VAL(offset >= sizeof(Eina_Model_Type), NULL); | ||
4966 | EINA_SAFETY_ON_FALSE_RETURN_VAL(offset % sizeof(void *) == 0, NULL); | ||
4967 | |||
4968 | desc = model->desc; | ||
4969 | EINA_SAFETY_ON_FALSE_RETURN_VAL | ||
4970 | (offset + sizeof(void *) <= desc->cache.types[0]->type_size, NULL); | ||
4971 | |||
4972 | offset -= sizeof(Eina_Model_Type); | ||
4973 | offset /= sizeof(void *); | ||
4974 | return desc->ops.type.extension[offset]; | ||
4975 | } | ||
4976 | |||
4977 | EAPI const void * | ||
4978 | eina_model_type_method_offset_resolve(const Eina_Model_Type *type, const Eina_Model *model, unsigned int offset) | ||
4979 | { | ||
4980 | const Eina_Model_Description *desc; | ||
4981 | |||
4982 | EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, NULL); | ||
4983 | EINA_SAFETY_ON_FALSE_RETURN_VAL(offset >= sizeof(Eina_Model_Type), NULL); | ||
4984 | EINA_SAFETY_ON_FALSE_RETURN_VAL(offset % sizeof(void *) == 0, NULL); | ||
4985 | |||
4986 | desc = model->desc; | ||
4987 | EINA_SAFETY_ON_FALSE_RETURN_VAL | ||
4988 | (offset + sizeof(void *) <= desc->cache.types[0]->type_size, NULL); | ||
4989 | |||
4990 | return _eina_model_type_find_offset(type, offset); | ||
4991 | } | ||
4992 | |||
4993 | /* interface functions ************************************************/ | ||
4994 | |||
4995 | EAPI Eina_Bool | ||
4996 | eina_model_interface_check(const Eina_Model_Interface *iface) | ||
4997 | { | ||
4998 | EINA_SAFETY_ON_NULL_RETURN_VAL(iface, EINA_FALSE); | ||
4999 | return _eina_model_interface_check(iface); | ||
5000 | } | ||
5001 | |||
5002 | EAPI void * | ||
5003 | eina_model_interface_private_data_get(const Eina_Model *model, const Eina_Model_Interface *iface) | ||
5004 | { | ||
5005 | const Eina_Model_Description *desc; | ||
5006 | unsigned int i; | ||
5007 | |||
5008 | EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL); | ||
5009 | EINA_SAFETY_ON_NULL_RETURN_VAL(iface, NULL); | ||
5010 | EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_interface_check(iface), NULL); | ||
5011 | |||
5012 | desc = model->desc; | ||
5013 | |||
5014 | for (i = 0; i < desc->total.ifaces; i++) | ||
5015 | if (desc->cache.ifaces[i] == iface) | ||
5016 | return model->privates[desc->total.types + i]; | ||
5017 | |||
5018 | CRITICAL("Model %p (%s) does not implement interface %p (%s)", | ||
5019 | model, desc->cache.types[0]->name, | ||
5020 | iface, iface->name); | ||
5021 | return NULL; | ||
5022 | } | ||
5023 | |||
5024 | static Eina_Bool | ||
5025 | _eina_model_interface_implemented(const Eina_Model *model, const Eina_Model_Interface *iface) | ||
5026 | { | ||
5027 | const Eina_Model_Interface **itr, **itr_end; | ||
5028 | |||
5029 | itr = model->desc->cache.ifaces; | ||
5030 | itr_end = itr + model->desc->total.ifaces; | ||
5031 | |||
5032 | for (; itr < itr_end; itr++) | ||
5033 | if (*itr == iface) | ||
5034 | return EINA_TRUE; | ||
5035 | |||
5036 | return EINA_FALSE; | ||
5037 | } | ||
5038 | |||
5039 | EAPI Eina_Bool | ||
5040 | eina_model_interface_implemented(const Eina_Model *model, const Eina_Model_Interface *iface) | ||
5041 | { | ||
5042 | EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE); | ||
5043 | EINA_SAFETY_ON_NULL_RETURN_VAL(iface, EINA_FALSE); | ||
5044 | EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_interface_check(iface), | ||
5045 | EINA_FALSE); | ||
5046 | return _eina_model_interface_implemented(model, iface); | ||
5047 | } | ||
5048 | |||
5049 | #define EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK(iface, model) \ | ||
5050 | EINA_SAFETY_ON_NULL_RETURN(iface); \ | ||
5051 | EINA_SAFETY_ON_FALSE_RETURN(_eina_model_interface_check(iface)); \ | ||
5052 | EINA_MODEL_INSTANCE_CHECK(model); \ | ||
5053 | EINA_SAFETY_ON_FALSE_RETURN(_eina_model_interface_implemented(model, iface)); | ||
5054 | |||
5055 | #define EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, retval) \ | ||
5056 | EINA_SAFETY_ON_NULL_RETURN_VAL(iface, retval); \ | ||
5057 | EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_interface_check(iface), retval); \ | ||
5058 | EINA_MODEL_INSTANCE_CHECK_VAL(model, retval); \ | ||
5059 | EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_interface_implemented(model, iface), retval); | ||
5060 | |||
5061 | |||
5062 | EAPI Eina_Bool | ||
5063 | eina_model_interface_constructor(const Eina_Model_Interface *iface, Eina_Model *model) | ||
5064 | { | ||
5065 | Eina_Bool (*constructor)(Eina_Model *); | ||
5066 | |||
5067 | EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE); | ||
5068 | |||
5069 | constructor = _eina_model_interface_find_offset | ||
5070 | (iface, offsetof(Eina_Model_Interface, constructor)); | ||
5071 | EINA_SAFETY_ON_NULL_RETURN_VAL(constructor, EINA_FALSE); | ||
5072 | return constructor(model); | ||
5073 | } | ||
5074 | |||
5075 | EAPI Eina_Bool | ||
5076 | eina_model_interface_destructor(const Eina_Model_Interface *iface, Eina_Model *model) | ||
5077 | { | ||
5078 | Eina_Bool (*destructor)(Eina_Model *); | ||
5079 | |||
5080 | EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE); | ||
5081 | |||
5082 | destructor = _eina_model_interface_find_offset | ||
5083 | (iface, offsetof(Eina_Model_Interface, destructor)); | ||
5084 | EINA_SAFETY_ON_NULL_RETURN_VAL(destructor, EINA_FALSE); | ||
5085 | return destructor(model); | ||
5086 | } | ||
5087 | |||
5088 | EAPI Eina_Bool | ||
5089 | eina_model_interface_copy(const Eina_Model_Interface *iface, const Eina_Model *src, Eina_Model *dst) | ||
5090 | { | ||
5091 | Eina_Bool (*copy)(const Eina_Model *, Eina_Model *); | ||
5092 | |||
5093 | EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, src, EINA_FALSE); | ||
5094 | EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, dst, EINA_FALSE); | ||
5095 | |||
5096 | copy = _eina_model_interface_find_offset | ||
5097 | (iface, offsetof(Eina_Model_Interface, copy)); | ||
5098 | EINA_SAFETY_ON_NULL_RETURN_VAL(copy, EINA_FALSE); | ||
5099 | return copy(src, dst); | ||
5100 | } | ||
5101 | |||
5102 | EAPI Eina_Bool | ||
5103 | eina_model_interface_deep_copy(const Eina_Model_Interface *iface, const Eina_Model *src, Eina_Model *dst) | ||
5104 | { | ||
5105 | Eina_Bool (*deep_copy)(const Eina_Model *, Eina_Model *); | ||
5106 | |||
5107 | EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, src, EINA_FALSE); | ||
5108 | EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, dst, EINA_FALSE); | ||
5109 | |||
5110 | deep_copy = _eina_model_interface_find_offset | ||
5111 | (iface, offsetof(Eina_Model_Interface, deep_copy)); | ||
5112 | EINA_SAFETY_ON_NULL_RETURN_VAL(deep_copy, EINA_FALSE); | ||
5113 | return deep_copy(src, dst); | ||
5114 | } | ||
5115 | |||
5116 | EAPI const void | ||
5117 | *eina_model_interface_method_offset_resolve(const Eina_Model_Interface *iface, const Eina_Model *model, unsigned int offset) | ||
5118 | { | ||
5119 | EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, NULL); | ||
5120 | EINA_SAFETY_ON_FALSE_RETURN_VAL(offset >= sizeof(Eina_Model_Interface), NULL); | ||
5121 | EINA_SAFETY_ON_FALSE_RETURN_VAL(offset % sizeof(void *) == 0, NULL); | ||
5122 | return _eina_model_interface_find_offset(iface, offset); | ||
5123 | } | ||
5124 | |||
5125 | |||
5126 | /* Eina_Model_Interface_Properties ************************************/ | ||
5127 | |||
5128 | EAPI Eina_Bool | ||
5129 | eina_model_interface_properties_compare(const Eina_Model_Interface *iface, const Eina_Model *a, const Eina_Model *b, int *cmp) | ||
5130 | { | ||
5131 | Eina_Bool (*compare)(const Eina_Model *, const Eina_Model *, int *cmp); | ||
5132 | |||
5133 | EINA_SAFETY_ON_NULL_RETURN_VAL(cmp, EINA_FALSE); | ||
5134 | |||
5135 | *cmp = 0; | ||
5136 | EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, a, EINA_FALSE); | ||
5137 | EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, b, EINA_FALSE); | ||
5138 | |||
5139 | compare = _eina_model_interface_find_offset | ||
5140 | (iface, offsetof(Eina_Model_Interface_Properties, compare)); | ||
5141 | EINA_SAFETY_ON_NULL_RETURN_VAL(compare, EINA_FALSE); | ||
5142 | return compare(a, b, cmp); | ||
5143 | } | ||
5144 | |||
5145 | EAPI Eina_Bool | ||
5146 | eina_model_interface_properties_load(const Eina_Model_Interface *iface, Eina_Model *model) | ||
5147 | { | ||
5148 | Eina_Bool (*load)(Eina_Model *); | ||
5149 | Eina_Bool ret; | ||
5150 | |||
5151 | EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE); | ||
5152 | |||
5153 | load = _eina_model_interface_find_offset | ||
5154 | (iface, offsetof(Eina_Model_Interface_Properties, load)); | ||
5155 | EINA_SAFETY_ON_NULL_RETURN_VAL(load, EINA_FALSE); | ||
5156 | ret = load(model); | ||
5157 | |||
5158 | if (ret) | ||
5159 | _eina_model_event_callback_call | ||
5160 | (model, _eina_model_str_properties_loaded, NULL); | ||
5161 | |||
5162 | return ret; | ||
5163 | } | ||
5164 | |||
5165 | EAPI Eina_Bool | ||
5166 | eina_model_interface_properties_unload(const Eina_Model_Interface *iface, Eina_Model *model) | ||
5167 | { | ||
5168 | Eina_Bool (*unload)(Eina_Model *); | ||
5169 | Eina_Bool ret; | ||
5170 | |||
5171 | EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE); | ||
5172 | |||
5173 | unload = _eina_model_interface_find_offset | ||
5174 | (iface, offsetof(Eina_Model_Interface_Properties, unload)); | ||
5175 | EINA_SAFETY_ON_NULL_RETURN_VAL(unload, EINA_FALSE); | ||
5176 | ret = unload(model); | ||
5177 | |||
5178 | if (ret) | ||
5179 | _eina_model_event_callback_call | ||
5180 | (model, _eina_model_str_properties_unloaded, NULL); | ||
5181 | |||
5182 | return ret; | ||
5183 | } | ||
5184 | |||
5185 | EAPI Eina_Bool | ||
5186 | eina_model_interface_properties_get(const Eina_Model_Interface *iface, const Eina_Model *model, const char *name, Eina_Value *value) | ||
5187 | { | ||
5188 | Eina_Bool (*get)(const Eina_Model *, const char *, Eina_Value *); | ||
5189 | |||
5190 | EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE); | ||
5191 | EINA_SAFETY_ON_NULL_RETURN_VAL(value, EINA_FALSE); | ||
5192 | EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE); | ||
5193 | |||
5194 | get = _eina_model_interface_find_offset | ||
5195 | (iface, offsetof(Eina_Model_Interface_Properties, get)); | ||
5196 | EINA_SAFETY_ON_NULL_RETURN_VAL(get, EINA_FALSE); | ||
5197 | return get(model, name, value); | ||
5198 | } | ||
5199 | |||
5200 | EAPI Eina_Bool | ||
5201 | eina_model_interface_properties_set(const Eina_Model_Interface *iface, Eina_Model *model, const char *name, const Eina_Value *value) | ||
5202 | { | ||
5203 | Eina_Bool (*set)(Eina_Model *, const char *, const Eina_Value *); | ||
5204 | |||
5205 | EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE); | ||
5206 | EINA_SAFETY_ON_NULL_RETURN_VAL(value, EINA_FALSE); | ||
5207 | EINA_SAFETY_ON_FALSE_RETURN_VAL(eina_value_type_check(value->type), EINA_FALSE); | ||
5208 | EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE); | ||
5209 | |||
5210 | set = _eina_model_interface_find_offset | ||
5211 | (iface, offsetof(Eina_Model_Interface_Properties, set)); | ||
5212 | EINA_SAFETY_ON_NULL_RETURN_VAL(set, EINA_FALSE); | ||
5213 | return set(model, name, value); | ||
5214 | } | ||
5215 | |||
5216 | EAPI Eina_Bool | ||
5217 | eina_model_interface_properties_del(const Eina_Model_Interface *iface, Eina_Model *model, const char *name) | ||
5218 | { | ||
5219 | Eina_Bool (*del)(Eina_Model *, const char *); | ||
5220 | |||
5221 | EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE); | ||
5222 | EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE); | ||
5223 | |||
5224 | del = _eina_model_interface_find_offset | ||
5225 | (iface, offsetof(Eina_Model_Interface_Properties, del)); | ||
5226 | EINA_SAFETY_ON_NULL_RETURN_VAL(del, EINA_FALSE); | ||
5227 | return del(model, name); | ||
5228 | } | ||
5229 | |||
5230 | EAPI Eina_List * | ||
5231 | eina_model_interface_properties_names_list_get(const Eina_Model_Interface *iface, const Eina_Model *model) | ||
5232 | { | ||
5233 | Eina_List *(*names_list_get)(const Eina_Model *); | ||
5234 | |||
5235 | EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, NULL); | ||
5236 | |||
5237 | names_list_get = _eina_model_interface_find_offset | ||
5238 | (iface, offsetof(Eina_Model_Interface_Properties, names_list_get)); | ||
5239 | EINA_SAFETY_ON_NULL_RETURN_VAL(names_list_get, NULL); | ||
5240 | return names_list_get(model); | ||
5241 | } | ||
5242 | |||
5243 | /* Eina_Model_Interface_Children **************************************/ | ||
5244 | |||
5245 | EAPI Eina_Bool | ||
5246 | eina_model_interface_children_compare(const Eina_Model_Interface *iface, const Eina_Model *a, const Eina_Model *b, int *cmp) | ||
5247 | { | ||
5248 | Eina_Bool (*compare)(const Eina_Model *, const Eina_Model *, int *); | ||
5249 | |||
5250 | EINA_SAFETY_ON_NULL_RETURN_VAL(cmp, EINA_FALSE); | ||
5251 | |||
5252 | *cmp = 0; | ||
5253 | |||
5254 | EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, a, EINA_FALSE); | ||
5255 | EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, b, EINA_FALSE); | ||
5256 | |||
5257 | compare = _eina_model_interface_find_offset | ||
5258 | (iface, offsetof(Eina_Model_Interface_Children, compare)); | ||
5259 | EINA_SAFETY_ON_NULL_RETURN_VAL(compare, EINA_FALSE); | ||
5260 | return compare(a, b, cmp); | ||
5261 | } | ||
5262 | |||
5263 | EAPI Eina_Bool | ||
5264 | eina_model_interface_children_load(const Eina_Model_Interface *iface, Eina_Model *model) | ||
5265 | { | ||
5266 | Eina_Bool (*load)(Eina_Model *); | ||
5267 | Eina_Bool ret; | ||
5268 | |||
5269 | EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE); | ||
5270 | |||
5271 | load = _eina_model_interface_find_offset | ||
5272 | (iface, offsetof(Eina_Model_Interface_Children, load)); | ||
5273 | EINA_SAFETY_ON_NULL_RETURN_VAL(load, EINA_FALSE); | ||
5274 | ret = load(model); | ||
5275 | |||
5276 | if (ret) | ||
5277 | _eina_model_event_callback_call | ||
5278 | (model, _eina_model_str_children_loaded, NULL); | ||
5279 | |||
5280 | return ret; | ||
5281 | } | ||
5282 | |||
5283 | EAPI Eina_Bool | ||
5284 | eina_model_interface_children_unload(const Eina_Model_Interface *iface, Eina_Model *model) | ||
5285 | { | ||
5286 | Eina_Bool (*unload)(Eina_Model *); | ||
5287 | Eina_Bool ret; | ||
5288 | |||
5289 | EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE); | ||
5290 | |||
5291 | unload = _eina_model_interface_find_offset | ||
5292 | (iface, offsetof(Eina_Model_Interface_Children, unload)); | ||
5293 | EINA_SAFETY_ON_NULL_RETURN_VAL(unload, EINA_FALSE); | ||
5294 | ret = unload(model); | ||
5295 | |||
5296 | if (ret) | ||
5297 | _eina_model_event_callback_call | ||
5298 | (model, _eina_model_str_children_unloaded, NULL); | ||
5299 | |||
5300 | return ret; | ||
5301 | } | ||
5302 | |||
5303 | EAPI int | ||
5304 | eina_model_interface_children_count(const Eina_Model_Interface *iface, const Eina_Model *model) | ||
5305 | { | ||
5306 | int (*count)(const Eina_Model *); | ||
5307 | |||
5308 | EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, -1); | ||
5309 | |||
5310 | count = _eina_model_interface_find_offset | ||
5311 | (iface, offsetof(Eina_Model_Interface_Children, count)); | ||
5312 | EINA_SAFETY_ON_NULL_RETURN_VAL(count, -1); | ||
5313 | return count(model); | ||
5314 | } | ||
5315 | |||
5316 | EAPI Eina_Model * | ||
5317 | eina_model_interface_children_get(const Eina_Model_Interface *iface, const Eina_Model *model, unsigned int position) | ||
5318 | { | ||
5319 | Eina_Model *(*get)(const Eina_Model *, unsigned int); | ||
5320 | |||
5321 | EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, NULL); | ||
5322 | |||
5323 | get = _eina_model_interface_find_offset | ||
5324 | (iface, offsetof(Eina_Model_Interface_Children, get)); | ||
5325 | EINA_SAFETY_ON_NULL_RETURN_VAL(get, NULL); | ||
5326 | return get(model, position); | ||
5327 | } | ||
5328 | |||
5329 | EAPI Eina_Bool eina_model_interface_children_set(const Eina_Model_Interface *iface, Eina_Model *model, unsigned int position, Eina_Model *child) | ||
5330 | { | ||
5331 | Eina_Bool (*set)(const Eina_Model *, unsigned int, Eina_Model *); | ||
5332 | |||
5333 | EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE); | ||
5334 | EINA_MODEL_INSTANCE_CHECK_VAL(child, EINA_FALSE); | ||
5335 | |||
5336 | set = _eina_model_interface_find_offset | ||
5337 | (iface, offsetof(Eina_Model_Interface_Children, set)); | ||
5338 | EINA_SAFETY_ON_NULL_RETURN_VAL(set, EINA_FALSE); | ||
5339 | return set(model, position, child); | ||
5340 | } | ||
5341 | |||
5342 | EAPI Eina_Bool | ||
5343 | eina_model_interface_children_del(const Eina_Model_Interface *iface, Eina_Model *model, unsigned int position) | ||
5344 | { | ||
5345 | Eina_Bool (*del)(Eina_Model *, unsigned int); | ||
5346 | |||
5347 | EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE); | ||
5348 | |||
5349 | del = _eina_model_interface_find_offset | ||
5350 | (iface, offsetof(Eina_Model_Interface_Children, del)); | ||
5351 | EINA_SAFETY_ON_NULL_RETURN_VAL(del, EINA_FALSE); | ||
5352 | return del(model, position); | ||
5353 | } | ||
5354 | |||
5355 | |||
5356 | EAPI Eina_Bool | ||
5357 | eina_model_interface_children_insert_at(const Eina_Model_Interface *iface, Eina_Model *model, unsigned int position, Eina_Model *child) | ||
5358 | { | ||
5359 | Eina_Bool (*insert_at)(const Eina_Model *, unsigned int, Eina_Model *); | ||
5360 | |||
5361 | EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE); | ||
5362 | EINA_MODEL_INSTANCE_CHECK_VAL(child, EINA_FALSE); | ||
5363 | |||
5364 | insert_at = _eina_model_interface_find_offset | ||
5365 | (iface, offsetof(Eina_Model_Interface_Children, insert_at)); | ||
5366 | EINA_SAFETY_ON_NULL_RETURN_VAL(insert_at, EINA_FALSE); | ||
5367 | return insert_at(model, position, child); | ||
5368 | } | ||
5369 | |||
5370 | EAPI void | ||
5371 | eina_model_interface_children_sort(const Eina_Model_Interface *iface, Eina_Model *model, Eina_Compare_Cb compare) | ||
5372 | { | ||
5373 | void (*sort)(const Eina_Model *, Eina_Compare_Cb); | ||
5374 | |||
5375 | EINA_SAFETY_ON_NULL_RETURN(compare); | ||
5376 | EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK(iface, model); | ||
5377 | |||
5378 | sort = _eina_model_interface_find_offset | ||
5379 | (iface, offsetof(Eina_Model_Interface_Children, sort)); | ||
5380 | EINA_SAFETY_ON_NULL_RETURN(sort); | ||
5381 | return sort(model, compare); | ||
5382 | } | ||
5383 | |||
5384 | static Eina_Bool | ||
5385 | _eina_model_struct_set(Eina_Model *m, const Eina_Value_Struct_Desc *desc, void *memory) | ||
5386 | { | ||
5387 | Eina_Value_Struct st = {desc, memory}; | ||
5388 | Eina_Value *val = eina_model_interface_private_data_get | ||
5389 | (m, &_EINA_MODEL_INTERFACE_PROPERTIES_STRUCT.base); | ||
5390 | return eina_value_pset(val, &st); | ||
5391 | } | ||
5392 | |||
5393 | EAPI Eina_Model * | ||
5394 | eina_model_struct_new(const Eina_Value_Struct_Desc *desc) | ||
5395 | { | ||
5396 | Eina_Model *m; | ||
5397 | |||
5398 | EINA_SAFETY_ON_NULL_RETURN_VAL(desc, NULL); | ||
5399 | EINA_SAFETY_ON_FALSE_RETURN_VAL | ||
5400 | (desc->version == EINA_VALUE_STRUCT_DESC_VERSION, NULL); | ||
5401 | |||
5402 | m = eina_model_new(EINA_MODEL_TYPE_STRUCT); | ||
5403 | EINA_SAFETY_ON_NULL_RETURN_VAL(m, NULL); | ||
5404 | |||
5405 | EINA_SAFETY_ON_FALSE_GOTO(_eina_model_struct_set(m, desc, NULL), error); | ||
5406 | return m; | ||
5407 | |||
5408 | error: | ||
5409 | eina_model_del(m); | ||
5410 | return NULL; | ||
5411 | } | ||
5412 | |||
5413 | EAPI Eina_Model * | ||
5414 | eina_model_type_struct_new(const Eina_Model_Type *type, const Eina_Value_Struct_Desc *desc) | ||
5415 | { | ||
5416 | Eina_Model *m; | ||
5417 | |||
5418 | EINA_SAFETY_ON_FALSE_RETURN_VAL | ||
5419 | (eina_model_type_subclass_check(type, EINA_MODEL_TYPE_STRUCT), NULL); | ||
5420 | EINA_SAFETY_ON_NULL_RETURN_VAL(desc, NULL); | ||
5421 | EINA_SAFETY_ON_FALSE_RETURN_VAL | ||
5422 | (desc->version == EINA_VALUE_STRUCT_DESC_VERSION, NULL); | ||
5423 | |||
5424 | m = eina_model_new(type); | ||
5425 | EINA_SAFETY_ON_NULL_RETURN_VAL(m, NULL); | ||
5426 | |||
5427 | EINA_SAFETY_ON_FALSE_GOTO(_eina_model_struct_set(m, desc, NULL), error); | ||
5428 | return m; | ||
5429 | |||
5430 | error: | ||
5431 | eina_model_del(m); | ||
5432 | return NULL; | ||
5433 | } | ||
5434 | |||
5435 | EAPI Eina_Bool | ||
5436 | eina_model_struct_set(Eina_Model *model, const Eina_Value_Struct_Desc *desc, void *memory) | ||
5437 | { | ||
5438 | EINA_SAFETY_ON_NULL_RETURN_VAL(desc, EINA_FALSE); | ||
5439 | EINA_SAFETY_ON_FALSE_RETURN_VAL | ||
5440 | (desc->version == EINA_VALUE_STRUCT_DESC_VERSION, EINA_FALSE); | ||
5441 | EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL | ||
5442 | (&_EINA_MODEL_INTERFACE_PROPERTIES_STRUCT.base, model, EINA_FALSE); | ||
5443 | |||
5444 | return _eina_model_struct_set(model, desc, memory); | ||
5445 | } | ||
5446 | |||
5447 | EAPI Eina_Bool | ||
5448 | eina_model_struct_get(const Eina_Model *model, const Eina_Value_Struct_Desc **p_desc, void **p_memory) | ||
5449 | { | ||
5450 | const Eina_Value *val; | ||
5451 | Eina_Value_Struct st; | ||
5452 | |||
5453 | EINA_SAFETY_ON_NULL_RETURN_VAL(p_desc, EINA_FALSE); | ||
5454 | |||
5455 | *p_desc = NULL; | ||
5456 | if (p_memory) *p_memory = NULL; | ||
5457 | |||
5458 | EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL | ||
5459 | (&_EINA_MODEL_INTERFACE_PROPERTIES_STRUCT.base, model, EINA_FALSE); | ||
5460 | |||
5461 | val = eina_model_interface_private_data_get | ||
5462 | (model, &_EINA_MODEL_INTERFACE_PROPERTIES_STRUCT.base); | ||
5463 | |||
5464 | EINA_SAFETY_ON_FALSE_RETURN_VAL(eina_value_pget(val, &st), EINA_FALSE); | ||
5465 | |||
5466 | *p_desc = st.desc; | ||
5467 | if (p_memory) *p_memory = st.memory; | ||
5468 | return EINA_FALSE; | ||
5469 | } | ||
5470 | |||
5471 | EAPI void | ||
5472 | eina_models_usage_dump(void) | ||
5473 | { | ||
5474 | const Eina_List *l; | ||
5475 | const Eina_Model *m; | ||
5476 | |||
5477 | eina_lock_take(&_eina_model_debug_list_lock); | ||
5478 | |||
5479 | puts("DDD: model refs info (type, holders, backtrace)"); | ||
5480 | puts("DDD: -------------- -------------- ---------------------------------"); | ||
5481 | |||
5482 | EINA_LIST_FOREACH(_eina_model_debug_list, l, m) | ||
5483 | { | ||
5484 | Eina_Model_XRef *ref; | ||
5485 | |||
5486 | printf("DDD: %14p %14d %s\n", | ||
5487 | m, m->refcount, m->desc->cache.types[0]->name); | ||
5488 | |||
5489 | EINA_INLIST_FOREACH(m->xrefs, ref) | ||
5490 | { | ||
5491 | printf("DDD: id: %p '%s'\n", | ||
5492 | ref->id, ref->label); | ||
5493 | if (ref->backtrace.count) | ||
5494 | { | ||
5495 | char **symbols; | ||
5496 | unsigned int i; | ||
5497 | |||
5498 | #ifdef HAVE_BACKTRACE_SYMBOLS | ||
5499 | symbols = backtrace_symbols((void * const *)ref->backtrace.symbols, | ||
5500 | ref->backtrace.count); | ||
5501 | #else | ||
5502 | symbols = NULL; | ||
5503 | #endif | ||
5504 | |||
5505 | printf("DDD: Backtrace: Address Symbol\n"); | ||
5506 | for (i = 0; i < ref->backtrace.count; i++) | ||
5507 | printf("DDD: %14p %s\n", | ||
5508 | ref->backtrace.symbols[i], | ||
5509 | symbols ? symbols[i] : "???"); | ||
5510 | |||
5511 | free(symbols); | ||
5512 | puts("DDD:"); | ||
5513 | } | ||
5514 | } | ||
5515 | } | ||
5516 | |||
5517 | eina_lock_release(&_eina_model_debug_list_lock); | ||
5518 | } | ||
5519 | |||
5520 | EAPI Eina_List * | ||
5521 | eina_models_list_get(void) | ||
5522 | { | ||
5523 | const Eina_List *l; | ||
5524 | Eina_Model *m; | ||
5525 | Eina_List *ret = NULL; | ||
5526 | |||
5527 | eina_lock_take(&_eina_model_debug_list_lock); | ||
5528 | |||
5529 | EINA_LIST_FOREACH(_eina_model_debug_list, l, m) | ||
5530 | { | ||
5531 | ret = eina_list_append | ||
5532 | (ret, eina_model_xref | ||
5533 | (m, eina_models_list_get, "eina_models_list_get")); | ||
5534 | } | ||
5535 | |||
5536 | eina_lock_release(&_eina_model_debug_list_lock); | ||
5537 | |||
5538 | return ret; | ||
5539 | } | ||
5540 | |||
5541 | EAPI void | ||
5542 | eina_models_list_free(Eina_List *list) | ||
5543 | { | ||
5544 | Eina_Model *m; | ||
5545 | |||
5546 | EINA_LIST_FREE(list, m) | ||
5547 | eina_model_xunref(m, eina_models_list_get); | ||
5548 | } | ||