Eobj: Add named (by obj ptr) ref - xref.

SVN revision: 70273
This commit is contained in:
Tom Hacohen 2012-04-17 15:22:22 +00:00
parent 69afa9d2ad
commit d6146c132e
3 changed files with 131 additions and 0 deletions

View 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.

View 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)

View 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);
}