From 8be56c94983c3d2772bb332c0e5c878b4b7d785c Mon Sep 17 00:00:00 2001 From: "Carsten Haitzler (Rasterman)" Date: Wed, 13 Apr 2016 01:04:11 +0900 Subject: [PATCH] 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 --- src/lib/eo/eo_base.eo | 29 ++++ src/lib/eo/eo_base_class.c | 249 +++++++++++++++++++++------ src/tests/eo/suite/eo_test_general.c | 33 ++++ 3 files changed, 260 insertions(+), 51 deletions(-) diff --git a/src/lib/eo/eo_base.eo b/src/lib/eo/eo_base.eo index 4e93495f6c..ad6cd68bee 100644 --- a/src/lib/eo/eo_base.eo +++ b/src/lib/eo/eo_base.eo @@ -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. diff --git a/src/lib/eo/eo_base_class.c b/src/lib/eo/eo_base_class.c index 776e92a542..bd402e7b24 100644 --- a/src/lib/eo/eo_base_class.c +++ b/src/lib/eo/eo_base_class.c @@ -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); diff --git a/src/tests/eo/suite/eo_test_general.c b/src/tests/eo/suite/eo_test_general.c index fcaa115e99..9f689f3082 100644 --- a/src/tests/eo/suite/eo_test_general.c +++ b/src/tests/eo/suite/eo_test_general.c @@ -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(); }