diff --git a/src/lib/eo/eo_base.eo b/src/lib/eo/eo_base.eo index 72d7906a68..01ae857262 100644 --- a/src/lib/eo/eo_base.eo +++ b/src/lib/eo/eo_base.eo @@ -253,6 +253,29 @@ abstract Eo.Base () } } } + @property key_obj_weak { + [[Generic weak object reference with string key to object. + + The object key will be removed if the object is removed, but + will not take or removed references like key_obj. + + This is the same key store used by key_data and key_value so keys + are shared and can store only one thing + ]] + keys { + key: string; [[the key associated with the object ref]] + } + set { + values { + objdata: const(Eo.Base); [[the object to set]] + } + } + get { + values { + objdata: Eo.Base; [[the object to set]] + } + } + } @property key_value { [[Value on with string key on the object. diff --git a/src/lib/eo/eo_base_class.c b/src/lib/eo/eo_base_class.c index 82ab7d601b..3a7f0a3117 100644 --- a/src/lib/eo/eo_base_class.c +++ b/src/lib/eo/eo_base_class.c @@ -41,17 +41,19 @@ typedef struct typedef enum { DATA_PTR, DATA_OBJ, + DATA_OBJ_WEAK, DATA_VAL } Eo_Generic_Data_Node_Type; typedef struct { EINA_INLIST; + const Eo *obj; Eina_Stringshare *key; union { - Eina_Value *val; - Eo *obj; - void *ptr; + Eina_Value *val; + Eo *obj; + void *ptr; } d; Eo_Generic_Data_Node_Type d_type; } Eo_Generic_Data_Node; @@ -86,22 +88,25 @@ _eo_base_extension_noneed(Eo_Base_Data *pd) pd->ext = NULL; } - - +static void _key_generic_cb_del(void *data, const Eo_Event *event); static void _eo_generic_data_node_free(Eo_Generic_Data_Node *node) { switch (node->d_type) { - case DATA_OBJ: - eo_unref(node->d.obj); - break; - case DATA_VAL: - eina_value_free(node->d.val); - break; case DATA_PTR: - break; + break; + case DATA_OBJ: + eo_event_callback_del(node->d.obj, EO_EVENT_DEL, _key_generic_cb_del, node); + eo_unref(node->d.obj); + break; + case DATA_OBJ_WEAK: + eo_event_callback_del(node->d.obj, EO_EVENT_DEL, _key_generic_cb_del, node); + break; + case DATA_VAL: + eina_value_free(node->d.val); + break; } eina_stringshare_del(node->key); free(node); @@ -126,7 +131,17 @@ _eo_generic_data_del_all(Eo *obj EINA_UNUSED, Eo_Base_Data *pd) } static void -_eo_key_generic_del(const Eo *obj EINA_UNUSED, Eo_Base_Data *pd, const char *key) +_eo_key_generic_direct_del(Eo_Base_Data *pd, Eo_Generic_Data_Node *node, Eina_Bool call_free) +{ + Eo_Base_Extension *ext = pd->ext; + + ext->generic_data = eina_inlist_remove + (ext->generic_data, EINA_INLIST_GET(node)); + if (call_free) _eo_generic_data_node_free(node); +} + +static void +_eo_key_generic_del(const Eo *obj EINA_UNUSED, Eo_Base_Data *pd, const char *key, Eina_Bool call_free) { Eo_Generic_Data_Node *node; Eo_Base_Extension *ext = pd->ext; @@ -137,26 +152,26 @@ _eo_key_generic_del(const Eo *obj EINA_UNUSED, Eo_Base_Data *pd, const char *key { ext->generic_data = eina_inlist_remove (ext->generic_data, EINA_INLIST_GET(node)); - _eo_generic_data_node_free(node); + if (call_free) _eo_generic_data_node_free(node); return; } } } /* Return TRUE if the object was newly added. */ -static Eina_Bool -_key_generic_set(const Eo *obj, Eo_Base_Data *pd, const char *key, const void *data, Eo_Generic_Data_Node_Type d_type) +static Eo_Generic_Data_Node * +_key_generic_set(const Eo *obj, Eo_Base_Data *pd, const char *key, const void *data, Eo_Generic_Data_Node_Type d_type, Eina_Bool call_free) { Eo_Generic_Data_Node *node; Eo_Base_Extension *ext = pd->ext; - if (!key) return EINA_FALSE; + if (!key) return NULL; if (ext) { if (!data) { - _eo_key_generic_del(obj, pd, key); - return EINA_TRUE; + _eo_key_generic_del(obj, pd, key, call_free); + return NULL; } EINA_INLIST_FOREACH(ext->generic_data, node) { @@ -178,15 +193,16 @@ _key_generic_set(const Eo *obj, Eo_Base_Data *pd, const char *key, const void *d { node = calloc(1, sizeof(Eo_Generic_Data_Node)); if (!node) return EINA_FALSE; + node->obj = obj; node->key = eina_stringshare_add(key); node->d.ptr = (void *) data; node->d_type = d_type; ext->generic_data = eina_inlist_prepend (ext->generic_data, EINA_INLIST_GET(node)); - return EINA_TRUE; + return node; } - return EINA_FALSE; + return NULL; } static void * @@ -218,10 +234,18 @@ _key_generic_get(const Eo *obj, Eo_Base_Data *pd, const char *key, Eo_Generic_Da return NULL; } +static void +_key_generic_cb_del(void *data, const Eo_Event *event EINA_UNUSED) +{ + Eo_Generic_Data_Node *node = data; + Eo_Base_Data *pd = eo_data_scope_get(node->obj, EO_BASE_CLASS); + _eo_key_generic_direct_del(pd, node, EINA_FALSE); +} + EOLIAN static void _eo_base_key_data_set(Eo *obj, Eo_Base_Data *pd, const char *key, const void *data) { - _key_generic_set(obj, pd, key, data, DATA_PTR); + _key_generic_set(obj, pd, key, data, DATA_PTR, EINA_TRUE); } EOLIAN static void * @@ -233,8 +257,14 @@ _eo_base_key_data_get(Eo *obj, Eo_Base_Data *pd, const char *key) EOLIAN static void _eo_base_key_obj_set(Eo *obj EINA_UNUSED, Eo_Base_Data *pd, const char *key, const Eo *objdata) { - if (_key_generic_set(obj, pd, key, objdata, DATA_OBJ)) - eo_ref(objdata); + Eo_Generic_Data_Node *node; + + node = _key_generic_set(obj, pd, key, objdata, DATA_OBJ, EINA_TRUE); + if (node) + { + eo_ref(objdata); + eo_event_callback_add((Eo *)objdata, EO_EVENT_DEL, _key_generic_cb_del, node); + } } EOLIAN static Eo * @@ -243,10 +273,28 @@ _eo_base_key_obj_get(Eo *obj, Eo_Base_Data *pd, const char *key) return _key_generic_get(obj, pd, key, DATA_OBJ); } +EOLIAN static void +_eo_base_key_obj_weak_set(Eo *obj, Eo_Base_Data *pd, const char * key, const Eo_Base *objdata) +{ + Eo_Generic_Data_Node *node; + + node = _key_generic_set(obj, pd, key, objdata, DATA_OBJ_WEAK, EINA_TRUE); + if (node) + { + eo_event_callback_add((Eo *)objdata, EO_EVENT_DEL, _key_generic_cb_del, node); + } +} + +EOLIAN static Eo * +_eo_base_key_obj_weak_get(Eo *obj, Eo_Base_Data *pd, const char * key) +{ + return _key_generic_get(obj, pd, key, DATA_OBJ_WEAK); +} + EOLIAN static void _eo_base_key_value_set(Eo *obj EINA_UNUSED, Eo_Base_Data *pd, const char *key, Eina_Value *value) { - _key_generic_set(obj, pd, key, value, DATA_VAL); + _key_generic_set(obj, pd, key, value, DATA_VAL, EINA_TRUE); } EOLIAN static Eina_Value * diff --git a/src/tests/eo/suite/eo_test_general.c b/src/tests/eo/suite/eo_test_general.c index 2e2698d729..ea94823f53 100644 --- a/src/tests/eo/suite/eo_test_general.c +++ b/src/tests/eo/suite/eo_test_general.c @@ -698,9 +698,12 @@ START_TEST(eo_generic_data) Eina_Value *value; Eina_Value *value2; + + eo_key_data_set(obj, "test1", (void *) 1); data = eo_key_data_get(obj, "test1"); fail_if(1 != (intptr_t) data); + eo_key_data_set(obj, "test1", NULL); data = eo_key_data_get(obj, "test1"); fail_if(data); @@ -709,17 +712,20 @@ START_TEST(eo_generic_data) eo_key_data_set(obj, "test2", (void *) 2); data = eo_key_data_get(obj, "test1"); fail_if(1 != (intptr_t) data); + data = eo_key_data_get(obj, "test2"); fail_if(2 != (intptr_t) data); data = eo_key_data_get(obj, "test2"); fail_if(2 != (intptr_t) data); + eo_key_data_set(obj, "test2", NULL); data = eo_key_data_get(obj, "test2"); fail_if(data); data = eo_key_data_get(obj, "test1"); fail_if(1 != (intptr_t) data); + eo_key_data_set(obj, "test1", NULL); data = eo_key_data_get(obj, "test1"); fail_if(data); @@ -729,29 +735,108 @@ START_TEST(eo_generic_data) eo_key_obj_set(obj, "test1", obj2); objtmp = eo_key_obj_get(obj, "test1"); fail_if(obj2 != objtmp); + eo_key_obj_set(obj, "test1", NULL); objtmp = eo_key_obj_get(obj, "test1"); fail_if(objtmp); eo_key_obj_set(obj, "test1", obj2); + fail_if(eo_ref_get(obj2) != 2); + eo_key_obj_set(obj, "test2", obj3); + fail_if(eo_ref_get(obj3) != 2); + 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_set(obj, "test2", NULL); + fail_if(eo_ref_get(obj3) != 1); + objtmp = eo_key_obj_get(obj, "test2"); fail_if(objtmp); objtmp = eo_key_obj_get(obj, "test1"); fail_if(obj2 != objtmp); + eo_key_obj_set(obj, "test1", NULL); + fail_if(eo_ref_get(obj2) != 1); + objtmp = eo_key_obj_get(obj, "test1"); fail_if(objtmp); + eo_key_obj_set(obj, "test1", obj2); + eo_key_obj_set(obj, "test2", obj3); + eo_del(obj2); + eo_del(obj2); + eo_del(obj3); + eo_del(obj3); + objtmp = eo_key_obj_get(obj, "test1"); + fail_if(objtmp); + + objtmp = eo_key_obj_get(obj, "test2"); + fail_if(objtmp); + + + + obj2 = eo_add(SIMPLE_CLASS, NULL); + obj3 = eo_add(SIMPLE_CLASS, NULL); + + eo_key_obj_weak_set(obj, "test1", obj2); + objtmp = eo_key_obj_weak_get(obj, "test1"); + fail_if(obj2 != objtmp); + + eo_key_obj_weak_set(obj, "test1", NULL); + objtmp = eo_key_obj_weak_get(obj, "test1"); + fail_if(objtmp); + + eo_key_obj_weak_set(obj, "test1", obj2); + fail_if(eo_ref_get(obj2) != 1); + + eo_key_obj_weak_set(obj, "test2", obj3); + fail_if(eo_ref_get(obj3) != 1); + + objtmp = eo_key_obj_weak_get(obj, "test1"); + fail_if(obj2 != objtmp); + + objtmp = eo_key_obj_weak_get(obj, "test2"); + fail_if(obj3 != objtmp); + + data = eo_key_obj_weak_get(obj, "test2"); + fail_if(obj3 != objtmp); + + eo_key_obj_weak_set(obj, "test2", NULL); + fail_if(eo_ref_get(obj3) != 1); + + objtmp = eo_key_obj_weak_get(obj, "test2"); + fail_if(objtmp); + + objtmp = eo_key_obj_weak_get(obj, "test1"); + fail_if(obj2 != objtmp); + + eo_key_obj_weak_set(obj, "test1", NULL); + fail_if(eo_ref_get(obj2) != 1); + + objtmp = eo_key_obj_weak_get(obj, "test1"); + fail_if(objtmp); + + eo_key_obj_weak_set(obj, "test1", obj2); + eo_key_obj_weak_set(obj, "test2", obj3); + eo_del(obj2); + eo_del(obj3); + objtmp = eo_key_obj_weak_get(obj, "test1"); + fail_if(objtmp); + + objtmp = eo_key_obj_weak_get(obj, "test2"); + fail_if(objtmp); + + + value = eina_value_new(EINA_VALUE_TYPE_INT); eina_value_set(value, 1234); value2 = eo_key_value_get(obj, "value1"); @@ -764,6 +849,7 @@ START_TEST(eo_generic_data) eo_key_value_set(obj, "value1", NULL); value2 = eo_key_value_get(obj, "value1"); fail_if(value2 != NULL); + eo_key_value_set(obj, "value1", NULL); eo_unref(obj);