Commit 9ae62494 authored by Kevin J. McCarthy's avatar Kevin J. McCarthy

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.
parent f58e89c8
...@@ -1268,9 +1268,6 @@ int mutt_index_menu (void) ...@@ -1268,9 +1268,6 @@ int mutt_index_menu (void)
FREE (&Context); FREE (&Context);
} }
if (Labels)
hash_destroy(&Labels, NULL);
mutt_sleep (0); mutt_sleep (0);
/* Set CurrentMenu to MENU_MAIN before executing any folder /* Set CurrentMenu to MENU_MAIN before executing any folder
...@@ -1285,8 +1282,6 @@ int mutt_index_menu (void) ...@@ -1285,8 +1282,6 @@ int mutt_index_menu (void)
(option (OPTREADONLY) || op == OP_MAIN_CHANGE_FOLDER_READONLY) ? (option (OPTREADONLY) || op == OP_MAIN_CHANGE_FOLDER_READONLY) ?
MUTT_READONLY : 0, NULL)) != NULL) MUTT_READONLY : 0, NULL)) != NULL)
{ {
Labels = hash_create(131, 0);
mutt_scan_labels(Context);
menu->current = ci_first_message (); menu->current = ci_first_message ();
} }
else else
......
...@@ -162,7 +162,6 @@ WHERE char *LastFolder; ...@@ -162,7 +162,6 @@ WHERE char *LastFolder;
WHERE const char *ReleaseDate; WHERE const char *ReleaseDate;
WHERE HASH *Groups; WHERE HASH *Groups;
WHERE HASH *Labels;
WHERE HASH *ReverseAlias; WHERE HASH *ReverseAlias;
WHERE LIST *AutoViewList INITVAL(0); WHERE LIST *AutoViewList INITVAL(0);
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
#include <stdint.h>
void mutt_edit_headers (const char *editor, void mutt_edit_headers (const char *editor,
const char *body, const char *body,
...@@ -212,45 +213,60 @@ void mutt_edit_headers (const char *editor, ...@@ -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; uintptr_t count;
count = (uintptr_t)hash_find(Labels, label); elem = hash_find_elem (ctx->label_hash, label);
if (count) if (!elem)
return;
count = (uintptr_t)elem->data;
if (count <= 1)
{ {
hash_delete(Labels, label, NULL, NULL); hash_delete(ctx->label_hash, label, NULL, NULL);
count--; return;
if (count > 0)
hash_insert(Labels, label, (void *)count, 0);
} }
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; uintptr_t count;
count = (uintptr_t)hash_find(Labels, label); elem = hash_find_elem (ctx->label_hash, label);
if (count) if (!elem)
hash_delete(Labels, label, NULL, NULL); {
count++; /* was zero if not found */ count = 1;
hash_insert(Labels, label, (void *)count, 0); 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. * 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) if (hdr == NULL)
return 0; return 0;
if (mutt_strcmp (hdr->env->x_label, new) == 0) if (mutt_strcmp (hdr->env->x_label, new) == 0)
return 0; return 0;
if (hdr->env->x_label != NULL) 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); mutt_str_replace (&hdr->env->x_label, new);
if (hdr->env->x_label != NULL) 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; return hdr->changed = hdr->xlabel_changed = 1;
} }
...@@ -260,6 +276,9 @@ int mutt_label_message(HEADER *hdr) ...@@ -260,6 +276,9 @@ int mutt_label_message(HEADER *hdr)
int i; int i;
int changed; int changed;
if (!Context || !Context->label_hash)
return 0;
*buf = '\0'; *buf = '\0';
if (hdr != NULL && hdr->env->x_label != NULL) { if (hdr != NULL && hdr->env->x_label != NULL) {
strncpy(buf, hdr->env->x_label, LONG_STRING); strncpy(buf, hdr->env->x_label, LONG_STRING);
...@@ -275,12 +294,12 @@ int mutt_label_message(HEADER *hdr) ...@@ -275,12 +294,12 @@ int mutt_label_message(HEADER *hdr)
changed = 0; changed = 0;
if (hdr != NULL) { if (hdr != NULL) {
changed += label_message(hdr, new); changed += label_message(Context, hdr, new);
} else { } else {
#define HDR_OF(index) Context->hdrs[Context->v2r[(index)]] #define HDR_OF(index) Context->hdrs[Context->v2r[(index)]]
for (i = 0; i < Context->vcount; ++i) { for (i = 0; i < Context->vcount; ++i) {
if (HDR_OF(i)->tagged) if (HDR_OF(i)->tagged)
if (label_message(HDR_OF(i), new)) { if (label_message(Context, HDR_OF(i), new)) {
++changed; ++changed;
mutt_set_flag(Context, HDR_OF(i), mutt_set_flag(Context, HDR_OF(i),
MUTT_TAG, 0); MUTT_TAG, 0);
...@@ -291,13 +310,26 @@ int mutt_label_message(HEADER *hdr) ...@@ -291,13 +310,26 @@ int mutt_label_message(HEADER *hdr)
return changed; return changed;
} }
/* scan a context (mailbox) and hash all labels we find */ void mutt_make_label_hash (CONTEXT *ctx)
void mutt_scan_labels(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++) void mutt_label_hash_add (CONTEXT *ctx, HEADER *hdr)
if (ctx->hdrs[i]->env->x_label) {
label_ref_inc(ctx->hdrs[i]->env->x_label); 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);
}
...@@ -3635,6 +3635,9 @@ int mutt_label_complete (char *buffer, size_t len, int pos, int numtabs) ...@@ -3635,6 +3635,9 @@ int mutt_label_complete (char *buffer, size_t len, int pos, int numtabs)
char *pt = buffer; char *pt = buffer;
int spaces; /* keep track of the number of leading spaces on the line */ int spaces; /* keep track of the number of leading spaces on the line */
if (!Context || !Context->label_hash)
return 0;
SKIPWS (buffer); SKIPWS (buffer);
spaces = buffer - pt; spaces = buffer - pt;
...@@ -3653,7 +3656,7 @@ int mutt_label_complete (char *buffer, size_t len, int pos, int numtabs) ...@@ -3653,7 +3656,7 @@ int mutt_label_complete (char *buffer, size_t len, int pos, int numtabs)
memset (Matches, 0, Matches_listsize); memset (Matches, 0, Matches_listsize);
memset (Completed, 0, sizeof (Completed)); memset (Completed, 0, sizeof (Completed));
memset (&state, 0, sizeof(state)); 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)); candidate (Completed, User_typed, entry->key.strkey, sizeof (Completed));
matches_ensure_morespace (Num_matched); matches_ensure_morespace (Num_matched);
qsort(Matches, Num_matched, sizeof(char *), (sort_t *) mutt_strcasecmp); qsort(Matches, Num_matched, sizeof(char *), (sort_t *) mutt_strcasecmp);
......
...@@ -1240,16 +1240,12 @@ int main (int argc, char **argv, char **environ) ...@@ -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)) if((Context = mx_open_mailbox (folder, ((flags & MUTT_RO) || option (OPTREADONLY)) ? MUTT_READONLY : 0, NULL))
|| !explicit_folder) || !explicit_folder)
{ {
Labels = hash_create (131, 0);
mutt_scan_labels(Context);
#ifdef USE_SIDEBAR #ifdef USE_SIDEBAR
mutt_sb_set_open_buffy (); mutt_sb_set_open_buffy ();
#endif #endif
mutt_index_menu (); mutt_index_menu ();
if (Context) if (Context)
FREE (&Context); FREE (&Context);
if (Labels)
hash_destroy(&Labels, NULL);
} }
#ifdef USE_IMAP #ifdef USE_IMAP
imap_logout_all (); imap_logout_all ();
......
...@@ -1198,6 +1198,7 @@ int mutt_reopen_mailbox (CONTEXT *ctx, int *index_hint) ...@@ -1198,6 +1198,7 @@ int mutt_reopen_mailbox (CONTEXT *ctx, int *index_hint)
hash_destroy (&ctx->id_hash, NULL); hash_destroy (&ctx->id_hash, NULL);
if (ctx->subj_hash) if (ctx->subj_hash)
hash_destroy (&ctx->subj_hash, NULL); hash_destroy (&ctx->subj_hash, NULL);
hash_destroy (&ctx->label_hash, NULL);
mutt_clear_threads (ctx); mutt_clear_threads (ctx);
FREE (&ctx->v2r); FREE (&ctx->v2r);
if (ctx->readonly) if (ctx->readonly)
...@@ -1225,6 +1226,7 @@ int mutt_reopen_mailbox (CONTEXT *ctx, int *index_hint) ...@@ -1225,6 +1226,7 @@ int mutt_reopen_mailbox (CONTEXT *ctx, int *index_hint)
ctx->changed = 0; ctx->changed = 0;
ctx->id_hash = NULL; ctx->id_hash = NULL;
ctx->subj_hash = NULL; ctx->subj_hash = NULL;
mutt_make_label_hash (ctx);
switch (ctx->magic) switch (ctx->magic)
{ {
......
...@@ -955,6 +955,7 @@ typedef struct _context ...@@ -955,6 +955,7 @@ typedef struct _context
HASH *id_hash; /* hash table by msg id */ HASH *id_hash; /* hash table by msg id */
HASH *subj_hash; /* hash table by subject */ HASH *subj_hash; /* hash table by subject */
HASH *thread_hash; /* hash table for threading */ HASH *thread_hash; /* hash table for threading */
HASH *label_hash; /* hash table for x-labels */
int *v2r; /* mapping from virtual to real msgno */ int *v2r; /* mapping from virtual to real msgno */
int hdrmax; /* number of pointers in hdrs */ int hdrmax; /* number of pointers in hdrs */
int msgcount; /* number of messages in the mailbox */ int msgcount; /* number of messages in the mailbox */
......
...@@ -611,7 +611,9 @@ CONTEXT *mx_open_mailbox (const char *path, int flags, CONTEXT *pctx) ...@@ -611,7 +611,9 @@ CONTEXT *mx_open_mailbox (const char *path, int flags, CONTEXT *pctx)
FREE (&ctx); FREE (&ctx);
return (NULL); return (NULL);
} }
mutt_make_label_hash (ctx);
/* if the user has a `push' command in their .muttrc, or in a folder-hook, /* 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 * 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 * 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) ...@@ -680,6 +682,7 @@ void mx_fastclose_mailbox (CONTEXT *ctx)
hash_destroy (&ctx->subj_hash, NULL); hash_destroy (&ctx->subj_hash, NULL);
if (ctx->id_hash) if (ctx->id_hash)
hash_destroy (&ctx->id_hash, NULL); hash_destroy (&ctx->id_hash, NULL);
hash_destroy (&ctx->label_hash, NULL);
mutt_clear_threads (ctx); mutt_clear_threads (ctx);
for (i = 0; i < ctx->msgcount; i++) for (i = 0; i < ctx->msgcount; i++)
mutt_free_header (&ctx->hdrs[i]); mutt_free_header (&ctx->hdrs[i]);
...@@ -1069,6 +1072,7 @@ void mx_update_tables(CONTEXT *ctx, int committing) ...@@ -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); 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) 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); 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() -> /* The path mx_check_mailbox() -> imap_check_mailbox() ->
* imap_expunge_mailbox() -> mx_update_tables() * imap_expunge_mailbox() -> mx_update_tables()
* can occur before a call to mx_sync_mailbox(), resulting in * can occur before a call to mx_sync_mailbox(), resulting in
...@@ -1419,6 +1423,7 @@ void mx_update_context (CONTEXT *ctx, int new_messages) ...@@ -1419,6 +1423,7 @@ void mx_update_context (CONTEXT *ctx, int new_messages)
hash_insert (ctx->id_hash, h->env->message_id, h, 0); hash_insert (ctx->id_hash, h->env->message_id, h, 0);
if (ctx->subj_hash && h->env->real_subj) if (ctx->subj_hash && h->env->real_subj)
hash_insert (ctx->subj_hash, h->env->real_subj, h, 1); hash_insert (ctx->subj_hash, h->env->real_subj, h, 1);
mutt_label_hash_add (ctx, h);
if (option (OPTSCORE)) if (option (OPTSCORE))
mutt_score_message (ctx, h, 0); mutt_score_message (ctx, h, 0);
......
...@@ -632,10 +632,12 @@ static int pop_fetch_message (CONTEXT* ctx, MESSAGE* msg, int msgno) ...@@ -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 */ /* we replace envelop, key in subj_hash has to be updated as well */
if (ctx->subj_hash && h->env->real_subj) if (ctx->subj_hash && h->env->real_subj)
hash_delete (ctx->subj_hash, h->env->real_subj, h, NULL); hash_delete (ctx->subj_hash, h->env->real_subj, h, NULL);
mutt_label_hash_remove (ctx, h);
mutt_free_envelope (&h->env); mutt_free_envelope (&h->env);
h->env = mutt_read_rfc822_header (msg->fp, h, 0, 0); h->env = mutt_read_rfc822_header (msg->fp, h, 0, 0);
if (ctx->subj_hash && h->env->real_subj) if (ctx->subj_hash && h->env->real_subj)
hash_insert (ctx->subj_hash, h->env->real_subj, h, 1); hash_insert (ctx->subj_hash, h->env->real_subj, h, 1);
mutt_label_hash_add (ctx, h);
h->data = uidl; h->data = uidl;
h->lines = 0; h->lines = 0;
......
...@@ -187,7 +187,9 @@ void mutt_edit_file (const char *, const char *); ...@@ -187,7 +187,9 @@ void mutt_edit_file (const char *, const char *);
void mutt_edit_headers (const char *, const char *, HEADER *, char *, size_t); void mutt_edit_headers (const char *, const char *, HEADER *, char *, size_t);
int mutt_filter_unprintable (char **); int mutt_filter_unprintable (char **);
int mutt_label_message (HEADER *); 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); int mutt_label_complete (char *, size_t, int, int);
void mutt_curses_error (const char *, ...); void mutt_curses_error (const char *, ...);
void mutt_curses_message (const char *, ...); void mutt_curses_message (const char *, ...);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment