Eobj: Add named (by obj ptr) ref - xref.
authortasn <tasn>
Tue, 17 Apr 2012 15:22:22 +0000 (15:22 +0000)
committertasn <tasn@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Tue, 17 Apr 2012 15:22:22 +0000 (15:22 +0000)
git-svn-id: http://svn.enlightenment.org/svn/e/trunk/PROTO/eobj@70273 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

lib/Eobj.h
lib/eobj.c
tests/eobj_test_general.c

index 255dae5..6303c23 100644 (file)
@@ -399,6 +399,25 @@ EAPI void eobj_unref(Eobj *obj);
  */
 EAPI int eobj_ref_get(const Eobj *obj);
 
+#define eobj_xref(obj, ref_obj) eobj_xref_internal(obj, ref_obj, __FILE__, __LINE__)
+
+/**
+ * @brief Increment the object's reference count by 1.
+ * @param obj the object to work on.
+ * @return The object passed.
+ *
+ * @see eobj_xunref()
+ */
+EAPI Eobj *eobj_xref_internal(Eobj *obj, const Eobj *ref_obj, const char *file, int line);
+
+/**
+ * @brief Decrement the object's reference count by 1 and free it if needed.
+ * @param obj the object to work on.
+ *
+ * @see eobj_xref_internal()
+ */
+EAPI void eobj_xunref(Eobj *obj, const Eobj *ref_obj);
+
 /**
  * @brief Delete the object passed (disregarding ref count).
  * @param obj the object to work on.
index e449575..36a8674 100644 (file)
@@ -26,6 +26,10 @@ struct _Eobj {
      const Eobj_Class *klass;
      void *data_blob;
      int refcount;
+#ifndef NDEBUG
+     Eina_Inlist *xrefs;
+#endif
+
      Eina_List *composite_objects;
 
      Eina_Inlist *callbacks;
@@ -755,6 +759,63 @@ fail:
    return NULL;
 }
 
+typedef struct
+{
+   EINA_INLIST;
+   const Eobj *ref_obj;
+   const char *file;
+   int line;
+} Eobj_Xref_Node;
+
+EAPI Eobj *
+eobj_xref_internal(Eobj *obj, const Eobj *ref_obj, const char *file, int line)
+{
+   eobj_ref(obj);
+
+#ifndef NDEBUG
+   Eobj_Xref_Node *xref = calloc(1, sizeof(*xref));
+   xref->ref_obj = ref_obj;
+   xref->file = file;
+   xref->line = line;
+
+   /* FIXME: Make it sorted. */
+   obj->xrefs = eina_inlist_prepend(obj->xrefs, EINA_INLIST_GET(xref));
+#else
+   (void) ref_obj;
+   (void) file;
+   (void) line;
+#endif
+
+   return obj;
+}
+
+EAPI void
+eobj_xunref(Eobj *obj, const Eobj *ref_obj)
+{
+#ifndef NDEBUG
+   Eobj_Xref_Node *xref = NULL;
+   EINA_INLIST_FOREACH(obj->xrefs, xref)
+     {
+        if (xref->ref_obj == ref_obj)
+           break;
+     }
+
+   if (xref)
+     {
+        obj->xrefs = eina_inlist_remove(obj->xrefs, EINA_INLIST_GET(xref));
+        free(xref);
+     }
+   else
+     {
+        ERR("ref_obj (%p) does not reference obj (%p). Aborting unref.", ref_obj, obj);
+        return;
+     }
+#else
+   (void) ref_obj;
+#endif
+   eobj_unref(obj);
+}
+
 EAPI Eobj *
 eobj_ref(Eobj *obj)
 {
@@ -804,6 +865,17 @@ eobj_unref(Eobj *obj)
              obj->kls_itr = nitr;
           }
 
+#ifndef NDEBUG
+        /* If for some reason it's not empty, clear it. */
+        while (obj->xrefs)
+          {
+             WRN("obj->xrefs is not empty, possibly a bug, please report. - An error will be reported for each xref in the stack.");
+             Eina_Inlist *nitr = nitr->next;
+             free(EINA_INLIST_CONTAINER_GET(obj->xrefs, Eobj_Kls_Itr_Node));
+             obj->xrefs = nitr;
+          }
+#endif
+
         Eina_List *itr, *itr_n;
         Eobj *emb_obj;
         EINA_LIST_FOREACH_SAFE(obj->composite_objects, itr, itr_n, emb_obj)
index f553d50..6809f7d 100644 (file)
@@ -19,6 +19,45 @@ START_TEST(eobj_simple)
 }
 END_TEST
 
+START_TEST(eobj_xrefs)
+{
+   eobj_init();
+   Eobj *obj = eobj_add(SIMPLE_CLASS, NULL);
+   Eobj *obj2 = eobj_add(SIMPLE_CLASS, NULL);
+   Eobj *obj3 = eobj_add(SIMPLE_CLASS, NULL);
+
+   eobj_xref(obj, obj2);
+   fail_if(eobj_ref_get(obj) != 2);
+   eobj_xref(obj, obj3);
+   fail_if(eobj_ref_get(obj) != 3);
+
+   eobj_xunref(obj, obj2);
+   fail_if(eobj_ref_get(obj) != 2);
+   eobj_xunref(obj, obj3);
+   fail_if(eobj_ref_get(obj) != 1);
+
+#ifndef NDEBUG
+   eobj_xunref(obj, obj3);
+   fail_if(eobj_ref_get(obj) != 1);
+
+   eobj_xref(obj, obj2);
+   fail_if(eobj_ref_get(obj) != 2);
+
+   eobj_xunref(obj, obj3);
+   fail_if(eobj_ref_get(obj) != 2);
+
+   eobj_xunref(obj, obj2);
+   fail_if(eobj_ref_get(obj) != 1);
+#endif
+
+   eobj_unref(obj);
+   eobj_unref(obj2);
+   eobj_unref(obj3);
+
+   eobj_shutdown();
+}
+END_TEST
+
 START_TEST(eobj_weak_reference)
 {
    eobj_init();
@@ -161,4 +200,5 @@ void eobj_test_general(TCase *tc)
    tcase_add_test(tc, eobj_op_errors);
    tcase_add_test(tc, eobj_simple);
    tcase_add_test(tc, eobj_weak_reference);
+   tcase_add_test(tc, eobj_xrefs);
 }