From: Kevin McCarthy Date: Sun, 29 Jan 2017 02:48:08 +0000 (-0800) Subject: Improve the label completion hash table usage. X-Git-Tag: neomutt-20170225~33^2~4 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=540d5faced57a4df5edde8120e91f78d89766170;p=neomutt Improve the label completion hash table usage. 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. --- diff --git a/curs_main.c b/curs_main.c index 8b386de3b..4a480f62d 100644 --- a/curs_main.c +++ b/curs_main.c @@ -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 diff --git a/globals.h b/globals.h index 6263d9fa2..f5d7ee795 100644 --- 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; diff --git a/headers.c b/headers.c index 481c9995d..ffba7a18f 100644 --- a/headers.c +++ b/headers.c @@ -27,6 +27,7 @@ #include #include #include +#include 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 b7dacf036..6f6ec9196 100644 --- 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 a0cb3c71f..fd911907b 100644 --- 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 f5c9cc5b5..97c3d19b0 100644 --- 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 4d0c7a273..12cfd56fe 100644 --- 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 3a3feaccd..0c16f0b5f 100644 --- 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 abe505103..faf11bc58 100644 --- 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; diff --git a/protos.h b/protos.h index d6063fe4b..1304e4035 100644 --- 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 *, ...);