]> granicus.if.org Git - neomutt/commitdiff
Improve the label completion hash table usage.
authorKevin McCarthy <kevin@8t8.us>
Sun, 29 Jan 2017 02:48:08 +0000 (18:48 -0800)
committerRichard Russon <rich@flatcap.org>
Fri, 10 Feb 2017 03:32:55 +0000 (03:32 +0000)
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 8b386de3b35559dfabe83f8b88644a633b418108..4a480f62dee23bb0f31c284e248861e6530badd3 100644 (file)
@@ -754,9 +754,6 @@ static int main_change_folder(MUTTMENU *menu, int op, char *buf, size_t bufsz,
     FREE (&Context);
   }
 
-  if (Labels)
-    hash_destroy(&Labels, NULL);
-
   mutt_sleep (0);
 
   /* Set CurrentMenu to MENU_MAIN before executing any folder
@@ -771,7 +768,6 @@ static int main_change_folder(MUTTMENU *menu, int op, char *buf, size_t bufsz,
                (option (OPTREADONLY) || op == OP_MAIN_CHANGE_FOLDER_READONLY) ?
                MUTT_READONLY : 0, NULL)) != NULL)
   {
-    Labels = hash_create(131, 0);
     menu->current = ci_first_message ();
   }
   else
index 6263d9fa2f2adde85ad1e50b00f62b1f7c9ece77..f5d7ee795658be7bdfb9bca2460592e0613459df 100644 (file)
--- a/globals.h
+++ b/globals.h
@@ -180,7 +180,6 @@ WHERE char *LastFolder;
 WHERE const char *GitVer;
 
 WHERE HASH *Groups;
-WHERE HASH *Labels;
 WHERE HASH *ReverseAlias;
 #ifdef USE_NOTMUCH
 WHERE HASH *TagTransforms;
index 481c9995d6aa529ffcaf59ac006411349935757c..ffba7a18f70d3607af6a938f58f496aacc7dffe8 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,
@@ -215,45 +216,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;
 }
 
@@ -263,6 +279,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);
@@ -278,12 +297,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);
@@ -294,16 +313,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);
+}
 
-  if (!ctx)
+void mutt_label_hash_add (CONTEXT *ctx, HEADER *hdr)
+{
+  if (!ctx || !ctx->label_hash)
     return;
-
-  for (i = 0; i < ctx->msgcount; i++)
-    if (ctx->hdrs[i]->env->x_label)
-      label_ref_inc(ctx->hdrs[i]->env->x_label);
+  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 b7dacf036e88a19a8a97464c17f95c916620087a..6f6ec9196522520f8c7a79c0ee8dc9f10878d97b 100644 (file)
--- a/init.c
+++ b/init.c
@@ -4148,6 +4148,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;
 
@@ -4166,7 +4169,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 a0cb3c71f5066df889f3500dddb85c7dbe69e41e..fd911907b0e6bed2026525afdae898fb78c46235 100644 (file)
--- a/main.c
+++ b/main.c
@@ -895,16 +895,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 f5c9cc5b53ded2013d88a21d0054aa03b456c2b9..97c3d19b06e225352cbf7decd87eb521ad5f11e4 100644 (file)
--- a/mbox.c
+++ b/mbox.c
@@ -1221,6 +1221,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)
@@ -1248,6 +1249,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 4d0c7a2734f6d98578c9c60ebccf4d0f3fc94857..12cfd56fe115a42fadbbd2944f1b68b094df39e4 100644 (file)
--- a/mutt.h
+++ b/mutt.h
@@ -1077,6 +1077,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 3a3feaccda88f14ce03ebba68b0f957160d2f445..0c16f0b5f179caadbba264bc8f36912ce13aadb5 100644 (file)
--- a/mx.c
+++ b/mx.c
@@ -674,7 +674,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
@@ -745,6 +747,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]);
@@ -1164,6 +1167,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
@@ -1517,6 +1521,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 abe50510332d759e676a6e83d698323ede67fc5a..faf11bc582976a35a63d19f6323715e23d8c1b7b 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 d6063fe4bc6840750a0e97aabb672fa0f980e2bf..1304e40351b9b6756c52a836870147bc29ae2409 100644 (file)
--- a/protos.h
+++ b/protos.h
@@ -200,7 +200,6 @@ int mutt_label_message (HEADER *);
 void mutt_make_label_hash (CONTEXT *);
 void mutt_label_hash_add (CONTEXT *ctx, HEADER *hdr);
 void mutt_label_hash_remove (CONTEXT *ctx, HEADER *hdr);
-void mutt_scan_labels (CONTEXT *);
 int mutt_label_complete (char *, size_t, int, int);
 void mutt_curses_error (const char *, ...);
 void mutt_curses_message (const char *, ...);