Mercurial > pidgin
diff libpurple/blist.c @ 26764:0e99b80b54c6
Make purple_find_buddies(account, NULL) O(# buddies in the account) and rewrite purple_ssi_parselist to take advantage of said efficiency.
Applied HanzZ's patch with a few tweaks, mostly making the hash table local
to blist.c and using the signals from the previous commit.
committer: Paul Aurich <paul@darkrain42.org>
author | hanzz@soc.pidgin.im |
---|---|
date | Fri, 01 May 2009 08:07:12 +0000 |
parents | 3e274d6fcfaa |
children | 0924698e2362 |
line wrap: on
line diff
--- a/libpurple/blist.c Fri May 01 06:59:36 2009 +0000 +++ b/libpurple/blist.c Fri May 01 08:07:12 2009 +0000 @@ -40,6 +40,14 @@ static PurpleBlistUiOps *blist_ui_ops = NULL; static PurpleBuddyList *purplebuddylist = NULL; + +/** + * A hash table used for efficient lookups of buddies by name. + * PurpleAccount* => GHashTable*, with the inner hash table being + * struct _purple_hbuddy => PurpleBuddy* + */ +static GHashTable *buddies_cache = NULL; + static guint save_timer = 0; static gboolean blist_loaded = FALSE; @@ -91,6 +99,21 @@ g_free(hb); } +static void +purple_blist_buddies_cache_add_account(PurpleAccount *account) +{ + GHashTable *account_buddies = g_hash_table_new_full((GHashFunc)_purple_blist_hbuddy_hash, + (GEqualFunc)_purple_blist_hbuddy_equal, + (GDestroyNotify)_purple_blist_hbuddy_free_key, NULL); + g_hash_table_insert(buddies_cache, account, account_buddies); +} + +static void +purple_blist_buddies_cache_remove_account(const PurpleAccount *account) +{ + g_hash_table_remove(buddies_cache, account); +} + /********************************************************************* * Writing to disk * @@ -666,6 +689,7 @@ PurpleBuddyList *purple_blist_new() { PurpleBlistUiOps *ui_ops; + GList *account; PurpleBuddyList *gbl = g_new0(PurpleBuddyList, 1); PURPLE_DBUS_REGISTER_POINTER(gbl, PurpleBuddyList); @@ -675,6 +699,14 @@ (GEqualFunc)_purple_blist_hbuddy_equal, (GDestroyNotify)_purple_blist_hbuddy_free_key, NULL); + buddies_cache = g_hash_table_new_full(g_direct_hash, g_direct_equal, + NULL, (GDestroyNotify)g_hash_table_destroy); + + for (account = purple_accounts_get_all(); account != NULL; account = account->next) + { + purple_blist_buddies_cache_add_account(account->data); + } + if (ui_ops != NULL && ui_ops->new_list != NULL) ui_ops->new_list(gbl); @@ -898,7 +930,8 @@ void purple_blist_rename_buddy(PurpleBuddy *buddy, const char *name) { PurpleBlistUiOps *ops = purple_blist_get_ui_ops(); - struct _purple_hbuddy *hb; + struct _purple_hbuddy *hb, *hb2; + GHashTable *account_buddies; g_return_if_fail(buddy != NULL); @@ -907,11 +940,21 @@ hb->account = buddy->account; hb->group = ((PurpleBlistNode *)buddy)->parent->parent; g_hash_table_remove(purplebuddylist->buddies, hb); + + account_buddies = g_hash_table_lookup(buddies_cache, buddy->account); + g_hash_table_remove(account_buddies, hb); g_free(hb->name); hb->name = g_strdup(purple_normalize(buddy->account, name)); g_hash_table_replace(purplebuddylist->buddies, hb, buddy); + hb2 = g_new(struct _purple_hbuddy, 1); + hb2->name = g_strdup(hb->name); + hb2->account = buddy->account; + hb2->group = ((PurpleBlistNode *)buddy)->parent->parent; + + g_hash_table_replace(account_buddies, hb2, buddy); + g_free(buddy->name); buddy->name = g_strdup(name); @@ -1433,7 +1476,8 @@ PurpleGroup *g; PurpleContact *c; PurpleBlistUiOps *ops = purple_blist_get_ui_ops(); - struct _purple_hbuddy *hb; + struct _purple_hbuddy *hb, *hb2; + GHashTable *account_buddies; g_return_if_fail(buddy != NULL); g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY((PurpleBlistNode*)buddy)); @@ -1503,6 +1547,10 @@ hb->account = buddy->account; hb->group = bnode->parent->parent; g_hash_table_remove(purplebuddylist->buddies, hb); + + account_buddies = g_hash_table_lookup(buddies_cache, buddy->account); + g_hash_table_remove(account_buddies, hb); + g_free(hb->name); g_free(hb); } @@ -1549,6 +1597,15 @@ g_hash_table_replace(purplebuddylist->buddies, hb, buddy); + account_buddies = g_hash_table_lookup(buddies_cache, buddy->account); + + hb2 = g_new(struct _purple_hbuddy, 1); + hb2->name = g_strdup(hb->name); + hb2->account = buddy->account; + hb2->group = ((PurpleBlistNode*)buddy)->parent->parent; + + g_hash_table_replace(account_buddies, hb2, buddy); + purple_contact_invalidate_priority_buddy(purple_buddy_get_contact(buddy)); purple_blist_schedule_save(); @@ -1707,18 +1764,31 @@ while (bnode) { PurpleBlistNode *next_bnode = bnode->next; PurpleBuddy *b = (PurpleBuddy*)bnode; - - struct _purple_hbuddy *hb = g_new(struct _purple_hbuddy, 1); + GHashTable *account_buddies; + + struct _purple_hbuddy *hb, *hb2; + + hb = g_new(struct _purple_hbuddy, 1); hb->name = g_strdup(purple_normalize(b->account, b->name)); hb->account = b->account; hb->group = cnode->parent; g_hash_table_remove(purplebuddylist->buddies, hb); + account_buddies = g_hash_table_lookup(buddies_cache, b->account); + g_hash_table_remove(account_buddies, hb); + if (!purple_find_buddy_in_group(b->account, b->name, g)) { hb->group = gnode; g_hash_table_replace(purplebuddylist->buddies, hb, b); + hb2 = g_new(struct _purple_hbuddy, 1); + hb2->name = g_strdup(hb->name); + hb2->account = b->account; + hb2->group = gnode; + + g_hash_table_replace(account_buddies, hb2, b); + if (purple_account_get_connection(b->account)) serv_move_buddy(b, (PurpleGroup *)cnode->parent, g); } else { @@ -1936,6 +2006,7 @@ PurpleContact *contact; PurpleGroup *group; struct _purple_hbuddy hb; + GHashTable *account_buddies; g_return_if_fail(buddy != NULL); @@ -1982,6 +2053,10 @@ hb.account = buddy->account; hb.group = gnode; g_hash_table_remove(purplebuddylist->buddies, &hb); + + account_buddies = g_hash_table_lookup(buddies_cache, buddy->account); + g_hash_table_remove(account_buddies, &hb); + g_free(hb.name); /* Update the UI */ @@ -2256,13 +2331,10 @@ static void find_acct_buddies(gpointer key, gpointer value, gpointer data) { - struct _purple_hbuddy *hb = key; PurpleBuddy *buddy = value; - struct _list_account_buddies *ab = data; - - if (hb->account == ab->account) { - ab->list = g_slist_prepend(ab->list, buddy); - } + GSList **list = data; + + *list = g_slist_prepend(*list, buddy); } GSList *purple_find_buddies(PurpleAccount *account, const char *name) @@ -2274,7 +2346,6 @@ g_return_val_if_fail(purplebuddylist != NULL, NULL); g_return_val_if_fail(account != NULL, NULL); - if ((name != NULL) && (*name != '\0')) { struct _purple_hbuddy hb; @@ -2288,11 +2359,10 @@ } g_free(hb.name); } else { - struct _list_account_buddies *ab = g_new0(struct _list_account_buddies, 1); - ab->account = account; - g_hash_table_foreach(purplebuddylist->buddies, find_acct_buddies, ab); - ret = ab->list; - g_free(ab); + GSList *list = NULL; + GHashTable *buddies = g_hash_table_lookup(buddies_cache, account); + g_hash_table_foreach(buddies, find_acct_buddies, &list); + ret = list; } return ret; @@ -2931,6 +3001,16 @@ purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_BLIST_NODE), purple_value_new(PURPLE_TYPE_STRING)); + + purple_signal_connect(purple_accounts_get_handle(), "account-created", + handle, + PURPLE_CALLBACK(purple_blist_buddies_cache_add_account), + NULL); + + purple_signal_connect(purple_accounts_get_handle(), "account-destroying", + handle, + PURPLE_CALLBACK(purple_blist_buddies_cache_remove_account), + NULL); } void @@ -2951,6 +3031,10 @@ node = next_node; } purplebuddylist->root = NULL; - + + g_hash_table_destroy(purplebuddylist->buddies); + g_hash_table_destroy(buddies_cache); + + purple_signals_disconnect_by_handle(purple_blist_get_handle()); purple_signals_unregister_by_instance(purple_blist_get_handle()); }