[notmuch] [PATCH 2/2] Added backwards iterator to threads
Ruben Pollan
meskio at sindominio.net
Sun Mar 21 14:32:33 PDT 2010
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
More information about the notmuch
mailing list