From 07274513e984f0b5544586c74508ccd16e7dcafa Mon Sep 17 00:00:00 2001 From: David Walter Seikel Date: Sun, 13 Jan 2013 17:29:19 +1000 Subject: Remove EFL, since it's been released now. --- libraries/eina/src/lib/eina_model.c | 5548 ----------------------------------- 1 file changed, 5548 deletions(-) delete mode 100644 libraries/eina/src/lib/eina_model.c (limited to 'libraries/eina/src/lib/eina_model.c') diff --git a/libraries/eina/src/lib/eina_model.c b/libraries/eina/src/lib/eina_model.c deleted file mode 100644 index ae06c1b..0000000 --- a/libraries/eina/src/lib/eina_model.c +++ /dev/null @@ -1,5548 +0,0 @@ -/* EINA - EFL data type library - * Copyright (C) 2012 ProFUSION embedded systems - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; - * if not, see . - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#ifdef HAVE_ALLOCA_H -# include -#elif defined __GNUC__ -# define alloca __builtin_alloca -#elif defined _AIX -# define alloca __alloca -#elif defined _MSC_VER -# include -# define alloca _alloca -#else -# include -# ifdef __cplusplus -extern "C" -# endif -void *alloca (size_t); -#endif - -#ifdef HAVE_EXECINFO_H -#include -#endif - -#include "eina_config.h" -#include "eina_private.h" -#include "eina_error.h" -#include "eina_log.h" -#include "eina_mempool.h" -#include "eina_lock.h" -#include "eina_inlist.h" -#include "eina_strbuf.h" - -/* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */ -#include "eina_safety_checks.h" -#include "eina_value.h" /* eina-safety used in inline.x */ -#include "eina_model.h" - -/*============================================================================* - * Local * - *============================================================================*/ - -/** - * @cond LOCAL - */ - -static Eina_Mempool *_eina_model_mp = NULL; -static Eina_Hash *_eina_model_inner_mps = NULL; -static Eina_Lock _eina_model_inner_mps_lock; -static char *_eina_model_mp_choice = NULL; -static Eina_Hash *_eina_model_descriptions = NULL; -static Eina_Lock _eina_model_descriptions_lock; -static int _eina_model_log_dom = -1; -static enum { - EINA_MODEL_DEBUG_NONE = 0, - EINA_MODEL_DEBUG_CHECK = 1, - EINA_MODEL_DEBUG_BACKTRACE = 2, -} _eina_model_debug = EINA_MODEL_DEBUG_NONE; -static Eina_Lock _eina_model_debug_list_lock; -static Eina_List *_eina_model_debug_list = NULL; - -static const char _eina_model_str_deleted[] = "deleted"; -static const char _eina_model_str_freed[] = "freed"; -static const char _eina_model_str_property_set[] = "property,set"; -static const char _eina_model_str_property_del[] = "property,deleted"; -static const char _eina_model_str_children_changed[] = "children,changed"; -static const char _eina_model_str_child_inserted[] = "child,inserted"; -static const char _eina_model_str_child_set[] = "child,set"; -static const char _eina_model_str_child_del[] = "child,deleted"; -static const char _eina_model_str_loaded[] = "loaded"; -static const char _eina_model_str_unloaded[] = "unloaded"; -static const char _eina_model_str_properties_loaded[] = "properties,loaded"; -static const char _eina_model_str_properties_unloaded[] = "properties,unloaded"; -static const char _eina_model_str_children_loaded[] = "children,loaded"; -static const char _eina_model_str_children_unloaded[] = "children,unloaded"; - -#ifdef CRITICAL -#undef CRITICAL -#endif -#define CRITICAL(...) EINA_LOG_DOM_CRIT(_eina_model_log_dom, __VA_ARGS__) - -#ifdef ERR -#undef ERR -#endif -#define ERR(...) EINA_LOG_DOM_ERR(_eina_model_log_dom, __VA_ARGS__) - -#ifdef WRN -#undef WRN -#endif -#define WRN(...) EINA_LOG_DOM_WARN(_eina_model_log_dom, __VA_ARGS__) - -#ifdef INF -#undef INF -#endif -#define INF(...) EINA_LOG_DOM_INFO(_eina_model_log_dom, __VA_ARGS__) - -#ifdef DBG -#undef DBG -#endif -#define DBG(...) EINA_LOG_DOM_DBG(_eina_model_log_dom, __VA_ARGS__) - - -/* convenience sort array of Eina_Model* giving compare Eina_Model* instead of - * Eina_Model** - */ -static unsigned int -_eina_model_array_partition(Eina_Model **array, unsigned int start, unsigned int last, unsigned int pivot, Eina_Compare_Cb compare) -{ - Eina_Model **itr, **itr_end, *tmp, *pivot_value; - - pivot_value = tmp = array[pivot]; - array[pivot] = array[last]; - array[last] = tmp; - - pivot = start; - itr = array + start; - itr_end = array + last; - for (; itr < itr_end; itr++) - { - if (compare(*itr, pivot_value) < 0) - { - tmp = *itr; - *itr = array[pivot]; - array[pivot] = tmp; - pivot++; - } - } - - tmp = array[last]; - array[last] = array[pivot]; - array[pivot] = tmp; - - return pivot; -} - -static void -_eina_model_array_sort(Eina_Model **array, unsigned int start, unsigned int last, Eina_Compare_Cb compare) -{ - unsigned int pivot, new_pivot; - - if (last <= start) - return; - - pivot = start + (last - start) / 2; /* avoid overflow */ - new_pivot = _eina_model_array_partition(array, start, last, pivot, compare); - - if (start + 1 < new_pivot) - _eina_model_array_sort(array, start, new_pivot - 1, compare); - - if (new_pivot + 1 < last) - _eina_model_array_sort(array, new_pivot + 1, last, compare); -} - -/* - * Most of inner allocations are made with internal mempools, types - * and thus instace private data will repeat and it's good to use them. - * - * To save on the number of mempools, they are kept per size, not per - * type. - * - * This is done by means of _eina_model_inner_alloc() and - * _eina_model_inner_free(), both at thread safe. - * - */ -typedef struct _Eina_Model_Inner_Mp Eina_Model_Inner_Mp; -struct _Eina_Model_Inner_Mp -{ - Eina_Mempool *mempool; - int refcount; -}; - -static inline void -_eina_model_inner_mp_dispose(int size, Eina_Model_Inner_Mp *imp) -{ - EINA_SAFETY_ON_FALSE_RETURN(imp->refcount == 0); - - eina_hash_del_by_key(_eina_model_inner_mps, &size); - eina_mempool_del(imp->mempool); - free(imp); -} - -static inline Eina_Model_Inner_Mp * -_eina_model_inner_mp_get(int size) -{ - Eina_Model_Inner_Mp *imp = eina_hash_find(_eina_model_inner_mps, &size); - if (imp) return imp; - - imp = malloc(sizeof(Eina_Model_Inner_Mp)); - if (!imp) - return NULL; - - imp->refcount = 0; - - imp->mempool = eina_mempool_add(_eina_model_mp_choice, - "Eina_Model_Inner_Mp", NULL, size, 128); - if (!imp->mempool) - { - free(imp); - return NULL; - } - - if (!eina_hash_add(_eina_model_inner_mps, &size, imp)) - { - eina_mempool_del(imp->mempool); - free(imp); - return NULL; - } - - return imp; -} - -static inline void * -_eina_model_inner_alloc_internal(int size) -{ - Eina_Model_Inner_Mp *imp; - void *mem; - - imp = _eina_model_inner_mp_get(size); - if (!imp) return NULL; - - mem = eina_mempool_malloc(imp->mempool, size); - if (mem) imp->refcount++; - else if (imp->refcount == 0) _eina_model_inner_mp_dispose(size, imp); - - return mem; -} - -static inline void -_eina_model_inner_free_internal(int size, void *mem) -{ - Eina_Model_Inner_Mp *imp = eina_hash_find(_eina_model_inner_mps, &size); - EINA_SAFETY_ON_NULL_RETURN(imp); - - eina_mempool_free(imp->mempool, mem); - - imp->refcount--; - if (imp->refcount > 0) return; - _eina_model_inner_mp_dispose(size, imp); -} - -static void * -_eina_model_inner_alloc(size_t size) -{ - void *mem; - - if (size > 512) return malloc(size); - - eina_lock_take(&_eina_model_inner_mps_lock); - mem = _eina_model_inner_alloc_internal(size); - eina_lock_release(&_eina_model_inner_mps_lock); - - return mem; -} - -static void -_eina_model_inner_free(size_t size, void *mem) -{ - if (size > 512) - { - free(mem); - return; - } - - eina_lock_take(&_eina_model_inner_mps_lock); - _eina_model_inner_free_internal(size, mem); - eina_lock_release(&_eina_model_inner_mps_lock); -} - - -typedef union _Eina_Model_Provider Eina_Model_Provider; -union _Eina_Model_Provider -{ - const Eina_Model_Type *type; - const Eina_Model_Interface *iface; -}; - -/* store event name to aid searching */ -typedef struct _Eina_Model_Event_Description_Cache Eina_Model_Event_Description_Cache; -struct _Eina_Model_Event_Description_Cache -{ - const char *name; - const Eina_Model_Event_Description *desc; - Eina_Model_Provider provider; -}; - -/* description is an optimized structure for type. It's built at runtime - * to avoid user input errors and help declaration. - * - * lookups (ifaces, events) are sorted for binary search. - * - * recursion is avoided by expansion of every possible value in "cache" - * struct. - * - * the first usable operation is stopred for type at "ops" struct, - * avoiding usage of _eina_model_type_find_offset(). - * - * Get a model type description using _eina_model_description_get(), - * when it's not used anymore use - * _eina_model_description_dispose(). These operations are thread - * safe. - */ -typedef struct _Eina_Model_Description Eina_Model_Description; -struct _Eina_Model_Description -{ - struct { - const Eina_Model_Type **types; /* size = total.types */ - const Eina_Model_Interface **ifaces; /* sorted, size = total.ifaces */ - Eina_Model_Provider *privates; /* size = total.privates (types + ifaces) */ - Eina_Model_Event_Description_Cache *events; /* size = total.events */ - } cache; - struct { - /* ops are the topmost operation to use for type/interface */ - struct { - Eina_Bool (*setup)(Eina_Model *model); - Eina_Bool (*flush)(Eina_Model *model); - Eina_Bool (*constructor)(Eina_Model *model); - Eina_Bool (*destructor)(Eina_Model *model); - Eina_Bool (*copy)(const Eina_Model *src, Eina_Model *dst); - Eina_Bool (*deep_copy)(const Eina_Model *src, Eina_Model *dst); - Eina_Bool (*compare)(const Eina_Model *a, const Eina_Model *b, int *cmp); - Eina_Bool (*load)(Eina_Model *model); - Eina_Bool (*unload)(Eina_Model *model); - Eina_Bool (*property_get)(const Eina_Model *model, const char *name, Eina_Value *value); - Eina_Bool (*property_set)(Eina_Model *model, const char *name, const Eina_Value *value); - Eina_Bool (*property_del)(Eina_Model *model, const char *name); - Eina_List *(*properties_names_list_get)(const Eina_Model *model); - int (*child_count)(const Eina_Model *model); - Eina_Model *(*child_get)(const Eina_Model *model, unsigned int position); - Eina_Bool (*child_set)(Eina_Model *model, unsigned int position, Eina_Model *child); - Eina_Bool (*child_del)(Eina_Model *model, unsigned int position); - Eina_Bool (*child_insert_at)(Eina_Model *model, unsigned int position, Eina_Model *child); - int (*child_find)(const Eina_Model *model, unsigned int start_position, const Eina_Model *other); - int (*child_criteria_match)(const Eina_Model *model, unsigned int start_position, Eina_Each_Cb match, const void *data); - void (*child_sort)(Eina_Model *model, Eina_Compare_Cb compare); - Eina_Iterator *(*child_iterator_get)(Eina_Model *model, unsigned int start, unsigned int count); - Eina_Iterator *(*child_reversed_iterator_get)(Eina_Model *model, unsigned int start, unsigned int count); - Eina_Iterator *(*child_sorted_iterator_get)(Eina_Model *model, unsigned int start, unsigned int count, Eina_Compare_Cb compare); - Eina_Iterator *(*child_filtered_iterator_get)(Eina_Model *model, unsigned int start, unsigned int count, Eina_Each_Cb match, const void *data); - char *(*to_string)(const Eina_Model *model); /**< used to represent model as string, usually for debug purposes or user convenience */ - const void **extension; - } type; - } ops; - struct { - unsigned int types; - unsigned int ifaces; - unsigned int privates; - unsigned int size; /* sum of all private sizes */ - unsigned int events; - } total; - int refcount; -}; - -static Eina_Bool -_eina_model_description_type_fill(Eina_Model_Description *desc, const Eina_Model_Type *type) -{ - const Eina_Model_Type *itr, *last_itr = NULL; - unsigned int count, child_size = 0; - - for (count = 0, itr = type; itr != NULL; itr = itr->parent, count++) - { - if (itr->version != EINA_MODEL_TYPE_VERSION) - { - CRITICAL("Type %p version is %u, expected %u instead.", - itr, itr->version, EINA_MODEL_TYPE_VERSION); - return EINA_FALSE; - } - if (!itr->name) - { - CRITICAL("Type %p provides no name!", itr); - return EINA_FALSE; - } - if (itr->type_size < sizeof(Eina_Model_Type)) - { - CRITICAL("Type %p %s size must be >= sizeof(Eina_Model_Type)!", - itr, itr->name); - return EINA_FALSE; - } - if (child_size == 0) child_size = itr->type_size; - else if (child_size < itr->type_size) - { - CRITICAL("Type %p %s size is bigger than its child type %p %s!", - itr, itr->name, last_itr, last_itr->name); - return EINA_FALSE; - } - last_itr = itr; - -#define DEF_METH(meth) \ - if (!desc->ops.type.meth) desc->ops.type.meth = itr->meth - DEF_METH(setup); - DEF_METH(flush); - DEF_METH(constructor); - DEF_METH(destructor); - DEF_METH(copy); - DEF_METH(deep_copy); - DEF_METH(compare); - DEF_METH(load); - DEF_METH(unload); - DEF_METH(property_get); - DEF_METH(property_set); - DEF_METH(property_del); - DEF_METH(properties_names_list_get); - DEF_METH(child_count); - DEF_METH(child_get); - DEF_METH(child_set); - DEF_METH(child_del); - DEF_METH(child_insert_at); - DEF_METH(child_find); - DEF_METH(child_criteria_match); - DEF_METH(child_sort); - DEF_METH(child_iterator_get); - DEF_METH(child_reversed_iterator_get); - DEF_METH(child_sorted_iterator_get); - DEF_METH(child_filtered_iterator_get); - DEF_METH(to_string); -#undef DEF_METH - - if ((!itr->parent) && (itr != EINA_MODEL_TYPE_BASE)) - { - CRITICAL("Type %p (%s) does not inherit from EINA_MODEL_TYPE_BASE!", - type, type->name); - return EINA_FALSE; - } - } - -#define CK_METH(meth) \ - if (!desc->ops.type.meth) \ - { \ - CRITICAL("Mandatory method "#meth \ - "() was not provided by type %p (%s).", \ - type, type->name); \ - return EINA_FALSE; \ - } - CK_METH(setup); - CK_METH(flush); - CK_METH(constructor); - CK_METH(destructor); - CK_METH(property_get); -#undef CK_METH - - if (child_size <= sizeof(Eina_Model_Type)) - desc->ops.type.extension = NULL; - else - { - unsigned ext_size = child_size - sizeof(Eina_Model_Type); - unsigned ext_count = ext_size / sizeof(void *); - - if (ext_size % sizeof(void *) != 0) - { - CRITICAL("Extension size %u is not multiple of sizeof(void*)", - ext_size); - return EINA_FALSE; - } - - desc->ops.type.extension = calloc(ext_count, sizeof(void *)); - EINA_SAFETY_ON_NULL_RETURN_VAL(desc->ops.type.extension, EINA_FALSE); - - for (itr = type; itr != NULL; itr = itr->parent) - { - unsigned cur_size = itr->type_size - sizeof(Eina_Model_Type); - unsigned i, cur_count = cur_size / sizeof(void *); - const void * const *ptr = (const void **)((const char *)itr + sizeof(Eina_Model_Type)); - - if (cur_size == 0) break; - - for (i = 0; i < cur_count; i++) - { - if (desc->ops.type.extension[i]) continue; - desc->ops.type.extension[i] = ptr[i]; - } - } - } - - desc->cache.types = malloc(count * sizeof(Eina_Model_Type *)); - EINA_SAFETY_ON_NULL_GOTO(desc->cache.types, cache_types_failed); - desc->total.types = count; - - for (count = 0, itr = type; itr != NULL; itr = itr->parent, count++) - desc->cache.types[count] = itr; - - return EINA_TRUE; - - cache_types_failed: - free(desc->ops.type.extension); - return EINA_FALSE; -} - -static inline Eina_Bool -_eina_model_interface_implements(const Eina_Model_Interface *iface, const Eina_Model_Interface *query) -{ - const Eina_Model_Interface **itr; - - if (iface == query) - return EINA_TRUE; - - if (!iface->interfaces) - return EINA_FALSE; - - for (itr = iface->interfaces; *itr != NULL; itr++) - if (_eina_model_interface_implements(*itr, query)) - return EINA_TRUE; - - return EINA_FALSE; -} - -/* apply topological sort and remove duplicates */ -/* - * TODO: Topological sort will only work for linked interfaces, but - * will ignore original ordering provided by types. Consider the - * following: - * - * - A_Type -> X_Iface (name: "MyIface") - * - B_Type -> Y_Iface (name: "MyIface") - * - * Both X_Iface and Y_Iface are different implementations of the - * "MyIface". - * - * B_Type inherits from A_Type, then Y_Iface must be looked up - * first, even though there is no link between Y_Iface and - * X_Iface. - * - * However, the way the current topological sort behaves, the - * roots may come out in any order. We need a stable version - * that sorts roots before removing them from graph. - * - * Thanks to Tasn to report it :-) - */ -static Eina_Bool -_eina_model_description_ifaces_fix(Eina_Model_Description *desc) -{ - struct node { - const Eina_Model_Interface *iface; - unsigned int users; - Eina_List *deps; - } *nodes, **pending, **roots; - unsigned int n_nodes = desc->total.ifaces, n_pending = 0, n_roots = 0, i, j; - Eina_Bool ret = EINA_TRUE; - - nodes = alloca(n_nodes * sizeof(struct node)); - pending = alloca(n_nodes * sizeof(struct node *)); - roots = alloca(n_nodes * sizeof(struct node *)); - - /* populate */ - for (i = 0, j = 0; i < n_nodes; i++) - { - unsigned int k; - for (k = 0; k < j; k++) - { - if (nodes[k].iface == desc->cache.ifaces[i]) - break; - } - if (k < j) - continue; /* already exists */ - - nodes[j].iface = desc->cache.ifaces[i]; - nodes[j].users = 0; - nodes[j].deps = NULL; - j++; - } - n_nodes = j; - - for (i = 0; i < n_nodes; i++) - { - for (j = 0; j < n_nodes; j++) - { - if (i == j) continue; - if (!_eina_model_interface_implements(nodes[j].iface, - nodes[i].iface)) - continue; - - nodes[i].users++; - nodes[j].deps = eina_list_append(nodes[j].deps, nodes + i); - } - } - for (i = 0; i < n_nodes; i++) - { - if (nodes[i].users == 0) - { - roots[n_roots] = nodes + i; - n_roots++; - } - else - { - pending[n_pending] = nodes + i; - n_pending++; - } - } - - /* topological sort */ - desc->total.ifaces = 0; - while (n_roots > 0) - { - struct node *r, *d; - - /* TODO: sort roots using input order? Or at least study if - * it's enough to change roots append to prepend. - * - * See comments above. - */ - n_roots--; - r = roots[n_roots]; - - desc->cache.ifaces[desc->total.ifaces] = r->iface; - desc->total.ifaces++; - - EINA_LIST_FREE(r->deps, d) - { - d->users--; - if (d->users > 0) continue; - - roots[n_roots] = d; - n_roots++; - - /* remove node, it became a root */ - for (j = 0; j < n_pending; j++) - { - if (pending[j] == d) - { - n_pending--; - if (j < n_pending) - pending[j] = pending[n_pending]; - break; - } - } - } - } - - if (n_pending > 0) - { - ERR("Dependency loop found for interfaces!"); - for (i = 0; i < n_pending; i++) - ERR("%p (%s) is part of dependency loop!", - pending[i]->iface, pending[i]->iface->name); - CRITICAL("Cannot use type %p (%s) with broken interfaces!", - desc->cache.types[0], desc->cache.types[0]->name); - free(desc->cache.ifaces); - ret = EINA_FALSE; - } - - /* likely from still pending (dependency loops) */ - for (i = 0; i < n_nodes; i++) - eina_list_free(nodes[i].deps); - - return ret; -} - -static Eina_Bool -_eina_model_description_ifaces_validate_and_count(const Eina_Model_Interface *iface, unsigned int *count) -{ - if (iface->version != EINA_MODEL_INTERFACE_VERSION) - { - CRITICAL("Interface %p version is %u, expected %u instead.", - iface, iface->version, EINA_MODEL_INTERFACE_VERSION); - return EINA_FALSE; - } - - if (!iface->name) - { - CRITICAL("Interface %p provides no name!", iface); - return EINA_FALSE; - } - - if (iface->interfaces) - { - const Eina_Model_Interface **itr = iface->interfaces; - for (; *itr != NULL; itr++) - if (!_eina_model_description_ifaces_validate_and_count(*itr, count)) - return EINA_FALSE; - } - - (*count)++; - return EINA_TRUE; -} - -static void -_eina_model_description_ifaces_populate(Eina_Model_Description *desc, const Eina_Model_Interface *iface) -{ - desc->cache.ifaces[desc->total.ifaces] = iface; - desc->total.ifaces++; - - if (iface->interfaces) - { - const Eina_Model_Interface **itr = iface->interfaces; - for (; *itr != NULL; itr++) - _eina_model_description_ifaces_populate(desc, *itr); - } -} - -static Eina_Bool -_eina_model_description_ifaces_fill(Eina_Model_Description *desc) -{ - const Eina_Model_Type **titr, **titr_end; - unsigned int count; - - titr = desc->cache.types; - titr_end = titr + desc->total.types; - - /* naively count all interfaces, remove duplicates later */ - for (count = 0; titr < titr_end; titr++) - { - const Eina_Model_Type *type = *titr; - const Eina_Model_Interface **iitr = type->interfaces; - if (!type->interfaces) continue; - - for (; *iitr != NULL; iitr++) - if (!_eina_model_description_ifaces_validate_and_count(*iitr, &count)) - return EINA_FALSE; - } - if (count == 0) - { - desc->cache.ifaces = NULL; - desc->total.ifaces = 0; - return EINA_TRUE; - } - - desc->cache.ifaces = malloc(count * sizeof(Eina_Model_Interface *)); - EINA_SAFETY_ON_NULL_RETURN_VAL(desc->cache.ifaces, EINA_FALSE); - - titr = desc->cache.types; - desc->total.ifaces = 0; - for (; titr < titr_end; titr++) - { - const Eina_Model_Type *type = *titr; - const Eina_Model_Interface **iitr = type->interfaces; - - if (!type->interfaces) continue; - - for (; *iitr != NULL; iitr++) - _eina_model_description_ifaces_populate(desc, *iitr); - } - - return _eina_model_description_ifaces_fix(desc); -} - -static Eina_Bool -_eina_model_description_privates_fill(Eina_Model_Description *desc) -{ - unsigned int i; - - desc->total.privates = desc->total.types + desc->total.ifaces; - desc->cache.privates = malloc(desc->total.privates * - sizeof(Eina_Model_Provider)); - EINA_SAFETY_ON_NULL_RETURN_VAL(desc->cache.privates, EINA_FALSE); - - desc->total.size = 0; - - for (i = 0; i < desc->total.types; i++) - { - const Eina_Model_Type *type = desc->cache.types[i]; - desc->cache.privates[i].type = type; - if (type->private_size > 0) - { - unsigned int size = type->private_size; - if (size % sizeof(void *) != 0) - size += sizeof(void *) - (size % sizeof(void *)); - desc->total.size += size; - } - } - - for (i = 0; i < desc->total.ifaces; i++) - { - const Eina_Model_Interface *iface = desc->cache.ifaces[i]; - desc->cache.privates[desc->total.types + i].iface = iface; - if (iface->private_size > 0) - { - unsigned int size = iface->private_size; - if (size % sizeof(void *) != 0) - size += sizeof(void *) - (size % sizeof(void *)); - desc->total.size += size; - } - } - - return EINA_TRUE; -} - -static int -_eina_model_description_events_cmp(const void *pa, const void *pb) -{ - const Eina_Model_Event_Description_Cache *a = pa, *b = pb; - return strcmp(a->name, b->name); -} - -static int -_eina_model_description_events_find(const Eina_Model_Description *desc, const Eina_Model_Event_Description *query) -{ - unsigned int i; - for (i = 0; i < desc->total.events; i++) - { - const Eina_Model_Event_Description_Cache *itr = desc->cache.events + i; - if ((itr->name == query->name) || (strcmp(itr->name, query->name) == 0)) - return i; - } - - return -1; -} - -/* warn and remove duplicates, sort items to speed up lookups */ -static Eina_Bool -_eina_model_description_events_fill(Eina_Model_Description *desc) -{ - unsigned int i, count = 0, type_events; - - for (i = 0; i < desc->total.types; i++) - { - const Eina_Model_Event_Description *itr = desc->cache.types[i]->events; - if (!itr) continue; - for (; itr->name != NULL; itr++) - { - count++; - } - } - type_events = count; - - for (i = 0; i < desc->total.ifaces; i++) - { - const Eina_Model_Event_Description *itr = desc->cache.ifaces[i]->events; - if (!itr) continue; - for (; itr->name != NULL; itr++) - count++; - } - - if (count == 0) - { - desc->cache.events = NULL; - desc->total.events = 0; - return EINA_TRUE; - } - - desc->cache.events = malloc(count * - sizeof(Eina_Model_Event_Description_Cache)); - EINA_SAFETY_ON_NULL_RETURN_VAL(desc->cache.events, EINA_FALSE); - desc->total.events = 0; - - for (i = 0; i < desc->total.types; i++) - { - const Eina_Model_Type *mtype = desc->cache.types[i]; - const Eina_Model_Event_Description *itr = mtype->events; - if (!itr) continue; - for (; itr->name != NULL; itr++) - { - int j = _eina_model_description_events_find(desc, itr); - if (j >= 0) - { - const Eina_Model_Event_Description_Cache *o = desc->cache.events + j; - const Eina_Model_Type *omtype = o->provider.type; - WRN("Ignored duplicated event '%s' (type: '%s') from " - "model type %p (%s): already exists with type '%s' " - "from model type %p (%s)", - itr->name, - itr->type ? itr->type : "", - mtype, mtype->name, - o->desc->type ? o->desc->type : "", - omtype, omtype->name); - continue; - } - - desc->cache.events[desc->total.events].name = itr->name; - desc->cache.events[desc->total.events].desc = itr; - desc->cache.events[desc->total.events].provider.type = mtype; - desc->total.events++; - } - } - - for (i = 0; i < desc->total.ifaces; i++) - { - const Eina_Model_Interface *miface = desc->cache.ifaces[i]; - const Eina_Model_Event_Description *itr = desc->cache.ifaces[i]->events; - if (!itr) continue; - for (; itr->name != NULL; itr++) - { - int j = _eina_model_description_events_find(desc, itr); - if (j >= 0) - { - const Eina_Model_Event_Description_Cache *o = desc->cache.events + j; - if ((unsigned)j < type_events) - { - const Eina_Model_Type *omtype = o->provider.type; - WRN("Ignored duplicated event '%s' (type: '%s') from " - "model interface %p (%s): already exists with " - "type '%s' from model interface %p (%s)", - itr->name, - itr->type ? itr->type : "", - miface, miface->name, - o->desc->type ? o->desc->type : "", - omtype, omtype->name); - } - else - { - const Eina_Model_Interface *omiface = o->provider.iface; - WRN("Ignored duplicated event '%s' (iface: '%s') from " - "model interface %p (%s): already exists with " - "interface '%s' from model interface %p (%s)", - itr->name, - itr->type ? itr->type : "", - miface, miface->name, - o->desc->type ? o->desc->type : "", - omiface, omiface->name); - } - continue; - } - - desc->cache.events[desc->total.events].name = itr->name; - desc->cache.events[desc->total.events].desc = itr; - desc->cache.events[desc->total.events].provider.iface = miface; - desc->total.events++; - } - } - - qsort(desc->cache.events, desc->total.events, - sizeof(Eina_Model_Event_Description_Cache), - _eina_model_description_events_cmp); - - return EINA_TRUE; -} - -static const Eina_Model_Description * -_eina_model_description_get_internal(const Eina_Model_Type *type) -{ - Eina_Model_Description *desc; - - desc = eina_hash_find(_eina_model_descriptions, &type); - if (desc) - { - desc->refcount++; - return desc; - } - - desc = calloc(1, sizeof(Eina_Model_Description)); - EINA_SAFETY_ON_NULL_RETURN_VAL(desc, NULL); - - if (!_eina_model_description_type_fill(desc, type)) goto failed_type; - if (!_eina_model_description_ifaces_fill(desc)) goto failed_ifaces; - if (!_eina_model_description_privates_fill(desc)) goto failed_privates; - if (!_eina_model_description_events_fill(desc)) goto failed_events; - if (!eina_hash_add(_eina_model_descriptions, &type, desc)) goto failed_hash; - - desc->refcount = 1; - return desc; - - failed_hash: - free(desc->cache.events); - failed_events: - free(desc->cache.privates); - failed_privates: - free(desc->cache.ifaces); - failed_ifaces: - free(desc->cache.types); - free(desc->ops.type.extension); - failed_type: - free(desc); - return NULL; -} - -static void -_eina_model_description_dispose_internal(Eina_Model_Description *desc) -{ - const Eina_Model_Type *type; - - EINA_SAFETY_ON_FALSE_RETURN(desc->refcount > 0); - desc->refcount--; - if (desc->refcount > 0) return; - - type = desc->cache.types[0]; - if (!eina_hash_del_by_key(_eina_model_descriptions, &type)) - ERR("Cannot find type %p (%s) in descriptions hash!", - type, type->name); - - INF("Disposed model description for type %p (%s)", type, type->name); - - free(desc->ops.type.extension); - free(desc->cache.types); - free(desc->cache.ifaces); - free(desc->cache.privates); - free(desc->cache.events); - free(desc); -} - -static const Eina_Model_Description * -_eina_model_description_get(const Eina_Model_Type *type) -{ - const Eina_Model_Description *desc; - - eina_lock_take(&_eina_model_descriptions_lock); - desc = _eina_model_description_get_internal(type); - eina_lock_release(&_eina_model_descriptions_lock); - - return desc; -} - -static void -_eina_model_description_dispose(const Eina_Model_Description *desc) -{ - eina_lock_take(&_eina_model_descriptions_lock); - _eina_model_description_dispose_internal((Eina_Model_Description *)desc); - eina_lock_release(&_eina_model_descriptions_lock); -} - -static inline int -_eina_model_description_event_id_find(const Eina_Model_Description *desc, const char *event_name) -{ - const Eina_Model_Event_Description_Cache *cache; - Eina_Model_Event_Description_Cache criteria_match; - - criteria_match.name = event_name; - cache = bsearch(&criteria_match, desc->cache.events, desc->total.events, - sizeof(Eina_Model_Event_Description_Cache), - _eina_model_description_events_cmp); - if (!cache) - { - ERR("No event named %s for type %p (%s)", event_name, - desc->cache.types[0], desc->cache.types[0]->name); - return -1; - } - - return cache - desc->cache.events; -} - -/* - * Model management and book keeping - */ -typedef struct _Eina_Model_Event_Listener Eina_Model_Event_Listener; -struct _Eina_Model_Event_Listener -{ - EINA_INLIST; - Eina_Model_Event_Cb cb; - const void *data; - Eina_Bool deleted:1; -}; - -struct _Eina_Model -{ - const Eina_Model_Description *desc; /**< optimized model description */ - struct { - Eina_Inlist **entries; /**< connected/listeners for each event, array of lists of Eina_Model_Event_Listener */ - Eina_List **deleted; /**< deleted listeners while was walking. array of lists of Eina_Model_Event_Listener with deleted flag */ - int *freeze; /**< freeze count for each event */ - int walking; /**< increased while walking entries lists */ - } listeners; - void **privates; /**< private data per type and interface, each level gets its own stuff */ - Eina_Inlist *xrefs; /**< if EINA_MODEL_DEBUG and eina_model_xref() is used */ - int refcount; /**< number of users of this model instance */ - Eina_Bool deleted:1; /**< if deleted but still have references */ - EINA_MAGIC -}; - -static inline Eina_Bool -_eina_model_type_check(const Eina_Model_Type *type) -{ - EINA_SAFETY_ON_NULL_RETURN_VAL(type, EINA_FALSE); - EINA_SAFETY_ON_FALSE_RETURN_VAL(type->version == EINA_MODEL_TYPE_VERSION, - EINA_FALSE); - return EINA_TRUE; -} - -/* find in type hierarchy the first one that the given offset is not a null - * pointer. Use this to discover which method to call on a parent. - */ -static const void * -_eina_model_type_find_offset(const Eina_Model_Type *type, unsigned int offset) -{ - const unsigned char *ptr = (const unsigned char *)type; - const void **addr = (const void **)(ptr + offset); - - if (*addr) return *addr; - if (!type->parent) return NULL; - return _eina_model_type_find_offset(type->parent, offset); -} - -/* find in interface hierarchy the first one that the given offset is - * not a null pointer. Use this to discover which method to call on a - * parent. - * - * TODO: Keep Eina_Model_Interface_Description with topological sorted - * entries for each interface? - * I smell problems with the current code in more complex - * situations (k-s) - * - * iface1 - * ^ - * | - * .---------+---------. - * | | | - * iface2 iface3 iface4 - * ^ ^ ^ - * | | | - * `---------+---------' - * | - * iface5 - * - * It should look: iface5 -> iface2 -> iface3 -> iface4 -> iface1 - * Now it does: iface5 -> iface2 -> iface1 -> iface3 -> iface1 -> iface4 -> iface1 - * - * - * iface1 - * ^ - * | - * iface2 - * ^ - * | - * .---------+---------. - * | | - * iface3 iface4 - * ^ ^ - * | | - * `---------+---------' - * | - * iface5 - * - * It should look: iface5 -> iface3 -> iface4 -> iface2 -> iface1 - * Now it does: iface5 -> iface3 -> iface2 -> iface1 -> iface4 -> iface2 -> iface1 - * - * - * iface1 iface2 - * ^ ^ - * | | - * `---------+---------' - * | - * iface3 - * - * It should look: iface3 -> iface1 -> iface2 - * Now it does: iface3 -> iface1 -> iface2 - * - * For the common case it should work, let's see. - */ -static const void * -_eina_model_interface_find_offset(const Eina_Model_Interface *iface, unsigned int offset) -{ - const Eina_Model_Interface **itr; - const unsigned char *ptr = (const unsigned char *)iface; - const void **addr = (const void **)(ptr + offset); - - if (offset + sizeof(void *) > iface->interface_size) return NULL; - - if (*addr) return *addr; - if (!iface->interfaces) return NULL; - - for (itr = iface->interfaces; *itr != NULL; itr++) - { - const void *r = _eina_model_interface_find_offset(*itr, offset); - if (r) - return r; - } - - return NULL; -} - -static void -_eina_model_event_callback_free_deleted(Eina_Model *model) -{ - unsigned int i; - - for (i = 0; i < model->desc->total.events; i++) - { - Eina_Model_Event_Listener *el; - EINA_LIST_FREE(model->listeners.deleted[i], el) - { - model->listeners.entries[i] = eina_inlist_remove - (model->listeners.entries[i], EINA_INLIST_GET(el)); - _eina_model_inner_free(sizeof(Eina_Model_Event_Listener), el); - } - } - - _eina_model_inner_free(model->desc->total.events * sizeof(Eina_List *), - model->listeners.deleted); - model->listeners.deleted = NULL; -} - -static inline Eina_Bool -_eina_model_event_callback_call(Eina_Model *model, const char *name, const void *event_info) -{ - Eina_Inlist *lst; - Eina_Model_Event_Listener *el; - const Eina_Model_Event_Description *ev_desc; - int event_id = _eina_model_description_event_id_find(model->desc, name); - - if (event_id < 0) return EINA_FALSE; - if (!model->listeners.entries) return EINA_TRUE; - - if ((model->listeners.freeze) && (model->listeners.freeze[event_id])) - { - DBG("Ignored event callback '%s' of model %p (%s): frozen", - name, model, model->desc->cache.types[0]->name); - return EINA_TRUE; - } - - lst = model->listeners.entries[event_id]; - if (!lst) return EINA_TRUE; - - ev_desc = model->desc->cache.events[event_id].desc; - - model->listeners.walking++; - EINA_INLIST_FOREACH(lst, el) - { - if (el->deleted) continue; - el->cb((void *)el->data, model, ev_desc, (void *)event_info); - } - model->listeners.walking--; - - if ((model->listeners.walking == 0) && (model->listeners.deleted)) - _eina_model_event_callback_free_deleted(model); - - return EINA_FALSE; -} - -static const char EINA_ERROR_MODEL_FAILED_STR[] = "Model check failed."; -static const char EINA_ERROR_MODEL_METHOD_MISSING_STR[] = "Model method is missing."; -static const char EINA_MAGIC_MODEL_STR[] = "Eina Model"; - -static void _eina_model_unref(Eina_Model *model); - -/** - * @endcond - */ - -/* EINA_MODEL_TYPE_BASE: base of all other types **********************/ - -static Eina_Bool -_eina_model_type_base_setup(Eina_Model *model) -{ - DBG("base setup of %p", model); - return EINA_TRUE; -} - -static Eina_Bool -_eina_model_type_base_flush(Eina_Model *model) -{ - DBG("base flush of %p", model); - return EINA_TRUE; -} - -static Eina_Bool -_eina_model_type_base_constructor(Eina_Model *model) -{ - DBG("base constructor of %p", model); - return EINA_TRUE; -} - -static Eina_Bool -_eina_model_type_base_destructor(Eina_Model *model) -{ - DBG("base destructor of %p", model); - return EINA_TRUE; -} - -static Eina_Bool -_eina_model_type_base_properties_copy(const Eina_Model *model, Eina_Model *copy) -{ - Eina_List *l, *props = eina_model_properties_names_list_get(model); - const char *name; - EINA_LIST_FOREACH(props, l, name) - { - Eina_Value tmp; - if (!eina_model_property_get(model, name, &tmp)) - { - ERR("Could not get property %s from model %p (%s)", - name, model, model->desc->cache.types[0]->name); - eina_model_properties_names_list_free(props); - return EINA_FALSE; - } - if (!eina_model_property_set(copy, name, &tmp)) - { - ERR("Could not set property %s on model %p (%s)", - name, copy, copy->desc->cache.types[0]->name); - eina_value_flush(&tmp); - eina_model_properties_names_list_free(props); - return EINA_FALSE; - } - eina_value_flush(&tmp); - } - eina_model_properties_names_list_free(props); - return EINA_TRUE; -} - -static Eina_Bool -_eina_model_type_base_children_copy(const Eina_Model *model, Eina_Model *copy) -{ - int i, count = eina_model_child_count(model); - - if (count < 0) - { - ERR("Could not get children count of model %p (%s)", - model, model->desc->cache.types[0]->name); - return EINA_FALSE; - } - - for (i = 0; i < count; i++) - { - Eina_Model *child = eina_model_child_get(model, i); - Eina_Bool ret; - - if (!child) - { - ERR("Could not get child #%d from model %p (%s)", - i, model, model->desc->cache.types[0]->name); - return EINA_FALSE; - } - - ret = eina_model_child_insert_at(copy, i, child); - _eina_model_unref(child); - - if (!ret) - { - ERR("Could not set child #%d on model %p (%s)", - i, copy, copy->desc->cache.types[0]->name); - return EINA_FALSE; - } - } - - return EINA_TRUE; -} - -static Eina_Bool -_eina_model_type_base_copy(const Eina_Model *model, Eina_Model *copy) -{ - DBG("base copy of %p to %p", model, copy); - - return _eina_model_type_base_properties_copy(model, copy) && - _eina_model_type_base_children_copy(model, copy); -} - -static Eina_Bool -_eina_model_type_base_children_deep_copy(const Eina_Model *model, Eina_Model *copy) -{ - int i, count = eina_model_child_count(model); - - if (count < 0) - { - ERR("Could not get children count of model %p (%s)", - model, model->desc->cache.types[0]->name); - return EINA_FALSE; - } - - for (i = 0; i < count; i++) - { - Eina_Model *child_copy, *child = eina_model_child_get(model, i); - Eina_Bool ret; - - if (!child) - { - ERR("Could not get child #%d from model %p (%s)", - i, model, model->desc->cache.types[0]->name); - return EINA_FALSE; - } - - child_copy = eina_model_deep_copy(child); - if (!child_copy) - { - ERR("Could not deep copy child #%d %p (%s) from model %p (%s)", i, - child, child->desc->cache.types[0]->name, - model, model->desc->cache.types[0]->name); - _eina_model_unref(child); - return EINA_FALSE; - } - _eina_model_unref(child); - - ret = eina_model_child_insert_at(copy, i, child_copy); - _eina_model_unref(child_copy); - - if (!ret) - { - ERR("Could not set child #%d on model %p (%s)", - i, copy, copy->desc->cache.types[0]->name); - return EINA_FALSE; - } - } - - return EINA_TRUE; -} - -static Eina_Bool -_eina_model_type_base_deep_copy(const Eina_Model *model, Eina_Model *copy) -{ - DBG("base deep copy of %p to %p", model, copy); - - return _eina_model_type_base_properties_copy(model, copy) && - _eina_model_type_base_children_deep_copy(model, copy); -} - -static Eina_Bool -_eina_model_type_base_properties_compare(const Eina_Model *a, const Eina_Model *b, int *cmp) -{ - Eina_List *al, *aprops = eina_model_properties_names_list_get(a); - Eina_List *bl, *bprops = eina_model_properties_names_list_get(b); - Eina_List *l, *props = NULL; - const char *aname, *bname, *name; - Eina_Bool ret = EINA_TRUE; - - EINA_LIST_FOREACH(aprops, al, aname) - { - EINA_LIST_FOREACH(bprops, bl, bname) - if (strcmp(aname, bname) == 0) - { - props = eina_list_append(props, aname); - break; - } - } - - *cmp = 0; - EINA_LIST_FOREACH(props, l, name) - { - Eina_Value atmp, btmp; - - if (!eina_model_property_get(a, name, &atmp)) - { - ERR("Could not get property %s from model %p (%s)", - name, a, a->desc->cache.types[0]->name); - ret = EINA_FALSE; - *cmp = -1; - break; - } - - if (!eina_model_property_get(b, name, &btmp)) - { - ERR("Could not get property %s from model %p (%s)", - name, b, b->desc->cache.types[0]->name); - ret = EINA_FALSE; - *cmp = -1; - eina_value_flush(&atmp); - break; - } - - *cmp = eina_value_compare(&atmp, &btmp); - if (eina_error_get() != 0) - { - char *astr = eina_value_to_string(&atmp); - char *bstr = eina_value_to_string(&btmp); - ERR("Could not compare property %s: %s=%s, %s=%s", name, - eina_value_type_name_get(eina_value_type_get(&atmp)), astr, - eina_value_type_name_get(eina_value_type_get(&btmp)), bstr); - free(astr); - free(bstr); - ret = EINA_FALSE; - *cmp = -1; - } - - eina_value_flush(&atmp); - eina_value_flush(&btmp); - - if ((!ret) || (*cmp != 0)) - break; - } - - if ((ret) && (*cmp == 0)) - { - int acount = eina_list_count(aprops); - int bcount = eina_list_count(bprops); - - if (acount < bcount) - *cmp = -1; - else if (acount > bcount) - *cmp = 1; - } - - eina_model_properties_names_list_free(aprops); - eina_model_properties_names_list_free(bprops); - eina_list_free(props); - return ret; -} - -static Eina_Bool -_eina_model_type_base_children_compare(const Eina_Model *a, const Eina_Model *b, int *cmp) -{ - int acount = eina_model_child_count(a); - int bcount = eina_model_child_count(b); - int i, count; - Eina_Bool ret = EINA_TRUE; - - if (acount < 0) - { - ERR("Could not get children count of model %p (%s)", - a, a->desc->cache.types[0]->name); - return EINA_FALSE; - } - if (bcount < 0) - { - ERR("Could not get children count of model %p (%s)", - b, b->desc->cache.types[0]->name); - return EINA_FALSE; - } - - if (acount < bcount) - count = acount; - else - count = bcount; - - for (i = 0; i < count; i++) - { - Eina_Model *achild, *bchild; - - achild = eina_model_child_get(a, i); - if (!achild) - { - ERR("Could not get child #%d from model %p (%s)", - i, a, a->desc->cache.types[0]->name); - *cmp = -1; - return EINA_FALSE; - } - - bchild = eina_model_child_get(b, i); - if (!bchild) - { - ERR("Could not get child #%d from model %p (%s)", - i, b, b->desc->cache.types[0]->name); - *cmp = -1; - _eina_model_unref(achild); - return EINA_FALSE; - } - - *cmp = eina_model_compare(achild, bchild); - if (eina_error_get()) - { - ERR("Could not compare children #%d %p (%s) and %p (%s) " - "from models %p (%s) and %p (%s)", i, - achild, - eina_model_type_name_get(eina_model_type_get(achild)), - bchild, - eina_model_type_name_get(eina_model_type_get(bchild)), - a, a->desc->cache.types[0]->name, - b, b->desc->cache.types[0]->name); - ret = EINA_FALSE; - } - _eina_model_unref(achild); - _eina_model_unref(bchild); - - if ((!ret) || (*cmp != 0)) - break; - } - - if ((ret) && (*cmp == 0)) - { - if (acount < bcount) - *cmp = -1; - else if (acount > bcount) - *cmp = 1; - } - - return ret; -} - -static Eina_Bool -_eina_model_type_base_compare(const Eina_Model *a, const Eina_Model *b, int *cmp) -{ - *cmp = 0; - DBG("base compare of %p and %p", a, b); - - if (!_eina_model_type_base_properties_compare(a, b, cmp)) - return EINA_FALSE; - - if (*cmp != 0) - return EINA_TRUE; - - return _eina_model_type_base_children_compare(a, b, cmp); -} - -static int -_eina_model_type_base_child_count(const Eina_Model *model) -{ - DBG("base child_count of %p", model); - return 0; -} - -static int -_eina_model_type_base_child_find(const Eina_Model *model, unsigned int start_position, const Eina_Model *other) -{ - int x = eina_model_child_count(model); - unsigned int i, count; - - DBG("base child_find of %p, %d children", model, x); - - if (x < 0) - return -1; - - count = x; - for (i = start_position; i < count; i++) - { - Eina_Model *current = eina_model_child_get(model, i); - if (current) - { - _eina_model_unref(current); /* we'll not use it's value anyway */ - if (current == other) - return i; - } - } - - return -1; -} - -static int -_eina_model_type_base_child_criteria_match(const Eina_Model *model, unsigned int start_position, Eina_Each_Cb match, const void *user_data) -{ - int x = eina_model_child_count(model); - unsigned int i, count; - - DBG("base child_criteria_match of %p, %d children", model, x); - - if (x < 0) - return -1; - - count = x; - for (i = start_position; i < count; i++) - { - Eina_Model *current = eina_model_child_get(model, i); - if (current) - { - Eina_Bool r = match(model, current, (void *)user_data); - _eina_model_unref(current); - if (r) - return i; - } - } - - return -1; -} - -typedef struct _Eina_Iterator_Model_Base Eina_Iterator_Model_Base; -struct _Eina_Iterator_Model_Base -{ - Eina_Iterator base; - Eina_Model *model; - unsigned int current; - unsigned int end; -}; - -static Eina_Bool -_eina_model_type_base_child_iterator_next(Eina_Iterator *base, void **data) -{ - Eina_Iterator_Model_Base *it; - - it = (Eina_Iterator_Model_Base *)base; - if (it->current >= it->end) - return EINA_FALSE; - - *data = eina_model_child_get(it->model, it->current); - if (!*data) - return EINA_FALSE; - - it->current++; - return EINA_TRUE; -} - -static void * -_eina_model_type_base_child_iterator_get_container(Eina_Iterator *base) -{ - Eina_Iterator_Model_Base *it; - it = (Eina_Iterator_Model_Base *)base; - return it->model; -} - -static void -_eina_model_type_base_child_iterator_free(Eina_Iterator *base) -{ - Eina_Iterator_Model_Base *it; - it = (Eina_Iterator_Model_Base *)base; - eina_model_xunref(it->model, it); - free(it); -} - -static Eina_Iterator * -_eina_model_type_base_child_iterator_get(Eina_Model *model, unsigned int start, unsigned int count) -{ - Eina_Iterator_Model_Base *it = calloc(1, sizeof(*it)); - EINA_SAFETY_ON_NULL_RETURN_VAL(it, NULL); - - EINA_MAGIC_SET(&it->base, EINA_MAGIC_ITERATOR); - it->base.version = EINA_ITERATOR_VERSION; - it->base.next = _eina_model_type_base_child_iterator_next; - it->base.get_container = _eina_model_type_base_child_iterator_get_container; - it->base.free = _eina_model_type_base_child_iterator_free; - - it->model = eina_model_xref(model, it, "eina_model_child_slice_iterator_get"); - it->current = start; - it->end = start + count; - - return &it->base; -} - -typedef struct _Eina_Iterator_Model_Base_Reversed Eina_Iterator_Model_Base_Reversed; -struct _Eina_Iterator_Model_Base_Reversed -{ - Eina_Iterator base; - Eina_Model *model; - unsigned int current; - unsigned int end; -}; - -static Eina_Bool -_eina_model_type_base_child_reversed_iterator_next(Eina_Iterator *base, void **data) -{ - Eina_Iterator_Model_Base_Reversed *it; - - it = (Eina_Iterator_Model_Base_Reversed *)base; - if (it->current == it->end) - return EINA_FALSE; - - it->current--; - *data = eina_model_child_get(it->model, it->current); - if (!*data) - return EINA_FALSE; - - return EINA_TRUE; -} - -static void * -_eina_model_type_base_child_reversed_iterator_get_container(Eina_Iterator *base) -{ - Eina_Iterator_Model_Base_Reversed *it; - it = (Eina_Iterator_Model_Base_Reversed *)base; - return it->model; -} - -static void -_eina_model_type_base_child_reversed_iterator_free(Eina_Iterator *base) -{ - Eina_Iterator_Model_Base_Reversed *it; - it = (Eina_Iterator_Model_Base_Reversed *)base; - eina_model_xunref(it->model, it); - free(it); -} - -static Eina_Iterator * -_eina_model_type_base_child_reversed_iterator_get(Eina_Model *model, unsigned int start, unsigned int count) -{ - Eina_Iterator_Model_Base_Reversed *it; - int children_count; - - children_count = eina_model_child_count(model); - if (children_count < 0) - return NULL; - - if (start + count > (unsigned int)children_count) - { - if (start >= (unsigned int)children_count) - count = 0; - else - count = children_count - start; - } - - it = calloc(1, sizeof(*it)); - EINA_SAFETY_ON_NULL_RETURN_VAL(it, NULL); - EINA_MAGIC_SET(&it->base, EINA_MAGIC_ITERATOR); - it->base.version = EINA_ITERATOR_VERSION; - it->base.next = _eina_model_type_base_child_reversed_iterator_next; - it->base.get_container = _eina_model_type_base_child_reversed_iterator_get_container; - it->base.free = _eina_model_type_base_child_reversed_iterator_free; - - it->model = eina_model_xref(model, it, "eina_model_child_slice_reversed_iterator_get"); - it->current = start + count; - it->end = start; - - return &it->base; -} - -typedef struct _Eina_Iterator_Model_Base_Sorted Eina_Iterator_Model_Base_Sorted; -struct _Eina_Iterator_Model_Base_Sorted -{ - Eina_Iterator base; - Eina_Model *model; - unsigned int current; - unsigned int count; - Eina_Model *elements[]; -}; - -static Eina_Bool -_eina_model_type_base_child_sorted_iterator_next(Eina_Iterator *base, void **data) -{ - Eina_Iterator_Model_Base_Sorted *it; - - it = (Eina_Iterator_Model_Base_Sorted *)base; - if (it->current == it->count) - return EINA_FALSE; - - *data = eina_model_ref(it->elements[it->current]); - it->current++; - return EINA_TRUE; -} - -static void * -_eina_model_type_base_child_sorted_iterator_get_container(Eina_Iterator *base) -{ - Eina_Iterator_Model_Base_Sorted *it; - it = (Eina_Iterator_Model_Base_Sorted *)base; - return it->model; -} - -static void -_eina_model_type_base_child_sorted_iterator_free(Eina_Iterator *base) -{ - Eina_Iterator_Model_Base_Sorted *it; - unsigned int i; - it = (Eina_Iterator_Model_Base_Sorted *)base; - eina_model_xunref(it->model, it); - - for (i = 0; i < it->count; i++) - _eina_model_unref(it->elements[i]); - - free(it); -} - -static Eina_Iterator * -_eina_model_type_base_child_sorted_iterator_get(Eina_Model *model, unsigned int start, unsigned int count, Eina_Compare_Cb compare) -{ - Eina_Iterator_Model_Base_Sorted *it; - int children_count; - unsigned int i; - - children_count = eina_model_child_count(model); - if (children_count < 0) - return NULL; - - if (start + count > (unsigned int)children_count) - { - if (start >= (unsigned int)children_count) - count = 0; - else - count = children_count - start; - } - - it = calloc(1, sizeof(*it) + count * sizeof(Eina_Model *)); - EINA_SAFETY_ON_NULL_RETURN_VAL(it, NULL); - EINA_MAGIC_SET(&it->base, EINA_MAGIC_ITERATOR); - it->base.version = EINA_ITERATOR_VERSION; - it->base.next = _eina_model_type_base_child_sorted_iterator_next; - it->base.get_container = _eina_model_type_base_child_sorted_iterator_get_container; - it->base.free = _eina_model_type_base_child_sorted_iterator_free; - - it->model = eina_model_xref(model, it, "eina_model_child_slice_sorted_iterator_get"); - it->current = 0; - it->count = count; - - for (i = 0; i < count; i++) - { - it->elements[i] = eina_model_child_get(model, i + start); - if (!it->elements[i]) - { - ERR("Failed to get child %u of model %p (%s)", - i + start, model, model->desc->cache.types[0]->name); - free(it); - return NULL; - } - } - - if (count > 1) - _eina_model_array_sort(it->elements, 0, count - 1, compare); - - return &it->base; -} - -typedef struct _Eina_Iterator_Model_Base_Filtered Eina_Iterator_Model_Base_Filtered; -struct _Eina_Iterator_Model_Base_Filtered -{ - Eina_Iterator base; - Eina_Model *model; - Eina_Each_Cb match; - const void *data; - unsigned int current; - unsigned int count; -}; - -static Eina_Bool -_eina_model_type_base_child_filtered_iterator_next(Eina_Iterator *base, void **data) -{ - Eina_Iterator_Model_Base_Filtered *it; - unsigned int *ret; - int i; - - it = (Eina_Iterator_Model_Base_Filtered *)base; - if (it->count == 0) return EINA_FALSE; - - i = eina_model_child_criteria_match(it->model, it->current, it->match, it->data); - if (i < 0) return EINA_FALSE; - - it->current = i + 1; - it->count--; - ret = (unsigned int *)data; - *ret = i; - return EINA_TRUE; -} - -static void * -_eina_model_type_base_child_filtered_iterator_get_container(Eina_Iterator *base) -{ - Eina_Iterator_Model_Base_Filtered *it; - it = (Eina_Iterator_Model_Base_Filtered *)base; - return it->model; -} - -static void -_eina_model_type_base_child_filtered_iterator_free(Eina_Iterator *base) -{ - Eina_Iterator_Model_Base_Filtered *it; - it = (Eina_Iterator_Model_Base_Filtered *)base; - eina_model_xunref(it->model, it); - free(it); -} - -static Eina_Iterator * -_eina_model_type_base_child_filtered_iterator_get(Eina_Model *model, unsigned int start, unsigned int count, Eina_Each_Cb match, const void *data) -{ - Eina_Iterator_Model_Base_Filtered *it = calloc(1, sizeof(*it)); - EINA_SAFETY_ON_NULL_RETURN_VAL(it, NULL); - - EINA_MAGIC_SET(&it->base, EINA_MAGIC_ITERATOR); - it->base.version = EINA_ITERATOR_VERSION; - it->base.next = _eina_model_type_base_child_filtered_iterator_next; - it->base.get_container = _eina_model_type_base_child_filtered_iterator_get_container; - it->base.free = _eina_model_type_base_child_filtered_iterator_free; - - it->model = eina_model_xref(model, it, "eina_model_child_slice_filtered_iterator_get"); - it->match = match; - it->data = data; - it->current = start; - it->count = count; - - return &it->base; -} - -static char * -_eina_model_type_base_to_string(const Eina_Model *model) -{ - Eina_List *l, *props; - const char *name; - Eina_Strbuf *str; - Eina_Bool first; - int i, count; - char *ret; - - str = eina_strbuf_new(); - EINA_SAFETY_ON_NULL_RETURN_VAL(str, NULL); - - eina_strbuf_append_printf(str, "%s({", model->desc->cache.types[0]->name); - - props = eina_model_properties_names_list_get(model); - props = eina_list_sort(props, 0, EINA_COMPARE_CB(strcmp)); - - first = EINA_TRUE; - EINA_LIST_FOREACH(props, l, name) - { - Eina_Value val; - - if (!first) - eina_strbuf_append_printf(str, ", %s: ", name); - else - { - eina_strbuf_append_printf(str, "%s: ", name); - first = EINA_FALSE; - } - - if (!eina_model_property_get(model, name, &val)) - eina_strbuf_append_char(str, '?'); - else - { - char *tmp = eina_value_to_string(&val); - eina_strbuf_append(str, tmp ? tmp : "?"); - free(tmp); - eina_value_flush(&val); - } - } - eina_list_free(props); - - eina_strbuf_append(str, "}, ["); - - count = eina_model_child_count(model); - first = EINA_TRUE; - for (i = 0; i < count; i++) - { - Eina_Model *c = eina_model_child_get(model, i); - if (!c) - { - if (!first) - eina_strbuf_append(str, ", ?"); - else - { - eina_strbuf_append_char(str, '?'); - first = EINA_FALSE; - } - } - else - { - char *tmp = eina_model_to_string(c); - if (!first) - eina_strbuf_append_printf(str, ", %s", tmp ? tmp : "?"); - else - { - eina_strbuf_append(str, tmp ? tmp : "?"); - first = EINA_FALSE; - } - free(tmp); - _eina_model_unref(c); - } - } - - eina_strbuf_append(str, "])"); - - ret = eina_strbuf_string_steal(str); - eina_strbuf_free(str); - - return ret; -} - -static const Eina_Model_Event_Description _eina_model_type_base_events[] = { - EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_deleted, "", "model was deleted"), - EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_freed, "", "model memory was released"), - EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_property_set, "s", "model data was set, data name given as event information."), - EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_property_del, "s", "model data was deleted, data name given as event information."), - EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_children_changed, "", "model children changed (deleted, inserted)."), - EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_child_inserted, "u", "model child was inserted, child position is given."), - EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_child_set, "u", "model child was set, child position is given."), - EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_child_del, "u", "model child was deleted, child position is given."), - EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_loaded, "", "model was loaded"), - EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_unloaded, "", "model was unloaded"), - EINA_MODEL_EVENT_DESCRIPTION_SENTINEL -}; - -static const Eina_Model_Type _EINA_MODEL_TYPE_BASE = { - EINA_MODEL_TYPE_VERSION, - 0, /* there is no private data */ - sizeof(Eina_Model_Type), - "Eina_Model_Type_Base", - NULL, /* should be the only type with NULL here! */ - NULL, /* no interfaces implemented */ - _eina_model_type_base_events, - _eina_model_type_base_setup, - _eina_model_type_base_flush, - _eina_model_type_base_constructor, - _eina_model_type_base_destructor, - _eina_model_type_base_copy, - _eina_model_type_base_deep_copy, - _eina_model_type_base_compare, - NULL, /* no load */ - NULL, /* no unload */ - NULL, /* no property value get */ - NULL, /* no property value set */ - NULL, /* no property del */ - NULL, /* no properties names list */ - _eina_model_type_base_child_count, - NULL, /* no child get */ - NULL, /* no child set */ - NULL, /* no child del */ - NULL, /* no child insert */ - _eina_model_type_base_child_find, - _eina_model_type_base_child_criteria_match, - NULL, /* no child sort */ - _eina_model_type_base_child_iterator_get, - _eina_model_type_base_child_reversed_iterator_get, - _eina_model_type_base_child_sorted_iterator_get, - _eina_model_type_base_child_filtered_iterator_get, - _eina_model_type_base_to_string, - NULL, /* extension pointer */ - NULL, /* extension pointer */ - NULL, /* extension pointer */ - NULL /* extension pointer */ -}; - -/* - * EINA_MODEL_TYPE_MIXIN: - * - * Mix-in is a type that uses 2 interfaces, one for properties, - * another for children. Users should inherit this model and implement - * at least onf of the interfaces to get an usable model without - * defining the methods. - */ - -static const char _EINA_MODEL_INTERFACE_NAME_PROPERTIES[] = "Eina_Model_Interface_Properties"; -static const char _EINA_MODEL_INTERFACE_NAME_CHILDREN[] = "Eina_Model_Interface_Children"; - -typedef struct _Eina_Model_Type_Mixin_Data Eina_Model_Type_Mixin_Data; -struct _Eina_Model_Type_Mixin_Data -{ - /* just keep interfaces to avoid lookups */ - const Eina_Model_Interface *if_properties; - const Eina_Model_Interface *if_children; -}; - -static Eina_Bool -_eina_model_type_mixin_setup(Eina_Model *model) -{ - DBG("mix-in setup of %p", model); - return EINA_TRUE; -} - -static Eina_Bool -_eina_model_type_mixin_flush(Eina_Model *model) -{ - DBG("mix-in flush of %p", model); - return EINA_TRUE; -} - -static Eina_Bool -_eina_model_type_mixin_constructor(Eina_Model *model) -{ - Eina_Model_Type_Mixin_Data *priv = eina_model_type_private_data_get - (model, EINA_MODEL_TYPE_MIXIN); - - DBG("mix-in constructor of %p (priv=%p)", model, priv); - - priv->if_properties = eina_model_interface_get - (model, EINA_MODEL_INTERFACE_NAME_PROPERTIES); - if (priv->if_properties) - { - if (!eina_model_interface_constructor(priv->if_properties, model)) - { - ERR("Could not construct properties interface %p of %p (%s)", - model, priv->if_properties, model->desc->cache.types[0]->name); - return EINA_FALSE; - } - } - - priv->if_children = eina_model_interface_get - (model, EINA_MODEL_INTERFACE_NAME_CHILDREN); - if (priv->if_children) - { - if (!eina_model_interface_constructor(priv->if_children, model)) - { - ERR("Could not construct children interface %p of %p (%s)", - model, priv->if_children, model->desc->cache.types[0]->name); - return EINA_FALSE; - } - } - - if ((!priv->if_properties) && (!priv->if_children)) - { - ERR("Mix-in model %p (%s) does not implement properties or children " - "interfaces!", - model, model->desc->cache.types[0]->name); - return EINA_FALSE; - } - - return EINA_TRUE; -} - -#define EINA_MODEL_TYPE_MIXIN_GET(model) \ - Eina_Model_Type_Mixin_Data *priv = eina_model_type_private_data_get \ - (model, EINA_MODEL_TYPE_MIXIN) - -static Eina_Bool -_eina_model_type_mixin_destructor(Eina_Model *model) -{ - EINA_MODEL_TYPE_MIXIN_GET(model); - - DBG("mixin destructor of %p", model); - - if (priv->if_properties) - eina_model_interface_destructor(priv->if_properties, model); - - if (priv->if_children) - eina_model_interface_destructor(priv->if_children, model); - - return EINA_TRUE; -} - -static Eina_Bool -_eina_model_type_mixin_compare(const Eina_Model *a, const Eina_Model *b, int *cmp) -{ - Eina_Bool ret = EINA_TRUE, did_prop = EINA_FALSE, did_child = EINA_FALSE; - - *cmp = 0; - - EINA_MODEL_TYPE_MIXIN_GET(a); - - if (priv->if_properties) - { - Eina_Bool (*compare)(const Eina_Model*, const Eina_Model*, int *) = - _eina_model_interface_find_offset - (priv->if_properties, - offsetof(Eina_Model_Interface_Properties, compare)); - - if (compare) - { - ret &= compare(a, b, cmp); - did_prop = EINA_TRUE; - } - } - - if ((ret) && (*cmp == 0)) - { - if (priv->if_children) - { - Eina_Bool (*compare)(const Eina_Model*, const Eina_Model*, int *) = - _eina_model_interface_find_offset - (priv->if_children, - offsetof(Eina_Model_Interface_Children, compare)); - - if (compare) - { - ret &= compare(a, b, cmp); - did_child = EINA_TRUE; - } - } - } - - if ((!did_prop) && (!did_child)) - return eina_model_type_compare(EINA_MODEL_TYPE_BASE, a, b, cmp); - - return ret; -} - -static Eina_Bool -_eina_model_type_mixin_load(Eina_Model *model) -{ - Eina_Bool ret = EINA_TRUE; - - EINA_MODEL_TYPE_MIXIN_GET(model); - - if (priv->if_properties) - ret &= eina_model_interface_properties_load(priv->if_properties, model); - - if (priv->if_children) - ret &= eina_model_interface_children_load(priv->if_children, model); - - return ret; -} - -static Eina_Bool -_eina_model_type_mixin_unload(Eina_Model *model) -{ - Eina_Bool ret = EINA_TRUE; - - EINA_MODEL_TYPE_MIXIN_GET(model); - - if (priv->if_properties) - ret &= eina_model_interface_properties_unload(priv->if_properties, model); - - if (priv->if_children) - ret &= eina_model_interface_children_unload(priv->if_children, model); - - return ret; -} - -static Eina_Bool -_eina_model_type_mixin_property_get(const Eina_Model *model, const char *name, Eina_Value *value) -{ - Eina_Bool ret = EINA_FALSE; - - EINA_MODEL_TYPE_MIXIN_GET(model); - - if (priv->if_properties) - ret = eina_model_interface_properties_get - (priv->if_properties, model, name, value); - - return ret; -} - -static Eina_Bool -_eina_model_type_mixin_property_set(Eina_Model *model, const char *name, const Eina_Value *value) -{ - Eina_Bool ret = EINA_FALSE; - - EINA_MODEL_TYPE_MIXIN_GET(model); - - if (priv->if_properties) - ret = eina_model_interface_properties_set - (priv->if_properties, model, name, value); - - return ret; -} - -static Eina_Bool -_eina_model_type_mixin_property_del(Eina_Model *model, const char *name) -{ - Eina_Bool ret = EINA_FALSE; - - EINA_MODEL_TYPE_MIXIN_GET(model); - - if (priv->if_properties) - ret = eina_model_interface_properties_del - (priv->if_properties, model, name); - - return ret; -} - -static Eina_List * -_eina_model_type_mixin_properties_names_list_get(const Eina_Model *model) -{ - Eina_List *ret = NULL; - - EINA_MODEL_TYPE_MIXIN_GET(model); - - if (priv->if_properties) - ret = eina_model_interface_properties_names_list_get - (priv->if_properties, model); - - return ret; -} - -static int -_eina_model_type_mixin_child_count(const Eina_Model *model) -{ - EINA_MODEL_TYPE_MIXIN_GET(model); - - if (!priv->if_children) - return 0; - - return eina_model_interface_children_count(priv->if_children, model); -} - -static Eina_Model * -_eina_model_type_mixin_child_get(const Eina_Model *model, unsigned int position) -{ - EINA_MODEL_TYPE_MIXIN_GET(model); - - if (!priv->if_children) - return 0; - - return eina_model_interface_children_get(priv->if_children, model, position); -} - -static Eina_Bool -_eina_model_type_mixin_child_set(Eina_Model *model, unsigned int position, Eina_Model *child) -{ - EINA_MODEL_TYPE_MIXIN_GET(model); - - if (!priv->if_children) - return 0; - - return eina_model_interface_children_set - (priv->if_children, model, position, child); -} - -static Eina_Bool -_eina_model_type_mixin_child_del(Eina_Model *model, unsigned int position) -{ - EINA_MODEL_TYPE_MIXIN_GET(model); - - if (!priv->if_children) - return 0; - - return eina_model_interface_children_del - (priv->if_children, model, position); -} - -static Eina_Bool -_eina_model_type_mixin_child_insert_at(Eina_Model *model, unsigned int position, Eina_Model *child) -{ - EINA_MODEL_TYPE_MIXIN_GET(model); - - if (!priv->if_children) - return 0; - - return eina_model_interface_children_insert_at - (priv->if_children, model, position, child); -} - -static void -_eina_model_type_mixin_child_sort(Eina_Model *model, Eina_Compare_Cb compare) -{ - EINA_MODEL_TYPE_MIXIN_GET(model); - - if (!priv->if_children) - return; - eina_model_interface_children_sort(priv->if_children, model, compare); -} - -static const Eina_Model_Type _EINA_MODEL_TYPE_MIXIN = { - EINA_MODEL_TYPE_VERSION, - sizeof(Eina_Model_Type_Mixin_Data), - sizeof(Eina_Model_Type), - "Eina_Model_Type_Mixin", - &_EINA_MODEL_TYPE_BASE, - NULL, /* no interfaces implemented */ - NULL, /* no extra events */ - _eina_model_type_mixin_setup, - _eina_model_type_mixin_flush, - _eina_model_type_mixin_constructor, - _eina_model_type_mixin_destructor, - NULL, /* no copy, as interface is called automatically */ - NULL, /* no deep copy, as interface is called automatically */ - _eina_model_type_mixin_compare, - _eina_model_type_mixin_load, - _eina_model_type_mixin_unload, - _eina_model_type_mixin_property_get, - _eina_model_type_mixin_property_set, - _eina_model_type_mixin_property_del, - _eina_model_type_mixin_properties_names_list_get, - _eina_model_type_mixin_child_count, - _eina_model_type_mixin_child_get, - _eina_model_type_mixin_child_set, - _eina_model_type_mixin_child_del, - _eina_model_type_mixin_child_insert_at, - NULL, /* use default find */ - NULL, /* use default criteria_match */ - _eina_model_type_mixin_child_sort, - NULL, /* use default iterator get */ - NULL, /* use default reversed iterator get */ - NULL, /* use default sorted iterator get */ - NULL, /* use default filtered iterator get */ - NULL, /* use default to string */ - NULL, /* extension pointer */ - NULL, /* extension pointer */ - NULL, /* extension pointer */ - NULL /* extension pointer */ -}; -#undef EINA_MODEL_TYPE_MIXIN_GET - -/* Events for all Properties interface */ -static const Eina_Model_Event_Description _eina_model_interface_properties_events[] = { - EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_properties_loaded, "", "model properties were loaded"), - EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_properties_unloaded, "", "model properties were unloaded"), - EINA_MODEL_EVENT_DESCRIPTION_SENTINEL -}; - -/* EINA_MODEL_INTERFACE_PROPERTIES_HASH ******************************/ - -#define EINA_MODEL_INTERFACE_PROPERTIES_HASH_GET(model) \ - Eina_Hash *priv = *(Eina_Hash **)eina_model_interface_private_data_get \ - (model, EINA_MODEL_INTERFACE_PROPERTIES_HASH) - -static Eina_Bool -_eina_model_interface_properties_hash_setup(Eina_Model *model) -{ - Eina_Hash **p_priv = eina_model_interface_private_data_get - (model, EINA_MODEL_INTERFACE_PROPERTIES_HASH); - - DBG("setup interface properties (hash) at %p model %p (%s)", - p_priv, model, model->desc->cache.types[0]->name); - - *p_priv = eina_hash_string_small_new(NULL); - return !!*p_priv; -} - -static Eina_Bool -_eina_model_interface_properties_hash_flush(Eina_Model *model) -{ - EINA_MODEL_INTERFACE_PROPERTIES_HASH_GET(model); - - DBG("flush interface properties (hash) at %p model %p (%s)", - priv, model, model->desc->cache.types[0]->name); - - if (priv) - { - ERR("interface properties flushed with values! priv=%p, model %p (%s)", - priv, model, model->desc->cache.types[0]->name); - eina_hash_free(priv); - } - - return EINA_TRUE; -} - -static Eina_Bool -_eina_model_interface_properties_hash_constructor(Eina_Model *model) -{ - EINA_MODEL_INTERFACE_PROPERTIES_HASH_GET(model); - - DBG("construct interface properties (hash) at %p model %p (%s)", - priv, model, model->desc->cache.types[0]->name); - - return EINA_TRUE; -} - -static Eina_Bool -_eina_model_interface_properties_hash_destructor_foreach(const Eina_Hash *hash __UNUSED__, const void *key __UNUSED__, void *data, void *fdata __UNUSED__) -{ - eina_value_free(data); - return EINA_TRUE; -} - -static Eina_Bool -_eina_model_interface_properties_hash_destructor(Eina_Model *model) -{ - Eina_Hash **p_priv = eina_model_interface_private_data_get - (model, EINA_MODEL_INTERFACE_PROPERTIES_HASH); - int count = eina_hash_population(*p_priv); - - DBG("destroy interface properties (hash) at %p model %p (%s). %d values.", - *p_priv, model, model->desc->cache.types[0]->name, count); - - eina_hash_foreach - (*p_priv, _eina_model_interface_properties_hash_destructor_foreach, NULL); - eina_hash_free(*p_priv); - *p_priv = NULL; - - return EINA_TRUE; -} - -static Eina_Bool -_eina_model_interface_properties_hash_get(const Eina_Model *model, const char *name, Eina_Value *value) -{ - EINA_MODEL_INTERFACE_PROPERTIES_HASH_GET(model); - const Eina_Value *prop = eina_hash_find(priv, name); - EINA_SAFETY_ON_NULL_RETURN_VAL(prop, EINA_FALSE); - return eina_value_copy(prop, value); -} - -static Eina_Bool -_eina_model_interface_properties_hash_set(Eina_Model *model, const char *name, const Eina_Value *value) -{ - EINA_MODEL_INTERFACE_PROPERTIES_HASH_GET(model); - Eina_Value *prop, *old = eina_hash_find(priv, name); - - prop = eina_value_new(eina_value_type_get(value)); - EINA_SAFETY_ON_NULL_RETURN_VAL(prop, EINA_FALSE); - - eina_value_flush(prop); - if (!eina_value_copy(value, prop)) - { - ERR("Could not copy value '%s' from %p to %p", name, value, prop); - eina_value_free(prop); - return EINA_FALSE; - } - - if (!old) - { - if (!eina_hash_add(priv, name, prop)) - { - ERR("Could not add value %p to hash as key '%s'", prop, name); - eina_value_free(prop); - return EINA_FALSE; - } - } - else - { - eina_value_free(old); - if (!eina_hash_modify(priv, name, prop)) - { - ERR("Could not modify hash key '%s' value from %p to %p", - name, old, prop); - eina_hash_del_by_key(priv, name); - eina_value_free(prop); - return EINA_FALSE; - } - } - - return EINA_TRUE; -} - -static Eina_Bool -_eina_model_interface_properties_hash_del(Eina_Model *model, const char *name) -{ - EINA_MODEL_INTERFACE_PROPERTIES_HASH_GET(model); - Eina_Value *old = eina_hash_find(priv, name); - EINA_SAFETY_ON_NULL_RETURN_VAL(old, EINA_FALSE); - eina_value_free(old); - return eina_hash_del_by_key(priv, name); -} - -static Eina_Bool -_eina_model_interface_properties_hash_names_list_foreach(const Eina_Hash *hash __UNUSED__, const void *key, void *data __UNUSED__, void *fdata) -{ - Eina_List **p_list = fdata; - *p_list = eina_list_append(*p_list, eina_stringshare_add(key)); - return EINA_TRUE; -} - -static Eina_List * -_eina_model_interface_properties_hash_names_list(const Eina_Model *model) -{ - EINA_MODEL_INTERFACE_PROPERTIES_HASH_GET(model); - Eina_List *list = NULL; - eina_hash_foreach - (priv, _eina_model_interface_properties_hash_names_list_foreach, &list); - return list; -} -#undef EINA_MODEL_INTERFACE_PROPERTIES_HASH_GET - -static const Eina_Model_Interface_Properties _EINA_MODEL_INTERFACE_PROPERTIES_HASH = { - { - EINA_MODEL_INTERFACE_VERSION, - sizeof(Eina_Hash *), - sizeof(Eina_Model_Interface_Properties), - _EINA_MODEL_INTERFACE_NAME_PROPERTIES, - NULL, /* no parent interfaces */ - _eina_model_interface_properties_events, - _eina_model_interface_properties_hash_setup, - _eina_model_interface_properties_hash_flush, - _eina_model_interface_properties_hash_constructor, - _eina_model_interface_properties_hash_destructor, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL - }, - EINA_MODEL_INTERFACE_PROPERTIES_VERSION, - NULL, /* no compare */ - NULL, /* no load */ - NULL, /* no unload */ - _eina_model_interface_properties_hash_get, - _eina_model_interface_properties_hash_set, - _eina_model_interface_properties_hash_del, - _eina_model_interface_properties_hash_names_list -}; - -/* EINA_MODEL_INTERFACE_PROPERTIES_STRUCT ******************************/ - -static Eina_Value_Struct * -_eina_model_interface_properties_struct_private_get(const Eina_Model *model) -{ - Eina_Value *val = eina_model_interface_private_data_get - (model, EINA_MODEL_INTERFACE_PROPERTIES_STRUCT); - return eina_value_memory_get(val); -} - -#define EINA_MODEL_INTERFACE_PROPERTIES_STRUCT_GET(model) \ - Eina_Value_Struct *priv = \ - _eina_model_interface_properties_struct_private_get(model) - -static Eina_Bool -_eina_model_interface_properties_struct_setup(Eina_Model *model) -{ - Eina_Value *val = eina_model_interface_private_data_get - (model, EINA_MODEL_INTERFACE_PROPERTIES_STRUCT); - - DBG("setup interface properties (struct) at %p model %p (%s)", - val, model, model->desc->cache.types[0]->name); - - return eina_value_setup(val, EINA_VALUE_TYPE_STRUCT); -} - -static Eina_Bool -_eina_model_interface_properties_struct_flush(Eina_Model *model) -{ - Eina_Value *val = eina_model_interface_private_data_get - (model, EINA_MODEL_INTERFACE_PROPERTIES_STRUCT); - - DBG("flush interface properties (struct) at %p model %p (%s)", - val, model, model->desc->cache.types[0]->name); - - if (val->type) - { - ERR("interface properties flushed with values! val=%p, model %p (%s)", - val, model, model->desc->cache.types[0]->name); - eina_value_flush(val); - } - - return EINA_TRUE; -} - -static Eina_Bool -_eina_model_interface_properties_struct_constructor(Eina_Model *model) -{ - EINA_MODEL_INTERFACE_PROPERTIES_STRUCT_GET(model); - - DBG("construct interface properties (struct) at %p model %p (%s)", - priv, model, model->desc->cache.types[0]->name); - - return EINA_TRUE; -} - -static Eina_Bool -_eina_model_interface_properties_struct_destructor(Eina_Model *model) -{ - Eina_Value *val = eina_model_interface_private_data_get - (model, EINA_MODEL_INTERFACE_PROPERTIES_STRUCT); - - DBG("destroy interface properties (struct) at %p model %p (%s)", - val, model, model->desc->cache.types[0]->name); - - eina_value_flush(val); - val->type = NULL; - - return EINA_TRUE; -} - -static Eina_Bool -_eina_model_interface_properties_struct_get(const Eina_Model *model, const char *name, Eina_Value *val) -{ - const Eina_Value *v = eina_model_interface_private_data_get - (model, EINA_MODEL_INTERFACE_PROPERTIES_STRUCT); - return eina_value_struct_value_get(v, name, val); -} - -static Eina_Bool -_eina_model_interface_properties_struct_set(Eina_Model *model, const char *name, const Eina_Value *val) -{ - Eina_Value *v = eina_model_interface_private_data_get - (model, EINA_MODEL_INTERFACE_PROPERTIES_STRUCT); - return eina_value_struct_value_set(v, name, val); -} - -static Eina_Bool -_eina_model_interface_properties_struct_del(Eina_Model *model __UNUSED__, const char *name __UNUSED__) -{ - return EINA_FALSE; /* not allowed */ -} - -static Eina_List * -_eina_model_interface_properties_struct_names_list(const Eina_Model *model) -{ - EINA_MODEL_INTERFACE_PROPERTIES_STRUCT_GET(model); - const Eina_Value_Struct_Member *itr; - Eina_List *list = NULL; - - EINA_SAFETY_ON_NULL_RETURN_VAL(priv, NULL); - EINA_SAFETY_ON_NULL_RETURN_VAL(priv->desc, NULL); - EINA_SAFETY_ON_NULL_RETURN_VAL(priv->desc->members, NULL); - - itr = priv->desc->members; - if (priv->desc->member_count) - { - const Eina_Value_Struct_Member *end = itr + priv->desc->member_count; - for (; itr < end; itr++) - list = eina_list_append(list, eina_stringshare_add(itr->name)); - } - else - { - for (; itr->name != NULL; itr++) - list = eina_list_append(list, eina_stringshare_add(itr->name)); - } - - return list; -} -#undef EINA_MODEL_INTERFACE_PROPERTIES_STRUCT_GET - -static const Eina_Model_Interface_Properties _EINA_MODEL_INTERFACE_PROPERTIES_STRUCT = { - { - EINA_MODEL_INTERFACE_VERSION, - sizeof(Eina_Value), - sizeof(Eina_Model_Interface_Properties), - _EINA_MODEL_INTERFACE_NAME_PROPERTIES, - NULL, /* no parent interfaces */ - _eina_model_interface_properties_events, - _eina_model_interface_properties_struct_setup, - _eina_model_interface_properties_struct_flush, - _eina_model_interface_properties_struct_constructor, - _eina_model_interface_properties_struct_destructor, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL - }, - EINA_MODEL_INTERFACE_PROPERTIES_VERSION, - NULL, /* no compare */ - NULL, /* no load */ - NULL, /* no unload */ - _eina_model_interface_properties_struct_get, - _eina_model_interface_properties_struct_set, - _eina_model_interface_properties_struct_del, - _eina_model_interface_properties_struct_names_list -}; - -/* Events for all Children interface */ -static const Eina_Model_Event_Description _eina_model_interface_children_events[] = { - EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_children_loaded, "", "model children were loaded"), - EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_children_unloaded, "", "model children were unloaded"), - EINA_MODEL_EVENT_DESCRIPTION_SENTINEL -}; - -/* EINA_MODEL_INTERFACE_CHILDREN_INARRAY ******************************/ - -#define EINA_MODEL_INTERFACE_CHILDREN_INARRAY_GET(model) \ - Eina_Inarray *priv = eina_model_interface_private_data_get \ - (model, EINA_MODEL_INTERFACE_CHILDREN_INARRAY) - -static Eina_Bool -_eina_model_interface_children_inarray_setup(Eina_Model *model) -{ - EINA_MODEL_INTERFACE_CHILDREN_INARRAY_GET(model); - - DBG("setup interface children (inarray) at %p model %p (%s)", - priv, model, model->desc->cache.types[0]->name); - - eina_inarray_setup(priv, sizeof(Eina_Model *), 0); - return EINA_TRUE; -} - -static Eina_Bool -_eina_model_interface_children_inarray_flush(Eina_Model *model) -{ - EINA_MODEL_INTERFACE_CHILDREN_INARRAY_GET(model); - int count; - - DBG("flush interface children (inarray) at %p model %p (%s)", - priv, model, model->desc->cache.types[0]->name); - - count = eina_inarray_count(priv); - if (count > 0) - ERR("interface children flushed with %d members! priv=%p, model %p (%s)", - count, priv, model, model->desc->cache.types[0]->name); - - eina_inarray_flush(priv); - return EINA_TRUE; -} - -static Eina_Bool -_eina_model_interface_children_inarray_constructor(Eina_Model *model) -{ - EINA_MODEL_INTERFACE_CHILDREN_INARRAY_GET(model); - - DBG("construct interface children (inarray) at %p model %p (%s)", - priv, model, model->desc->cache.types[0]->name); - - return EINA_TRUE; -} - -static Eina_Bool -_eina_model_interface_children_inarray_destructor(Eina_Model *model) -{ - Eina_Model **itr, **itr_end; - int count; - - EINA_MODEL_INTERFACE_CHILDREN_INARRAY_GET(model); - - count = eina_inarray_count(priv); - - DBG("destroy interface children (inarray) at %p model %p (%s). %d members.", - priv, model, model->desc->cache.types[0]->name, count); - - itr = priv->members; - itr_end = itr + count; - for (; itr < itr_end; itr++) - eina_model_xunref(*itr, EINA_MODEL_INTERFACE_CHILDREN_INARRAY); - eina_inarray_flush(priv); - - return EINA_TRUE; -} - -static int -_eina_model_interface_children_inarray_count(const Eina_Model *model) -{ - EINA_MODEL_INTERFACE_CHILDREN_INARRAY_GET(model); - return eina_inarray_count(priv); -} - -static Eina_Model * -_eina_model_interface_children_inarray_get(const Eina_Model *model, unsigned int position) -{ - EINA_MODEL_INTERFACE_CHILDREN_INARRAY_GET(model); - Eina_Model **child = eina_inarray_nth(priv, position); - if (!child) - return NULL; - return eina_model_ref(*child); -} - -static Eina_Bool -_eina_model_interface_children_inarray_set(Eina_Model *model, unsigned int position, Eina_Model *child) -{ - EINA_MODEL_INTERFACE_CHILDREN_INARRAY_GET(model); - Eina_Model **p_old = eina_inarray_nth(priv, position); - Eina_Model *old; - - if (!p_old) - return EINA_FALSE; - - old = *p_old; - if (!eina_inarray_replace_at(priv, position, &child)) - return EINA_FALSE; - - eina_model_xref(child, EINA_MODEL_INTERFACE_CHILDREN_INARRAY, - "eina_model_child_set"); - eina_model_xunref(old, EINA_MODEL_INTERFACE_CHILDREN_INARRAY); - return EINA_TRUE; -} - -static Eina_Bool -_eina_model_interface_children_inarray_del(Eina_Model *model, unsigned int position) -{ - EINA_MODEL_INTERFACE_CHILDREN_INARRAY_GET(model); - Eina_Model **p_old = eina_inarray_nth(priv, position); - Eina_Model *old; - - if (!p_old) - return EINA_FALSE; - - old = *p_old; - if (!eina_inarray_remove_at(priv, position)) - return EINA_FALSE; - - eina_model_xunref(old, EINA_MODEL_INTERFACE_CHILDREN_INARRAY); - return EINA_TRUE; -} - -static Eina_Bool -_eina_model_interface_children_inarray_insert_at(Eina_Model *model, unsigned int position, Eina_Model *child) -{ - EINA_MODEL_INTERFACE_CHILDREN_INARRAY_GET(model); - - if (!eina_inarray_insert_at(priv, position, &child)) - return EINA_FALSE; - - eina_model_xref(child, EINA_MODEL_INTERFACE_CHILDREN_INARRAY, - "eina_model_child_insert_at"); - return EINA_TRUE; -} - -static void -_eina_model_interface_children_inarray_sort(Eina_Model *model, Eina_Compare_Cb compare) -{ - EINA_MODEL_INTERFACE_CHILDREN_INARRAY_GET(model); - int count = eina_inarray_count(priv); - EINA_SAFETY_ON_FALSE_RETURN(count >= 0); - - if (count > 1) - _eina_model_array_sort(priv->members, 0, count - 1, compare); -} -#undef EINA_MODEL_INTERFACE_CHILDREN_INARRAY_GET - -static const Eina_Model_Interface_Children _EINA_MODEL_INTERFACE_CHILDREN_INARRAY = { - { - EINA_MODEL_INTERFACE_VERSION, - sizeof(Eina_Inarray), - sizeof(Eina_Model_Interface_Children), - _EINA_MODEL_INTERFACE_NAME_CHILDREN, - NULL, /* no parent interfaces */ - _eina_model_interface_children_events, - _eina_model_interface_children_inarray_setup, - _eina_model_interface_children_inarray_flush, - _eina_model_interface_children_inarray_constructor, - _eina_model_interface_children_inarray_destructor, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL - }, - EINA_MODEL_INTERFACE_CHILDREN_VERSION, - NULL, /* no compare */ - NULL, /* no load */ - NULL, /* no unload */ - _eina_model_interface_children_inarray_count, - _eina_model_interface_children_inarray_get, - _eina_model_interface_children_inarray_set, - _eina_model_interface_children_inarray_del, - _eina_model_interface_children_inarray_insert_at, - _eina_model_interface_children_inarray_sort -}; - -/* EINA_MODEL_TYPE_GENERIC ********************************************/ - -static const Eina_Model_Interface *_EINA_MODEL_TYPE_GENERIC_IFACES[] = { - &_EINA_MODEL_INTERFACE_PROPERTIES_HASH.base, - &_EINA_MODEL_INTERFACE_CHILDREN_INARRAY.base, - NULL -}; - -static const Eina_Model_Type _EINA_MODEL_TYPE_GENERIC = - EINA_MODEL_TYPE_INIT_NOPRIVATE("Eina_Model_Type_Generic", - Eina_Model_Type, - &_EINA_MODEL_TYPE_MIXIN, - _EINA_MODEL_TYPE_GENERIC_IFACES, - NULL); - -/* EINA_MODEL_TYPE_STRUCT ********************************************/ - -static const Eina_Model_Interface *_EINA_MODEL_TYPE_STRUCT_IFACES[] = { - &_EINA_MODEL_INTERFACE_PROPERTIES_STRUCT.base, - &_EINA_MODEL_INTERFACE_CHILDREN_INARRAY.base, - NULL -}; - -static const Eina_Model_Type _EINA_MODEL_TYPE_STRUCT = - EINA_MODEL_TYPE_INIT_NOPRIVATE("Eina_Model_Type_Struct", - Eina_Model_Type, - &_EINA_MODEL_TYPE_MIXIN, - _EINA_MODEL_TYPE_STRUCT_IFACES, - NULL); - -/** - */ - -/** - * @internal - * @brief Initialize the model module. - * - * @return #EINA_TRUE on success, #EINA_FALSE on failure. - * - * This function sets up the model module of Eina. It is called - * by eina_init(). - * - * @see eina_init() - */ -Eina_Bool -eina_model_init(void) -{ - const char *choice, *tmp; - - _eina_model_log_dom = eina_log_domain_register("eina_model", - EINA_LOG_COLOR_DEFAULT); - if (_eina_model_log_dom < 0) - { - EINA_LOG_ERR("Could not register log domain: eina_model"); - return EINA_FALSE; - } - - choice = getenv("EINA_MODEL_DEBUG"); - if (choice) - { - if (strcmp(choice, "1") == 0) - _eina_model_debug = EINA_MODEL_DEBUG_CHECK; - else if (strcmp(choice, "backtrace") == 0) - _eina_model_debug = EINA_MODEL_DEBUG_BACKTRACE; - } - -#ifdef EINA_DEFAULT_MEMPOOL - choice = "pass_through"; -#else - choice = "chained_mempool"; -#endif - tmp = getenv("EINA_MEMPOOL"); - if (tmp && tmp[0]) - choice = tmp; - - if (choice) - _eina_model_mp_choice = strdup(choice); - - _eina_model_mp = eina_mempool_add - (_eina_model_mp_choice, "model", NULL, sizeof(Eina_Model), 320); - if (!_eina_model_mp) - { - ERR("Mempool for model cannot be allocated in model init."); - goto on_init_fail_mp; - } - - if (!eina_lock_new(&_eina_model_inner_mps_lock)) - { - ERR("Cannot create inner mempools lock in model init."); - goto on_init_fail_lock_mp; - } - _eina_model_inner_mps = eina_hash_int32_new(NULL); - if (!_eina_model_inner_mps) - { - ERR("Cannot create hash for inner mempools in model init."); - goto on_init_fail_hash_mp; - } - - if (!eina_lock_new(&_eina_model_descriptions_lock)) - { - ERR("Cannot create model descriptions lock in model init."); - goto on_init_fail_lock_desc; - } - _eina_model_descriptions = eina_hash_pointer_new(NULL); - if (!_eina_model_descriptions) - { - ERR("Cannot create model descriptions hash in model init."); - goto on_init_fail_hash_desc; - } - - if (!eina_lock_new(&_eina_model_debug_list_lock)) - { - ERR("Cannot create model debug list lock in model init."); - goto on_init_fail_lock_debug; - } - - EINA_ERROR_MODEL_FAILED = eina_error_msg_static_register( - EINA_ERROR_MODEL_FAILED_STR); - EINA_ERROR_MODEL_METHOD_MISSING = eina_error_msg_static_register( - EINA_ERROR_MODEL_METHOD_MISSING_STR); - - EINA_MODEL_TYPE_BASE = &_EINA_MODEL_TYPE_BASE; - EINA_MODEL_TYPE_MIXIN = &_EINA_MODEL_TYPE_MIXIN; - EINA_MODEL_TYPE_GENERIC = &_EINA_MODEL_TYPE_GENERIC; - EINA_MODEL_TYPE_STRUCT = &_EINA_MODEL_TYPE_STRUCT; - - EINA_MODEL_INTERFACE_PROPERTIES_HASH = &_EINA_MODEL_INTERFACE_PROPERTIES_HASH.base; - EINA_MODEL_INTERFACE_PROPERTIES_STRUCT = &_EINA_MODEL_INTERFACE_PROPERTIES_STRUCT.base; - - EINA_MODEL_INTERFACE_CHILDREN_INARRAY = &_EINA_MODEL_INTERFACE_CHILDREN_INARRAY.base; - - EINA_MODEL_INTERFACE_NAME_PROPERTIES = _EINA_MODEL_INTERFACE_NAME_PROPERTIES; - EINA_MODEL_INTERFACE_NAME_CHILDREN = _EINA_MODEL_INTERFACE_NAME_CHILDREN; - - eina_magic_string_static_set(EINA_MAGIC_MODEL, EINA_MAGIC_MODEL_STR); - - return EINA_TRUE; - - on_init_fail_lock_debug: - eina_hash_free(_eina_model_descriptions); - on_init_fail_hash_desc: - eina_lock_free(&_eina_model_descriptions_lock); - on_init_fail_lock_desc: - eina_hash_free(_eina_model_inner_mps); - _eina_model_inner_mps = NULL; - on_init_fail_hash_mp: - eina_lock_free(&_eina_model_inner_mps_lock); - on_init_fail_lock_mp: - eina_mempool_del(_eina_model_mp); - on_init_fail_mp: - free(_eina_model_mp_choice); - _eina_model_mp_choice = NULL; - eina_log_domain_unregister(_eina_model_log_dom); - _eina_model_log_dom = -1; - return EINA_FALSE; -} - -/** - * @internal - * @brief Shut down the model module. - * - * @return #EINA_TRUE on success, #EINA_FALSE on failure. - * - * This function shuts down the model module set up by - * eina_model_init(). It is called by eina_shutdown(). - * - * @see eina_shutdown() - */ -Eina_Bool -eina_model_shutdown(void) -{ - eina_lock_take(&_eina_model_debug_list_lock); - if (eina_list_count(_eina_model_debug_list) > 0) - ERR("%d models are still alive!", eina_list_count(_eina_model_debug_list)); - eina_lock_release(&_eina_model_debug_list_lock); - eina_lock_free(&_eina_model_debug_list_lock); - - eina_lock_take(&_eina_model_inner_mps_lock); - if (eina_hash_population(_eina_model_inner_mps) != 0) - ERR("Cannot free eina_model internal memory pools -- still in use!"); - else - eina_hash_free(_eina_model_inner_mps); - eina_lock_release(&_eina_model_inner_mps_lock); - eina_lock_free(&_eina_model_inner_mps_lock); - - eina_lock_take(&_eina_model_descriptions_lock); - if (eina_hash_population(_eina_model_descriptions) != 0) - ERR("Cannot free eina_model internal descriptions -- still in use!"); - else - eina_hash_free(_eina_model_descriptions); - eina_lock_release(&_eina_model_descriptions_lock); - eina_lock_free(&_eina_model_descriptions_lock); - - free(_eina_model_mp_choice); - _eina_model_mp_choice = NULL; - eina_mempool_del(_eina_model_mp); - eina_log_domain_unregister(_eina_model_log_dom); - _eina_model_log_dom = -1; - return EINA_TRUE; -} - -/*============================================================================* - * Global * - *============================================================================*/ - -/*============================================================================* - * API * - *============================================================================*/ - - -EAPI Eina_Error EINA_ERROR_MODEL_FAILED = 0; -EAPI Eina_Error EINA_ERROR_MODEL_METHOD_MISSING = 0; - -EAPI const Eina_Model_Type *EINA_MODEL_TYPE_BASE = NULL; -EAPI const Eina_Model_Type *EINA_MODEL_TYPE_MIXIN = NULL; -EAPI const Eina_Model_Type *EINA_MODEL_TYPE_GENERIC = NULL; -EAPI const Eina_Model_Type *EINA_MODEL_TYPE_STRUCT = NULL; - -EAPI const Eina_Model_Interface *EINA_MODEL_INTERFACE_PROPERTIES_HASH = NULL; -EAPI const Eina_Model_Interface *EINA_MODEL_INTERFACE_PROPERTIES_STRUCT = NULL; -EAPI const Eina_Model_Interface *EINA_MODEL_INTERFACE_CHILDREN_INARRAY = NULL; - -EAPI const char *EINA_MODEL_INTERFACE_NAME_PROPERTIES = "Eina_Model_Interface_Properties"; -EAPI const char *EINA_MODEL_INTERFACE_NAME_CHILDREN = "Eina_Model_Interface_Children"; - -EAPI Eina_Model * -eina_model_new(const Eina_Model_Type *type) -{ - const Eina_Model_Description *desc; - Eina_Model *model; - unsigned int i; - - EINA_SAFETY_ON_NULL_RETURN_VAL(type, NULL); - EINA_SAFETY_ON_FALSE_RETURN_VAL(eina_model_type_check(type), NULL); - - desc = _eina_model_description_get(type); - EINA_SAFETY_ON_NULL_RETURN_VAL(desc, NULL); - - model = eina_mempool_malloc(_eina_model_mp, sizeof(Eina_Model)); - EINA_SAFETY_ON_NULL_GOTO(model, failed_model); - - model->desc = desc; - model->listeners.entries = NULL; - model->listeners.deleted = NULL; - model->listeners.freeze = NULL; - model->listeners.walking = 0; - - if (desc->total.size == 0) - model->privates = NULL; - else - { - unsigned char *ptr; - - model->privates = _eina_model_inner_alloc - (desc->total.privates * sizeof(void *) + - desc->total.size); - EINA_SAFETY_ON_NULL_GOTO(model->privates, failed_privates); - - ptr = (unsigned char *)(model->privates + desc->total.privates); - for (i = 0; i < desc->total.privates; i++) - { - unsigned int size; - if (i < desc->total.types) - size = desc->cache.privates[i].type->private_size; - else - size = desc->cache.privates[i].iface->private_size; - - if (size == 0) - { - model->privates[i] = NULL; - continue; - } - - model->privates[i] = ptr; - memset(ptr, 0, size); - - if (size % sizeof(void *) != 0) - size += sizeof(void *) - (size % sizeof(void *)); - ptr += size; - } - } - - model->refcount = 1; - model->xrefs = NULL; - model->deleted = EINA_FALSE; - EINA_MAGIC_SET(model, EINA_MAGIC_MODEL); - - /* call setup of every type in the reverse order, - * they should not call parent's setup. - */ - for (i = desc->total.types; i > 0; i--) - { - if (desc->cache.types[i - 1]->setup) - { - if (!desc->cache.types[i - 1]->setup(model)) - { - ERR("Failed to setup model %p at type %p (%s)", - model, desc->cache.types[i - 1], - desc->cache.types[i - 1]->name); - goto failed_types; - } - } - } - - /* call setup of every interface in the reverse order, - * they should not call parent's setup. - */ - for (i = desc->total.ifaces; i > 0; i--) - { - if (desc->cache.ifaces[i - 1]->setup) - { - if (!desc->cache.ifaces[i - 1]->setup(model)) - { - ERR("Failed to setup model %p at interface %p (%s)", - model, desc->cache.ifaces[i - 1], - desc->cache.ifaces[i - 1]->name); - goto failed_ifaces; - } - } - } - - if (!desc->ops.type.constructor(model)) - { - ERR("Failed to construct model %p, type %p (%s)", - model, desc->cache.types[0], desc->cache.types[0]->name); - goto failed_constructor; - } - - if (EINA_UNLIKELY(_eina_model_debug)) - { - eina_lock_take(&_eina_model_debug_list_lock); - _eina_model_debug_list = eina_list_append - (_eina_model_debug_list, model); - eina_lock_release(&_eina_model_debug_list_lock); - } - - return model; - - failed_constructor: - i = 0; - failed_ifaces: - /* flush every setup interface, natural order */ - for (; i < desc->total.ifaces; i++) - desc->cache.ifaces[i]->flush(model); - i = 0; - failed_types: - /* flush every setup type, natural order */ - for (; i < desc->total.types; i++) - desc->cache.types[i]->flush(model); - - if (model->privates) - _eina_model_inner_free(desc->total.privates * sizeof(void *) + - desc->total.size, - model->privates); - - failed_privates: - EINA_MAGIC_SET(model, EINA_MAGIC_NONE); - eina_mempool_free(_eina_model_mp, model); - failed_model: - _eina_model_description_dispose(desc); - return NULL; -} - -static void -_eina_model_free(Eina_Model *model) -{ - const Eina_Model_Description *desc = model->desc; - unsigned int i; - - DBG("model %p (%s) refcount=%d deleted=%hhu", - model, model->desc->cache.types[0]->name, - model->refcount, model->deleted); - - if (EINA_UNLIKELY(_eina_model_debug)) - { - if (model->xrefs) - { - ERR("Model %p (%s) released with references pending:", - model, model->desc->cache.types[0]->name); - while (model->xrefs) - { - Eina_Model_XRef *ref = (Eina_Model_XRef *)model->xrefs; - model->xrefs = eina_inlist_remove(model->xrefs, model->xrefs); - - ERR("xref: %p '%s'", ref->id, ref->label); - free(ref); - } - } - - eina_lock_take(&_eina_model_debug_list_lock); - _eina_model_debug_list = eina_list_remove - (_eina_model_debug_list, model); - eina_lock_release(&_eina_model_debug_list_lock); - } - - /* flush every interface, natural order */ - for (i = 0; i < desc->total.ifaces; i++) - if (desc->cache.ifaces[i]->flush) - desc->cache.ifaces[i]->flush(model); - - /* flush every type, natural order */ - for (i = 0; i < desc->total.types; i++) - if (desc->cache.types[i]->flush) - desc->cache.types[i]->flush(model); - - model->refcount--; - _eina_model_event_callback_call(model, _eina_model_str_freed, NULL); - - if (model->privates) - _eina_model_inner_free(desc->total.privates * sizeof(void *) + - desc->total.size, - model->privates); - - if (model->listeners.deleted) - _eina_model_event_callback_free_deleted(model); - - if (model->listeners.entries) - { - for (i = 0; i < desc->total.events; i++) - { - Eina_Inlist *lst = model->listeners.entries[i]; - while (lst) - { - void *tmp = lst; - lst = lst->next; - _eina_model_inner_free(sizeof(Eina_Model_Event_Listener), - tmp); - } - } - - _eina_model_inner_free(desc->total.events * sizeof(Eina_Inlist *), - model->listeners.entries); - } - - if (model->listeners.freeze) - _eina_model_inner_free(model->desc->total.events * sizeof(int), - model->listeners.freeze); - - EINA_MAGIC_SET(model, EINA_MAGIC_NONE); - eina_mempool_free(_eina_model_mp, model); - - _eina_model_description_dispose(desc); -} - -static void -_eina_model_del(Eina_Model *model) -{ - const Eina_Model_Description *desc = model->desc; - - DBG("model %p (%s) refcount=%d deleted=%hhu", - model, model->desc->cache.types[0]->name, - model->refcount, model->deleted); - - EINA_SAFETY_ON_TRUE_RETURN(model->deleted); - - model->deleted = EINA_TRUE; - _eina_model_event_callback_call(model, _eina_model_str_deleted, NULL); - - if (!desc->ops.type.destructor(model)) - ERR("Failed to destroy model %p, type %p (%s)", - model, desc->cache.types[0], desc->cache.types[0]->name); -} - -static void -_eina_model_unref(Eina_Model *model) -{ - DBG("model %p (%s) refcount=%d deleted=%hhu", - model, model->desc->cache.types[0]->name, - model->refcount, model->deleted); - - if (model->refcount > 1) - { - model->refcount--; - return; - } - - if (!model->deleted) _eina_model_del(model); - _eina_model_free(model); -} - -#define EINA_MODEL_INSTANCE_CHECK_VAL(inst, retval) \ - do \ - { \ - if (!EINA_MAGIC_CHECK(inst, EINA_MAGIC_MODEL)) \ - { \ - EINA_MAGIC_FAIL(inst, EINA_MAGIC_MODEL); \ - return retval; \ - } \ - EINA_SAFETY_ON_NULL_RETURN_VAL(inst->desc, retval); \ - EINA_SAFETY_ON_FALSE_RETURN_VAL(inst->refcount > 0, retval); \ - EINA_SAFETY_ON_FALSE_RETURN_VAL(inst->desc->refcount > 0, retval); \ - } \ - while (0) - -#define EINA_MODEL_INSTANCE_CHECK(inst) \ - do \ - { \ - if (!EINA_MAGIC_CHECK(inst, EINA_MAGIC_MODEL)) \ - { \ - EINA_MAGIC_FAIL(inst, EINA_MAGIC_MODEL); \ - return; \ - } \ - EINA_SAFETY_ON_NULL_RETURN(inst->desc); \ - EINA_SAFETY_ON_FALSE_RETURN(inst->refcount > 0); \ - EINA_SAFETY_ON_FALSE_RETURN(inst->desc->refcount > 0); \ - } \ - while (0) - -#define EINA_MODEL_TYPE_CALL_OPTIONAL_RETURN(model, method, def_retval, ...) \ - do \ - { \ - eina_error_set(0); \ - if (model->desc->ops.type.method) \ - return model->desc->ops.type.method(model, ## __VA_ARGS__); \ - DBG("Optional method" # method "() not implemented for model %p (%s)", \ - model, model->desc->cache.types[0]->name); \ - return def_retval; \ - } \ - while (0) - -#define EINA_MODEL_TYPE_CALL_OPTIONAL(model, method, ...) \ - do \ - { \ - eina_error_set(0); \ - if (model->desc->ops.type.method) \ - model->desc->ops.type.method(model, ## __VA_ARGS__); \ - else \ - DBG("Optional method" # method "() not implemented for model %p (%s)", \ - model, model->desc->cache.types[0]->name); \ - } \ - while (0) - -#define EINA_MODEL_TYPE_CALL_MANDATORY_RETURN(model, method, def_retval, ...) \ - do \ - { \ - eina_error_set(0); \ - if (model->desc->ops.type.method) \ - return model->desc->ops.type.method(model, ## __VA_ARGS__); \ - eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING); \ - CRITICAL("Mandatory method" # method "() not implemented for model %p (%s)", \ - model, model->desc->cache.types[0]->name); \ - return def_retval; \ - } \ - while (0) - -#define EINA_MODEL_TYPE_CALL_MANDATORY(model, method, ...) \ - do \ - { \ - eina_error_set(0); \ - if (model->desc->ops.type.method) \ - model->desc->ops.type.method(model, ## __VA_ARGS__); \ - else \ - { \ - eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING); \ - CRITICAL("Mandatory method" # method "() not implemented for model %p (%s)", \ - model, model->desc->cache.types[0]->name); \ - } \ - } \ - while (0) - - -#define EINA_MODEL_TYPE_CALL_RETURN(model, method, def_retval, ...) \ - do \ - { \ - eina_error_set(0); \ - if (model->desc->ops.type.method) \ - return model->desc->ops.type.method(model, ## __VA_ARGS__); \ - eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING); \ - ERR("Method" # method "() not implemented for model %p (%s)", \ - model, model->desc->cache.types[0]->name); \ - return def_retval; \ - } \ - while (0) - -#define EINA_MODEL_TYPE_CALL(model, method, ...) \ - do \ - { \ - eina_error_set(0); \ - if (model->desc->ops.type.method) \ - model->desc->ops.type.method(model, ## __VA_ARGS__); \ - else \ - { \ - eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING); \ - ERR("Method" # method "() not implemented for model %p (%s)", \ - model, model->desc->cache.types[0]->name); \ - } \ - } \ - while (0) - -EAPI void -eina_model_del(Eina_Model *model) -{ - EINA_MODEL_INSTANCE_CHECK(model); - _eina_model_del(model); - _eina_model_unref(model); -} - -EAPI const Eina_Model_Type * -eina_model_type_get(const Eina_Model *model) -{ - EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL); - return model->desc->cache.types[0]; -} - -EAPI const Eina_Model_Interface * -eina_model_interface_get(const Eina_Model *model, const char *name) -{ - const Eina_Model_Description *desc; - const Eina_Model_Interface **itr, **itr_end; - - EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL); - EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL); - - desc = model->desc; - itr = desc->cache.ifaces; - itr_end = itr + desc->total.ifaces; - - /* fallback to strcmp if user is lazy about speed */ - for (; itr < itr_end; itr++) - if (strcmp((*itr)->name, name) == 0) - return *itr; - - return NULL; -} - -static Eina_Bool -_eina_model_instance_check(const Eina_Model *model, const Eina_Model_Type *type) -{ - const Eina_Model_Type **itr, **itr_end; - - itr = model->desc->cache.types; - itr_end = itr + model->desc->total.types; - - for (; itr < itr_end; itr++) - if (*itr == type) - return EINA_TRUE; - - return EINA_FALSE; -} - -EAPI Eina_Bool -eina_model_instance_check(const Eina_Model *model, const Eina_Model_Type *type) -{ - EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE); - EINA_SAFETY_ON_NULL_RETURN_VAL(type, EINA_FALSE); - EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_type_check(type), EINA_FALSE); - return _eina_model_instance_check(model, type); -} - -EAPI Eina_Model * -eina_model_ref(Eina_Model *model) -{ - EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL); - DBG("model %p (%s) refcount=%d deleted=%hhu", - model, model->desc->cache.types[0]->name, - model->refcount, model->deleted); - model->refcount++; - return model; -} - -static Eina_Model * -_eina_model_xref_add(Eina_Model *model, const void *id, const char *label) -{ - Eina_Model_XRef *ref; - void *bt[256]; - int btlen, labellen; - - labellen = label ? strlen(label): 0; - btlen = 0; - -#ifdef HAVE_BACKTRACE - if (_eina_model_debug == EINA_MODEL_DEBUG_BACKTRACE) - btlen = backtrace(bt, EINA_C_ARRAY_LENGTH(bt)); -#endif - - ref = calloc(1, sizeof(*ref) + (btlen * sizeof(void *)) + (labellen + 1)); - EINA_SAFETY_ON_NULL_RETURN_VAL(ref, NULL); - - ref->id = id; - memcpy(ref->label, label, labellen); - ref->label[labellen] = '\0'; - ref->backtrace.count = btlen; - if (btlen == 0) ref->backtrace.symbols = NULL; - else - { - void *ptr = (unsigned char *)ref + sizeof(*ref) + (labellen + 1); - ref->backtrace.symbols = ptr; - memcpy(ptr, bt, btlen * sizeof(void *)); - } - - model->xrefs = eina_inlist_append(model->xrefs, EINA_INLIST_GET(ref)); - return model; -} - -EAPI Eina_Model * -eina_model_xref(Eina_Model *model, const void *id, const char *label) -{ - EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL); - DBG("model %p (%s) refcount=%d deleted=%hhu id=%p label=%s", - model, model->desc->cache.types[0]->name, - model->refcount, model->deleted, id, label ? label : ""); - - model->refcount++; - - if (EINA_LIKELY(!_eina_model_debug)) - return model; - - return _eina_model_xref_add(model, id, label); -} - -EAPI void -eina_model_unref(Eina_Model *model) -{ - EINA_MODEL_INSTANCE_CHECK(model); - _eina_model_unref(model); -} - -EAPI void -eina_model_xunref(Eina_Model *model, const void *id) -{ - Eina_Model_XRef *ref; - EINA_MODEL_INSTANCE_CHECK(model); - - if (EINA_LIKELY(!_eina_model_debug)) - { - _eina_model_unref(model); - return; - } - - EINA_INLIST_FOREACH(model->xrefs, ref) - { - if (ref->id != id) continue; - - model->xrefs = eina_inlist_remove(model->xrefs, EINA_INLIST_GET(ref)); - free(ref); - _eina_model_unref(model); - return; - } - - ERR("Could not find existing reference %p to model %p", id, model); -} - -EAPI int -eina_model_refcount(const Eina_Model *model) -{ - EINA_MODEL_INSTANCE_CHECK_VAL(model, -1); - return model->refcount; -} - -EAPI const Eina_Inlist * -eina_model_xrefs_get(const Eina_Model *model) -{ - EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL); - return model->xrefs; -} - -EAPI Eina_Bool -eina_model_event_callback_add(Eina_Model *model, const char *event_name, Eina_Model_Event_Cb cb, const void *data) -{ - const Eina_Model_Description *desc; - Eina_Model_Event_Listener *el; - int event_id; - - EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE); - EINA_SAFETY_ON_NULL_RETURN_VAL(event_name, EINA_FALSE); - EINA_SAFETY_ON_NULL_RETURN_VAL(cb, EINA_FALSE); - - desc = model->desc; - event_id = _eina_model_description_event_id_find(desc, event_name); - if (event_id < 0) - { - ERR("No event named %s for model %p (%s)", - event_name, model, model->desc->cache.types[0]->name); - return EINA_FALSE; - } - - if (!model->listeners.entries) - { - model->listeners.entries = _eina_model_inner_alloc - (desc->total.events * sizeof(Eina_Inlist *)); - EINA_SAFETY_ON_NULL_RETURN_VAL(model->listeners.entries, EINA_FALSE); - memset(model->listeners.entries, 0, - desc->total.events * sizeof(Eina_Inlist *)); - } - - el = _eina_model_inner_alloc(sizeof(Eina_Model_Event_Listener)); - EINA_SAFETY_ON_NULL_RETURN_VAL(el, EINA_FALSE); - - el->cb = cb; - el->data = data; - el->deleted = EINA_FALSE; - model->listeners.entries[event_id] = eina_inlist_append - (model->listeners.entries[event_id], EINA_INLIST_GET(el)); - - return EINA_TRUE; -} - -EAPI Eina_Bool -eina_model_event_callback_del(Eina_Model *model, const char *event_name, Eina_Model_Event_Cb cb, const void *data) -{ - int event_id; - Eina_Inlist *lst; - Eina_Model_Event_Listener *el; - - EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE); - EINA_SAFETY_ON_NULL_RETURN_VAL(event_name, EINA_FALSE); - EINA_SAFETY_ON_NULL_RETURN_VAL(cb, EINA_FALSE); - - if (!model->listeners.entries) - { - ERR("No event callbacks for model %p (%s)", - model, model->desc->cache.types[0]->name); - return EINA_FALSE; - } - - event_id = _eina_model_description_event_id_find(model->desc, event_name); - if (event_id < 0) - { - ERR("No event named %s for model %p (%s)", - event_name, model, model->desc->cache.types[0]->name); - return EINA_FALSE; - } - - lst = model->listeners.entries[event_id]; - EINA_INLIST_FOREACH(lst, el) - { - if (el->cb != cb) continue; - if ((data) && (el->data != data)) continue; - - if (model->listeners.walking == 0) - { - model->listeners.entries[event_id] = eina_inlist_remove - (model->listeners.entries[event_id], EINA_INLIST_GET(el)); - _eina_model_inner_free(sizeof(Eina_Model_Event_Listener), el); - } - else - { - el->deleted = EINA_TRUE; - if (!model->listeners.deleted) - { - model->listeners.deleted = _eina_model_inner_alloc - (model->desc->total.events * sizeof(Eina_List *)); - EINA_SAFETY_ON_NULL_RETURN_VAL(model->listeners.deleted, - EINA_FALSE); - - memset(model->listeners.deleted, 0, - model->desc->total.events * sizeof(Eina_List *)); - - } - model->listeners.deleted[event_id] = eina_list_append - (model->listeners.deleted[event_id], el); - } - return EINA_TRUE; - } - - ERR("No callback %p data %p found for event named %s for model %p (%s)", - cb, data, event_name, model, model->desc->cache.types[0]->name); - return EINA_FALSE; -} - -EAPI const Eina_Model_Event_Description * -eina_model_event_description_get(const Eina_Model *model, const char *event_name) -{ - const Eina_Model_Description *desc; - int event_id; - - EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL); - EINA_SAFETY_ON_NULL_RETURN_VAL(event_name, NULL); - - desc = model->desc; - event_id = _eina_model_description_event_id_find(desc, event_name); - if (event_id < 0) - return NULL; - - return desc->cache.events[event_id].desc; -} - -EAPI Eina_List * -eina_model_event_names_list_get(const Eina_Model *model) -{ - const Eina_Model_Event_Description_Cache *itr, *itr_end; - Eina_List *lst = NULL; - - EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL); - - itr = model->desc->cache.events; - itr_end = itr + model->desc->total.events; - - for (; itr < itr_end; itr++) - lst = eina_list_append(lst, eina_stringshare_add(itr->name)); - - return lst; -} - -EAPI void -eina_model_event_names_list_free(Eina_List *list) -{ - const char *str; - EINA_LIST_FREE(list, str) - eina_stringshare_del(str); -} - -EAPI Eina_Bool -eina_model_event_callback_call(Eina_Model *model, const char *name, const void *event_info) -{ - EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE); - EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE); - return _eina_model_event_callback_call(model, name, event_info); -} - -EAPI int -eina_model_event_callback_freeze(Eina_Model *model, const char *name) -{ - int event_id; - - EINA_MODEL_INSTANCE_CHECK_VAL(model, -1); - EINA_SAFETY_ON_NULL_RETURN_VAL(name, -1); - - event_id = _eina_model_description_event_id_find(model->desc, name); - if (event_id < 0) return -1; - - if (!model->listeners.freeze) - { - model->listeners.freeze = _eina_model_inner_alloc - (model->desc->total.events * sizeof(int)); - EINA_SAFETY_ON_NULL_RETURN_VAL(model->listeners.freeze, -1); - - memset(model->listeners.freeze, 0, - model->desc->total.events * sizeof(int)); - } - - if (model->listeners.freeze[event_id] == 0) - DBG("model %p (%s) event %s frozen", - model, model->desc->cache.types[0]->name, name); - - model->listeners.freeze[event_id]++; - return model->listeners.freeze[event_id]; -} - -EAPI int -eina_model_event_callback_thaw(Eina_Model *model, const char *name) -{ - int event_id; - - EINA_MODEL_INSTANCE_CHECK_VAL(model, -1); - EINA_SAFETY_ON_NULL_RETURN_VAL(name, -1); - EINA_SAFETY_ON_NULL_RETURN_VAL(model->listeners.freeze, -1); - - event_id = _eina_model_description_event_id_find(model->desc, name); - if (event_id < 0) return -1; - - model->listeners.freeze[event_id]--; - if (model->listeners.freeze[event_id] == 0) - DBG("model %p (%s) event %s unfrozen", - model, model->desc->cache.types[0]->name, name); - return model->listeners.freeze[event_id]; -} - -EAPI Eina_Model * -eina_model_copy(const Eina_Model *model) -{ - const Eina_Model_Description *desc; - Eina_Model *copy; - unsigned int i; - - EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL); - desc = model->desc; - copy = eina_model_new(desc->cache.types[0]); - EINA_SAFETY_ON_NULL_RETURN_VAL(copy, NULL); - - /* call copy of every type in the reverse order, - * they should not call parent's copy. - */ - for (i = desc->total.types; i > 0; i--) - { - if (desc->cache.types[i - 1]->copy) - { - if (!desc->cache.types[i - 1]->copy(model, copy)) - goto failed; - } - } - - /* call copy of every interface in the reverse order, - * they should not call parent's copy. - */ - for (i = desc->total.ifaces; i > 0; i--) - { - if (desc->cache.ifaces[i - 1]->copy) - { - if (!desc->cache.ifaces[i - 1]->copy(model, copy)) - goto failed; - } - } - - return copy; - - failed: - ERR("Failed to copy model %p %s", model, desc->cache.types[0]->name); - eina_model_del(copy); - return NULL; -} - -EAPI Eina_Model * -eina_model_deep_copy(const Eina_Model *model) -{ - const Eina_Model_Description *desc; - Eina_Model *deep_copy; - unsigned int i; - - EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL); - desc = model->desc; - deep_copy = eina_model_new(desc->cache.types[0]); - EINA_SAFETY_ON_NULL_RETURN_VAL(deep_copy, NULL); - - /* call deep_copy of every type in the reverse order, - * they should not call parent's deep_copy. - */ - for (i = desc->total.types; i > 0; i--) - { - if (desc->cache.types[i - 1]->deep_copy) - { - if (!desc->cache.types[i - 1]->deep_copy(model, deep_copy)) - goto failed; - } - } - - /* call deep_copy of every interface in the reverse order, - * they should not call parent's deep_copy. - */ - for (i = desc->total.ifaces; i > 0; i--) - { - if (desc->cache.ifaces[i - 1]->deep_copy) - { - if (!desc->cache.ifaces[i - 1]->deep_copy(model, deep_copy)) - goto failed; - } - } - - return deep_copy; - - failed: - ERR("Failed to deep copy model %p %s", model, desc->cache.types[0]->name); - eina_model_del(deep_copy); - return NULL; -} - -EAPI int -eina_model_compare(const Eina_Model *a, const Eina_Model *b) -{ - const Eina_Model_Description *desc_a, *desc_b; - Eina_Bool ok; - int cmp = -1; - - EINA_MODEL_INSTANCE_CHECK_VAL(a, -1); - EINA_MODEL_INSTANCE_CHECK_VAL(b, -1); - desc_a = a->desc; - desc_b = b->desc; - - if ((!desc_a->ops.type.compare) && (!desc_b->ops.type.compare)) - { - ERR("Models %p (%s) and %p (%s) can't compare", - a, desc_a->cache.types[0]->name, - b, desc_b->cache.types[0]->name); - eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING); - return -1; - } - else if ((desc_a->ops.type.compare) && (desc_b->ops.type.compare)) - { - ok = desc_a->ops.type.compare(a, b, &cmp); - if (!ok) - { - ok = desc_b->ops.type.compare(b, a, &cmp); - if (ok) - cmp = -cmp; /* swapped sides! */ - } - } - else if (desc_a->ops.type.compare) - ok = desc_a->ops.type.compare(a, b, &cmp); - else - { - ok = desc_b->ops.type.compare(b, a, &cmp); - if (ok) - cmp = -cmp; /* swapped sides! */ - } - - if (!ok) - { - ERR("Could not compare models %p (%s) and %p (%s)", - a, desc_a->cache.types[0]->name, - b, desc_b->cache.types[0]->name); - eina_error_set(EINA_ERROR_MODEL_FAILED); - return -1; - } - - return cmp; -} - -EAPI Eina_Bool -eina_model_load(Eina_Model *model) -{ - Eina_Bool ret; - - EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE); - - eina_error_set(0); - if (model->desc->ops.type.load) - { - ret = model->desc->ops.type.load(model); - if (ret) - _eina_model_event_callback_call(model, _eina_model_str_loaded, NULL); - } - else - { - eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING); - ret = EINA_FALSE; - ERR("Method load() not implemented for model %p (%s)", - model, model->desc->cache.types[0]->name); - } - - return ret; -} - -EAPI Eina_Bool -eina_model_unload(Eina_Model *model) -{ - Eina_Bool ret; - - EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE); - - eina_error_set(0); - if (model->desc->ops.type.unload) - { - ret = model->desc->ops.type.unload(model); - if (ret) - _eina_model_event_callback_call - (model, _eina_model_str_unloaded, NULL); - } - else - { - eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING); - ret = EINA_FALSE; - ERR("Method unload() not implemented for model %p (%s)", - model, model->desc->cache.types[0]->name); - } - - return ret; -} - -EAPI Eina_Bool -eina_model_property_get(const Eina_Model *model, const char *name, Eina_Value *value) -{ - EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE); - EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE); - EINA_SAFETY_ON_NULL_RETURN_VAL(value, EINA_FALSE); - EINA_MODEL_TYPE_CALL_MANDATORY_RETURN(model, property_get, EINA_FALSE, - name, value); -} - -EAPI Eina_Bool -eina_model_property_set(Eina_Model *model, const const char *name, const Eina_Value *value) -{ - Eina_Bool ret; - - EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE); - EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE); - EINA_SAFETY_ON_NULL_RETURN_VAL(value, EINA_FALSE); - EINA_SAFETY_ON_FALSE_RETURN_VAL(eina_value_type_check(value->type), EINA_FALSE); - - eina_error_set(0); - if (model->desc->ops.type.property_set) - { - ret = model->desc->ops.type.property_set(model, name, value); - if (ret) - _eina_model_event_callback_call - (model, _eina_model_str_property_set, name); - } - else - { - eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING); - ret = EINA_FALSE; - ERR("Method property_set() not implemented for model %p (%s)", - model, model->desc->cache.types[0]->name); - } - - return ret; -} - -EAPI Eina_Bool -eina_model_property_del(Eina_Model *model, const char *name) -{ - Eina_Bool ret; - - EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE); - EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE); - - eina_error_set(0); - if (model->desc->ops.type.property_del) - { - ret = model->desc->ops.type.property_del(model, name); - if (ret) - _eina_model_event_callback_call - (model, _eina_model_str_property_del, name); - } - else - { - eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING); - ret = EINA_FALSE; - ERR("Method property_del() not implemented for model %p (%s)", - model, model->desc->cache.types[0]->name); - } - - return ret; -} - -EAPI Eina_List * -eina_model_properties_names_list_get(const Eina_Model *model) -{ - EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL); - EINA_MODEL_TYPE_CALL_OPTIONAL_RETURN(model, properties_names_list_get, NULL); -} - -EAPI void -eina_model_properties_names_list_free(Eina_List *list) -{ - const char *str; - EINA_LIST_FREE(list, str) - eina_stringshare_del(str); -} - -EAPI int -eina_model_child_count(const Eina_Model *model) -{ - EINA_MODEL_INSTANCE_CHECK_VAL(model, -1); - EINA_MODEL_TYPE_CALL_OPTIONAL_RETURN(model, child_count, 0); -} - -EAPI Eina_Model * -eina_model_child_get(const Eina_Model *model, unsigned int position) -{ - EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL); - EINA_MODEL_TYPE_CALL_RETURN(model, child_get, NULL, position); -} - -EAPI Eina_Bool -eina_model_child_set(Eina_Model *model, unsigned int position, Eina_Model *child) -{ - Eina_Bool ret; - - EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE); - EINA_MODEL_INSTANCE_CHECK_VAL(child, EINA_FALSE); - - eina_error_set(0); - if (model->desc->ops.type.child_set) - { - ret = model->desc->ops.type.child_set(model, position, child); - if (ret) - _eina_model_event_callback_call - (model, _eina_model_str_child_set, &position); - } - else - { - eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING); - ret = EINA_FALSE; - ERR("Method child_set() not implemented for model %p (%s)", - model, model->desc->cache.types[0]->name); - } - - return ret; -} - -EAPI Eina_Bool -eina_model_child_del(Eina_Model *model, unsigned int position) -{ - Eina_Bool ret; - - EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE); - - eina_error_set(0); - if (model->desc->ops.type.child_del) - { - ret = model->desc->ops.type.child_del(model, position); - if (ret) - { - _eina_model_event_callback_call - (model, _eina_model_str_child_del, &position); - _eina_model_event_callback_call - (model, _eina_model_str_children_changed, NULL); - } - } - else - { - eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING); - ret = EINA_FALSE; - ERR("Method child_del() not implemented for model %p (%s)", - model, model->desc->cache.types[0]->name); - } - - return ret; -} - -EAPI Eina_Bool -eina_model_child_insert_at(Eina_Model *model, unsigned int position, Eina_Model *child) -{ - Eina_Bool ret; - - EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE); - EINA_SAFETY_ON_NULL_RETURN_VAL(child, EINA_FALSE); - - eina_error_set(0); - if (model->desc->ops.type.child_insert_at) - { - ret = model->desc->ops.type.child_insert_at(model, position, child); - if (ret) - { - _eina_model_event_callback_call - (model, _eina_model_str_child_inserted, &position); - _eina_model_event_callback_call - (model, _eina_model_str_children_changed, NULL); - } - } - else - { - eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING); - ret = EINA_FALSE; - ERR("Method child_insert_at() not implemented for model %p (%s)", - model, model->desc->cache.types[0]->name); - } - - return ret; -} - -EAPI int -eina_model_child_append(Eina_Model *model, Eina_Model *child) -{ - Eina_Bool ret; - int position; - - EINA_MODEL_INSTANCE_CHECK_VAL(model, -1); - EINA_SAFETY_ON_NULL_RETURN_VAL(child, -1); - - position = eina_model_child_count(model); - if (position < 0) - return -1; - - eina_error_set(0); - if (model->desc->ops.type.child_insert_at) - { - ret = model->desc->ops.type.child_insert_at(model, position, child); - if (ret) - { - _eina_model_event_callback_call - (model, _eina_model_str_child_inserted, &position); - _eina_model_event_callback_call - (model, _eina_model_str_children_changed, NULL); - } - } - else - { - eina_error_set(EINA_ERROR_MODEL_METHOD_MISSING); - ret = EINA_FALSE; - ERR("Method child_insert_at() not implemented for model %p (%s)", - model, model->desc->cache.types[0]->name); - } - - return ret ? position : -1; -} - -EAPI int -eina_model_child_find(const Eina_Model *model, unsigned int start_position, const Eina_Model *other) -{ - EINA_MODEL_INSTANCE_CHECK_VAL(model, -1); - EINA_SAFETY_ON_NULL_RETURN_VAL(other, -1); - EINA_MODEL_TYPE_CALL_RETURN(model, child_find, -1, start_position, other); -} - -EAPI int -eina_model_child_criteria_match(const Eina_Model *model, unsigned int start_position, Eina_Each_Cb match, const void *data) -{ - EINA_MODEL_INSTANCE_CHECK_VAL(model, -1); - EINA_SAFETY_ON_NULL_RETURN_VAL(match, -1); - EINA_MODEL_TYPE_CALL_RETURN(model, child_criteria_match, -1, - start_position, match, data); -} - -EAPI Eina_Bool -eina_model_child_sort(Eina_Model *model, Eina_Compare_Cb compare) -{ - EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE); - EINA_SAFETY_ON_NULL_RETURN_VAL(compare, EINA_FALSE); - EINA_MODEL_TYPE_CALL(model, child_sort, compare); - _eina_model_event_callback_call - (model, _eina_model_str_children_changed, NULL); - return EINA_TRUE; -} - -EAPI Eina_Iterator * -eina_model_child_iterator_get(Eina_Model *model) -{ - int count; - EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL); - count = eina_model_child_count(model); - if (count < 0) - return NULL; - EINA_MODEL_TYPE_CALL_RETURN(model, child_iterator_get, NULL, 0, count); -} - -EAPI Eina_Iterator * -eina_model_child_slice_iterator_get(Eina_Model *model, unsigned int start, unsigned int count) -{ - EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL); - EINA_MODEL_TYPE_CALL_RETURN(model, child_iterator_get, NULL, start, count); -} - -EAPI Eina_Iterator * -eina_model_child_reversed_iterator_get(Eina_Model *model) -{ - int count; - EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL); - count = eina_model_child_count(model); - if (count < 0) - return NULL; - EINA_MODEL_TYPE_CALL_RETURN(model, child_reversed_iterator_get, NULL, - 0, count); -} - -EAPI Eina_Iterator * -eina_model_child_slice_reversed_iterator_get(Eina_Model *model, unsigned int start, unsigned int count) -{ - EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL); - EINA_MODEL_TYPE_CALL_RETURN(model, child_reversed_iterator_get, NULL, - start, count); -} - -EAPI Eina_Iterator * -eina_model_child_sorted_iterator_get(Eina_Model *model, Eina_Compare_Cb compare) -{ - int count; - EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL); - EINA_SAFETY_ON_NULL_RETURN_VAL(compare, NULL); - count = eina_model_child_count(model); - if (count < 0) - return NULL; - EINA_MODEL_TYPE_CALL_RETURN(model, child_sorted_iterator_get, NULL, - 0, count, compare); -} - -EAPI Eina_Iterator * -eina_model_child_slice_sorted_iterator_get(Eina_Model *model, unsigned int start, unsigned int count, Eina_Compare_Cb compare) -{ - EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL); - EINA_SAFETY_ON_NULL_RETURN_VAL(compare, NULL); - EINA_MODEL_TYPE_CALL_RETURN(model, child_sorted_iterator_get, NULL, - start, count, compare); -} - -EAPI Eina_Iterator * -eina_model_child_filtered_iterator_get(Eina_Model *model, Eina_Each_Cb match, const void *data) -{ - int count; - EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL); - EINA_SAFETY_ON_NULL_RETURN_VAL(match, NULL); - count = eina_model_child_count(model); - if (count < 0) - return NULL; - EINA_MODEL_TYPE_CALL_RETURN(model, child_filtered_iterator_get, NULL, - 0, count, match, data); -} - -EAPI Eina_Iterator * -eina_model_child_slice_filtered_iterator_get(Eina_Model *model, unsigned int start, unsigned int count, Eina_Each_Cb match, const void *data) -{ - EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL); - EINA_SAFETY_ON_NULL_RETURN_VAL(match, NULL); - EINA_MODEL_TYPE_CALL_RETURN(model, child_filtered_iterator_get, NULL, - start, count, match, data); -} - -EAPI char * -eina_model_to_string(const Eina_Model *model) -{ - EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL); - EINA_MODEL_TYPE_CALL_RETURN(model, to_string, NULL); -} - -/* type functions *****************************************************/ - -EAPI Eina_Bool -eina_model_type_check(const Eina_Model_Type *type) -{ - EINA_SAFETY_ON_NULL_RETURN_VAL(type, EINA_FALSE); - return _eina_model_type_check(type); -} - -EAPI const char * -eina_model_type_name_get(const Eina_Model_Type *type) -{ - EINA_SAFETY_ON_NULL_RETURN_VAL(type, NULL); - EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_type_check(type), NULL); - return type->name; -} - -EAPI const Eina_Model_Type * -eina_model_type_parent_get(const Eina_Model_Type *type) -{ - EINA_SAFETY_ON_NULL_RETURN_VAL(type, NULL); - EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_type_check(type), NULL); - return type->parent; -} - -#define EINA_MODEL_TYPE_INSTANCE_CHECK(type, model) \ - EINA_SAFETY_ON_NULL_RETURN(type); \ - EINA_SAFETY_ON_FALSE_RETURN(_eina_model_type_check(type)); \ - EINA_MODEL_INSTANCE_CHECK(model); \ - EINA_SAFETY_ON_FALSE_RETURN(_eina_model_instance_check(model, type)); - -#define EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, retval) \ - EINA_SAFETY_ON_NULL_RETURN_VAL(type, retval); \ - EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_type_check(type), retval); \ - EINA_MODEL_INSTANCE_CHECK_VAL(model, retval); \ - EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_instance_check(model, type), retval); - -EAPI Eina_Bool -eina_model_type_constructor(const Eina_Model_Type *type, Eina_Model *model) -{ - Eina_Bool (*constructor)(Eina_Model *); - - EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, EINA_FALSE); - - constructor = _eina_model_type_find_offset - (type, offsetof(Eina_Model_Type, constructor)); - EINA_SAFETY_ON_NULL_RETURN_VAL(constructor, EINA_FALSE); - - return constructor(model); -} - -EAPI Eina_Bool -eina_model_type_destructor(const Eina_Model_Type *type, Eina_Model *model) -{ - Eina_Bool (*destructor)(Eina_Model *); - - EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, EINA_FALSE); - - destructor = _eina_model_type_find_offset - (type, offsetof(Eina_Model_Type, destructor)); - EINA_SAFETY_ON_NULL_RETURN_VAL(destructor, EINA_FALSE); - - return destructor(model); -} - -EAPI Eina_Bool -eina_model_type_copy(const Eina_Model_Type *type, const Eina_Model *src, Eina_Model *dst) -{ - Eina_Bool (*copy)(const Eina_Model *, Eina_Model *); - - EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, src, EINA_FALSE); - EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, dst, EINA_FALSE); - - copy = _eina_model_type_find_offset - (type, offsetof(Eina_Model_Type, copy)); - EINA_SAFETY_ON_NULL_RETURN_VAL(copy, EINA_FALSE); - - return copy(src, dst); -} - -EAPI Eina_Bool -eina_model_type_deep_copy(const Eina_Model_Type *type, const Eina_Model *src, Eina_Model *dst) -{ - Eina_Bool (*deep_copy)(const Eina_Model *, Eina_Model *); - - EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, src, EINA_FALSE); - EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, dst, EINA_FALSE); - - deep_copy = _eina_model_type_find_offset - (type, offsetof(Eina_Model_Type, deep_copy)); - EINA_SAFETY_ON_NULL_RETURN_VAL(deep_copy, EINA_FALSE); - - return deep_copy(src, dst); -} - -EAPI Eina_Bool -eina_model_type_compare(const Eina_Model_Type *type, const Eina_Model *a, const Eina_Model *b, int *cmp) -{ - Eina_Bool (*compare)(const Eina_Model *, const Eina_Model *, int *); - - EINA_SAFETY_ON_NULL_RETURN_VAL(cmp, EINA_FALSE); - *cmp = 0; - - EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, a, EINA_FALSE); - EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, b, EINA_FALSE); - - compare = _eina_model_type_find_offset - (type, offsetof(Eina_Model_Type, compare)); - EINA_SAFETY_ON_NULL_RETURN_VAL(compare, EINA_FALSE); - - return compare(a, b, cmp); -} - -EAPI Eina_Bool -eina_model_type_load(const Eina_Model_Type *type, Eina_Model *model) -{ - Eina_Bool (*load)(Eina_Model *); - - EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, EINA_FALSE); - - load = _eina_model_type_find_offset - (type, offsetof(Eina_Model_Type, load)); - EINA_SAFETY_ON_NULL_RETURN_VAL(load, EINA_FALSE); - - return load(model); -} - -EAPI Eina_Bool -eina_model_type_unload(const Eina_Model_Type *type, Eina_Model *model) -{ - Eina_Bool (*unload)(Eina_Model *); - - EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, EINA_FALSE); - - unload = _eina_model_type_find_offset - (type, offsetof(Eina_Model_Type, unload)); - EINA_SAFETY_ON_NULL_RETURN_VAL(unload, EINA_FALSE); - - return unload(model); -} - -EAPI Eina_Bool -eina_model_type_property_get(const Eina_Model_Type *type, const Eina_Model *model, const char *name, Eina_Value *value) -{ - Eina_Bool (*property_get)(const Eina_Model *, const char *, Eina_Value *); - - EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE); - EINA_SAFETY_ON_NULL_RETURN_VAL(value, EINA_FALSE); - - EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, EINA_FALSE); - - property_get = _eina_model_type_find_offset - (type, offsetof(Eina_Model_Type, property_get)); - EINA_SAFETY_ON_NULL_RETURN_VAL(property_get, EINA_FALSE); - - return property_get(model, name, value); -} - -EAPI Eina_Bool -eina_model_type_property_set(const Eina_Model_Type *type, Eina_Model *model, const char *name, const Eina_Value *value) -{ - Eina_Bool (*property_set)(Eina_Model *, const char *, const Eina_Value *); - - EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE); - EINA_SAFETY_ON_NULL_RETURN_VAL(value, EINA_FALSE); - EINA_SAFETY_ON_FALSE_RETURN_VAL(eina_value_type_check(value->type), EINA_FALSE); - - EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, EINA_FALSE); - - property_set = _eina_model_type_find_offset - (type, offsetof(Eina_Model_Type, property_set)); - EINA_SAFETY_ON_NULL_RETURN_VAL(property_set, EINA_FALSE); - - return property_set(model, name, value); -} - -EAPI Eina_Bool -eina_model_type_property_del(const Eina_Model_Type *type, Eina_Model *model, const char *name) -{ - Eina_Bool (*property_del)(const Eina_Model *, const char *); - - EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE); - EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, EINA_FALSE); - - property_del = _eina_model_type_find_offset - (type, offsetof(Eina_Model_Type, property_del)); - EINA_SAFETY_ON_NULL_RETURN_VAL(property_del, EINA_FALSE); - - return property_del(model, name); -} - -EAPI Eina_List * -eina_model_type_properties_names_list_get(const Eina_Model_Type *type, const Eina_Model *model) -{ - Eina_List *(*properties_names_list_get)(const Eina_Model *); - - EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, NULL); - - properties_names_list_get = _eina_model_type_find_offset - (type, offsetof(Eina_Model_Type, properties_names_list_get)); - EINA_SAFETY_ON_NULL_RETURN_VAL(properties_names_list_get, NULL); - - return properties_names_list_get(model); -} - -EAPI int -eina_model_type_child_count(const Eina_Model_Type *type, const Eina_Model *model) -{ - int (*child_count)(const Eina_Model *); - - EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, -1); - - child_count = _eina_model_type_find_offset - (type, offsetof(Eina_Model_Type, child_count)); - EINA_SAFETY_ON_NULL_RETURN_VAL(child_count, -1); - - return child_count(model); -} - -EAPI Eina_Model * -eina_model_type_child_get(const Eina_Model_Type *type, const Eina_Model *model, unsigned int position) -{ - Eina_Model *(*child_get)(const Eina_Model *, unsigned int); - - EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, NULL); - - child_get = _eina_model_type_find_offset - (type, offsetof(Eina_Model_Type, child_get)); - EINA_SAFETY_ON_NULL_RETURN_VAL(child_get, NULL); - - return child_get(model, position); -} - -EAPI Eina_Bool -eina_model_type_child_set(const Eina_Model_Type *type, Eina_Model *model, unsigned int position, Eina_Model *child) -{ - Eina_Bool (*child_set)(Eina_Model *, unsigned int, Eina_Model *); - - EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, EINA_FALSE); - EINA_MODEL_INSTANCE_CHECK_VAL(child, EINA_FALSE); - - child_set = _eina_model_type_find_offset - (type, offsetof(Eina_Model_Type, child_set)); - EINA_SAFETY_ON_NULL_RETURN_VAL(child_set, EINA_FALSE); - - return child_set(model, position, child); -} - -EAPI Eina_Bool -eina_model_type_child_del(const Eina_Model_Type *type, Eina_Model *model, unsigned int position) -{ - Eina_Bool (*child_del)(Eina_Model *, unsigned int); - - EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, EINA_FALSE); - - child_del = _eina_model_type_find_offset - (type, offsetof(Eina_Model_Type, child_del)); - EINA_SAFETY_ON_NULL_RETURN_VAL(child_del, EINA_FALSE); - - return child_del(model, position); -} - -EAPI Eina_Bool -eina_model_type_child_insert_at(const Eina_Model_Type *type, Eina_Model *model, unsigned int position, Eina_Model *child) -{ - Eina_Bool (*child_insert_at)(Eina_Model *, unsigned int, Eina_Model *); - - EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, EINA_FALSE); - EINA_MODEL_INSTANCE_CHECK_VAL(child, EINA_FALSE); - - child_insert_at = _eina_model_type_find_offset - (type, offsetof(Eina_Model_Type, child_insert_at)); - EINA_SAFETY_ON_NULL_RETURN_VAL(child_insert_at, EINA_FALSE); - - return child_insert_at(model, position, child); -} - -EAPI int -eina_model_type_child_find(const Eina_Model_Type *type, const Eina_Model *model, unsigned int start_position, const Eina_Model *other) -{ - int (*child_find)(const Eina_Model *, unsigned int, const Eina_Model *); - - EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, -1); - EINA_MODEL_INSTANCE_CHECK_VAL(other, -1); - - child_find = _eina_model_type_find_offset - (type, offsetof(Eina_Model_Type, child_find)); - EINA_SAFETY_ON_NULL_RETURN_VAL(child_find, -1); - - return child_find(model, start_position, other); -} - -EAPI int -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) -{ - int (*child_criteria_match)(const Eina_Model *, unsigned int, Eina_Each_Cb, const void *); - - EINA_SAFETY_ON_NULL_RETURN_VAL(match, -1); - EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, -1); - - child_criteria_match = _eina_model_type_find_offset - (type, offsetof(Eina_Model_Type, child_criteria_match)); - EINA_SAFETY_ON_NULL_RETURN_VAL(child_criteria_match, -1); - - return child_criteria_match(model, start_position, match, data); -} - -EAPI void -eina_model_type_child_sort(const Eina_Model_Type *type, Eina_Model *model, Eina_Compare_Cb compare) -{ - void (*child_sort)(Eina_Model *, Eina_Compare_Cb); - - EINA_SAFETY_ON_NULL_RETURN(compare); - EINA_MODEL_TYPE_INSTANCE_CHECK(type, model); - - child_sort = _eina_model_type_find_offset - (type, offsetof(Eina_Model_Type, child_sort)); - EINA_SAFETY_ON_NULL_RETURN(child_sort); - - return child_sort(model, compare); -} - -EAPI Eina_Iterator * -eina_model_type_child_iterator_get(const Eina_Model_Type *type, Eina_Model *model, unsigned int start, unsigned int count) -{ - Eina_Iterator *(*child_iterator_get)(const Eina_Model *, unsigned int, unsigned int); - - EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, NULL); - - child_iterator_get = _eina_model_type_find_offset - (type, offsetof(Eina_Model_Type, child_iterator_get)); - EINA_SAFETY_ON_NULL_RETURN_VAL(child_iterator_get, NULL); - - return child_iterator_get(model, start, count); -} - -EAPI Eina_Iterator * -eina_model_type_child_reversed_iterator_get(const Eina_Model_Type *type, Eina_Model *model, unsigned int start, unsigned int count) -{ - Eina_Iterator *(*child_reversed_iterator_get)(const Eina_Model *, unsigned int, unsigned int); - - EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, NULL); - - child_reversed_iterator_get = _eina_model_type_find_offset - (type, offsetof(Eina_Model_Type, child_reversed_iterator_get)); - EINA_SAFETY_ON_NULL_RETURN_VAL(child_reversed_iterator_get, NULL); - - return child_reversed_iterator_get(model, start, count); -} - -EAPI Eina_Iterator * -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) -{ - Eina_Iterator *(*child_sorted_iterator_get)(const Eina_Model *, unsigned int, unsigned int, Eina_Compare_Cb); - - EINA_SAFETY_ON_NULL_RETURN_VAL(compare, NULL); - EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, NULL); - - child_sorted_iterator_get = _eina_model_type_find_offset - (type, offsetof(Eina_Model_Type, child_sorted_iterator_get)); - EINA_SAFETY_ON_NULL_RETURN_VAL(child_sorted_iterator_get, NULL); - - return child_sorted_iterator_get(model, start, count, compare); -} - -EAPI Eina_Iterator * -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) -{ - Eina_Iterator *(*child_filtered_iterator_get)(const Eina_Model *, unsigned int, unsigned int, Eina_Each_Cb, const void *); - - EINA_SAFETY_ON_NULL_RETURN_VAL(match, NULL); - EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, NULL); - - child_filtered_iterator_get = _eina_model_type_find_offset - (type, offsetof(Eina_Model_Type, child_filtered_iterator_get)); - EINA_SAFETY_ON_NULL_RETURN_VAL(child_filtered_iterator_get, NULL); - - return child_filtered_iterator_get(model, start, count, match, data); -} - -EAPI char * -eina_model_type_to_string(const Eina_Model_Type *type, const Eina_Model *model) -{ - char *(*to_string)(const Eina_Model *); - - EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, NULL); - - to_string = _eina_model_type_find_offset - (type, offsetof(Eina_Model_Type, to_string)); - EINA_SAFETY_ON_NULL_RETURN_VAL(to_string, NULL); - - return to_string(model); -} - -EAPI Eina_Bool -eina_model_type_subclass_setup(Eina_Model_Type *type, const Eina_Model_Type *parent) -{ - EINA_SAFETY_ON_NULL_RETURN_VAL(type, EINA_FALSE); - EINA_SAFETY_ON_NULL_RETURN_VAL(parent, EINA_FALSE); - EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_type_check(parent), EINA_FALSE); - EINA_SAFETY_ON_FALSE_RETURN_VAL(type->version == EINA_MODEL_TYPE_VERSION, - EINA_FALSE); - - type->parent = parent; - type->type_size = parent->type_size; - type->interfaces = NULL; - type->events = NULL; - - type->setup = NULL; - type->flush = NULL; - type->constructor = NULL; - type->destructor = NULL; - type->copy = NULL; - type->deep_copy = NULL; - type->compare = NULL; - type->load = NULL; - type->unload = NULL; - type->property_get = NULL; - type->property_set = NULL; - type->property_del = NULL; - type->properties_names_list_get = NULL; - type->child_count = NULL; - type->child_get = NULL; - type->child_set = NULL; - type->child_del = NULL; - type->child_insert_at = NULL; - type->child_find = NULL; - type->child_criteria_match = NULL; - type->child_sort = NULL; - type->child_iterator_get = NULL; - type->child_reversed_iterator_get = NULL; - type->child_sorted_iterator_get = NULL; - type->child_filtered_iterator_get = NULL; - type->to_string = NULL; - type->__extension_ptr0 = NULL; - type->__extension_ptr1 = NULL; - type->__extension_ptr2 = NULL; - type->__extension_ptr3 = NULL; - - if (type->type_size > sizeof(Eina_Model_Type)) - { - unsigned char *p = (unsigned char *)type; - p += sizeof(Eina_Model_Type); - memset(p, 0, type->type_size - sizeof(Eina_Model_Type)); - } - - return EINA_TRUE; -} - -EAPI Eina_Bool -eina_model_type_subclass_check(const Eina_Model_Type *type, const Eina_Model_Type *self_or_parent) -{ - EINA_SAFETY_ON_NULL_RETURN_VAL(type, EINA_FALSE); - EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_type_check(type), EINA_FALSE); - EINA_SAFETY_ON_NULL_RETURN_VAL(self_or_parent, EINA_FALSE); - - for (; type != NULL; type = type->parent) - { - if (type == self_or_parent) - return EINA_TRUE; - } - - return EINA_FALSE; -} - -static inline const Eina_Model_Interface * -_eina_model_type_interface_get(const Eina_Model_Type *type, const char *name, Eina_Bool ptr_cmp __UNUSED__) -{ - const Eina_Model_Interface **itr; - - if (!type) - return NULL; - - if (!type->interfaces) - return _eina_model_type_interface_get(type->parent, name, ptr_cmp); - - { - for (itr = type->interfaces ; itr != NULL ; itr++) - if (strcmp((*itr)->name, name) == 0) - return *itr; - } - - return NULL; -} - -static inline Eina_Bool -_eina_model_interface_check(const Eina_Model_Interface *iface) -{ - EINA_SAFETY_ON_FALSE_RETURN_VAL - (iface->version == EINA_MODEL_INTERFACE_VERSION, EINA_FALSE); - return EINA_TRUE; -} - -EAPI const Eina_Model_Interface * -eina_model_type_interface_get(const Eina_Model_Type *type, const char *name) -{ - const Eina_Model_Interface *iface; - - EINA_SAFETY_ON_NULL_RETURN_VAL(type, NULL); - EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_type_check(type), NULL); - - /* search for pointer, make speed-aware users fast */ - iface = _eina_model_type_interface_get(type, name, EINA_TRUE); - - if (!iface) - { - /* search using strcmp(), slow users don't care */ - iface = _eina_model_type_interface_get(type, name, EINA_FALSE); - } - else if (!_eina_model_interface_check(iface)) - iface = NULL; - - return iface; -} - -EAPI void * -eina_model_type_private_data_get(const Eina_Model *model, const Eina_Model_Type *type) -{ - const Eina_Model_Description *desc; - unsigned int i; - - EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL); - EINA_SAFETY_ON_NULL_RETURN_VAL(type, NULL); - EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_type_check(type), NULL); - - desc = model->desc; - - for (i = 0; i < desc->total.types; i++) - if (desc->cache.types[i] == type) - return model->privates[i]; - - CRITICAL("Model %p (%s) is not an instance of type %p (%s)", - model, desc->cache.types[0]->name, - type, type->name); - return NULL; -} - -EAPI const void * -eina_model_method_offset_resolve(const Eina_Model *model, unsigned int offset) -{ - const Eina_Model_Description *desc; - - EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL); - EINA_SAFETY_ON_FALSE_RETURN_VAL(offset >= sizeof(Eina_Model_Type), NULL); - EINA_SAFETY_ON_FALSE_RETURN_VAL(offset % sizeof(void *) == 0, NULL); - - desc = model->desc; - EINA_SAFETY_ON_FALSE_RETURN_VAL - (offset + sizeof(void *) <= desc->cache.types[0]->type_size, NULL); - - offset -= sizeof(Eina_Model_Type); - offset /= sizeof(void *); - return desc->ops.type.extension[offset]; -} - -EAPI const void * -eina_model_type_method_offset_resolve(const Eina_Model_Type *type, const Eina_Model *model, unsigned int offset) -{ - const Eina_Model_Description *desc; - - EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, NULL); - EINA_SAFETY_ON_FALSE_RETURN_VAL(offset >= sizeof(Eina_Model_Type), NULL); - EINA_SAFETY_ON_FALSE_RETURN_VAL(offset % sizeof(void *) == 0, NULL); - - desc = model->desc; - EINA_SAFETY_ON_FALSE_RETURN_VAL - (offset + sizeof(void *) <= desc->cache.types[0]->type_size, NULL); - - return _eina_model_type_find_offset(type, offset); -} - -/* interface functions ************************************************/ - -EAPI Eina_Bool -eina_model_interface_check(const Eina_Model_Interface *iface) -{ - EINA_SAFETY_ON_NULL_RETURN_VAL(iface, EINA_FALSE); - return _eina_model_interface_check(iface); -} - -EAPI void * -eina_model_interface_private_data_get(const Eina_Model *model, const Eina_Model_Interface *iface) -{ - const Eina_Model_Description *desc; - unsigned int i; - - EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL); - EINA_SAFETY_ON_NULL_RETURN_VAL(iface, NULL); - EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_interface_check(iface), NULL); - - desc = model->desc; - - for (i = 0; i < desc->total.ifaces; i++) - if (desc->cache.ifaces[i] == iface) - return model->privates[desc->total.types + i]; - - CRITICAL("Model %p (%s) does not implement interface %p (%s)", - model, desc->cache.types[0]->name, - iface, iface->name); - return NULL; -} - -static Eina_Bool -_eina_model_interface_implemented(const Eina_Model *model, const Eina_Model_Interface *iface) -{ - const Eina_Model_Interface **itr, **itr_end; - - itr = model->desc->cache.ifaces; - itr_end = itr + model->desc->total.ifaces; - - for (; itr < itr_end; itr++) - if (*itr == iface) - return EINA_TRUE; - - return EINA_FALSE; -} - -EAPI Eina_Bool -eina_model_interface_implemented(const Eina_Model *model, const Eina_Model_Interface *iface) -{ - EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE); - EINA_SAFETY_ON_NULL_RETURN_VAL(iface, EINA_FALSE); - EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_interface_check(iface), - EINA_FALSE); - return _eina_model_interface_implemented(model, iface); -} - -#define EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK(iface, model) \ - EINA_SAFETY_ON_NULL_RETURN(iface); \ - EINA_SAFETY_ON_FALSE_RETURN(_eina_model_interface_check(iface)); \ - EINA_MODEL_INSTANCE_CHECK(model); \ - EINA_SAFETY_ON_FALSE_RETURN(_eina_model_interface_implemented(model, iface)); - -#define EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, retval) \ - EINA_SAFETY_ON_NULL_RETURN_VAL(iface, retval); \ - EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_interface_check(iface), retval); \ - EINA_MODEL_INSTANCE_CHECK_VAL(model, retval); \ - EINA_SAFETY_ON_FALSE_RETURN_VAL(_eina_model_interface_implemented(model, iface), retval); - - -EAPI Eina_Bool -eina_model_interface_constructor(const Eina_Model_Interface *iface, Eina_Model *model) -{ - Eina_Bool (*constructor)(Eina_Model *); - - EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE); - - constructor = _eina_model_interface_find_offset - (iface, offsetof(Eina_Model_Interface, constructor)); - EINA_SAFETY_ON_NULL_RETURN_VAL(constructor, EINA_FALSE); - return constructor(model); -} - -EAPI Eina_Bool -eina_model_interface_destructor(const Eina_Model_Interface *iface, Eina_Model *model) -{ - Eina_Bool (*destructor)(Eina_Model *); - - EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE); - - destructor = _eina_model_interface_find_offset - (iface, offsetof(Eina_Model_Interface, destructor)); - EINA_SAFETY_ON_NULL_RETURN_VAL(destructor, EINA_FALSE); - return destructor(model); -} - -EAPI Eina_Bool -eina_model_interface_copy(const Eina_Model_Interface *iface, const Eina_Model *src, Eina_Model *dst) -{ - Eina_Bool (*copy)(const Eina_Model *, Eina_Model *); - - EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, src, EINA_FALSE); - EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, dst, EINA_FALSE); - - copy = _eina_model_interface_find_offset - (iface, offsetof(Eina_Model_Interface, copy)); - EINA_SAFETY_ON_NULL_RETURN_VAL(copy, EINA_FALSE); - return copy(src, dst); -} - -EAPI Eina_Bool -eina_model_interface_deep_copy(const Eina_Model_Interface *iface, const Eina_Model *src, Eina_Model *dst) -{ - Eina_Bool (*deep_copy)(const Eina_Model *, Eina_Model *); - - EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, src, EINA_FALSE); - EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, dst, EINA_FALSE); - - deep_copy = _eina_model_interface_find_offset - (iface, offsetof(Eina_Model_Interface, deep_copy)); - EINA_SAFETY_ON_NULL_RETURN_VAL(deep_copy, EINA_FALSE); - return deep_copy(src, dst); -} - -EAPI const void -*eina_model_interface_method_offset_resolve(const Eina_Model_Interface *iface, const Eina_Model *model, unsigned int offset) -{ - EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, NULL); - EINA_SAFETY_ON_FALSE_RETURN_VAL(offset >= sizeof(Eina_Model_Interface), NULL); - EINA_SAFETY_ON_FALSE_RETURN_VAL(offset % sizeof(void *) == 0, NULL); - return _eina_model_interface_find_offset(iface, offset); -} - - -/* Eina_Model_Interface_Properties ************************************/ - -EAPI Eina_Bool -eina_model_interface_properties_compare(const Eina_Model_Interface *iface, const Eina_Model *a, const Eina_Model *b, int *cmp) -{ - Eina_Bool (*compare)(const Eina_Model *, const Eina_Model *, int *cmp); - - EINA_SAFETY_ON_NULL_RETURN_VAL(cmp, EINA_FALSE); - - *cmp = 0; - EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, a, EINA_FALSE); - EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, b, EINA_FALSE); - - compare = _eina_model_interface_find_offset - (iface, offsetof(Eina_Model_Interface_Properties, compare)); - EINA_SAFETY_ON_NULL_RETURN_VAL(compare, EINA_FALSE); - return compare(a, b, cmp); -} - -EAPI Eina_Bool -eina_model_interface_properties_load(const Eina_Model_Interface *iface, Eina_Model *model) -{ - Eina_Bool (*load)(Eina_Model *); - Eina_Bool ret; - - EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE); - - load = _eina_model_interface_find_offset - (iface, offsetof(Eina_Model_Interface_Properties, load)); - EINA_SAFETY_ON_NULL_RETURN_VAL(load, EINA_FALSE); - ret = load(model); - - if (ret) - _eina_model_event_callback_call - (model, _eina_model_str_properties_loaded, NULL); - - return ret; -} - -EAPI Eina_Bool -eina_model_interface_properties_unload(const Eina_Model_Interface *iface, Eina_Model *model) -{ - Eina_Bool (*unload)(Eina_Model *); - Eina_Bool ret; - - EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE); - - unload = _eina_model_interface_find_offset - (iface, offsetof(Eina_Model_Interface_Properties, unload)); - EINA_SAFETY_ON_NULL_RETURN_VAL(unload, EINA_FALSE); - ret = unload(model); - - if (ret) - _eina_model_event_callback_call - (model, _eina_model_str_properties_unloaded, NULL); - - return ret; -} - -EAPI Eina_Bool -eina_model_interface_properties_get(const Eina_Model_Interface *iface, const Eina_Model *model, const char *name, Eina_Value *value) -{ - Eina_Bool (*get)(const Eina_Model *, const char *, Eina_Value *); - - EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE); - EINA_SAFETY_ON_NULL_RETURN_VAL(value, EINA_FALSE); - EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE); - - get = _eina_model_interface_find_offset - (iface, offsetof(Eina_Model_Interface_Properties, get)); - EINA_SAFETY_ON_NULL_RETURN_VAL(get, EINA_FALSE); - return get(model, name, value); -} - -EAPI Eina_Bool -eina_model_interface_properties_set(const Eina_Model_Interface *iface, Eina_Model *model, const char *name, const Eina_Value *value) -{ - Eina_Bool (*set)(Eina_Model *, const char *, const Eina_Value *); - - EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE); - EINA_SAFETY_ON_NULL_RETURN_VAL(value, EINA_FALSE); - EINA_SAFETY_ON_FALSE_RETURN_VAL(eina_value_type_check(value->type), EINA_FALSE); - EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE); - - set = _eina_model_interface_find_offset - (iface, offsetof(Eina_Model_Interface_Properties, set)); - EINA_SAFETY_ON_NULL_RETURN_VAL(set, EINA_FALSE); - return set(model, name, value); -} - -EAPI Eina_Bool -eina_model_interface_properties_del(const Eina_Model_Interface *iface, Eina_Model *model, const char *name) -{ - Eina_Bool (*del)(Eina_Model *, const char *); - - EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE); - EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE); - - del = _eina_model_interface_find_offset - (iface, offsetof(Eina_Model_Interface_Properties, del)); - EINA_SAFETY_ON_NULL_RETURN_VAL(del, EINA_FALSE); - return del(model, name); -} - -EAPI Eina_List * -eina_model_interface_properties_names_list_get(const Eina_Model_Interface *iface, const Eina_Model *model) -{ - Eina_List *(*names_list_get)(const Eina_Model *); - - EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, NULL); - - names_list_get = _eina_model_interface_find_offset - (iface, offsetof(Eina_Model_Interface_Properties, names_list_get)); - EINA_SAFETY_ON_NULL_RETURN_VAL(names_list_get, NULL); - return names_list_get(model); -} - -/* Eina_Model_Interface_Children **************************************/ - -EAPI Eina_Bool -eina_model_interface_children_compare(const Eina_Model_Interface *iface, const Eina_Model *a, const Eina_Model *b, int *cmp) -{ - Eina_Bool (*compare)(const Eina_Model *, const Eina_Model *, int *); - - EINA_SAFETY_ON_NULL_RETURN_VAL(cmp, EINA_FALSE); - - *cmp = 0; - - EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, a, EINA_FALSE); - EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, b, EINA_FALSE); - - compare = _eina_model_interface_find_offset - (iface, offsetof(Eina_Model_Interface_Children, compare)); - EINA_SAFETY_ON_NULL_RETURN_VAL(compare, EINA_FALSE); - return compare(a, b, cmp); -} - -EAPI Eina_Bool -eina_model_interface_children_load(const Eina_Model_Interface *iface, Eina_Model *model) -{ - Eina_Bool (*load)(Eina_Model *); - Eina_Bool ret; - - EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE); - - load = _eina_model_interface_find_offset - (iface, offsetof(Eina_Model_Interface_Children, load)); - EINA_SAFETY_ON_NULL_RETURN_VAL(load, EINA_FALSE); - ret = load(model); - - if (ret) - _eina_model_event_callback_call - (model, _eina_model_str_children_loaded, NULL); - - return ret; -} - -EAPI Eina_Bool -eina_model_interface_children_unload(const Eina_Model_Interface *iface, Eina_Model *model) -{ - Eina_Bool (*unload)(Eina_Model *); - Eina_Bool ret; - - EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE); - - unload = _eina_model_interface_find_offset - (iface, offsetof(Eina_Model_Interface_Children, unload)); - EINA_SAFETY_ON_NULL_RETURN_VAL(unload, EINA_FALSE); - ret = unload(model); - - if (ret) - _eina_model_event_callback_call - (model, _eina_model_str_children_unloaded, NULL); - - return ret; -} - -EAPI int -eina_model_interface_children_count(const Eina_Model_Interface *iface, const Eina_Model *model) -{ - int (*count)(const Eina_Model *); - - EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, -1); - - count = _eina_model_interface_find_offset - (iface, offsetof(Eina_Model_Interface_Children, count)); - EINA_SAFETY_ON_NULL_RETURN_VAL(count, -1); - return count(model); -} - -EAPI Eina_Model * -eina_model_interface_children_get(const Eina_Model_Interface *iface, const Eina_Model *model, unsigned int position) -{ - Eina_Model *(*get)(const Eina_Model *, unsigned int); - - EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, NULL); - - get = _eina_model_interface_find_offset - (iface, offsetof(Eina_Model_Interface_Children, get)); - EINA_SAFETY_ON_NULL_RETURN_VAL(get, NULL); - return get(model, position); -} - -EAPI Eina_Bool eina_model_interface_children_set(const Eina_Model_Interface *iface, Eina_Model *model, unsigned int position, Eina_Model *child) -{ - Eina_Bool (*set)(const Eina_Model *, unsigned int, Eina_Model *); - - EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE); - EINA_MODEL_INSTANCE_CHECK_VAL(child, EINA_FALSE); - - set = _eina_model_interface_find_offset - (iface, offsetof(Eina_Model_Interface_Children, set)); - EINA_SAFETY_ON_NULL_RETURN_VAL(set, EINA_FALSE); - return set(model, position, child); -} - -EAPI Eina_Bool -eina_model_interface_children_del(const Eina_Model_Interface *iface, Eina_Model *model, unsigned int position) -{ - Eina_Bool (*del)(Eina_Model *, unsigned int); - - EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE); - - del = _eina_model_interface_find_offset - (iface, offsetof(Eina_Model_Interface_Children, del)); - EINA_SAFETY_ON_NULL_RETURN_VAL(del, EINA_FALSE); - return del(model, position); -} - - -EAPI Eina_Bool -eina_model_interface_children_insert_at(const Eina_Model_Interface *iface, Eina_Model *model, unsigned int position, Eina_Model *child) -{ - Eina_Bool (*insert_at)(const Eina_Model *, unsigned int, Eina_Model *); - - EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE); - EINA_MODEL_INSTANCE_CHECK_VAL(child, EINA_FALSE); - - insert_at = _eina_model_interface_find_offset - (iface, offsetof(Eina_Model_Interface_Children, insert_at)); - EINA_SAFETY_ON_NULL_RETURN_VAL(insert_at, EINA_FALSE); - return insert_at(model, position, child); -} - -EAPI void -eina_model_interface_children_sort(const Eina_Model_Interface *iface, Eina_Model *model, Eina_Compare_Cb compare) -{ - void (*sort)(const Eina_Model *, Eina_Compare_Cb); - - EINA_SAFETY_ON_NULL_RETURN(compare); - EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK(iface, model); - - sort = _eina_model_interface_find_offset - (iface, offsetof(Eina_Model_Interface_Children, sort)); - EINA_SAFETY_ON_NULL_RETURN(sort); - return sort(model, compare); -} - -static Eina_Bool -_eina_model_struct_set(Eina_Model *m, const Eina_Value_Struct_Desc *desc, void *memory) -{ - Eina_Value_Struct st = {desc, memory}; - Eina_Value *val = eina_model_interface_private_data_get - (m, &_EINA_MODEL_INTERFACE_PROPERTIES_STRUCT.base); - return eina_value_pset(val, &st); -} - -EAPI Eina_Model * -eina_model_struct_new(const Eina_Value_Struct_Desc *desc) -{ - Eina_Model *m; - - EINA_SAFETY_ON_NULL_RETURN_VAL(desc, NULL); - EINA_SAFETY_ON_FALSE_RETURN_VAL - (desc->version == EINA_VALUE_STRUCT_DESC_VERSION, NULL); - - m = eina_model_new(EINA_MODEL_TYPE_STRUCT); - EINA_SAFETY_ON_NULL_RETURN_VAL(m, NULL); - - EINA_SAFETY_ON_FALSE_GOTO(_eina_model_struct_set(m, desc, NULL), error); - return m; - - error: - eina_model_del(m); - return NULL; -} - -EAPI Eina_Model * -eina_model_type_struct_new(const Eina_Model_Type *type, const Eina_Value_Struct_Desc *desc) -{ - Eina_Model *m; - - EINA_SAFETY_ON_FALSE_RETURN_VAL - (eina_model_type_subclass_check(type, EINA_MODEL_TYPE_STRUCT), NULL); - EINA_SAFETY_ON_NULL_RETURN_VAL(desc, NULL); - EINA_SAFETY_ON_FALSE_RETURN_VAL - (desc->version == EINA_VALUE_STRUCT_DESC_VERSION, NULL); - - m = eina_model_new(type); - EINA_SAFETY_ON_NULL_RETURN_VAL(m, NULL); - - EINA_SAFETY_ON_FALSE_GOTO(_eina_model_struct_set(m, desc, NULL), error); - return m; - - error: - eina_model_del(m); - return NULL; -} - -EAPI Eina_Bool -eina_model_struct_set(Eina_Model *model, const Eina_Value_Struct_Desc *desc, void *memory) -{ - EINA_SAFETY_ON_NULL_RETURN_VAL(desc, EINA_FALSE); - EINA_SAFETY_ON_FALSE_RETURN_VAL - (desc->version == EINA_VALUE_STRUCT_DESC_VERSION, EINA_FALSE); - EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL - (&_EINA_MODEL_INTERFACE_PROPERTIES_STRUCT.base, model, EINA_FALSE); - - return _eina_model_struct_set(model, desc, memory); -} - -EAPI Eina_Bool -eina_model_struct_get(const Eina_Model *model, const Eina_Value_Struct_Desc **p_desc, void **p_memory) -{ - const Eina_Value *val; - Eina_Value_Struct st; - - EINA_SAFETY_ON_NULL_RETURN_VAL(p_desc, EINA_FALSE); - - *p_desc = NULL; - if (p_memory) *p_memory = NULL; - - EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL - (&_EINA_MODEL_INTERFACE_PROPERTIES_STRUCT.base, model, EINA_FALSE); - - val = eina_model_interface_private_data_get - (model, &_EINA_MODEL_INTERFACE_PROPERTIES_STRUCT.base); - - EINA_SAFETY_ON_FALSE_RETURN_VAL(eina_value_pget(val, &st), EINA_FALSE); - - *p_desc = st.desc; - if (p_memory) *p_memory = st.memory; - return EINA_FALSE; -} - -EAPI void -eina_models_usage_dump(void) -{ - const Eina_List *l; - const Eina_Model *m; - - eina_lock_take(&_eina_model_debug_list_lock); - - puts("DDD: model refs info (type, holders, backtrace)"); - puts("DDD: -------------- -------------- ---------------------------------"); - - EINA_LIST_FOREACH(_eina_model_debug_list, l, m) - { - Eina_Model_XRef *ref; - - printf("DDD: %14p %14d %s\n", - m, m->refcount, m->desc->cache.types[0]->name); - - EINA_INLIST_FOREACH(m->xrefs, ref) - { - printf("DDD: id: %p '%s'\n", - ref->id, ref->label); - if (ref->backtrace.count) - { - char **symbols; - unsigned int i; - -#ifdef HAVE_BACKTRACE_SYMBOLS - symbols = backtrace_symbols((void * const *)ref->backtrace.symbols, - ref->backtrace.count); -#else - symbols = NULL; -#endif - - printf("DDD: Backtrace: Address Symbol\n"); - for (i = 0; i < ref->backtrace.count; i++) - printf("DDD: %14p %s\n", - ref->backtrace.symbols[i], - symbols ? symbols[i] : "???"); - - free(symbols); - puts("DDD:"); - } - } - } - - eina_lock_release(&_eina_model_debug_list_lock); -} - -EAPI Eina_List * -eina_models_list_get(void) -{ - const Eina_List *l; - Eina_Model *m; - Eina_List *ret = NULL; - - eina_lock_take(&_eina_model_debug_list_lock); - - EINA_LIST_FOREACH(_eina_model_debug_list, l, m) - { - ret = eina_list_append - (ret, eina_model_xref - (m, eina_models_list_get, "eina_models_list_get")); - } - - eina_lock_release(&_eina_model_debug_list_lock); - - return ret; -} - -EAPI void -eina_models_list_free(Eina_List *list) -{ - Eina_Model *m; - - EINA_LIST_FREE(list, m) - eina_model_xunref(m, eina_models_list_get); -} -- cgit v1.1