*/
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.
const Eobj_Class *klass;
void *data_blob;
int refcount;
+#ifndef NDEBUG
+ Eina_Inlist *xrefs;
+#endif
+
Eina_List *composite_objects;
Eina_Inlist *callbacks;
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)
{
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)
}
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();
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);
}