summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gobject/ChangeLog5
-rw-r--r--gobject/gsignal.c85
2 files changed, 69 insertions, 21 deletions
diff --git a/gobject/ChangeLog b/gobject/ChangeLog
index 4fd8b60c7..c0944777d 100644
--- a/gobject/ChangeLog
+++ b/gobject/ChangeLog
@@ -1,3 +1,8 @@
+Sun Nov 28 01:37:54 2004 <timj@birnet.org>
+
+ * gsignal.c: applied patch by sven@gimp.org (#153727) to reduce
+ signal connection complexity from O(n_handlers) to O(1).
+
Thu Nov 25 14:09:41 2004 Manish Singh <yosh@gimp.org>
* abicheck.sh: filter out G_GNUC stuff when doing the compare.
diff --git a/gobject/gsignal.c b/gobject/gsignal.c
index aa24dd9c8..ef8f3fb4e 100644
--- a/gobject/gsignal.c
+++ b/gobject/gsignal.c
@@ -209,7 +209,10 @@ struct _HandlerList
{
guint signal_id;
Handler *handlers;
+ Handler *tail_before; /* normal signal handlers are appended here */
+ Handler *tail_after; /* CONNECT_AFTER handlers are appended here */
};
+
struct _Handler
{
gulong sequential_number;
@@ -355,7 +358,9 @@ handler_list_ensure (guint signal_id,
HandlerList key;
key.signal_id = signal_id;
- key.handlers = NULL;
+ key.handlers = NULL;
+ key.tail_before = NULL;
+ key.tail_after = NULL;
if (!hlbsa)
{
hlbsa = g_bsearch_array_create (&g_signal_hlbsa_bconfig);
@@ -577,16 +582,45 @@ handler_unref_R (guint signal_id,
handler->ref_count -= 1;
if (!handler->ref_count)
{
+ HandlerList *hlist = NULL;
+
if (handler->next)
handler->next->prev = handler->prev;
- if (handler->prev) /* watch out for g_signal_handlers_destroy()! */
+ if (handler->prev) /* watch out for g_signal_handlers_destroy()! */
handler->prev->next = handler->next;
else
{
- HandlerList *hlist = handler_list_lookup (signal_id, instance);
-
+ hlist = handler_list_lookup (signal_id, instance);
hlist->handlers = handler->next;
}
+
+ if (instance)
+ {
+ /* check if we are removing the handler pointed to by tail_before */
+ if (!handler->after && (!handler->next || handler->next->after))
+ {
+ if (!hlist)
+ hlist = handler_list_lookup (signal_id, instance);
+ if (hlist)
+ {
+ g_assert (hlist->tail_before == handler); /* paranoid */
+ hlist->tail_before = handler->prev;
+ }
+ }
+
+ /* check if we are removing the handler pointed to by tail_after */
+ if (!handler->next)
+ {
+ if (!hlist)
+ hlist = handler_list_lookup (signal_id, instance);
+ if (hlist)
+ {
+ g_assert (hlist->tail_after == handler); /* paranoid */
+ hlist->tail_after = handler->prev;
+ }
+ }
+ }
+
SIGNAL_UNLOCK ();
g_closure_unref (handler->closure);
SIGNAL_LOCK ();
@@ -605,29 +639,38 @@ handler_insert (guint signal_id,
hlist = handler_list_ensure (signal_id, instance);
if (!hlist->handlers)
- hlist->handlers = handler;
- else if (hlist->handlers->after && !handler->after)
{
- handler->next = hlist->handlers;
- hlist->handlers->prev = handler;
hlist->handlers = handler;
+ if (!handler->after)
+ hlist->tail_before = handler;
+ }
+ else if (handler->after)
+ {
+ handler->prev = hlist->tail_after;
+ hlist->tail_after->next = handler;
}
else
{
- Handler *tmp = hlist->handlers;
-
- if (handler->after)
- while (tmp->next)
- tmp = tmp->next;
- else
- while (tmp->next && !tmp->next->after)
- tmp = tmp->next;
- if (tmp->next)
- tmp->next->prev = handler;
- handler->next = tmp->next;
- handler->prev = tmp;
- tmp->next = handler;
+ if (hlist->tail_before)
+ {
+ handler->next = hlist->tail_before->next;
+ if (handler->next)
+ handler->next->prev = handler;
+ handler->prev = hlist->tail_before;
+ hlist->tail_before->next = handler;
+ }
+ else /* insert !after handler into a list of only after handlers */
+ {
+ handler->next = hlist->handlers;
+ if (handler->next)
+ handler->next->prev = handler;
+ hlist->handlers = handler;
+ }
+ hlist->tail_before = handler;
}
+
+ if (!handler->next)
+ hlist->tail_after = handler;
}
static inline void