2012-01-20 17:30:09 -08:00
|
|
|
/* 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 <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include "config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_ALLOCA_H
|
|
|
|
# include <alloca.h>
|
|
|
|
#elif defined __GNUC__
|
|
|
|
# define alloca __builtin_alloca
|
|
|
|
#elif defined _AIX
|
|
|
|
# define alloca __alloca
|
|
|
|
#elif defined _MSC_VER
|
|
|
|
# include <malloc.h>
|
|
|
|
# define alloca _alloca
|
|
|
|
#else
|
|
|
|
# include <stddef.h>
|
|
|
|
# ifdef __cplusplus
|
|
|
|
extern "C"
|
|
|
|
# endif
|
|
|
|
void *alloca (size_t);
|
|
|
|
#endif
|
|
|
|
|
2012-02-10 02:48:39 -08:00
|
|
|
#ifdef HAVE_EXECINFO_H
|
|
|
|
#include <execinfo.h>
|
|
|
|
#endif
|
|
|
|
|
2012-01-20 17:30:09 -08:00
|
|
|
#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;
|
2012-02-10 02:48:39 -08:00
|
|
|
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;
|
2012-01-20 17:30:09 -08:00
|
|
|
|
|
|
|
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";
|
2012-02-16 11:48:13 -08:00
|
|
|
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";
|
2012-01-20 17:30:09 -08:00
|
|
|
|
|
|
|
#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,
|
2012-06-16 18:51:27 -07:00
|
|
|
"Eina_Model_Inner_Mp", NULL, size, 16);
|
2012-01-20 17:30:09 -08:00
|
|
|
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);
|
2012-02-09 08:29:50 -08:00
|
|
|
int (*child_criteria_match)(const Eina_Model *model, unsigned int start_position, Eina_Each_Cb match, const void *data);
|
2012-01-20 17:30:09 -08:00
|
|
|
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 */
|
2012-01-31 07:26:48 -08:00
|
|
|
const void **extension;
|
2012-01-20 17:30:09 -08:00
|
|
|
} 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)
|
|
|
|
{
|
2012-01-31 07:26:48 -08:00
|
|
|
const Eina_Model_Type *itr, *last_itr = NULL;
|
|
|
|
unsigned int count, child_size = 0;
|
2012-01-20 17:30:09 -08:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2012-01-31 07:26:48 -08:00
|
|
|
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;
|
2012-01-20 17:30:09 -08:00
|
|
|
|
|
|
|
#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);
|
2012-02-09 08:29:50 -08:00
|
|
|
DEF_METH(child_criteria_match);
|
2012-01-20 17:30:09 -08:00
|
|
|
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
|
|
|
|
|
2012-01-31 07:26:48 -08:00
|
|
|
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];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-20 17:30:09 -08:00
|
|
|
desc->cache.types = malloc(count * sizeof(Eina_Model_Type *));
|
2012-01-31 07:26:48 -08:00
|
|
|
EINA_SAFETY_ON_NULL_GOTO(desc->cache.types, cache_types_failed);
|
2012-01-20 17:30:09 -08:00
|
|
|
desc->total.types = count;
|
|
|
|
|
|
|
|
for (count = 0, itr = type; itr != NULL; itr = itr->parent, count++)
|
|
|
|
desc->cache.types[count] = itr;
|
|
|
|
|
|
|
|
return EINA_TRUE;
|
2012-01-31 07:26:48 -08:00
|
|
|
|
|
|
|
cache_types_failed:
|
|
|
|
free(desc->ops.type.extension);
|
|
|
|
return EINA_FALSE;
|
2012-01-20 17:30:09 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
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 */
|
2012-03-06 04:35:24 -08:00
|
|
|
/*
|
|
|
|
* 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 :-)
|
|
|
|
*/
|
2012-01-20 17:30:09 -08:00
|
|
|
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;
|
2012-02-16 11:31:56 -08:00
|
|
|
unsigned int n_nodes = desc->total.ifaces, n_pending = 0, n_roots = 0, i, j;
|
2012-01-20 17:30:09 -08:00
|
|
|
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 */
|
2012-02-16 11:31:56 -08:00
|
|
|
for (i = 0, j = 0; i < n_nodes; i++)
|
2012-01-20 17:30:09 -08:00
|
|
|
{
|
2012-02-16 11:31:56 -08:00
|
|
|
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++;
|
2012-01-20 17:30:09 -08:00
|
|
|
}
|
2012-02-16 11:31:56 -08:00
|
|
|
n_nodes = j;
|
|
|
|
|
2012-01-20 17:30:09 -08:00
|
|
|
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;
|
|
|
|
|
2012-03-06 04:35:24 -08:00
|
|
|
/* TODO: sort roots using input order? Or at least study if
|
|
|
|
* it's enough to change roots append to prepend.
|
|
|
|
*
|
|
|
|
* See comments above.
|
|
|
|
*/
|
2012-01-20 17:30:09 -08:00
|
|
|
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);
|
2012-01-31 07:26:48 -08:00
|
|
|
free(desc->ops.type.extension);
|
2012-01-20 17:30:09 -08:00
|
|
|
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);
|
|
|
|
|
2012-01-31 07:26:48 -08:00
|
|
|
free(desc->ops.type.extension);
|
2012-01-20 17:30:09 -08:00
|
|
|
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;
|
2012-02-09 08:29:50 -08:00
|
|
|
Eina_Model_Event_Description_Cache criteria_match;
|
2012-01-20 17:30:09 -08:00
|
|
|
|
2012-02-09 08:29:50 -08:00
|
|
|
criteria_match.name = event_name;
|
|
|
|
cache = bsearch(&criteria_match, desc->cache.events, desc->total.events,
|
2012-01-20 17:30:09 -08:00
|
|
|
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 */
|
2012-02-10 02:48:39 -08:00
|
|
|
Eina_Inlist *xrefs; /**< if EINA_MODEL_DEBUG and eina_model_xref() is used */
|
2012-01-20 17:30:09 -08:00
|
|
|
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);
|
|
|
|
|
2012-01-31 07:26:48 -08:00
|
|
|
if (offset + sizeof(void *) > iface->interface_size) return NULL;
|
|
|
|
|
2012-01-20 17:30:09 -08:00
|
|
|
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
|
2012-02-09 08:29:50 -08:00
|
|
|
_eina_model_type_base_child_criteria_match(const Eina_Model *model, unsigned int start_position, Eina_Each_Cb match, const void *user_data)
|
2012-01-20 17:30:09 -08:00
|
|
|
{
|
|
|
|
int x = eina_model_child_count(model);
|
|
|
|
unsigned int i, count;
|
|
|
|
|
2012-02-09 08:29:50 -08:00
|
|
|
DBG("base child_criteria_match of %p, %d children", model, x);
|
2012-01-20 17:30:09 -08:00
|
|
|
|
|
|
|
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;
|
2012-02-10 02:48:39 -08:00
|
|
|
eina_model_xunref(it->model, it);
|
2012-01-20 17:30:09 -08:00
|
|
|
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;
|
|
|
|
|
2012-02-10 02:48:39 -08:00
|
|
|
it->model = eina_model_xref(model, it, "eina_model_child_slice_iterator_get");
|
2012-01-20 17:30:09 -08:00
|
|
|
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;
|
2012-02-10 02:48:39 -08:00
|
|
|
eina_model_xunref(it->model, it);
|
2012-01-20 17:30:09 -08:00
|
|
|
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;
|
|
|
|
|
2012-02-10 02:48:39 -08:00
|
|
|
it->model = eina_model_xref(model, it, "eina_model_child_slice_reversed_iterator_get");
|
2012-01-20 17:30:09 -08:00
|
|
|
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;
|
2012-02-10 02:48:39 -08:00
|
|
|
eina_model_xunref(it->model, it);
|
2012-01-20 17:30:09 -08:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2012-02-10 02:48:39 -08:00
|
|
|
it->model = eina_model_xref(model, it, "eina_model_child_slice_sorted_iterator_get");
|
2012-01-20 17:30:09 -08:00
|
|
|
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;
|
|
|
|
|
2012-02-02 04:32:13 -08:00
|
|
|
i = eina_model_child_criteria_match(it->model, it->current, it->match, it->data);
|
2012-01-20 17:30:09 -08:00
|
|
|
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;
|
2012-02-10 02:48:39 -08:00
|
|
|
eina_model_xunref(it->model, it);
|
2012-01-20 17:30:09 -08:00
|
|
|
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;
|
|
|
|
|
2012-02-10 02:48:39 -08:00
|
|
|
it->model = eina_model_xref(model, it, "eina_model_child_slice_filtered_iterator_get");
|
2012-01-20 17:30:09 -08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2012-01-26 08:42:00 -08:00
|
|
|
eina_list_free(props);
|
2012-01-20 17:30:09 -08:00
|
|
|
|
|
|
|
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."),
|
2012-02-16 11:48:13 -08:00
|
|
|
EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_loaded, "", "model was loaded"),
|
|
|
|
EINA_MODEL_EVENT_DESCRIPTION(_eina_model_str_unloaded, "", "model was unloaded"),
|
2012-01-20 17:30:09 -08:00
|
|
|
EINA_MODEL_EVENT_DESCRIPTION_SENTINEL
|
|
|
|
};
|
|
|
|
|
|
|
|
static const Eina_Model_Type _EINA_MODEL_TYPE_BASE = {
|
|
|
|
EINA_MODEL_TYPE_VERSION,
|
|
|
|
0, /* there is no private data */
|
2012-01-31 07:26:48 -08:00
|
|
|
sizeof(Eina_Model_Type),
|
2012-01-20 17:30:09 -08:00
|
|
|
"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,
|
2012-02-09 08:29:50 -08:00
|
|
|
_eina_model_type_base_child_criteria_match,
|
2012-01-20 17:30:09 -08:00
|
|
|
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,
|
2012-01-31 07:26:48 -08:00
|
|
|
NULL, /* extension pointer */
|
|
|
|
NULL, /* extension pointer */
|
|
|
|
NULL, /* extension pointer */
|
|
|
|
NULL /* extension pointer */
|
2012-01-20 17:30:09 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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 *) =
|
2012-01-31 07:26:48 -08:00
|
|
|
_eina_model_interface_find_offset
|
2012-01-20 17:30:09 -08:00
|
|
|
(priv->if_properties,
|
|
|
|
offsetof(Eina_Model_Interface_Properties, compare));
|
|
|
|
|
|
|
|
if (compare)
|
|
|
|
{
|
|
|
|
ret &= compare(a, b, cmp);
|
|
|
|
did_prop = EINA_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-23 08:51:02 -08:00
|
|
|
if ((ret) && (*cmp == 0))
|
2012-01-20 17:30:09 -08:00
|
|
|
{
|
|
|
|
if (priv->if_children)
|
|
|
|
{
|
|
|
|
Eina_Bool (*compare)(const Eina_Model*, const Eina_Model*, int *) =
|
2012-01-31 07:26:48 -08:00
|
|
|
_eina_model_interface_find_offset
|
2012-01-20 17:30:09 -08:00
|
|
|
(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),
|
2012-01-31 07:26:48 -08:00
|
|
|
sizeof(Eina_Model_Type),
|
2012-01-20 17:30:09 -08:00
|
|
|
"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 */
|
2012-02-09 08:29:50 -08:00
|
|
|
NULL, /* use default criteria_match */
|
2012-01-20 17:30:09 -08:00
|
|
|
_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 */
|
2012-01-31 07:26:48 -08:00
|
|
|
NULL, /* extension pointer */
|
|
|
|
NULL, /* extension pointer */
|
|
|
|
NULL, /* extension pointer */
|
|
|
|
NULL /* extension pointer */
|
2012-01-20 17:30:09 -08:00
|
|
|
};
|
|
|
|
#undef EINA_MODEL_TYPE_MIXIN_GET
|
|
|
|
|
2012-02-16 11:48:13 -08:00
|
|
|
/* 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
|
|
|
|
};
|
2012-01-20 17:30:09 -08:00
|
|
|
|
|
|
|
/* 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
|
|
|
|
|
2012-01-31 07:26:48 -08:00
|
|
|
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 */
|
2012-02-16 11:48:13 -08:00
|
|
|
_eina_model_interface_properties_events,
|
2012-01-31 07:26:48 -08:00
|
|
|
_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
|
|
|
|
},
|
2012-01-20 17:30:09 -08:00
|
|
|
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
|
|
|
|
};
|
|
|
|
|
2012-01-24 14:17:57 -08:00
|
|
|
/* 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);
|
2012-02-08 07:13:25 -08:00
|
|
|
return eina_value_memory_get(val);
|
2012-01-24 14:17:57 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
#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)
|
|
|
|
{
|
2012-01-24 14:56:17 -08:00
|
|
|
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);
|
2012-01-24 14:17:57 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
static Eina_Bool
|
|
|
|
_eina_model_interface_properties_struct_set(Eina_Model *model, const char *name, const Eina_Value *val)
|
|
|
|
{
|
2012-01-24 14:56:17 -08:00
|
|
|
Eina_Value *v = eina_model_interface_private_data_get
|
|
|
|
(model, EINA_MODEL_INTERFACE_PROPERTIES_STRUCT);
|
|
|
|
return eina_value_struct_value_set(v, name, val);
|
2012-01-24 14:17:57 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
|
2012-01-31 07:26:48 -08:00
|
|
|
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 */
|
2012-02-16 11:48:13 -08:00
|
|
|
_eina_model_interface_properties_events,
|
2012-01-31 07:26:48 -08:00
|
|
|
_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
|
|
|
|
},
|
2012-01-24 14:17:57 -08:00
|
|
|
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
|
|
|
|
};
|
|
|
|
|
2012-02-16 11:48:13 -08:00
|
|
|
/* 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
|
|
|
|
};
|
|
|
|
|
2012-01-20 17:30:09 -08:00
|
|
|
/* 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++)
|
2012-02-10 02:48:39 -08:00
|
|
|
eina_model_xunref(*itr, EINA_MODEL_INTERFACE_CHILDREN_INARRAY);
|
2012-01-20 17:30:09 -08:00
|
|
|
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;
|
|
|
|
|
2012-02-10 02:48:39 -08:00
|
|
|
eina_model_xref(child, EINA_MODEL_INTERFACE_CHILDREN_INARRAY,
|
|
|
|
"eina_model_child_set");
|
|
|
|
eina_model_xunref(old, EINA_MODEL_INTERFACE_CHILDREN_INARRAY);
|
2012-01-20 17:30:09 -08:00
|
|
|
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;
|
|
|
|
|
2012-02-10 02:48:39 -08:00
|
|
|
eina_model_xunref(old, EINA_MODEL_INTERFACE_CHILDREN_INARRAY);
|
2012-01-20 17:30:09 -08:00
|
|
|
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;
|
|
|
|
|
2012-02-10 02:48:39 -08:00
|
|
|
eina_model_xref(child, EINA_MODEL_INTERFACE_CHILDREN_INARRAY,
|
|
|
|
"eina_model_child_insert_at");
|
2012-01-20 17:30:09 -08:00
|
|
|
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
|
|
|
|
|
2012-01-31 07:26:48 -08:00
|
|
|
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 */
|
2012-02-16 11:48:13 -08:00
|
|
|
_eina_model_interface_children_events,
|
2012-01-31 07:26:48 -08:00
|
|
|
_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
|
|
|
|
},
|
2012-01-20 17:30:09 -08:00
|
|
|
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[] = {
|
2012-01-31 07:26:48 -08:00
|
|
|
&_EINA_MODEL_INTERFACE_PROPERTIES_HASH.base,
|
|
|
|
&_EINA_MODEL_INTERFACE_CHILDREN_INARRAY.base,
|
2012-01-20 17:30:09 -08:00
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
2012-01-31 07:26:48 -08:00
|
|
|
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);
|
2012-01-20 17:30:09 -08:00
|
|
|
|
2012-01-24 14:17:57 -08:00
|
|
|
/* EINA_MODEL_TYPE_STRUCT ********************************************/
|
|
|
|
|
|
|
|
static const Eina_Model_Interface *_EINA_MODEL_TYPE_STRUCT_IFACES[] = {
|
2012-01-31 07:26:48 -08:00
|
|
|
&_EINA_MODEL_INTERFACE_PROPERTIES_STRUCT.base,
|
|
|
|
&_EINA_MODEL_INTERFACE_CHILDREN_INARRAY.base,
|
2012-01-24 14:17:57 -08:00
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
2012-01-31 07:26:48 -08:00
|
|
|
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);
|
2012-01-24 14:17:57 -08:00
|
|
|
|
2012-01-20 17:30:09 -08:00
|
|
|
/**
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @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;
|
|
|
|
}
|
|
|
|
|
2012-02-10 02:48:39 -08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-01-20 17:30:09 -08:00
|
|
|
#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
|
2012-06-16 18:51:27 -07:00
|
|
|
(_eina_model_mp_choice, "model", NULL, sizeof(Eina_Model), 32);
|
2012-01-20 17:30:09 -08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-02-10 02:48:39 -08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-01-20 17:30:09 -08:00
|
|
|
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;
|
2012-01-24 14:17:57 -08:00
|
|
|
EINA_MODEL_TYPE_STRUCT = &_EINA_MODEL_TYPE_STRUCT;
|
2012-01-20 17:30:09 -08:00
|
|
|
|
2012-01-31 07:26:48 -08:00
|
|
|
EINA_MODEL_INTERFACE_PROPERTIES_HASH = &_EINA_MODEL_INTERFACE_PROPERTIES_HASH.base;
|
|
|
|
EINA_MODEL_INTERFACE_PROPERTIES_STRUCT = &_EINA_MODEL_INTERFACE_PROPERTIES_STRUCT.base;
|
2012-01-20 17:30:09 -08:00
|
|
|
|
2012-01-31 07:26:48 -08:00
|
|
|
EINA_MODEL_INTERFACE_CHILDREN_INARRAY = &_EINA_MODEL_INTERFACE_CHILDREN_INARRAY.base;
|
2012-01-20 17:30:09 -08:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2012-02-10 02:48:39 -08:00
|
|
|
on_init_fail_lock_debug:
|
|
|
|
eina_hash_free(_eina_model_descriptions);
|
2012-01-20 17:30:09 -08:00
|
|
|
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)
|
|
|
|
{
|
2012-02-10 02:48:39 -08:00
|
|
|
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);
|
|
|
|
|
2012-01-20 17:30:09 -08:00
|
|
|
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;
|
2012-01-24 14:17:57 -08:00
|
|
|
EAPI const Eina_Model_Type *EINA_MODEL_TYPE_STRUCT = NULL;
|
2012-01-20 17:30:09 -08:00
|
|
|
|
|
|
|
EAPI const Eina_Model_Interface *EINA_MODEL_INTERFACE_PROPERTIES_HASH = NULL;
|
2012-01-24 14:17:57 -08:00
|
|
|
EAPI const Eina_Model_Interface *EINA_MODEL_INTERFACE_PROPERTIES_STRUCT = NULL;
|
2012-01-20 17:30:09 -08:00
|
|
|
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;
|
2012-02-10 02:48:39 -08:00
|
|
|
model->xrefs = NULL;
|
2012-01-20 17:30:09 -08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-02-10 02:48:39 -08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2012-01-20 17:30:09 -08:00
|
|
|
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;
|
|
|
|
|
2012-02-17 12:53:36 -08:00
|
|
|
DBG("model %p (%s) refcount=%d deleted=%hhu",
|
2012-01-20 17:30:09 -08:00
|
|
|
model, model->desc->cache.types[0]->name,
|
|
|
|
model->refcount, model->deleted);
|
|
|
|
|
2012-02-10 02:48:39 -08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2012-01-20 17:30:09 -08:00
|
|
|
/* 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;
|
|
|
|
|
2012-02-17 12:53:36 -08:00
|
|
|
DBG("model %p (%s) refcount=%d deleted=%hhu",
|
2012-01-20 17:30:09 -08:00
|
|
|
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)
|
|
|
|
{
|
2012-02-17 12:53:36 -08:00
|
|
|
DBG("model %p (%s) refcount=%d deleted=%hhu",
|
2012-01-20 17:30:09 -08:00
|
|
|
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;
|
2012-02-16 11:30:23 -08:00
|
|
|
const Eina_Model_Interface **itr, **itr_end;
|
2012-01-20 17:30:09 -08:00
|
|
|
|
|
|
|
EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL);
|
|
|
|
|
|
|
|
desc = model->desc;
|
2012-02-16 11:30:23 -08:00
|
|
|
itr = desc->cache.ifaces;
|
|
|
|
itr_end = itr + desc->total.ifaces;
|
2012-01-20 17:30:09 -08:00
|
|
|
|
|
|
|
/* fallback to strcmp if user is lazy about speed */
|
2012-02-16 11:30:23 -08:00
|
|
|
for (; itr < itr_end; itr++)
|
2012-01-20 17:30:09 -08:00
|
|
|
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);
|
2012-02-17 12:53:36 -08:00
|
|
|
DBG("model %p (%s) refcount=%d deleted=%hhu",
|
2012-01-20 17:30:09 -08:00
|
|
|
model, model->desc->cache.types[0]->name,
|
|
|
|
model->refcount, model->deleted);
|
|
|
|
model->refcount++;
|
|
|
|
return model;
|
|
|
|
}
|
|
|
|
|
2012-02-10 02:48:39 -08:00
|
|
|
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);
|
2012-02-17 12:53:36 -08:00
|
|
|
DBG("model %p (%s) refcount=%d deleted=%hhu id=%p label=%s",
|
2012-02-10 02:48:39 -08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2012-01-20 17:30:09 -08:00
|
|
|
EAPI void
|
|
|
|
eina_model_unref(Eina_Model *model)
|
|
|
|
{
|
|
|
|
EINA_MODEL_INSTANCE_CHECK(model);
|
|
|
|
_eina_model_unref(model);
|
|
|
|
}
|
|
|
|
|
2012-02-10 02:48:39 -08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2012-01-20 17:30:09 -08:00
|
|
|
EAPI int
|
|
|
|
eina_model_refcount(const Eina_Model *model)
|
|
|
|
{
|
|
|
|
EINA_MODEL_INSTANCE_CHECK_VAL(model, -1);
|
|
|
|
return model->refcount;
|
|
|
|
}
|
|
|
|
|
2012-02-10 02:48:39 -08:00
|
|
|
EAPI const Eina_Inlist *
|
|
|
|
eina_model_xrefs_get(const Eina_Model *model)
|
|
|
|
{
|
|
|
|
EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
|
|
|
|
return model->xrefs;
|
|
|
|
}
|
|
|
|
|
2012-01-20 17:30:09 -08:00
|
|
|
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;
|
2012-01-20 22:26:32 -08:00
|
|
|
el->deleted = EINA_FALSE;
|
2012-01-20 17:30:09 -08:00
|
|
|
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)
|
|
|
|
{
|
2012-02-16 11:48:13 -08:00
|
|
|
Eina_Bool ret;
|
|
|
|
|
2012-01-20 17:30:09 -08:00
|
|
|
EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE);
|
2012-02-16 11:48:13 -08:00
|
|
|
|
|
|
|
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;
|
2012-01-20 17:30:09 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
EAPI Eina_Bool
|
|
|
|
eina_model_unload(Eina_Model *model)
|
|
|
|
{
|
2012-02-16 11:48:13 -08:00
|
|
|
Eina_Bool ret;
|
|
|
|
|
2012-01-20 17:30:09 -08:00
|
|
|
EINA_MODEL_INSTANCE_CHECK_VAL(model, EINA_FALSE);
|
2012-02-16 11:48:13 -08:00
|
|
|
|
|
|
|
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;
|
2012-01-20 17:30:09 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
2012-02-02 04:32:13 -08:00
|
|
|
eina_model_child_criteria_match(const Eina_Model *model, unsigned int start_position, Eina_Each_Cb match, const void *data)
|
2012-01-20 17:30:09 -08:00
|
|
|
{
|
|
|
|
EINA_MODEL_INSTANCE_CHECK_VAL(model, -1);
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(match, -1);
|
2012-02-09 08:29:50 -08:00
|
|
|
EINA_MODEL_TYPE_CALL_RETURN(model, child_criteria_match, -1,
|
2012-01-20 17:30:09 -08:00
|
|
|
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
|
2012-02-09 08:29:50 -08:00
|
|
|
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)
|
2012-01-20 17:30:09 -08:00
|
|
|
{
|
2012-02-09 08:29:50 -08:00
|
|
|
int (*child_criteria_match)(const Eina_Model *, unsigned int, Eina_Each_Cb, const void *);
|
2012-01-20 17:30:09 -08:00
|
|
|
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(match, -1);
|
|
|
|
EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, -1);
|
|
|
|
|
2012-02-09 08:29:50 -08:00
|
|
|
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);
|
2012-01-20 17:30:09 -08:00
|
|
|
|
2012-02-09 08:29:50 -08:00
|
|
|
return child_criteria_match(model, start_position, match, data);
|
2012-01-20 17:30:09 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2012-02-09 08:20:16 -08:00
|
|
|
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;
|
2012-02-09 08:29:50 -08:00
|
|
|
type->child_criteria_match = NULL;
|
2012-02-09 08:20:16 -08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-01-20 17:30:09 -08:00
|
|
|
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 *
|
2012-02-14 01:48:00 -08:00
|
|
|
_eina_model_type_interface_get(const Eina_Model_Type *type, const char *name, Eina_Bool ptr_cmp __UNUSED__)
|
2012-01-20 17:30:09 -08:00
|
|
|
{
|
|
|
|
const Eina_Model_Interface **itr;
|
|
|
|
|
|
|
|
if (!type)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (!type->interfaces)
|
|
|
|
return _eina_model_type_interface_get(type->parent, name, ptr_cmp);
|
|
|
|
|
|
|
|
{
|
2012-02-14 01:48:00 -08:00
|
|
|
for (itr = type->interfaces ; itr != NULL ; itr++)
|
2012-01-20 17:30:09 -08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-01-31 07:26:48 -08:00
|
|
|
EAPI const void *
|
2012-02-08 07:37:07 -08:00
|
|
|
eina_model_method_offset_resolve(const Eina_Model *model, unsigned int offset)
|
2012-01-31 07:26:48 -08:00
|
|
|
{
|
|
|
|
const Eina_Model_Description *desc;
|
|
|
|
|
|
|
|
EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
|
2012-02-07 05:17:13 -08:00
|
|
|
EINA_SAFETY_ON_FALSE_RETURN_VAL(offset >= sizeof(Eina_Model_Type), NULL);
|
2012-01-31 07:26:48 -08:00
|
|
|
EINA_SAFETY_ON_FALSE_RETURN_VAL(offset % sizeof(void *) == 0, NULL);
|
|
|
|
|
|
|
|
desc = model->desc;
|
|
|
|
EINA_SAFETY_ON_FALSE_RETURN_VAL
|
2012-02-07 05:24:27 -08:00
|
|
|
(offset + sizeof(void *) <= desc->cache.types[0]->type_size, NULL);
|
2012-01-31 07:26:48 -08:00
|
|
|
|
|
|
|
offset -= sizeof(Eina_Model_Type);
|
|
|
|
offset /= sizeof(void *);
|
|
|
|
return desc->ops.type.extension[offset];
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI const void *
|
2012-02-08 07:37:07 -08:00
|
|
|
eina_model_type_method_offset_resolve(const Eina_Model_Type *type, const Eina_Model *model, unsigned int offset)
|
2012-01-31 07:26:48 -08:00
|
|
|
{
|
|
|
|
const Eina_Model_Description *desc;
|
|
|
|
|
|
|
|
EINA_MODEL_TYPE_INSTANCE_CHECK_VAL(type, model, NULL);
|
2012-02-07 05:17:13 -08:00
|
|
|
EINA_SAFETY_ON_FALSE_RETURN_VAL(offset >= sizeof(Eina_Model_Type), NULL);
|
2012-01-31 07:26:48 -08:00
|
|
|
EINA_SAFETY_ON_FALSE_RETURN_VAL(offset % sizeof(void *) == 0, NULL);
|
|
|
|
|
|
|
|
desc = model->desc;
|
|
|
|
EINA_SAFETY_ON_FALSE_RETURN_VAL
|
2012-02-07 05:24:27 -08:00
|
|
|
(offset + sizeof(void *) <= desc->cache.types[0]->type_size, NULL);
|
2012-01-31 07:26:48 -08:00
|
|
|
|
|
|
|
return _eina_model_type_find_offset(type, offset);
|
|
|
|
}
|
|
|
|
|
2012-01-20 17:30:09 -08:00
|
|
|
/* 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);
|
|
|
|
}
|
|
|
|
|
2012-02-09 02:32:14 -08:00
|
|
|
EAPI const void
|
|
|
|
*eina_model_interface_method_offset_resolve(const Eina_Model_Interface *iface, const Eina_Model *model, unsigned int offset)
|
2012-01-31 07:26:48 -08:00
|
|
|
{
|
|
|
|
EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, NULL);
|
2012-02-07 05:17:13 -08:00
|
|
|
EINA_SAFETY_ON_FALSE_RETURN_VAL(offset >= sizeof(Eina_Model_Interface), NULL);
|
2012-01-31 07:26:48 -08:00
|
|
|
EINA_SAFETY_ON_FALSE_RETURN_VAL(offset % sizeof(void *) == 0, NULL);
|
|
|
|
return _eina_model_interface_find_offset(iface, offset);
|
|
|
|
}
|
|
|
|
|
2012-01-20 17:30:09 -08:00
|
|
|
|
|
|
|
/* 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);
|
|
|
|
|
2012-01-31 07:26:48 -08:00
|
|
|
compare = _eina_model_interface_find_offset
|
2012-01-20 17:30:09 -08:00
|
|
|
(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 *);
|
2012-02-16 11:48:13 -08:00
|
|
|
Eina_Bool ret;
|
2012-01-20 17:30:09 -08:00
|
|
|
|
|
|
|
EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE);
|
|
|
|
|
2012-01-31 07:26:48 -08:00
|
|
|
load = _eina_model_interface_find_offset
|
2012-01-20 17:30:09 -08:00
|
|
|
(iface, offsetof(Eina_Model_Interface_Properties, load));
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(load, EINA_FALSE);
|
2012-02-16 11:48:13 -08:00
|
|
|
ret = load(model);
|
|
|
|
|
|
|
|
if (ret)
|
|
|
|
_eina_model_event_callback_call
|
|
|
|
(model, _eina_model_str_properties_loaded, NULL);
|
|
|
|
|
|
|
|
return ret;
|
2012-01-20 17:30:09 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
EAPI Eina_Bool
|
|
|
|
eina_model_interface_properties_unload(const Eina_Model_Interface *iface, Eina_Model *model)
|
|
|
|
{
|
|
|
|
Eina_Bool (*unload)(Eina_Model *);
|
2012-02-16 11:48:13 -08:00
|
|
|
Eina_Bool ret;
|
2012-01-20 17:30:09 -08:00
|
|
|
|
|
|
|
EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE);
|
|
|
|
|
2012-01-31 07:26:48 -08:00
|
|
|
unload = _eina_model_interface_find_offset
|
2012-01-20 17:30:09 -08:00
|
|
|
(iface, offsetof(Eina_Model_Interface_Properties, unload));
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(unload, EINA_FALSE);
|
2012-02-16 11:48:13 -08:00
|
|
|
ret = unload(model);
|
|
|
|
|
|
|
|
if (ret)
|
|
|
|
_eina_model_event_callback_call
|
|
|
|
(model, _eina_model_str_properties_unloaded, NULL);
|
|
|
|
|
|
|
|
return ret;
|
2012-01-20 17:30:09 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
2012-01-31 07:26:48 -08:00
|
|
|
get = _eina_model_interface_find_offset
|
2012-01-20 17:30:09 -08:00
|
|
|
(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);
|
|
|
|
|
2012-01-31 07:26:48 -08:00
|
|
|
set = _eina_model_interface_find_offset
|
2012-01-20 17:30:09 -08:00
|
|
|
(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);
|
|
|
|
|
2012-01-31 07:26:48 -08:00
|
|
|
del = _eina_model_interface_find_offset
|
2012-01-20 17:30:09 -08:00
|
|
|
(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);
|
|
|
|
|
2012-01-31 07:26:48 -08:00
|
|
|
names_list_get = _eina_model_interface_find_offset
|
2012-01-20 17:30:09 -08:00
|
|
|
(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);
|
|
|
|
|
2012-01-31 07:26:48 -08:00
|
|
|
compare = _eina_model_interface_find_offset
|
2012-01-20 17:30:09 -08:00
|
|
|
(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 *);
|
2012-02-16 11:48:13 -08:00
|
|
|
Eina_Bool ret;
|
2012-01-20 17:30:09 -08:00
|
|
|
|
|
|
|
EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE);
|
|
|
|
|
2012-01-31 07:26:48 -08:00
|
|
|
load = _eina_model_interface_find_offset
|
2012-01-20 17:30:09 -08:00
|
|
|
(iface, offsetof(Eina_Model_Interface_Children, load));
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(load, EINA_FALSE);
|
2012-02-16 11:48:13 -08:00
|
|
|
ret = load(model);
|
|
|
|
|
|
|
|
if (ret)
|
|
|
|
_eina_model_event_callback_call
|
|
|
|
(model, _eina_model_str_children_loaded, NULL);
|
|
|
|
|
|
|
|
return ret;
|
2012-01-20 17:30:09 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
EAPI Eina_Bool
|
|
|
|
eina_model_interface_children_unload(const Eina_Model_Interface *iface, Eina_Model *model)
|
|
|
|
{
|
|
|
|
Eina_Bool (*unload)(Eina_Model *);
|
2012-02-16 11:48:13 -08:00
|
|
|
Eina_Bool ret;
|
2012-01-20 17:30:09 -08:00
|
|
|
|
|
|
|
EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL(iface, model, EINA_FALSE);
|
|
|
|
|
2012-01-31 07:26:48 -08:00
|
|
|
unload = _eina_model_interface_find_offset
|
2012-01-20 17:30:09 -08:00
|
|
|
(iface, offsetof(Eina_Model_Interface_Children, unload));
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(unload, EINA_FALSE);
|
2012-02-16 11:48:13 -08:00
|
|
|
ret = unload(model);
|
|
|
|
|
|
|
|
if (ret)
|
|
|
|
_eina_model_event_callback_call
|
|
|
|
(model, _eina_model_str_children_unloaded, NULL);
|
|
|
|
|
|
|
|
return ret;
|
2012-01-20 17:30:09 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
2012-01-31 07:26:48 -08:00
|
|
|
count = _eina_model_interface_find_offset
|
2012-01-20 17:30:09 -08:00
|
|
|
(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);
|
|
|
|
|
2012-01-31 07:26:48 -08:00
|
|
|
get = _eina_model_interface_find_offset
|
2012-01-20 17:30:09 -08:00
|
|
|
(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);
|
|
|
|
|
2012-01-31 07:26:48 -08:00
|
|
|
set = _eina_model_interface_find_offset
|
2012-01-20 17:30:09 -08:00
|
|
|
(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);
|
|
|
|
|
2012-01-31 07:26:48 -08:00
|
|
|
del = _eina_model_interface_find_offset
|
2012-01-20 17:30:09 -08:00
|
|
|
(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);
|
|
|
|
|
2012-01-31 07:26:48 -08:00
|
|
|
insert_at = _eina_model_interface_find_offset
|
2012-01-20 17:30:09 -08:00
|
|
|
(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);
|
|
|
|
|
2012-01-31 07:26:48 -08:00
|
|
|
sort = _eina_model_interface_find_offset
|
2012-01-20 17:30:09 -08:00
|
|
|
(iface, offsetof(Eina_Model_Interface_Children, sort));
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN(sort);
|
|
|
|
return sort(model, compare);
|
|
|
|
}
|
2012-01-24 14:17:57 -08:00
|
|
|
|
|
|
|
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
|
2012-01-31 07:26:48 -08:00
|
|
|
(m, &_EINA_MODEL_INTERFACE_PROPERTIES_STRUCT.base);
|
2012-01-24 14:17:57 -08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-02-10 16:48:42 -08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-01-24 14:17:57 -08:00
|
|
|
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
|
2012-01-31 07:26:48 -08:00
|
|
|
(&_EINA_MODEL_INTERFACE_PROPERTIES_STRUCT.base, model, EINA_FALSE);
|
2012-01-24 14:17:57 -08:00
|
|
|
|
|
|
|
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
|
2012-01-31 07:26:48 -08:00
|
|
|
(&_EINA_MODEL_INTERFACE_PROPERTIES_STRUCT.base, model, EINA_FALSE);
|
2012-01-24 14:17:57 -08:00
|
|
|
|
|
|
|
val = eina_model_interface_private_data_get
|
2012-01-31 07:26:48 -08:00
|
|
|
(model, &_EINA_MODEL_INTERFACE_PROPERTIES_STRUCT.base);
|
2012-01-24 14:17:57 -08:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2012-02-10 02:48:39 -08:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|