diff --git a/lib/mu-container.c b/lib/mu-container.c index 59633032..64f9bf9a 100644 --- a/lib/mu-container.c +++ b/lib/mu-container.c @@ -80,15 +80,6 @@ set_parent (MuContainer *c, MuContainer *parent) } } -static MuContainer* -find_last (MuContainer *c) -{ - while (c && c->next) - c = c->next; - - return c; -} - G_GNUC_UNUSED static gboolean check_dup (MuContainer *c, GHashTable *hash) @@ -131,7 +122,21 @@ mu_container_append_siblings (MuContainer *c, MuContainer *sibling) /* assert_no_duplicates (c); */ set_parent (sibling, c->parent); - (find_last(c))->next = sibling; + + /* find the last sibling and append; first we try our cache + * 'last', otherwise we need to walk the chain. We use a + * cached last as to avoid walking the chain (which is + * O(n*n)) */ + if (c->last) + c->last->next = sibling; + else { + /* no 'last' cached, so walk the chain */ + MuContainer *c2; + for (c2 = c; c2 && c2->next; c2 = c2->next); + c2->next = sibling; + } + /* update the cached last */ + c->last = sibling->last ? sibling->last : sibling; /* assert_no_duplicates (c); */ @@ -158,6 +163,13 @@ mu_container_remove_sibling (MuContainer *c, MuContainer *sibling) prev = cur; } + /* unset the cached last; it's not valid anymore + * + * TODO: we could actually do a better job updating last + * rather than invalidating it. */ + if (c) + c->last = NULL; + return c; } @@ -201,7 +213,8 @@ typedef void (*MuContainerPathForeachFunc) (MuContainer*, gpointer, Path*); static void mu_container_path_foreach_real (MuContainer *c, guint level, Path *path, - MuContainerPathForeachFunc func, gpointer user_data) + MuContainerPathForeachFunc func, + gpointer user_data) { if (!c) return; @@ -210,7 +223,8 @@ mu_container_path_foreach_real (MuContainer *c, guint level, Path *path, func (c, user_data, path); /* children */ - mu_container_path_foreach_real (c->child, level + 1, path, func, user_data); + mu_container_path_foreach_real (c->child, level + 1, path, + func, user_data); /* siblings */ mu_container_path_foreach_real (c->next, level, path, func, user_data); diff --git a/lib/mu-container.h b/lib/mu-container.h index b0fc357e..b309462b 100644 --- a/lib/mu-container.h +++ b/lib/mu-container.h @@ -29,8 +29,7 @@ enum _MuContainerFlag { MU_CONTAINER_FLAG_SPLICE = 1 << 1, MU_CONTAINER_FLAG_DUP = 1 << 2 }; - -typedef guint8 MuContainerFlag; +typedef enum _MuContainerFlag MuContainerFlag; /* * MuContainer data structure, as seen in JWZs document: @@ -38,10 +37,21 @@ typedef guint8 MuContainerFlag; */ struct _MuContainer { struct _MuContainer *parent, *child, *next; - MuContainerFlag flags; - MuMsg *msg; - guint docid; - const char* msgid; + + /* note: we cache the last of the string of next->next->... + * `mu_container_append_siblings' shows up high in the + * profiles since it needs to walk to the end, and this give + * O(n*n) behavior. + * */ + struct _MuContainer *last; + + + MuMsg *msg; + const char *msgid; + + unsigned docid; + MuContainerFlag flags; + }; typedef struct _MuContainer MuContainer; @@ -177,7 +187,8 @@ typedef int (*MuContainerCmpFunc) (MuContainer *c1, MuContainer *c2, * * @return a sorted container */ -MuContainer* mu_container_sort (MuContainer *c, MuMsgFieldId mfid, gboolean revert, +MuContainer* mu_container_sort (MuContainer *c, MuMsgFieldId mfid, + gboolean revert, gpointer user_data);