typedef struct _LttvHookClosure {
- LttvHook hook;
- void *hook_data;
+ LttvHook hook;
+ void *hook_data;
+ LttvHookPrio prio;
+ guint ref_count;
} LttvHookClosure;
+gint lttv_hooks_prio_compare(LttvHookClosure *a, LttvHookClosure *b)
+{
+ if(a->prio < b->prio) return -1;
+ if(a->prio > b->prio) return 1;
+ return 0;
+}
+
LttvHooks *lttv_hooks_new()
{
}
-void lttv_hooks_add(LttvHooks *h, LttvHook f, void *hook_data)
+void lttv_hooks_add(LttvHooks *h, LttvHook f, void *hook_data, LttvHookPrio p)
{
- LttvHookClosure c;
-
+ LttvHookClosure *c, new_c;
+ guint i;
+
if(h == NULL)g_error("Null hook added");
- c.hook = f;
- c.hook_data = hook_data;
- g_array_append_val(h,c);
-}
+ new_c.hook = f;
+ new_c.hook_data = hook_data;
+ new_c.prio = p;
+ new_c.ref_count = 1;
+ /* Preliminary check for duplication */
+ /* only hook and hook data is checked */
+ for(i = 0; i < h->len; i++) {
+ c = &g_array_index(h, LttvHookClosure, i);
+ if(new_c.hook == c->hook && new_c.hook_data == c->hook_data) {
+ g_assert(new_c.prio == c->prio);
+ c->ref_count++;
+ return;
+ }
+ }
+
+
+ for(i = 0; i < h->len; i++) {
+ c = &g_array_index(h, LttvHookClosure, i);
+ if(new_c.prio < c->prio) {
+ g_array_insert_val(h,i,new_c);
+ return;
+ }
+ }
+ if(i == h->len)
+ g_array_append_val(h,new_c);
+}
-void lttv_hooks_add_list(LttvHooks *h, LttvHooks *list)
+/* lttv_hooks_add_list
+ *
+ * Adds a sorted list into another sorted list.
+ *
+ * Note : h->len is modified, but only incremented. This assures
+ * its coherence through the function.
+ *
+ * j is an index to the element following the last one added in the
+ * destination array.
+ */
+void lttv_hooks_add_list(LttvHooks *h, const LttvHooks *list)
{
- guint i;
+ guint i,j,k;
+ LttvHookClosure *c;
+ const LttvHookClosure *new_c;
if(list == NULL) return;
- for(i = 0 ; i < list->len; i++) {
- g_array_append_val(h,g_array_index(list, LttvHookClosure, i));
+ for(i = 0, j = 0 ; i < list->len; i++) {
+ new_c = &g_array_index(list, LttvHookClosure, i);
+ gboolean found=FALSE;
+
+ /* Preliminary check for duplication */
+ /* only hook and hook data is checked, not priority */
+ for(k = 0; k < h->len; k++) {
+ c = &g_array_index(h, LttvHookClosure, k);
+ if(new_c->hook == c->hook && new_c->hook_data == c->hook_data) {
+ /* Found another identical entry : increment its ref_count and
+ * jump over the source index */
+ g_assert(new_c->prio == c->prio);
+ found=TRUE;
+ c->ref_count++;
+ break;
+ }
+ }
+
+ if(!found) {
+ /* If not found, add it to the destination array */
+ while(j < h->len) {
+ c = &g_array_index(h, LttvHookClosure, j);
+ if(new_c->prio < c->prio) {
+ g_array_insert_val(h,j,*new_c);
+ j++;
+ break;
+ }
+ else j++;
+ }
+ if(j == h->len) {
+ g_array_append_val(h,*new_c);
+ j++;
+ }
+ }
}
}
for(i = 0 ; i < h->len ; i++) {
c = &g_array_index(h, LttvHookClosure, i);
if(c->hook == f) {
- hook_data = c->hook_data;
- lttv_hooks_remove_by_position(h, i);
- return hook_data;
+ if(c->ref_count == 1) {
+ hook_data = c->hook_data;
+ lttv_hooks_remove_by_position(h, i);
+ return hook_data;
+ } else {
+ g_assert(c->ref_count != 0);
+ c->ref_count--;
+ return NULL; /* We do not want anyone to free a hook_data
+ still referenced */
+ }
}
}
return NULL;
for(i = 0 ; i < h->len ; i++) {
c = &g_array_index(h, LttvHookClosure, i);
if(c->hook == f && c->hook_data == hook_data) {
- lttv_hooks_remove_by_position(h, i);
- return;
+ if(c->ref_count == 1) {
+ lttv_hooks_remove_by_position(h, i);
+ return;
+ } else {
+ g_assert(c->ref_count != 0);
+ c->ref_count--;
+ return;
+ }
}
}
}
c = &g_array_index(h, LttvHookClosure, i);
c_list = &g_array_index(list, LttvHookClosure, j);
if(c->hook == c_list->hook && c->hook_data == c_list->hook_data) {
- lttv_hooks_remove_by_position(h, i);
+ if(c->ref_count == 1) {
+ lttv_hooks_remove_by_position(h, i);
+ } else {
+ g_assert(c->ref_count != 0);
+ c->ref_count--;
+ }
j++;
}
else i++;
}
-void lttv_hooks_get(LttvHooks *h, unsigned i, LttvHook *f, void **hook_data)
+void lttv_hooks_get(LttvHooks *h, unsigned i, LttvHook *f, void **hook_data,
+ LttvHookPrio *p)
{
LttvHookClosure *c;
+ if(i >= h->len)
+ {
+ *f = NULL;
+ *hook_data = NULL;
+ *p = 0;
+ return;
+ }
+
c = &g_array_index(h, LttvHookClosure, i);
*f = c->hook;
*hook_data = c->hook_data;
+ *p = c->prio;
}
g_array_remove_index(h, i);
}
-
gboolean lttv_hooks_call(LttvHooks *h, void *call_data)
{
gboolean ret, sum_ret = FALSE;
return FALSE;
}
+gboolean lttv_hooks_call_merge(LttvHooks *h1, void *call_data1,
+ LttvHooks *h2, void *call_data2)
+{
+ gboolean ret, sum_ret = FALSE;
+
+ LttvHookClosure *c1, *c2;
+
+ guint i, j;
+
+ if(h1 != NULL && h2 != NULL) {
+ for(i = 0, j = 0 ; i < h1->len && j < h2->len ;) {
+ c1 = &g_array_index(h1, LttvHookClosure, i);
+ c2 = &g_array_index(h2, LttvHookClosure, j);
+ if(c1->prio <= c2->prio) {
+ ret = c1->hook(c1->hook_data,call_data1);
+ sum_ret = sum_ret || ret;
+ i++;
+ }
+ else {
+ ret = c2->hook(c2->hook_data,call_data2);
+ sum_ret = sum_ret || ret;
+ j++;
+ }
+ }
+ /* Finish the last list with hooks left */
+ for(;i < h1->len; i++) {
+ c1 = &g_array_index(h1, LttvHookClosure, i);
+ ret = c1->hook(c1->hook_data,call_data1);
+ sum_ret = sum_ret || ret;
+ }
+ for(;j < h2->len; j++) {
+ c2 = &g_array_index(h2, LttvHookClosure, j);
+ ret = c2->hook(c2->hook_data,call_data2);
+ sum_ret = sum_ret || ret;
+ }
+ }
+ else if(h1 != NULL && h2 == NULL) {
+ for(i = 0 ; i < h1->len ; i++) {
+ c1 = &g_array_index(h1, LttvHookClosure, i);
+ ret = c1->hook(c1->hook_data,call_data1);
+ sum_ret = sum_ret || ret;
+ }
+ }
+ else if(h1 == NULL && h2 != NULL) {
+ for(j = 0 ; j < h2->len ; j++) {
+ c2 = &g_array_index(h2, LttvHookClosure, j);
+ ret = c2->hook(c2->hook_data,call_data2);
+ sum_ret = sum_ret || ret;
+ }
+ }
+
+ return sum_ret;
+}
+
+gboolean lttv_hooks_call_check_merge(LttvHooks *h1, void *call_data1,
+ LttvHooks *h2, void *call_data2)
+{
+ LttvHookClosure *c1, *c2;
+
+ guint i, j;
+
+ if(h1 != NULL && h2 != NULL) {
+ for(i = 0, j = 0 ; i < h1->len && j < h2->len ;) {
+ c1 = &g_array_index(h1, LttvHookClosure, i);
+ c2 = &g_array_index(h2, LttvHookClosure, j);
+ if(c1->prio <= c2->prio) {
+ if(c1->hook(c1->hook_data,call_data1)) return TRUE;
+ i++;
+ }
+ else {
+ if(c2->hook(c2->hook_data,call_data2)) return TRUE;
+ j++;
+ }
+ }
+ /* Finish the last list with hooks left */
+ for(;i < h1->len; i++) {
+ c1 = &g_array_index(h1, LttvHookClosure, i);
+ if(c1->hook(c1->hook_data,call_data1)) return TRUE;
+ }
+ for(;j < h2->len; j++) {
+ c2 = &g_array_index(h2, LttvHookClosure, j);
+ if(c2->hook(c2->hook_data,call_data2)) return TRUE;
+ }
+ }
+ else if(h1 != NULL && h2 == NULL) {
+ for(i = 0 ; i < h1->len ; i++) {
+ c1 = &g_array_index(h1, LttvHookClosure, i);
+ if(c1->hook(c1->hook_data,call_data1)) return TRUE;
+ }
+ }
+ else if(h1 == NULL && h2 != NULL) {
+ for(j = 0 ; j < h2->len ; j++) {
+ c2 = &g_array_index(h2, LttvHookClosure, j);
+ if(c2->hook(c2->hook_data,call_data2)) return TRUE;
+ }
+ }
+
+ return FALSE;
+
+}
+
LttvHooksById *lttv_hooks_by_id_new()
{