changeset 31707:47f7b8ca6149

conversation: O(1) purple_conv_chat_cb_find I also deprecated what seems like a useless function. The ui_data is to implement constant-time lookups for the room list in Pidgin.
author Paul Aurich <paul@darkrain42.org>
date Mon, 20 Jun 2011 05:24:30 +0000
parents bb77a9ceca17
children 5847a4c212f0
files ChangeLog.API libpurple/conversation.c libpurple/conversation.h
diffstat 3 files changed, 69 insertions(+), 21 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog.API	Mon Jun 20 05:11:53 2011 +0000
+++ b/ChangeLog.API	Mon Jun 20 05:24:30 2011 +0000
@@ -1,6 +1,17 @@
 Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul
 
 version 2.9.0 (MM/DD/YYYY):
+	libpurple:
+		Added:
+		* Hash table and equivalence function to PurpleConvChat struct,
+		  which makes purple_conv_chat_cb_find O(1).  The equivalence
+		  function should only be set by a prpl, and must only be set
+		  before any occupants are in the room.
+		* ui_data opaque pointer to PurpleConvChatBuddy struct.
+
+		Deprecated:
+		* purple_conv_chat_set_users
+		* PurpleConvChat in_room list
 
 version 2.8.0 (06/07/2011):
 	libpurple:
--- a/libpurple/conversation.c	Mon Jun 20 05:11:53 2011 +0000
+++ b/libpurple/conversation.c	Mon Jun 20 05:24:30 2011 +0000
@@ -70,6 +70,25 @@
 	g_free(hc);
 }
 
+static guint _purple_conversation_user_hash(gconstpointer data)
+{
+	const gchar *name = data;
+	gchar *casefold, *collated;
+	guint hash;
+
+	casefold = g_utf8_casefold(name, -1);
+	collated = g_utf8_collate_key(casefold, -1);
+	hash     = g_str_hash(collated);
+	g_free(collated);
+	g_free(casefold);
+	return hash;
+}
+
+static gboolean _purple_conversation_user_equal(gconstpointer a, gconstpointer b)
+{
+	return !purple_utf8_strcasecmp(a, b);
+}
+
 void
 purple_conversations_set_ui_ops(PurpleConversationUiOps *ops)
 {
@@ -393,6 +412,10 @@
 
 		conv->u.chat = g_new0(PurpleConvChat, 1);
 		conv->u.chat->conv = conv;
+		conv->u.chat->user_hash_func = _purple_conversation_user_hash;
+		conv->u.chat->user_eq_func = _purple_conversation_user_equal;
+		conv->u.chat->users = g_hash_table_new_full(_purple_conversation_user_hash,
+				_purple_conversation_user_equal, NULL, NULL);
 		PURPLE_DBUS_REGISTER_POINTER(conv->u.chat, PurpleConvChat);
 
 		chats = g_list_prepend(chats, conv);
@@ -547,6 +570,8 @@
 		conv->u.im = NULL;
 	}
 	else if (conv->type == PURPLE_CONV_TYPE_CHAT) {
+		g_hash_table_destroy(conv->u.chat->users);
+		conv->u.chat->users = NULL;
 
 		g_list_foreach(conv->u.chat->in_room, (GFunc)purple_conv_chat_cb_destroy, NULL);
 		g_list_free(conv->u.chat->in_room);
@@ -1677,9 +1702,9 @@
 
 		cbuddy = purple_conv_chat_cb_new(user, alias, flag);
 		cbuddy->buddy = purple_find_buddy(conv->account, user) != NULL;
-		/* This seems dumb. Why should we set users thousands of times? */
-		purple_conv_chat_set_users(chat,
-				g_list_prepend(chat->in_room, cbuddy));
+
+		chat->in_room = g_list_prepend(chat->in_room, cbuddy);
+		g_hash_table_replace(chat->users, cbuddy->name, cbuddy);
 
 		cbuddies = g_list_prepend(cbuddies, cbuddy);
 
@@ -1771,8 +1796,9 @@
 	flags = purple_conv_chat_user_get_flags(chat, old_user);
 	cb = purple_conv_chat_cb_new(new_user, new_alias, flags);
 	cb->buddy = purple_find_buddy(conv->account, new_user) != NULL;
-	purple_conv_chat_set_users(chat,
-		g_list_prepend(chat->in_room, cb));
+
+	chat->in_room = g_list_prepend(chat->in_room, cb);
+	g_hash_table_replace(chat->users, cb->name, cb);
 
 	if (ops != NULL && ops->chat_rename_user != NULL)
 		ops->chat_rename_user(conv, old_user, new_user, new_alias);
@@ -1780,8 +1806,8 @@
 	cb = purple_conv_chat_cb_find(chat, old_user);
 
 	if (cb) {
-		purple_conv_chat_set_users(chat,
-				g_list_remove(chat->in_room, cb));
+		chat->in_room = g_list_remove(chat->in_room, cb);
+		g_hash_table_remove(chat->users, cb->name);
 		purple_conv_chat_cb_destroy(cb);
 	}
 
@@ -1874,8 +1900,8 @@
 		cb = purple_conv_chat_cb_find(chat, user);
 
 		if (cb) {
-			purple_conv_chat_set_users(chat,
-					g_list_remove(chat->in_room, cb));
+			chat->in_room = g_list_remove(chat->in_room, cb);
+			g_hash_table_remove(chat->users, cb);
 			purple_conv_chat_cb_destroy(cb);
 		}
 
@@ -1943,6 +1969,8 @@
 		g_list_free(names);
 	}
 
+	g_hash_table_remove_all(chat->users);
+
 	for (l = users; l; l = l->next)
 	{
 		PurpleConvChatBuddy *cb = l->data;
@@ -1956,7 +1984,7 @@
 	}
 
 	g_list_free(users);
-	purple_conv_chat_set_users(chat, NULL);
+	chat->in_room = NULL;
 }
 
 
@@ -2146,19 +2174,10 @@
 PurpleConvChatBuddy *
 purple_conv_chat_cb_find(PurpleConvChat *chat, const char *name)
 {
-	GList *l;
-	PurpleConvChatBuddy *cb = NULL;
-
 	g_return_val_if_fail(chat != NULL, NULL);
 	g_return_val_if_fail(name != NULL, NULL);
 
-	for (l = purple_conv_chat_get_users(chat); l; l = l->next) {
-		cb = l->data;
-		if (!g_utf8_collate(cb->name, name))
-			return cb;
-	}
-
-	return NULL;
+	return g_hash_table_lookup(chat->users, name);
 }
 
 void
--- a/libpurple/conversation.h	Mon Jun 20 05:11:53 2011 +0000
+++ b/libpurple/conversation.h	Mon Jun 20 05:24:30 2011 +0000
@@ -271,7 +271,9 @@
 {
 	PurpleConversation *conv;          /**< The parent conversation.      */
 
-	GList *in_room;                  /**< The users in the room.        */
+	GList *in_room;                  /**< The users in the room.
+	                                  *   @deprecated Will be removed in 3.0.0
+									  */
 	GList *ignored;                  /**< Ignored users.                */
 	char  *who;                      /**< The person who set the topic. */
 	char  *topic;                    /**< The topic.                    */
@@ -279,6 +281,19 @@
 	char *nick;                      /**< Your nick in this chat.       */
 
 	gboolean left;                   /**< We left the chat and kept the window open */
+	GHashTable *users;               /**< Hash table of the users in the room.
+	                                  *   @since 2.9.0
+	                                  */
+	GHashFunc user_hash_func;        /**< Function used to hash entries into
+	                                  *   the users hash. Defaults to a
+	                                  *   case-insensitive collation function.
+	                                  *   @since 2.9.0
+	                                  */
+	GEqualFunc user_eq_func;         /**< Function used for equality in the
+	                                  *   users hash.  Defaults to a wrapper
+	                                  *   around purple_utf8_strcasecmp.
+	                                  *   @since 2.9.0
+	                                  */
 };
 
 /**
@@ -304,6 +319,7 @@
 	GHashTable *attributes;          /**< A hash table of attributes about the user, such as
                                     *   real name, user@host, etc.
                                     */
+	gpointer ui_data;                /** < The UI can put whatever it wants here. */
 };
 
 /**
@@ -1065,6 +1081,8 @@
  * @param users The list of users.
  *
  * @return The list passed.
+ *
+ * @deprecated This function will be removed in 3.0.0.  You shouldn't be using it anyway.
  */
 GList *purple_conv_chat_set_users(PurpleConvChat *chat, GList *users);