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)
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
......
......@@ -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);
......
......@@ -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);
}
......@@ -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);
......
......@@ -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 ();
......
......@@ -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)
{
......
......@@ -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 */
......
......@@ -612,6 +612,8 @@ CONTEXT *mx_open_mailbox (const char *path, int flags, CONTEXT *pctx)
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);
......
......@@ -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;
......
......@@ -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 *, ...);
......
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