Eina model: Fix issues with interface inheritance.

The ptr comparison had issues.
Order of interface overrides was wrong.

SVN revision: 67915
This commit is contained in:
Tom Hacohen 2012-02-14 09:48:00 +00:00
parent 478d4c5cce
commit b1bb770688
2 changed files with 140 additions and 19 deletions

View File

@ -3487,23 +3487,17 @@ EAPI const Eina_Model_Interface *
eina_model_interface_get(const Eina_Model *model, const char *name)
{
const Eina_Model_Description *desc;
const Eina_Model_Interface **itr, **itr_end;
const Eina_Model_Interface **itr, **itr_first;
EINA_MODEL_INSTANCE_CHECK_VAL(model, NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL);
desc = model->desc;
itr = desc->cache.ifaces;
itr_end = itr + desc->total.ifaces;
/* try pointer comparison for the speed aware users */
for (; itr < itr_end; itr++)
if ((*itr)->name == name)
return *itr;
itr_first = desc->cache.ifaces;
itr = itr_first + desc->total.ifaces - 1;
/* fallback to strcmp if user is lazy about speed */
itr = desc->cache.ifaces;
for (; itr < itr_end; itr++)
for (; itr >= itr_first; itr--)
if (strcmp((*itr)->name, name) == 0)
return *itr;
@ -4798,7 +4792,7 @@ eina_model_type_subclass_check(const Eina_Model_Type *type, const Eina_Model_Typ
}
static inline const Eina_Model_Interface *
_eina_model_type_interface_get(const Eina_Model_Type *type, const char *name, Eina_Bool ptr_cmp)
_eina_model_type_interface_get(const Eina_Model_Type *type, const char *name, Eina_Bool ptr_cmp __UNUSED__)
{
const Eina_Model_Interface **itr;
@ -4808,15 +4802,8 @@ _eina_model_type_interface_get(const Eina_Model_Type *type, const char *name, Ei
if (!type->interfaces)
return _eina_model_type_interface_get(type->parent, name, ptr_cmp);
if (ptr_cmp)
{
for (itr = type->interfaces; itr != NULL; itr++)
if ((*itr)->name == name)
return *itr;
}
else
{
for (itr = type->interfaces; itr != NULL; itr++)
for (itr = type->interfaces ; itr != NULL ; itr++)
if (strcmp((*itr)->name, name) == 0)
return *itr;
}

View File

@ -967,6 +967,139 @@ START_TEST(eina_model_test_struct_complex_members)
}
END_TEST
typedef struct _Animal_Type
{
Eina_Model_Type parent_class;
void (*eat)(Eina_Model *mdl);
} Animal_Type;
typedef struct _Human_Type
{
Animal_Type parent_class;
void (*talk)(Eina_Model *mdl);
} Human_Type;
typedef struct _Pooper_Interface
{
Eina_Model_Interface base_interface;
void (*poop)(Eina_Model *mdl);
} Pooper_Interface;
#define ANIMAL_TYPE(x) ((Animal_Type *) x)
#define HUMAN_TYPE(x) ((Human_Type *) x)
#define POOPER_IFACE(x) ((Pooper_Interface *) x)
#define POOPER_IFACE_NAME "Pooper_Interace"
#define INHER_CB_COUNT(prefix) \
static int prefix ## _count = 0; \
static void \
prefix (Eina_Model *mdl) \
{ \
(void) mdl; \
(prefix ## _count)++; \
}
static void
animal_eat(Eina_Model *mdl)
{
void (*pf)(Eina_Model *mdl);
pf = eina_model_method_resolve(mdl, Animal_Type, eat);
EINA_SAFETY_ON_NULL_RETURN(pf);
pf(mdl);
}
static void
pooper_poop(Eina_Model *mdl)
{
const Eina_Model_Interface *iface = NULL;
iface = eina_model_interface_get(mdl, POOPER_IFACE_NAME);
EINA_SAFETY_ON_NULL_RETURN(iface);
void (*pf)(Eina_Model *);
pf = eina_model_interface_method_resolve(iface, mdl, Pooper_Interface, poop);
EINA_SAFETY_ON_NULL_RETURN(pf);
pf(mdl);
}
INHER_CB_COUNT(_animal_poop);
INHER_CB_COUNT(_human_poop);
INHER_CB_COUNT(_animal_eat);
INHER_CB_COUNT(_human_eat);
START_TEST(eina_model_test_inheritance)
{
eina_init();
Pooper_Interface _ANIMAL_POOPER_IFACE;
Eina_Model_Interface *ANIMAL_POOPER_IFACE = (Eina_Model_Interface *) &_ANIMAL_POOPER_IFACE;
memset(&_ANIMAL_POOPER_IFACE, 0, sizeof(_ANIMAL_POOPER_IFACE));
ANIMAL_POOPER_IFACE->version = EINA_MODEL_INTERFACE_VERSION;
ANIMAL_POOPER_IFACE->interface_size = sizeof(Pooper_Interface);
ANIMAL_POOPER_IFACE->name = POOPER_IFACE_NAME;
POOPER_IFACE(ANIMAL_POOPER_IFACE)->poop = _animal_poop;
Pooper_Interface _HUMAN_POOPER_IFACE;
Eina_Model_Interface *HUMAN_POOPER_IFACE = (Eina_Model_Interface *) &_HUMAN_POOPER_IFACE;
memset(&_HUMAN_POOPER_IFACE, 0, sizeof(_HUMAN_POOPER_IFACE));
HUMAN_POOPER_IFACE->version = EINA_MODEL_INTERFACE_VERSION;
HUMAN_POOPER_IFACE->interface_size = sizeof(Pooper_Interface);
HUMAN_POOPER_IFACE->name = POOPER_IFACE_NAME;
POOPER_IFACE(HUMAN_POOPER_IFACE)->poop = _human_poop;
const Eina_Model_Interface *ANIMAL_IFACES[] = {ANIMAL_POOPER_IFACE, NULL};
const Eina_Model_Interface *HUMAN_IFACES[] = {HUMAN_POOPER_IFACE, NULL};
/* Init Animal Type */
Animal_Type _ANIMAL_TYPE;
Eina_Model_Type *ANIMAL_TYPE = (Eina_Model_Type *) &_ANIMAL_TYPE;
memset(&_ANIMAL_TYPE, 0, sizeof(_ANIMAL_TYPE));
Eina_Model_Type *type = (Eina_Model_Type *) &_ANIMAL_TYPE;
type->version = EINA_MODEL_TYPE_VERSION;
type->parent = EINA_MODEL_TYPE_BASE;
type->type_size = sizeof(Animal_Type);
type->name = "Animal_Type";
type->parent = EINA_MODEL_TYPE_GENERIC;
type->interfaces = ANIMAL_IFACES;
ANIMAL_TYPE(type)->eat = _animal_eat;
/* Init Human Type */
Animal_Type _HUMAN_TYPE;
Eina_Model_Type *HUMAN_TYPE = (Eina_Model_Type *) &_HUMAN_TYPE;
memset(&_HUMAN_TYPE, 0, sizeof(_HUMAN_TYPE));
type = (Eina_Model_Type *) &_HUMAN_TYPE;
type->version = EINA_MODEL_TYPE_VERSION;
type->parent = ANIMAL_TYPE;
type->type_size = sizeof(Human_Type);
type->name = "Human_Type";
type->interfaces = HUMAN_IFACES;
ANIMAL_TYPE(type)->eat = _human_eat;
Eina_Model *hm, *am;
am = eina_model_new(ANIMAL_TYPE);
hm = eina_model_new(HUMAN_TYPE);
animal_eat(am);
fail_if(_animal_eat_count != 1);
animal_eat(hm);
fail_if(_human_eat_count != 1);
pooper_poop(am);
fail_if(_animal_poop_count != 1);
pooper_poop(hm);
fail_if(_human_poop_count != 1);
fail_if(_animal_eat_count != 1);
fail_if(_human_eat_count != 1);
fail_if(_animal_poop_count != 1);
fail_if(_human_poop_count != 1);
}
END_TEST
void
eina_test_model(TCase *tc)
{
@ -980,4 +1113,5 @@ eina_test_model(TCase *tc)
tcase_add_test(tc, eina_model_test_child_filtered_iterator);
tcase_add_test(tc, eina_model_test_struct);
tcase_add_test(tc, eina_model_test_struct_complex_members);
tcase_add_test(tc, eina_model_test_inheritance);
}