eo - add object sotrage in generic values with ref/unref

this adds eo_key_obj_set/get/del() like with data but for object
handles so the obj is ref'd as long as the key and parent obj exists
and then unreffed on deletion. it also tracks deletion of reffed
objects like weak refs and then removes the key automatically.

@feature
This commit is contained in:
Carsten Haitzler 2016-04-13 01:04:11 +09:00
parent 5065356ae6
commit 8be56c9498
3 changed files with 260 additions and 51 deletions

View File

@ -154,6 +154,35 @@ abstract Eo.Base ()
@in key: const(char)*; [[the key associated with the data]]
}
}
key_obj_set {
[[Set generic object reference to object.
The object will be automatically ref'd when set and unref'd
when replaced or deleted or referring object is deleted. If
the referenced object is deleted then the key is deleted
automatically.
This is the same key store used by key_data_set etc. so keys
are shared and can store only one thing
]]
params {
@in key: const(char)*; [[the key associated with the object ref]]
@in objdata: Eo *; [[the object to set]]
}
}
key_obj_get @const {
[[Get generic object reference from object.]]
params {
@in key: const(char)*; [[the key associated with the object ref]]
}
return: Eo *; [[the object reference for the key]]
}
key_obj_del {
[[Del generic objecrt reference from object.]]
params {
@in key: const(char)*; [[the key associated with the object ref]]
}
}
event_thaw {
[[thaw events of object.

View File

@ -33,7 +33,8 @@ typedef struct
{
EINA_INLIST;
Eina_Stringshare *key;
void *data;
void *data;
Eina_Bool data_is_obj : 1;
} Eo_Generic_Data_Node;
static void
@ -43,59 +44,224 @@ _eo_generic_data_node_free(Eo_Generic_Data_Node *node)
free(node);
}
static void
_eo_generic_data_del_all(Eo_Base_Data *pd)
static Eina_Bool
_eo_base_cb_key_obj_del(void *data, const Eo_Event *event)
{
Eina_Inlist *nnode;
Eo_Generic_Data_Node *node = NULL;
Eo *parent_obj = data;
Eo_Base_Data *pd = eo_data_scope_get(parent_obj, EO_BASE_CLASS);
EINA_INLIST_FOREACH_SAFE(pd->generic_data, nnode, node)
if (pd)
{
pd->generic_data = eina_inlist_remove(pd->generic_data,
EINA_INLIST_GET(node));
Eo_Generic_Data_Node *node;
EINA_INLIST_FOREACH(pd->generic_data, node)
{
if ((node->data_is_obj) && (node->data == event->obj))
{
pd->generic_data = eina_inlist_remove(pd->generic_data,
EINA_INLIST_GET(node));
eo_event_callback_del(node->data, EO_BASE_EVENT_DEL,
_eo_base_cb_key_obj_del, data);
eo_unref(node->data);
_eo_generic_data_node_free(node);
break;
}
}
}
return EINA_TRUE;
}
static void
_eo_generic_data_del_all(Eo *obj, Eo_Base_Data *pd)
{
Eo_Generic_Data_Node *node;
while (pd->generic_data)
{
node = (Eo_Generic_Data_Node *)pd->generic_data;
pd->generic_data = eina_inlist_remove(pd->generic_data,
EINA_INLIST_GET(node));
if (node->data_is_obj)
{
eo_event_callback_del(node->data, EO_BASE_EVENT_DEL,
_eo_base_cb_key_obj_del, obj);
eo_unref(node->data);
}
_eo_generic_data_node_free(node);
}
}
EOLIAN static void
_eo_base_key_data_set(Eo *obj, Eo_Base_Data *pd,
const char *key, const void *data)
_eo_base_key_data_set(Eo *obj, Eo_Base_Data *pd, const char *key, const void *data)
{
Eo_Generic_Data_Node *node;
if (!key) return;
eo_key_data_del(obj, key);
node = malloc(sizeof(Eo_Generic_Data_Node));
if (!node) return;
node->key = eina_stringshare_add(key);
node->data = (void *) data;
pd->generic_data = eina_inlist_prepend(pd->generic_data,
EINA_INLIST_GET(node));
}
EOLIAN static void *
_eo_base_key_data_get(const Eo *obj EINA_UNUSED, Eo_Base_Data *pd, const char *key)
{
/* We don't really change it... */
Eo_Generic_Data_Node *node;
if (!key) return NULL;
EINA_INLIST_FOREACH(pd->generic_data, node)
{
if (!strcmp(node->key, key))
{
pd->generic_data =
eina_inlist_promote(pd->generic_data, EINA_INLIST_GET(node));
return node->data;
if ((!node->data_is_obj) && (node->data == data)) return;
pd->generic_data = eina_inlist_remove(pd->generic_data,
EINA_INLIST_GET(node));
if (node->data_is_obj)
{
eo_event_callback_del(node->data, EO_BASE_EVENT_DEL,
_eo_base_cb_key_obj_del, obj);
eo_unref(node->data);
}
_eo_generic_data_node_free(node);
break;
}
}
node = calloc(1, sizeof(Eo_Generic_Data_Node));
if (!node) return;
node->key = eina_stringshare_add(key);
node->data = (void *)data;
node->data_is_obj = EINA_FALSE;
pd->generic_data = eina_inlist_prepend(pd->generic_data,
EINA_INLIST_GET(node));
}
EOLIAN static void *
_eo_base_key_data_get(const Eo *obj, Eo_Base_Data *pd, const char *key)
{
Eo_Generic_Data_Node *node;
if (!key) return NULL;
EINA_INLIST_FOREACH(pd->generic_data, node)
{
if (!strcmp(node->key, key))
{
if (!node->data_is_obj)
{
pd->generic_data = eina_inlist_promote(pd->generic_data,
EINA_INLIST_GET(node));
return node->data;
}
else
{
ERR("Object %p key '%s' is an object, not raw data",
obj, key);
return NULL;
}
}
}
return NULL;
}
EOLIAN static void
_eo_base_key_data_del(Eo *obj, Eo_Base_Data *pd, const char *key)
{
Eo_Generic_Data_Node *node;
if (!key) return;
EINA_INLIST_FOREACH(pd->generic_data, node)
{
if (!strcmp(node->key, key))
{
pd->generic_data = eina_inlist_remove(pd->generic_data,
EINA_INLIST_GET(node));
if (node->data_is_obj)
{
eo_event_callback_del(node->data, EO_BASE_EVENT_DEL,
_eo_base_cb_key_obj_del, obj);
eo_unref(node->data);
}
_eo_generic_data_node_free(node);
return;
}
}
}
EOLIAN static void
_eo_base_key_obj_set(Eo *obj, Eo_Base_Data *pd, const char *key, Eo *objdata)
{
Eo_Generic_Data_Node *node;
if (!key) return;
EINA_INLIST_FOREACH(pd->generic_data, node)
{
if (!strcmp(node->key, key))
{
if ((node->data_is_obj) && (node->data == objdata)) return;
pd->generic_data = eina_inlist_remove(pd->generic_data,
EINA_INLIST_GET(node));
if (node->data_is_obj)
{
eo_event_callback_del(node->data, EO_BASE_EVENT_DEL,
_eo_base_cb_key_obj_del, obj);
eo_unref(node->data);
}
_eo_generic_data_node_free(node);
break;
}
}
node = calloc(1, sizeof(Eo_Generic_Data_Node));
if (!node) return;
node->key = eina_stringshare_add(key);
node->data = (void *)objdata;
node->data_is_obj = EINA_TRUE;
eo_event_callback_add(node->data, EO_BASE_EVENT_DEL,
_eo_base_cb_key_obj_del, obj);
eo_ref(node->data);
pd->generic_data = eina_inlist_prepend(pd->generic_data,
EINA_INLIST_GET(node));
}
EOLIAN static Eo *
_eo_base_key_obj_get(const Eo *obj, Eo_Base_Data *pd, const char *key)
{
Eo_Generic_Data_Node *node;
if (!key) return NULL;
EINA_INLIST_FOREACH(pd->generic_data, node)
{
if (!strcmp(node->key, key))
{
if (node->data_is_obj)
{
pd->generic_data = eina_inlist_promote(pd->generic_data,
EINA_INLIST_GET(node));
return node->data;
}
else
{
ERR("Object %p key '%s' is an object, not an object",
obj, key);
return NULL;
}
}
}
return NULL;
}
EOLIAN static void
_eo_base_key_obj_del(Eo *obj EINA_UNUSED, Eo_Base_Data *pd, const char *key)
{
Eo_Generic_Data_Node *node;
if (!key) return;
EINA_INLIST_FOREACH(pd->generic_data, node)
{
if (!strcmp(node->key, key))
{
pd->generic_data = eina_inlist_remove(pd->generic_data,
EINA_INLIST_GET(node));
if (node->data_is_obj)
{
eo_event_callback_del(node->data, EO_BASE_EVENT_DEL,
_eo_base_cb_key_obj_del, obj);
eo_unref(node->data);
}
_eo_generic_data_node_free(node);
return;
}
}
}
EOLIAN static void
_eo_base_parent_set(Eo *obj, Eo_Base_Data *pd, Eo *parent_id)
{
@ -265,25 +431,6 @@ _eo_base_dbg_info_get(Eo *obj EINA_UNUSED, Eo_Base_Data *pd EINA_UNUSED, Eo_Dbg_
return;
}
EOLIAN static void
_eo_base_key_data_del(Eo *obj EINA_UNUSED, Eo_Base_Data *pd, const char *key)
{
Eo_Generic_Data_Node *node;
if (!key) return;
EINA_INLIST_FOREACH(pd->generic_data, node)
{
if (!strcmp(node->key, key))
{
pd->generic_data = eina_inlist_remove(pd->generic_data,
EINA_INLIST_GET(node));
_eo_generic_data_node_free(node);
return;
}
}
}
/* Weak reference. */
static inline size_t
@ -996,7 +1143,7 @@ _eo_base_destructor(Eo *obj, Eo_Base_Data *pd)
eo_parent_set(obj, NULL);
}
_eo_generic_data_del_all(pd);
_eo_generic_data_del_all(obj, pd);
_wref_destruct(pd);
_eo_callback_remove_all(pd);

View File

@ -598,6 +598,9 @@ START_TEST(eo_generic_data)
{
eo_init();
Eo *obj = eo_add(SIMPLE_CLASS, NULL);
Eo *obj2 = eo_add(SIMPLE_CLASS, NULL);
Eo *obj3 = eo_add(SIMPLE_CLASS, NULL);
Eo *objtmp;
void *data = NULL;
eo_key_data_set(obj, "test1", (void *) 1);
@ -626,7 +629,37 @@ START_TEST(eo_generic_data)
data = eo_key_data_get(obj, "test1");
fail_if(data);
eo_key_obj_set(obj, "test1", obj2);
objtmp = eo_key_obj_get(obj, "test1");
fail_if(obj2 != objtmp);
eo_key_obj_del(obj, "test1");
objtmp = eo_key_obj_get(obj, "test1");
fail_if(objtmp);
eo_key_obj_set(obj, "test1", obj2);
eo_key_obj_set(obj, "test2", obj3);
objtmp = eo_key_obj_get(obj, "test1");
fail_if(obj2 != objtmp);
objtmp = eo_key_obj_get(obj, "test2");
fail_if(obj3 != objtmp);
data = eo_key_obj_get(obj, "test2");
fail_if(obj3 != objtmp);
eo_key_obj_del(obj, "test2");
objtmp = eo_key_obj_get(obj, "test2");
fail_if(objtmp);
objtmp = eo_key_obj_get(obj, "test1");
fail_if(obj2 != objtmp);
eo_key_obj_del(obj, "test1");
objtmp = eo_key_obj_get(obj, "test1");
fail_if(objtmp);
eo_unref(obj);
eo_unref(obj2);
eo_unref(obj3);
eo_shutdown();
}