From: Kevin McCarthy Date: Sun, 29 Jan 2017 02:48:08 +0000 (-0800) Subject: Improve the label completion hash table usage. X-Git-Tag: mutt-1-8-rel~31 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9ae62494d8315234b48618301bc88d31b65f297e;p=mutt 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 68deab85..43417188 100644 --- a/curs_main.c +++ b/curs_main.c @@ -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 diff --git a/globals.h b/globals.h index d0d347e9..a68338a8 100644 --- 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); diff --git a/headers.c b/headers.c index 0cf3a6cc..0b4372d7 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, @@ -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 b61cf766..35f36ea7 100644 --- 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 bc46d610..cafb830d 100644 --- 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 37f426d8..74affebc 100644 --- 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 cbd28eb4..2d524780 100644 --- 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 70a41ad0..5e94d92b 100644 --- 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 81f739af..a2210d6d 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 cfb4d7c6..b26724c4 100644 --- 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 *, ...);