[notmuch] [PATCH 2/2] Added backwards iterator to threads
authorRuben Pollan <meskio@sindominio.net>
Sun, 21 Mar 2010 21:32:33 +0000 (22:32 +0100)
committerW. Trevor King <wking@tremily.us>
Fri, 7 Nov 2014 17:36:25 +0000 (09:36 -0800)
a1/530409d7ccf7cee13973f877e3acf5be66e980 [new file with mode: 0644]

diff --git a/a1/530409d7ccf7cee13973f877e3acf5be66e980 b/a1/530409d7ccf7cee13973f877e3acf5be66e980
new file mode 100644 (file)
index 0000000..a1ad5c4
--- /dev/null
@@ -0,0 +1,436 @@
+Return-Path: <meskio@sindominio.net>\r
+X-Original-To: notmuch@notmuchmail.org\r
+Delivered-To: notmuch@notmuchmail.org\r
+Received: from localhost (localhost [127.0.0.1])\r
+       by olra.theworths.org (Postfix) with ESMTP id 35759431FC1\r
+       for <notmuch@notmuchmail.org>; Sun, 21 Mar 2010 14:30:21 -0700 (PDT)\r
+X-Virus-Scanned: Debian amavisd-new at olra.theworths.org\r
+X-Spam-Flag: NO\r
+X-Spam-Score: -1.9\r
+X-Spam-Level: \r
+X-Spam-Status: No, score=-1.9 tagged_above=-999 required=5\r
+       tests=[BAYES_00=-1.9] autolearn=ham\r
+Received: from olra.theworths.org ([127.0.0.1])\r
+       by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024)\r
+       with ESMTP id ltOgh+LzfcdW for <notmuch@notmuchmail.org>;\r
+       Sun, 21 Mar 2010 14:30:19 -0700 (PDT)\r
+Received: from flatline.sindominio.net (flatline.sindominio.net [82.144.4.26])\r
+       by olra.theworths.org (Postfix) with ESMTP id D11A44196F0\r
+       for <notmuch@notmuchmail.org>; Sun, 21 Mar 2010 14:30:16 -0700 (PDT)\r
+Received: from localhost (localhost.localdomain [127.0.0.1])\r
+       by flatline.sindominio.net (Postfix) with ESMTP id E98DC348046;\r
+       Sun, 21 Mar 2010 22:30:15 +0100 (CET)\r
+X-Virus-Scanned: Debian amavisd-new at sindominio.net\r
+Received: from flatline.sindominio.net ([127.0.0.1])\r
+       by localhost (flatline.sindominio.net [127.0.0.1]) (amavisd-new,\r
+       port 10024)\r
+       with ESMTP id CoFItUAt1ChR; Sun, 21 Mar 2010 22:30:13 +0100 (CET)\r
+Received: from blackspot (heal.cauterized.net [89.140.131.167])\r
+       by flatline.sindominio.net (Postfix) with ESMTPA id BBABF348095;\r
+       Sun, 21 Mar 2010 22:29:28 +0100 (CET)\r
+Received: by blackspot (Postfix, from userid 1000)\r
+       id 78F448BDFD; Sun, 21 Mar 2010 22:32:42 +0100 (CET)\r
+From: Ruben Pollan <meskio@sindominio.net>\r
+To: notmuch@notmuchmail.org\r
+Date: Sun, 21 Mar 2010 22:32:33 +0100\r
+Message-Id: <1269207153-3687-3-git-send-email-meskio@sindominio.net>\r
+X-Mailer: git-send-email 1.7.0\r
+In-Reply-To: <1269080605-5617-1-git-send-email-meskio@sindominio.net>\r
+References: <1269080605-5617-1-git-send-email-meskio@sindominio.net>\r
+Subject: [notmuch] [PATCH 2/2] Added backwards iterator to threads\r
+X-BeenThere: notmuch@notmuchmail.org\r
+X-Mailman-Version: 2.1.13\r
+Precedence: list\r
+List-Id: "Use and development of the notmuch mail system."\r
+       <notmuch.notmuchmail.org>\r
+List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
+       <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
+List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
+List-Post: <mailto:notmuch@notmuchmail.org>\r
+List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
+List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
+       <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
+X-List-Received-Date: Sun, 21 Mar 2010 21:30:21 -0000\r
+\r
+Added the functions notmuch_threads_move_to_prevoius,\r
+notmuch_threads_move_to_last and  notmuch_threads_move_to_first to\r
+notmuch library. With them is possible to iterate backwards on threads.\r
+\r
+* notmuch_threads_move_to_prevoius do the opposite than\r
+  notmuch_threads_move_to_next, getting the threads iterator one\r
+  position backwards.\r
+\r
+* notmuch_threads_move_to_last move the iterator to the first last\r
+thread.\r
+\r
+* notmuch_threads_move_to_first move the iterator to the first valid\r
+  thread.\r
+\r
+For it has been implemented notmuch_thread_list_t structur that stores\r
+the thread_ids so the backwards iteration gets the thread_id in the same\r
+order that was show on forward iteration.\r
+---\r
+ lib/notmuch.h |   28 ++++++++\r
+ lib/query.cc  |  209 ++++++++++++++++++++++++++++++++++++++++++++++++++++----\r
+ 2 files changed, 222 insertions(+), 15 deletions(-)\r
+\r
+diff --git a/lib/notmuch.h b/lib/notmuch.h\r
+index 0d9cb0f..62f4ad4 100644\r
+--- a/lib/notmuch.h\r
++++ b/lib/notmuch.h\r
+@@ -466,6 +466,15 @@ notmuch_threads_valid (notmuch_threads_t *threads);\r
+ notmuch_thread_t *\r
+ notmuch_threads_get (notmuch_threads_t *threads);\r
\r
++/* Move the 'threads' iterator to the first thread.          \r
++ *\r
++ * After that the 'threads' iterator will be set to the first valid\r
++ * thread, so it can be use to iterate with\r
++ * notmuch_threads_move_to_next.\r
++ */\r
++void\r
++notmuch_threads_move_to_first (notmuch_threads_t *threads);\r
++\r
+ /* Move the 'threads' iterator to the next thread.\r
+  *\r
+  * If 'threads' is already pointing at the last thread then the\r
+@@ -479,6 +488,25 @@ notmuch_threads_get (notmuch_threads_t *threads);\r
+ void\r
+ notmuch_threads_move_to_next (notmuch_threads_t *threads);\r
\r
++/* Move the 'threads' iterator to the last thread.\r
++ *\r
++ * After that the 'threads' iterator will be set to the last valid\r
++ * thread, so it can be use to iterate with\r
++ * notmuch_threads_move_to_previous.\r
++ */\r
++void\r
++notmuch_threads_move_to_last (notmuch_threads_t *threads);\r
++\r
++/* Move the 'threads' iterator to the previous thread.\r
++ *\r
++ * If 'threads' is already pointing at the first thread then the\r
++ * iterator will be moved to a point just beyond that first thread,\r
++ * (where notmuch_threads_valid will return FALSE and\r
++ * notmuch_threads_get will return NULL).\r
++ */\r
++void\r
++notmuch_threads_move_to_previous (notmuch_threads_t *threads);\r
++\r
+ /* Destroy a notmuch_threads_t object.\r
+  *\r
+  * It's not strictly necessary to call this function. All memory from\r
+diff --git a/lib/query.cc b/lib/query.cc\r
+index 514a156..727f449 100644\r
+--- a/lib/query.cc\r
++++ b/lib/query.cc\r
+@@ -35,16 +35,29 @@ typedef struct _notmuch_mset_messages {\r
+     notmuch_messages_t base;\r
+     notmuch_database_t *notmuch;\r
+     Xapian::MSetIterator iterator;\r
++    Xapian::MSetIterator iterator_begin;\r
+     Xapian::MSetIterator iterator_end;\r
+ } notmuch_mset_messages_t;\r
\r
++typedef struct _notmuch_thread_node {\r
++    const char *thread_id;\r
++    struct _notmuch_thread_node *next;\r
++    struct _notmuch_thread_node *prev;\r
++} notmuch_thread_node_t;\r
++\r
++typedef struct _notmuch_thread_list {\r
++    notmuch_thread_node_t *head;\r
++    notmuch_thread_node_t *tail;\r
++    notmuch_thread_node_t *iterator;\r
++} notmuch_thread_list_t;\r
++\r
+ struct _notmuch_threads {\r
+     notmuch_query_t *query;\r
+     GHashTable *threads;\r
+     notmuch_messages_t *messages;\r
\r
+-    /* This thread ID is our iterator state. */\r
+-    const char *thread_id;\r
++    /* thread list with the thread_id of the showed messages */\r
++    notmuch_thread_list_t *list;\r
+ };\r
\r
+ notmuch_query_t *\r
+@@ -86,6 +99,7 @@ static int\r
+ _notmuch_messages_destructor (notmuch_mset_messages_t *messages)\r
+ {\r
+     messages->iterator.~MSetIterator ();\r
++    messages->iterator_begin.~MSetIterator ();\r
+     messages->iterator_end.~MSetIterator ();\r
\r
+     return 0;\r
+@@ -108,6 +122,7 @@ notmuch_query_search_messages (notmuch_query_t *query)\r
+       messages->base.iterator = NULL;\r
+       messages->notmuch = notmuch;\r
+       new (&messages->iterator) Xapian::MSetIterator ();\r
++      new (&messages->iterator_begin) Xapian::MSetIterator ();\r
+       new (&messages->iterator_end) Xapian::MSetIterator ();\r
\r
+       talloc_set_destructor (messages, _notmuch_messages_destructor);\r
+@@ -157,6 +172,7 @@ notmuch_query_search_messages (notmuch_query_t *query)\r
+       mset = enquire.get_mset (0, notmuch->xapian_db->get_doccount ());\r
\r
+       messages->iterator = mset.begin ();\r
++      messages->iterator_begin = mset.begin ();\r
+       messages->iterator_end = mset.end ();\r
\r
+     } catch (const Xapian::Error &error) {\r
+@@ -208,6 +224,16 @@ _notmuch_mset_messages_get (notmuch_messages_t *messages)\r
+ }\r
\r
+ void\r
++_notmuch_mset_messages_move_to_first (notmuch_messages_t *messages)\r
++{\r
++    notmuch_mset_messages_t *mset_messages;\r
++\r
++    mset_messages = (notmuch_mset_messages_t *) messages;\r
++\r
++    mset_messages->iterator = mset_messages->iterator_begin;\r
++}\r
++\r
++void\r
+ _notmuch_mset_messages_move_to_next (notmuch_messages_t *messages)\r
+ {\r
+     notmuch_mset_messages_t *mset_messages;\r
+@@ -217,6 +243,113 @@ _notmuch_mset_messages_move_to_next (notmuch_messages_t *messages)\r
+     mset_messages->iterator++;\r
+ }\r
\r
++void\r
++_notmuch_mset_messages_move_to_last (notmuch_messages_t *messages)\r
++{\r
++    notmuch_mset_messages_t *mset_messages;\r
++\r
++    mset_messages = (notmuch_mset_messages_t *) messages;\r
++\r
++    mset_messages->iterator = mset_messages->iterator_end;\r
++    mset_messages->iterator--;\r
++}\r
++\r
++void\r
++_notmuch_mset_messages_move_to_previous (notmuch_messages_t *messages)\r
++{\r
++    notmuch_mset_messages_t *mset_messages;\r
++\r
++    mset_messages = (notmuch_mset_messages_t *) messages;\r
++\r
++    if (mset_messages->iterator == mset_messages->iterator_begin)\r
++    {\r
++        /*\r
++         * Xapian iterators can not be beyond the first element, so we\r
++         * assign the iterator_end to mark the iterator as invalid in case\r
++         * of move_to_previous with the iterator at the beginning\r
++         */\r
++        mset_messages->iterator = mset_messages->iterator_end;\r
++    }\r
++    else if (_notmuch_mset_messages_valid (messages))\r
++    {\r
++        /*\r
++         * If is valid move the iterator. To emulate the same behavior \r
++         * than notmuch_messages_t the iterator won't be updated if is \r
++         * not valid\r
++         */\r
++        mset_messages->iterator--;\r
++    }\r
++}\r
++\r
++static notmuch_thread_list_t *\r
++_notmuch_thread_list_create (void *ctx)\r
++{\r
++    notmuch_thread_list_t *list;\r
++\r
++    list = talloc (ctx, notmuch_thread_list_t);\r
++    list->tail = NULL;\r
++    list->head = NULL;\r
++    list->iterator = NULL;\r
++\r
++    return list;\r
++}\r
++\r
++static void\r
++_notmuch_thread_list_append (notmuch_thread_list_t *list, const char *thread_id)\r
++{\r
++    list->iterator = talloc (list, notmuch_thread_node_t);\r
++    if (list->head == NULL)\r
++    {\r
++        list->head = list->iterator;\r
++        list->iterator->prev = NULL;\r
++    }\r
++    else\r
++    {\r
++        list->tail->next = list->iterator;\r
++        list->iterator->prev = list->tail;\r
++    }\r
++\r
++    list->iterator->thread_id = thread_id;\r
++    list->iterator->next = NULL;\r
++    list->tail = list->iterator;\r
++}\r
++\r
++static const char *\r
++_notmuch_thread_list_get_id (notmuch_thread_list_t *list)\r
++{\r
++    return list->iterator->thread_id;\r
++}\r
++\r
++static notmuch_bool_t\r
++_notmuch_thread_list_valid (notmuch_thread_list_t *list)\r
++{\r
++    return (list->iterator != NULL);\r
++}\r
++\r
++static void\r
++_notmuch_thread_list_move_to_first (notmuch_thread_list_t *list)\r
++{\r
++    list->iterator = list->head;\r
++}\r
++\r
++static void\r
++_notmuch_thread_list_move_to_next (notmuch_thread_list_t *list)\r
++{\r
++    list->iterator = list->iterator->next;\r
++}\r
++\r
++static void\r
++_notmuch_thread_list_move_to_last (notmuch_thread_list_t *list)\r
++{\r
++    list->iterator = list->tail;\r
++}\r
++\r
++static void\r
++_notmuch_thread_list_move_to_previous (notmuch_thread_list_t *list)\r
++{\r
++    list->iterator = list->iterator->prev;\r
++}\r
++\r
+ /* Glib objects force use to use a talloc destructor as well, (but not\r
+  * nearly as ugly as the for messages due to C++ objects). At\r
+  * this point, I'd really like to have some talloc-friendly\r
+@@ -244,16 +377,15 @@ notmuch_query_search_threads (notmuch_query_t *query)\r
+                                             free, NULL);\r
\r
+     threads->messages = notmuch_query_search_messages (query);\r
++    threads->list = _notmuch_thread_list_create (threads);\r
+     if (!notmuch_messages_valid (threads->messages))\r
+-    {\r
+-        threads->thread_id = NULL;\r
+         return threads;\r
+-    }\r
\r
+     message = notmuch_messages_get (threads->messages);\r
+-    threads->thread_id = notmuch_message_get_thread_id (message);\r
++    _notmuch_thread_list_append (threads->list,\r
++                                 notmuch_message_get_thread_id (message));\r
+     g_hash_table_insert (threads->threads,\r
+-                         xstrdup (threads->thread_id),\r
++                         xstrdup (_notmuch_thread_list_get_id (threads->list)),\r
+                          NULL);\r
\r
+     talloc_set_destructor (threads, _notmuch_threads_destructor);\r
+@@ -270,7 +402,7 @@ notmuch_query_destroy (notmuch_query_t *query)\r
+ notmuch_bool_t\r
+ notmuch_threads_valid (notmuch_threads_t *threads)\r
+ {\r
+-    return (threads->thread_id != NULL);\r
++    return _notmuch_thread_list_valid (threads->list);\r
+ }\r
\r
+ notmuch_thread_t *\r
+@@ -281,35 +413,82 @@ notmuch_threads_get (notmuch_threads_t *threads)\r
\r
+     return _notmuch_thread_create (threads->query,\r
+                                  threads->query->notmuch,\r
+-                                 threads->thread_id,\r
++                                 _notmuch_thread_list_get_id (threads->list),\r
+                                  threads->query->query_string);\r
+ }\r
\r
+ void\r
++notmuch_threads_move_to_first (notmuch_threads_t *threads)\r
++{\r
++    _notmuch_thread_list_move_to_first (threads->list);\r
++}\r
++\r
++void\r
+ notmuch_threads_move_to_next (notmuch_threads_t *threads)\r
+ {\r
+-    notmuch_message_t *message;\r
++    if (!_notmuch_thread_list_valid (threads->list))\r
++        return;\r
++\r
++    _notmuch_thread_list_move_to_next (threads->list);\r
++    if (_notmuch_thread_list_valid (threads->list))\r
++        return;\r
\r
+     while (notmuch_messages_valid (threads->messages))\r
+     {\r
+-      message = notmuch_messages_get (threads->messages);\r
++        notmuch_message_t *message;\r
++        const char *thread_id;\r
\r
+-      threads->thread_id = notmuch_message_get_thread_id (message);\r
++      message = notmuch_messages_get (threads->messages);\r
++      thread_id = notmuch_message_get_thread_id (message);\r
\r
+       if (! g_hash_table_lookup_extended (threads->threads,\r
+-                                          threads->thread_id,\r
++                                          thread_id,\r
+                                           NULL, NULL))\r
+       {\r
+           g_hash_table_insert (threads->threads,\r
+-                               xstrdup (threads->thread_id), NULL);\r
++                               xstrdup (thread_id), NULL);\r
++            _notmuch_thread_list_append (threads->list, thread_id);\r
+           notmuch_messages_move_to_next (threads->messages);\r
+           return;\r
+       }\r
\r
+       notmuch_messages_move_to_next (threads->messages);\r
+     }\r
++}\r
++\r
++void\r
++notmuch_threads_move_to_last (notmuch_threads_t *threads)\r
++{\r
++    _notmuch_thread_list_move_to_last (threads->list);\r
++\r
++    while (notmuch_messages_valid (threads->messages))\r
++    {\r
++        notmuch_message_t *message;\r
++        const char *thread_id;\r
++\r
++      message = notmuch_messages_get (threads->messages);\r
++      thread_id = notmuch_message_get_thread_id (message);\r
++\r
++      if (! g_hash_table_lookup_extended (threads->threads,\r
++                                          thread_id,\r
++                                          NULL, NULL))\r
++      {\r
++          g_hash_table_insert (threads->threads,\r
++                               xstrdup (thread_id), NULL);\r
++            _notmuch_thread_list_append (threads->list, thread_id);\r
++        }\r
++\r
++      notmuch_messages_move_to_next (threads->messages);\r
++    }\r
++}\r
++\r
++void\r
++notmuch_threads_move_to_previous (notmuch_threads_t *threads)\r
++{\r
++    if (!_notmuch_thread_list_valid (threads->list))\r
++        return;\r
\r
+-    threads->thread_id = NULL;\r
++    _notmuch_thread_list_move_to_previous (threads->list);\r
+ }\r
\r
+ void\r
+-- \r
+1.7.0\r
+\r