raster pushed a commit to branch master.

http://git.enlightenment.org/core/efl.git/commit/?id=8be56c94983c3d2772bb332c0e5c878b4b7d785c

commit 8be56c94983c3d2772bb332c0e5c878b4b7d785c
Author: Carsten Haitzler (Rasterman) <ras...@rasterman.com>
Date:   Wed Apr 13 01:04:11 2016 +0900

    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           | 225 +++++++++++++++++++++++++++++------
 src/tests/eo/suite/eo_test_general.c |  33 +++++
 3 files changed, 248 insertions(+), 39 deletions(-)

diff --git a/src/lib/eo/eo_base.eo b/src/lib/eo/eo_base.eo
index 4e93495..ad6cd68 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 776e92a..bd402e7 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,60 +44,225 @@ _eo_generic_data_node_free(Eo_Generic_Data_Node *node)
    free(node);
 }
 
+static Eina_Bool
+_eo_base_cb_key_obj_del(void *data, const Eo_Event *event)
+{
+   Eo *parent_obj = data;
+   Eo_Base_Data *pd = eo_data_scope_get(parent_obj, EO_BASE_CLASS);
+
+   if (pd)
+     {
+        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_Base_Data *pd)
+_eo_generic_data_del_all(Eo *obj, Eo_Base_Data *pd)
 {
-   Eina_Inlist *nnode;
-   Eo_Generic_Data_Node *node = NULL;
+   Eo_Generic_Data_Node *node;
 
-   EINA_INLIST_FOREACH_SAFE(pd->generic_data, nnode, 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));
-
+                                              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;
+   EINA_INLIST_FOREACH(pd->generic_data, node)
+     {
+        if (!strcmp(node->key, key))
+          {
+             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;
+          }
+     }
 
-   eo_key_data_del(obj, key);
-
-   node = malloc(sizeof(Eo_Generic_Data_Node));
+   node = calloc(1, sizeof(Eo_Generic_Data_Node));
    if (!node) return;
    node->key = eina_stringshare_add(key);
-   node->data = (void *) data;
+   node->data = (void *)data;
+   node->data_is_obj = EINA_FALSE;
    pd->generic_data = eina_inlist_prepend(pd->generic_data,
-         EINA_INLIST_GET(node));
+                                          EINA_INLIST_GET(node));
 }
 
 EOLIAN static void *
-_eo_base_key_data_get(const Eo *obj EINA_UNUSED, Eo_Base_Data *pd, const char 
*key)
+_eo_base_key_data_get(const Eo *obj, 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))
+          {
+             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))
           {
-             pd->generic_data =
-                eina_inlist_promote(pd->generic_data, EINA_INLIST_GET(node));
-             return node->data;
+             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)
 {
    if (pd->parent == 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 fcaa115..9f689f3 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();
 }

-- 


Reply via email to