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