more efficient model properties based on struct.

this is a killer, should be very efficient in memory and speed to
set/get items: instead of a hash of properties, keep them in a C
struct!

The constraint is that properties have fixed types defined at compile
time and cannot be deleted, but this is expected in many cases (ie:
esql rows).




SVN revision: 67517
This commit is contained in:
Gustavo Sverzut Barbieri 2012-01-24 22:17:57 +00:00
parent 19a47340a5
commit 73b595df2f
3 changed files with 512 additions and 9 deletions

View File

@ -714,10 +714,31 @@ EAPI extern const Eina_Model_Type *EINA_MODEL_TYPE_MIXIN;
* Should be generic enough to hold lots of items with runtime
* configurable properties of any type.
*
* @see #EINA_MODEL_TYPE_STRUCT
*
* @since 1.2
*/
EAPI extern const Eina_Model_Type *EINA_MODEL_TYPE_GENERIC;
/**
* @var EINA_MODEL_TYPE_STRUCT
*
* Subclass of #EINA_MODEL_TYPE_MIXIN that uses
* #EINA_MODEL_INTERFACE_PROPERTIES_STRUCT and
* #EINA_MODEL_INTERFACE_CHILDREN_INARRAY.
*
* Should be struct enough to hold lots of items with compile time
* configurable properties of any type.
*
* @see #EINA_MODEL_TYPE_GENERIC
*
* @since 1.2
*/
EAPI extern const Eina_Model_Type *EINA_MODEL_TYPE_STRUCT;
EAPI Eina_Model *eina_model_struct_new(const Eina_Value_Struct_Desc *desc) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT EINA_MALLOC;
/**
* @var EINA_MODEL_INTERFACE_NAME_PROPERTIES
*
@ -775,10 +796,66 @@ EAPI Eina_List *eina_model_interface_properties_names_list_get(const Eina_Model_
* hash data type. For huge number of elements it's better to
* use custom implementation instead.
*
* @see EINA_MODEL_INTERFACE_PROPERTIES_STRUCT
*
* @since 1.2
*/
EAPI extern const Eina_Model_Interface *EINA_MODEL_INTERFACE_PROPERTIES_HASH;
/**
* @var EINA_MODEL_INTERFACE_PROPERTIES_STRUCT
*
* Implements #Eina_Model_Interface_Properties
* (#EINA_MODEL_INTERFACE_NAME_PROPERTIES) using #Eina_Value_Struct.
*
* The interface private data is #Eina_Value of type
* #EINA_VALUE_TYPE_STRUCT. Properties will be accessed using
* #Eina_Value_Struct::desc information that can be set by types such
* as #EINA_MODEL_TYPE_STRUCT
*
* @see EINA_MODEL_INTERFACE_PROPERTIES_HASH
*
* @since 1.2
*/
EAPI extern const Eina_Model_Interface *EINA_MODEL_INTERFACE_PROPERTIES_STRUCT;
/**
* @brief Configure the internal properties of model implementing #EINA_MODEL_INTERFACE_PROPERTIES_STRUCT.
*
* @param model The model instance to configure.
* @param desc The structure description to use.
* @param memory If not @c NULL, will be adopted by model.
* @return #EINA_TRUE on success, #EINA_FALSE on failure.
*
* This will setup the internal pointers so that the given @a desc is
* used to manage the properties of this struct.
*
* If a given memory is provided, it will be adopted (not copied!),
* being free'd when the model is gone.
*
* @see #EINA_VALUE_TYPE_STRUCT
*
* @since 1.2
*/
EAPI Eina_Bool eina_model_struct_set(Eina_Model *model,
const Eina_Value_Struct_Desc *desc,
void *memory) EINA_ARG_NONNULL(1, 2);
/**
* @brief Get the internal properties of model implementing #EINA_MODEL_INTERFACE_PROPERTIES_STRUCT.
*
* @param model the model instance.
* @param p_desc where to return the structure description in use.
* @param p_memory where to return the structure memory in use.
* @return #EINA_TRUE on success, #EINA_FALSE on failure.
*
* No copies are made! The memory and description may be invalidaded
* by calls to eina_model_struct_set() or eina_model_del().
*
* @since 1.2
*/
EAPI Eina_Bool eina_model_struct_get(const Eina_Model *model,
const Eina_Value_Struct_Desc **p_desc,
void **p_memory) EINA_ARG_NONNULL(1, 2);
/**
* @var EINA_MODEL_INTERFACE_NAME_CHILDREN

View File

@ -2493,13 +2493,189 @@ static const Eina_Model_Interface _EINA_MODEL_INTERFACE_PROPERTIES_HASH = {
&_EINA_MODEL_INTERFACE_PROPERTIES_HASH_VALUE
};
/* TODO: properties using Eina_Value_Type_Struct
*
* Would be bit more cumbersome to do, as the user still needs to
* derivate the interface to specify the Eina_Value_Struct_Desc, but
* given this struct everything should be easy to do (query it for
* valid properties and their type, covert type if needed).
*/
/* EINA_MODEL_INTERFACE_PROPERTIES_STRUCT ******************************/
static Eina_Value_Struct *
_eina_model_interface_properties_struct_private_get(const Eina_Model *model)
{
Eina_Value *val = eina_model_interface_private_data_get
(model, EINA_MODEL_INTERFACE_PROPERTIES_STRUCT);
return val->value.ptr;
}
#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)
{
EINA_MODEL_INTERFACE_PROPERTIES_STRUCT_GET(model);
const Eina_Value_Struct_Member *m;
const void *p;
/* highly optimized, but duplicates code from eina_inline_value.x */
m = eina_value_struct_member_find(priv, name);
EINA_SAFETY_ON_NULL_RETURN_VAL(m, EINA_FALSE);
p = eina_value_struct_member_memory_get(priv, m);
EINA_SAFETY_ON_NULL_RETURN_VAL(p, EINA_FALSE);
EINA_SAFETY_ON_FALSE_RETURN_VAL(eina_value_setup(val, m->type), EINA_FALSE);
EINA_SAFETY_ON_FALSE_GOTO(eina_value_pset(val, p), error);
return EINA_TRUE;
error:
eina_value_flush(val);
return EINA_FALSE;
}
static Eina_Bool
_eina_model_interface_properties_struct_set(Eina_Model *model, const char *name, const Eina_Value *val)
{
EINA_MODEL_INTERFACE_PROPERTIES_STRUCT_GET(model);
const Eina_Value_Struct_Member *m;
const void *src;
void *dst;
/* highly optimized, but duplicates code from eina_inline_value.x */
m = eina_value_struct_member_find(priv, name);
EINA_SAFETY_ON_NULL_RETURN_VAL(m, EINA_FALSE);
EINA_SAFETY_ON_FALSE_RETURN_VAL(val->type == m->type, EINA_FALSE);
dst = eina_value_struct_member_memory_get(priv, m);
EINA_SAFETY_ON_NULL_RETURN_VAL(dst, EINA_FALSE);
src = eina_value_memory_get(val);
EINA_SAFETY_ON_NULL_RETURN_VAL(src, EINA_FALSE);
eina_value_type_flush(m->type, dst);
if (!eina_value_type_setup(m->type, dst)) goto error_setup;
if (!eina_value_type_pset(m->type, dst, src)) goto error_set;
return EINA_TRUE;
error_set:
eina_value_type_flush(m->type, dst);
error_setup:
return EINA_FALSE;
}
static Eina_Bool
_eina_model_interface_properties_struct_del(Eina_Model *model __UNUSED__, const char *name __UNUSED__)
{
return EINA_FALSE; /* not allowed */
}
static Eina_List *
_eina_model_interface_properties_struct_names_list(const Eina_Model *model)
{
EINA_MODEL_INTERFACE_PROPERTIES_STRUCT_GET(model);
const Eina_Value_Struct_Member *itr;
Eina_List *list = NULL;
EINA_SAFETY_ON_NULL_RETURN_VAL(priv, NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(priv->desc, NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(priv->desc->members, NULL);
itr = priv->desc->members;
if (priv->desc->member_count)
{
const Eina_Value_Struct_Member *end = itr + priv->desc->member_count;
for (; itr < end; itr++)
list = eina_list_append(list, eina_stringshare_add(itr->name));
}
else
{
for (; itr->name != NULL; itr++)
list = eina_list_append(list, eina_stringshare_add(itr->name));
}
return list;
}
#undef EINA_MODEL_INTERFACE_PROPERTIES_STRUCT_GET
static const Eina_Model_Interface_Properties _EINA_MODEL_INTERFACE_PROPERTIES_STRUCT_VALUE = {
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
};
static const Eina_Model_Interface _EINA_MODEL_INTERFACE_PROPERTIES_STRUCT = {
EINA_MODEL_INTERFACE_VERSION,
sizeof(Eina_Value),
_EINA_MODEL_INTERFACE_NAME_PROPERTIES,
NULL, /* no parent interfaces */
NULL, /* no extra events */
_eina_model_interface_properties_struct_setup,
_eina_model_interface_properties_struct_flush,
_eina_model_interface_properties_struct_constructor,
_eina_model_interface_properties_struct_destructor,
NULL,
NULL,
&_EINA_MODEL_INTERFACE_PROPERTIES_STRUCT_VALUE
};
/* EINA_MODEL_INTERFACE_CHILDREN_INARRAY ******************************/
@ -2720,6 +2896,50 @@ static const Eina_Model_Type _EINA_MODEL_TYPE_GENERIC = {
NULL /* inherit from mix-in */
};
/* EINA_MODEL_TYPE_STRUCT ********************************************/
static const Eina_Model_Interface *_EINA_MODEL_TYPE_STRUCT_IFACES[] = {
&_EINA_MODEL_INTERFACE_PROPERTIES_STRUCT,
&_EINA_MODEL_INTERFACE_CHILDREN_INARRAY,
NULL
};
static const Eina_Model_Type _EINA_MODEL_TYPE_STRUCT = {
EINA_MODEL_TYPE_VERSION,
0,
"Eina_Model_Type_Struct",
&_EINA_MODEL_TYPE_MIXIN,
_EINA_MODEL_TYPE_STRUCT_IFACES,
NULL, /* inherit from mix-in */
NULL, /* inherit from mix-in */
NULL, /* inherit from mix-in */
NULL, /* inherit from mix-in */
NULL, /* inherit from mix-in */
NULL, /* inherit from mix-in */
NULL, /* inherit from mix-in */
NULL, /* inherit from mix-in */
NULL, /* inherit from mix-in */
NULL, /* inherit from mix-in */
NULL, /* inherit from mix-in */
NULL, /* inherit from mix-in */
NULL, /* inherit from mix-in */
NULL, /* inherit from mix-in */
NULL, /* inherit from mix-in */
NULL, /* inherit from mix-in */
NULL, /* inherit from mix-in */
NULL, /* inherit from mix-in */
NULL, /* inherit from mix-in */
NULL, /* inherit from mix-in */
NULL, /* inherit from mix-in */
NULL, /* inherit from mix-in */
NULL, /* inherit from mix-in */
NULL, /* inherit from mix-in */
NULL, /* inherit from mix-in */
NULL, /* inherit from mix-in */
NULL, /* inherit from mix-in */
NULL /* inherit from mix-in */
};
/**
*/
@ -2799,8 +3019,10 @@ eina_model_init(void)
EINA_MODEL_TYPE_BASE = &_EINA_MODEL_TYPE_BASE;
EINA_MODEL_TYPE_MIXIN = &_EINA_MODEL_TYPE_MIXIN;
EINA_MODEL_TYPE_GENERIC = &_EINA_MODEL_TYPE_GENERIC;
EINA_MODEL_TYPE_STRUCT = &_EINA_MODEL_TYPE_STRUCT;
EINA_MODEL_INTERFACE_PROPERTIES_HASH = &_EINA_MODEL_INTERFACE_PROPERTIES_HASH;
EINA_MODEL_INTERFACE_PROPERTIES_STRUCT = &_EINA_MODEL_INTERFACE_PROPERTIES_STRUCT;
EINA_MODEL_INTERFACE_CHILDREN_INARRAY = &_EINA_MODEL_INTERFACE_CHILDREN_INARRAY;
@ -2881,8 +3103,10 @@ EAPI Eina_Error EINA_ERROR_MODEL_METHOD_MISSING = 0;
EAPI const Eina_Model_Type *EINA_MODEL_TYPE_BASE = NULL;
EAPI const Eina_Model_Type *EINA_MODEL_TYPE_MIXIN = NULL;
EAPI const Eina_Model_Type *EINA_MODEL_TYPE_GENERIC = NULL;
EAPI const Eina_Model_Type *EINA_MODEL_TYPE_STRUCT = NULL;
EAPI const Eina_Model_Interface *EINA_MODEL_INTERFACE_PROPERTIES_HASH = NULL;
EAPI const Eina_Model_Interface *EINA_MODEL_INTERFACE_PROPERTIES_STRUCT = NULL;
EAPI const Eina_Model_Interface *EINA_MODEL_INTERFACE_CHILDREN_INARRAY = NULL;
EAPI const char *EINA_MODEL_INTERFACE_NAME_PROPERTIES = "Eina_Model_Interface_Properties";
@ -4846,3 +5070,68 @@ eina_model_interface_children_sort(const Eina_Model_Interface *iface, Eina_Model
EINA_SAFETY_ON_NULL_RETURN(sort);
return sort(model, compare);
}
static Eina_Bool
_eina_model_struct_set(Eina_Model *m, const Eina_Value_Struct_Desc *desc, void *memory)
{
Eina_Value_Struct st = {desc, memory};
Eina_Value *val = eina_model_interface_private_data_get
(m, &_EINA_MODEL_INTERFACE_PROPERTIES_STRUCT);
return eina_value_pset(val, &st);
}
EAPI Eina_Model *
eina_model_struct_new(const Eina_Value_Struct_Desc *desc)
{
Eina_Model *m;
EINA_SAFETY_ON_NULL_RETURN_VAL(desc, NULL);
EINA_SAFETY_ON_FALSE_RETURN_VAL
(desc->version == EINA_VALUE_STRUCT_DESC_VERSION, NULL);
m = eina_model_new(EINA_MODEL_TYPE_STRUCT);
EINA_SAFETY_ON_NULL_RETURN_VAL(m, NULL);
EINA_SAFETY_ON_FALSE_GOTO(_eina_model_struct_set(m, desc, NULL), error);
return m;
error:
eina_model_del(m);
return NULL;
}
EAPI Eina_Bool
eina_model_struct_set(Eina_Model *model, const Eina_Value_Struct_Desc *desc, void *memory)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(desc, EINA_FALSE);
EINA_SAFETY_ON_FALSE_RETURN_VAL
(desc->version == EINA_VALUE_STRUCT_DESC_VERSION, EINA_FALSE);
EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL
(&_EINA_MODEL_INTERFACE_PROPERTIES_STRUCT, model, EINA_FALSE);
return _eina_model_struct_set(model, desc, memory);
}
EAPI Eina_Bool
eina_model_struct_get(const Eina_Model *model, const Eina_Value_Struct_Desc **p_desc, void **p_memory)
{
const Eina_Value *val;
Eina_Value_Struct st;
EINA_SAFETY_ON_NULL_RETURN_VAL(p_desc, EINA_FALSE);
*p_desc = NULL;
if (p_memory) *p_memory = NULL;
EINA_MODEL_INTERFACE_IMPLEMENTED_CHECK_VAL
(&_EINA_MODEL_INTERFACE_PROPERTIES_STRUCT, model, EINA_FALSE);
val = eina_model_interface_private_data_get
(model, &_EINA_MODEL_INTERFACE_PROPERTIES_STRUCT);
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;
}

View File

@ -50,6 +50,30 @@ _eina_test_model_check_safety_null(const Eina_Log_Domain *d, Eina_Log_Level leve
eina_log_print_cb_stderr(d, level, file, fnc, line, fmt, NULL, args);
}
static void
_eina_test_model_check_safety_false(const Eina_Log_Domain *d, Eina_Log_Level level, const char *file, const char *fnc, int line, const char *fmt, void *data, va_list args)
{
Eina_Bool *ck = data;
if ((level == EINA_LOG_LEVEL_ERR) && (strcmp(fmt, "%s") == 0))
{
const char *str;
va_list cp_args;
va_copy(cp_args, args);
str = va_arg(cp_args, const char *);
va_end(cp_args);
if (eina_str_has_prefix(str, "safety check failed: ") &&
eina_str_has_suffix(str, " is false"))
{
*ck = EINA_TRUE;
return;
}
}
*ck = EINA_FALSE;
eina_log_print_cb_stderr(d, level, file, fnc, line, fmt, NULL, args);
}
static void
_eina_test_model_cb_count(void *data, Eina_Model *model, const Eina_Model_Event_Description *desc, void *event_info)
{
@ -213,7 +237,6 @@ START_TEST(eina_model_test_children)
char *s;
int i;
printf("eina_model_test_children: BEGIN\n");
eina_init();
m = eina_model_new(EINA_MODEL_TYPE_GENERIC);
@ -321,7 +344,6 @@ START_TEST(eina_model_test_children)
ck_assert_int_eq(count_cdel, 2);
eina_shutdown();
printf("eina_model_test_children: END\n");
}
END_TEST
@ -717,6 +739,120 @@ START_TEST(eina_model_test_child_filtered_iterator)
}
END_TEST
START_TEST(eina_model_test_struct)
{
unsigned int count_del = 0, count_pset = 0, count_pdel = 0;
Eina_Model *m;
struct myst {
int i;
char c;
};
const Eina_Value_Struct_Member myst_members[] = {
{"i", EINA_VALUE_TYPE_INT, 0},
{"c", EINA_VALUE_TYPE_CHAR, 4},
{NULL, NULL, 0}
};
const Eina_Value_Struct_Desc myst_desc = {
EINA_VALUE_STRUCT_DESC_VERSION,
NULL, myst_members, 2, sizeof(struct myst)
};
Eina_Value inv, outv;
int i;
char c;
Eina_List *lst;
Eina_Bool ck;
eina_init();
m = eina_model_struct_new(&myst_desc);
fail_unless(m != NULL);
eina_model_event_callback_add
(m, "deleted", _eina_test_model_cb_count, &count_del);
eina_model_event_callback_add
(m, "property,set", _eina_test_model_cb_count, &count_pset);
eina_model_event_callback_add
(m, "property,deleted", _eina_test_model_cb_count, &count_pdel);
fail_unless(eina_value_setup(&inv, EINA_VALUE_TYPE_INT));
fail_unless(eina_value_set(&inv, 1234));
fail_unless(eina_value_get(&inv, &i));
ck_assert_int_eq(i, 1234);
fail_unless(eina_model_property_set(m, "i", &inv));
eina_value_flush(&inv);
fail_unless(eina_value_setup(&inv, EINA_VALUE_TYPE_CHAR));
fail_unless(eina_value_set(&inv, 33));
fail_unless(eina_value_get(&inv, &c));
ck_assert_int_eq(c, 33);
fail_unless(eina_model_property_set(m, "c", &inv));
lst = eina_model_properties_names_list_get(m);
ck_assert_int_eq(eina_list_count(lst), 2);
lst = eina_list_sort(lst, 0, EINA_COMPARE_CB(strcmp));
ck_assert_str_eq("c", eina_list_nth(lst, 0));
ck_assert_str_eq("i", eina_list_nth(lst, 1));
eina_model_properties_names_list_free(lst);
fail_unless(eina_model_property_get(m, "i", &outv));
fail_unless(outv.type == EINA_VALUE_TYPE_INT);
fail_unless(eina_value_get(&outv, &i));
ck_assert_int_eq(i, 1234);
eina_value_flush(&outv);
fail_unless(eina_model_property_get(m, "c", &outv));
fail_unless(outv.type == EINA_VALUE_TYPE_CHAR);
fail_unless(eina_value_get(&outv, &c));
ck_assert_int_eq(c, 33);
eina_value_flush(&outv);
eina_value_flush(&inv);
/* negative test (check safety was displayed by using print_cb) */
eina_log_print_cb_set(_eina_test_model_check_safety_null, &ck);
ck = EINA_FALSE;
fail_if(eina_model_property_get(m, "non-existent", &outv));
fail_unless(ck == EINA_TRUE);
ck = EINA_FALSE;
fail_if(eina_model_property_get(m, NULL, &outv));
fail_unless(ck == EINA_TRUE);
fail_unless(eina_value_setup(&inv, EINA_VALUE_TYPE_STRING));
fail_unless(eina_value_set(&inv, "hello world"));
eina_log_print_cb_set(_eina_test_model_check_safety_false, &ck);
ck = EINA_FALSE;
fail_if(eina_model_property_set(m, "i", &inv));
fail_unless(ck == EINA_TRUE);
ck = EINA_FALSE;
fail_if(eina_model_property_set(m, "c", &inv));
fail_unless(ck == EINA_TRUE);
/* revert print_cb to default */
eina_log_print_cb_set(eina_log_print_cb_stderr, NULL);
fail_if(eina_model_property_del(m, "value"));
fail_if(eina_model_property_del(m, "i"));
fail_if(eina_model_property_del(m, "c"));
eina_value_flush(&inv);
ck_assert_int_eq(eina_model_refcount(m), 1);
eina_model_unref(m);
ck_assert_int_eq(count_del, 1);
ck_assert_int_eq(count_pset, 2);
ck_assert_int_eq(count_pdel, 0);
eina_shutdown();
}
END_TEST
void
eina_test_model(TCase *tc)
{
@ -728,4 +864,5 @@ eina_test_model(TCase *tc)
tcase_add_test(tc, eina_model_test_child_reversed_iterator);
tcase_add_test(tc, eina_model_test_child_sorted_iterator);
tcase_add_test(tc, eina_model_test_child_filtered_iterator);
tcase_add_test(tc, eina_model_test_struct);
}