]> granicus.if.org Git - mutt/commitdiff
Improve the label completion hash table usage.
authorKevin McCarthy <kevin@8t8.us>
Sun, 29 Jan 2017 02:48:08 +0000 (18:48 -0800)
committerKevin McCarthy <kevin@8t8.us>
Sun, 29 Jan 2017 02:48:08 +0000 (18:48 -0800)
Move the hash table inside the Context.  Hook message arrival/deletion
to update the label hash.

Change the label hash to strdup keys.

Use hash_find_elem when updating the counter, to reduce unnecessary
add/delete operations.

curs_main.c
globals.h
headers.c
init.c
main.c
mbox.c
mutt.h
mx.c
pop.c
protos.h

index 68deab859cbc97eaabed2417b8eb7c58b0f1ecaf..43417188e50655b944a9d2e8fe33117fb214d934 100644 (file)
@@ -1268,9 +1268,6 @@ int mutt_index_menu (void)
          FREE (&Context);
        }
 
-        if (Labels)
-          hash_destroy(&Labels, NULL);
-
         mutt_sleep (0);
 
        /* Set CurrentMenu to MENU_MAIN before executing any folder
@@ -1285,8 +1282,6 @@ int mutt_index_menu (void)
                                        (option (OPTREADONLY) || op == OP_MAIN_CHANGE_FOLDER_READONLY) ?
                                        MUTT_READONLY : 0, NULL)) != NULL)
        {
-         Labels = hash_create(131, 0);
-         mutt_scan_labels(Context);
          menu->current = ci_first_message ();
        }
        else
index d0d347e97974c25dcd0d9f4e441ededf805fed9b..a68338a85258a2a3d5802023a86842852bfd0b79 100644 (file)
--- a/globals.h
+++ b/globals.h
@@ -162,7 +162,6 @@ WHERE char *LastFolder;
 WHERE const char *ReleaseDate;
 
 WHERE HASH *Groups;
-WHERE HASH *Labels;
 WHERE HASH *ReverseAlias;
 
 WHERE LIST *AutoViewList INITVAL(0);
index 0cf3a6cc10f98977fc3bd8cab0acffc453eb4c6c..0b4372d7901751dbac70382385a1e73e9cba21b6 100644 (file)
--- a/headers.c
+++ b/headers.c
@@ -27,6 +27,7 @@
 #include <sys/stat.h>
 #include <string.h>
 #include <ctype.h>
+#include <stdint.h>
 
 void mutt_edit_headers (const char *editor,
                        const char *body,
@@ -212,45 +213,60 @@ void mutt_edit_headers (const char *editor,
   }
 }
 
-static void label_ref_dec(char *label)
+static void label_ref_dec(CONTEXT *ctx, char *label)
 {
+  struct hash_elem *elem;
   uintptr_t count;
 
-  count = (uintptr_t)hash_find(Labels, label);
-  if (count)
+  elem = hash_find_elem (ctx->label_hash, label);
+  if (!elem)
+    return;
+
+  count = (uintptr_t)elem->data;
+  if (count <= 1)
   {
-    hash_delete(Labels, label, NULL, NULL);
-    count--;
-    if (count > 0)
-      hash_insert(Labels, label, (void *)count, 0);
+    hash_delete(ctx->label_hash, label, NULL, NULL);
+    return;
   }
+
+  count--;
+  elem->data = (void *)count;
 }
 
-static void label_ref_inc(char *label)
+static void label_ref_inc(CONTEXT *ctx, char *label)
 {
+  struct hash_elem *elem;
   uintptr_t count;
 
-  count = (uintptr_t)hash_find(Labels, label);
-  if (count)
-    hash_delete(Labels, label, NULL, NULL);
-  count++;  /* was zero if not found */
-  hash_insert(Labels, label, (void *)count, 0);
+  elem = hash_find_elem (ctx->label_hash, label);
+  if (!elem)
+  {
+    count = 1;
+    hash_insert(ctx->label_hash, label, (void *)count, 0);
+    return;
+  }
+
+  count = (uintptr_t)elem->data;
+  count++;
+  elem->data = (void *)count;
 }
 
 /*
  * add an X-Label: field.
  */
-static int label_message(HEADER *hdr, char *new)
+static int label_message(CONTEXT *ctx, HEADER *hdr, char *new)
 {
   if (hdr == NULL)
     return 0;
   if (mutt_strcmp (hdr->env->x_label, new) == 0)
     return 0;
+
   if (hdr->env->x_label != NULL)
-    label_ref_dec(hdr->env->x_label);
+    label_ref_dec(ctx, hdr->env->x_label);
   mutt_str_replace (&hdr->env->x_label, new);
   if (hdr->env->x_label != NULL)
-    label_ref_inc(hdr->env->x_label);
+    label_ref_inc(ctx, hdr->env->x_label);
+
   return hdr->changed = hdr->xlabel_changed = 1;
 }
 
@@ -260,6 +276,9 @@ int mutt_label_message(HEADER *hdr)
   int i;
   int changed;
 
+  if (!Context || !Context->label_hash)
+    return 0;
+
   *buf = '\0';
   if (hdr != NULL && hdr->env->x_label != NULL) {
     strncpy(buf, hdr->env->x_label, LONG_STRING);
@@ -275,12 +294,12 @@ int mutt_label_message(HEADER *hdr)
 
   changed = 0;
   if (hdr != NULL) {
-    changed += label_message(hdr, new);
+    changed += label_message(Context, hdr, new);
   } else {
 #define HDR_OF(index) Context->hdrs[Context->v2r[(index)]]
     for (i = 0; i < Context->vcount; ++i) {
       if (HDR_OF(i)->tagged)
-        if (label_message(HDR_OF(i), new)) {
+        if (label_message(Context, HDR_OF(i), new)) {
           ++changed;
           mutt_set_flag(Context, HDR_OF(i),
             MUTT_TAG, 0);
@@ -291,13 +310,26 @@ int mutt_label_message(HEADER *hdr)
   return changed;
 }
 
-/* scan a context (mailbox) and hash all labels we find */
-void mutt_scan_labels(CONTEXT *ctx)
+void mutt_make_label_hash (CONTEXT *ctx)
 {
-  int i;
+  /* 131 is just a rough prime estimate of how many distinct
+   * labels someone might have in a mailbox.
+   */
+  ctx->label_hash = hash_create(131, MUTT_HASH_STRDUP_KEYS);
+}
 
-  for (i = 0; i < ctx->msgcount; i++)
-    if (ctx->hdrs[i]->env->x_label)
-      label_ref_inc(ctx->hdrs[i]->env->x_label);
+void mutt_label_hash_add (CONTEXT *ctx, HEADER *hdr)
+{
+  if (!ctx || !ctx->label_hash)
+    return;
+  if (hdr->env->x_label)
+    label_ref_inc (ctx, hdr->env->x_label);
 }
 
+void mutt_label_hash_remove (CONTEXT *ctx, HEADER *hdr)
+{
+  if (!ctx || !ctx->label_hash)
+    return;
+  if (hdr->env->x_label)
+    label_ref_dec (ctx, hdr->env->x_label);
+}
diff --git a/init.c b/init.c
index b61cf766ce37e96ce72005b69b1e3d67bb85e3fb..35f36ea727abcffe145660a01c978579a0712165 100644 (file)
--- a/init.c
+++ b/init.c
@@ -3635,6 +3635,9 @@ int mutt_label_complete (char *buffer, size_t len, int pos, int numtabs)
   char *pt = buffer;
   int spaces; /* keep track of the number of leading spaces on the line */
 
+  if (!Context || !Context->label_hash)
+    return 0;
+
   SKIPWS (buffer);
   spaces = buffer - pt;
 
@@ -3653,7 +3656,7 @@ int mutt_label_complete (char *buffer, size_t len, int pos, int numtabs)
     memset (Matches, 0, Matches_listsize);
     memset (Completed, 0, sizeof (Completed));
     memset (&state, 0, sizeof(state));
-    while ((entry = hash_walk(Labels, &state)))
+    while ((entry = hash_walk(Context->label_hash, &state)))
       candidate (Completed, User_typed, entry->key.strkey, sizeof (Completed));
     matches_ensure_morespace (Num_matched);
     qsort(Matches, Num_matched, sizeof(char *), (sort_t *) mutt_strcasecmp);
diff --git a/main.c b/main.c
index bc46d610ecfb0655c1069113d67a0f0ba10e3802..cafb830deb9fd870074c9f74bf6563b57f514159 100644 (file)
--- a/main.c
+++ b/main.c
@@ -1240,16 +1240,12 @@ int main (int argc, char **argv, char **environ)
     if((Context = mx_open_mailbox (folder, ((flags & MUTT_RO) || option (OPTREADONLY)) ? MUTT_READONLY : 0, NULL))
        || !explicit_folder)
     {
-      Labels = hash_create (131, 0);
-      mutt_scan_labels(Context);
 #ifdef USE_SIDEBAR
       mutt_sb_set_open_buffy ();
 #endif
       mutt_index_menu ();
       if (Context)
        FREE (&Context);
-      if (Labels)
-       hash_destroy(&Labels, NULL);
     }
 #ifdef USE_IMAP
     imap_logout_all ();
diff --git a/mbox.c b/mbox.c
index 37f426d8e55b7c36a5eae72624d24f10e6278e09..74affebc8ead9255a570ea8a7ae852d4bcb6b68a 100644 (file)
--- a/mbox.c
+++ b/mbox.c
@@ -1198,6 +1198,7 @@ int mutt_reopen_mailbox (CONTEXT *ctx, int *index_hint)
     hash_destroy (&ctx->id_hash, NULL);
   if (ctx->subj_hash)
     hash_destroy (&ctx->subj_hash, NULL);
+  hash_destroy (&ctx->label_hash, NULL);
   mutt_clear_threads (ctx);
   FREE (&ctx->v2r);
   if (ctx->readonly)
@@ -1225,6 +1226,7 @@ int mutt_reopen_mailbox (CONTEXT *ctx, int *index_hint)
   ctx->changed = 0;
   ctx->id_hash = NULL;
   ctx->subj_hash = NULL;
+  mutt_make_label_hash (ctx);
 
   switch (ctx->magic)
   {
diff --git a/mutt.h b/mutt.h
index cbd28eb4fd13a119d675be0fca65447d5a4c8c7a..2d5247806f5f1d15f5984f6db257437aa848f148 100644 (file)
--- a/mutt.h
+++ b/mutt.h
@@ -955,6 +955,7 @@ typedef struct _context
   HASH *id_hash;               /* hash table by msg id */
   HASH *subj_hash;             /* hash table by subject */
   HASH *thread_hash;           /* hash table for threading */
+  HASH *label_hash;             /* hash table for x-labels */
   int *v2r;                    /* mapping from virtual to real msgno */
   int hdrmax;                  /* number of pointers in hdrs */
   int msgcount;                        /* number of messages in the mailbox */
diff --git a/mx.c b/mx.c
index 70a41ad08688005d5ccf8e69874311ebec7c674c..5e94d92b5bb27f11e30c383574174c53bc8239d6 100644 (file)
--- a/mx.c
+++ b/mx.c
@@ -611,7 +611,9 @@ CONTEXT *mx_open_mailbox (const char *path, int flags, CONTEXT *pctx)
       FREE (&ctx);
     return (NULL);
   }
-  
+
+  mutt_make_label_hash (ctx);
+
   /* if the user has a `push' command in their .muttrc, or in a folder-hook,
    * it will cause the progress messages not to be displayed because
    * mutt_refresh() will think we are in the middle of a macro.  so set a
@@ -680,6 +682,7 @@ void mx_fastclose_mailbox (CONTEXT *ctx)
     hash_destroy (&ctx->subj_hash, NULL);
   if (ctx->id_hash)
     hash_destroy (&ctx->id_hash, NULL);
+  hash_destroy (&ctx->label_hash, NULL);
   mutt_clear_threads (ctx);
   for (i = 0; i < ctx->msgcount; i++)
     mutt_free_header (&ctx->hdrs[i]);
@@ -1069,6 +1072,7 @@ void mx_update_tables(CONTEXT *ctx, int committing)
        hash_delete (ctx->subj_hash, ctx->hdrs[i]->env->real_subj, ctx->hdrs[i], NULL);
       if (ctx->id_hash && ctx->hdrs[i]->env->message_id)
        hash_delete (ctx->id_hash, ctx->hdrs[i]->env->message_id, ctx->hdrs[i], NULL);
+      mutt_label_hash_remove (ctx, ctx->hdrs[i]);
       /* The path mx_check_mailbox() -> imap_check_mailbox() ->
        *          imap_expunge_mailbox() -> mx_update_tables()
        * can occur before a call to mx_sync_mailbox(), resulting in
@@ -1419,6 +1423,7 @@ void mx_update_context (CONTEXT *ctx, int new_messages)
       hash_insert (ctx->id_hash, h->env->message_id, h, 0);
     if (ctx->subj_hash && h->env->real_subj)
       hash_insert (ctx->subj_hash, h->env->real_subj, h, 1);
+    mutt_label_hash_add (ctx, h);
 
     if (option (OPTSCORE)) 
       mutt_score_message (ctx, h, 0);
diff --git a/pop.c b/pop.c
index 81f739af913529eaf89c56a457192637ffed174b..a2210d6d225c2e62c624f79358d14b914d38389e 100644 (file)
--- a/pop.c
+++ b/pop.c
@@ -632,10 +632,12 @@ static int pop_fetch_message (CONTEXT* ctx, MESSAGE* msg, int msgno)
   /* we replace envelop, key in subj_hash has to be updated as well */
   if (ctx->subj_hash && h->env->real_subj)
     hash_delete (ctx->subj_hash, h->env->real_subj, h, NULL);
+  mutt_label_hash_remove (ctx, h);
   mutt_free_envelope (&h->env);
   h->env = mutt_read_rfc822_header (msg->fp, h, 0, 0);
   if (ctx->subj_hash && h->env->real_subj)
     hash_insert (ctx->subj_hash, h->env->real_subj, h, 1);
+  mutt_label_hash_add (ctx, h);
 
   h->data = uidl;
   h->lines = 0;
index cfb4d7c668d9a7feefb60e21b1f3b3de1222d4c6..b26724c4cef346504bf41bb37cd2cc061c5951de 100644 (file)
--- a/protos.h
+++ b/protos.h
@@ -187,7 +187,9 @@ void mutt_edit_file (const char *, const char *);
 void mutt_edit_headers (const char *, const char *, HEADER *, char *, size_t);
 int mutt_filter_unprintable (char **);
 int mutt_label_message (HEADER *);
-void mutt_scan_labels (CONTEXT *);
+void mutt_make_label_hash (CONTEXT *);
+void mutt_label_hash_add (CONTEXT *ctx, HEADER *hdr);
+void mutt_label_hash_remove (CONTEXT *ctx, HEADER *hdr);
 int mutt_label_complete (char *, size_t, int, int);
 void mutt_curses_error (const char *, ...);
 void mutt_curses_message (const char *, ...);