1
0
forked from aniani/vim

patch 9.1.0891: building the completion list array is inefficient

Problem:  building the completion list array is inefficient
Solution: refactor and improve ins_compl_build_pum() func
          (glepnir)

current time complexity is O(n^2). I guess garray is not used here to save memory and avoid efficiency
is caused by heap memory allocation. A simple way is to add an extra pointer as a single linked list
to store the matching compl_T, and traverse this single linked list to generate compl_match_array.
The time complexity is O(n x m). The worst case is m=n, but we can still get a little improvement.
Because the if condition does not need to be run at one time. This should be a good solution for now.
Later we may be able to complete it in O(lgn) time. But this requires more reconstruction. So this is
the first step.

closes: #16125

Signed-off-by: glepnir <glephunter@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
glepnir
2024-11-27 21:53:53 +01:00
committed by Christian Brabandt
parent ac023e8baa
commit 80b662009c
2 changed files with 88 additions and 78 deletions

View File

@@ -95,6 +95,7 @@ struct compl_S
{ {
compl_T *cp_next; compl_T *cp_next;
compl_T *cp_prev; compl_T *cp_prev;
compl_T *cp_match_next; // matched next compl_T
string_T cp_str; // matched text string_T cp_str; // matched text
char_u *(cp_text[CPT_COUNT]); // text for the menu char_u *(cp_text[CPT_COUNT]); // text for the menu
#ifdef FEAT_EVAL #ifdef FEAT_EVAL
@@ -197,7 +198,7 @@ static int compl_selected_item = -1;
static int *compl_fuzzy_scores; static int *compl_fuzzy_scores;
static int ins_compl_add(char_u *str, int len, char_u *fname, char_u **cptext, typval_T *user_data, int cdir, int flags, int adup, int *extra_hl); static int ins_compl_add(char_u *str, int len, char_u *fname, char_u **cptext, typval_T *user_data, int cdir, int flags, int adup, int *user_hl);
static void ins_compl_longest_match(compl_T *match); static void ins_compl_longest_match(compl_T *match);
static void ins_compl_del_pum(void); static void ins_compl_del_pum(void);
static void ins_compl_files(int count, char_u **files, int thesaurus, int flags, regmatch_T *regmatch, char_u *buf, int *dir); static void ins_compl_files(int count, char_u **files, int thesaurus, int flags, regmatch_T *regmatch, char_u *buf, int *dir);
@@ -754,7 +755,7 @@ ins_compl_add_infercase(
* cdir - match direction. If 0, use "compl_direction". * cdir - match direction. If 0, use "compl_direction".
* flags_arg - match flags (cp_flags) * flags_arg - match flags (cp_flags)
* adup - accept this match even if it is already present. * adup - accept this match even if it is already present.
* *extra_hl - list of extra highlight attributes for abbr kind. * *user_hl - list of extra highlight attributes for abbr kind.
* If "cdir" is FORWARD, then the match is added after the current match. * If "cdir" is FORWARD, then the match is added after the current match.
* Otherwise, it is added before the current match. * Otherwise, it is added before the current match.
* *
@@ -772,7 +773,7 @@ ins_compl_add(
int cdir, int cdir,
int flags_arg, int flags_arg,
int adup, // accept duplicate match int adup, // accept duplicate match
int *extra_hl) // user abbr/kind hlattr int *user_hl) // user abbr/kind hlattr
{ {
compl_T *match; compl_T *match;
int dir = (cdir == 0 ? compl_direction : cdir); int dir = (cdir == 0 ? compl_direction : cdir);
@@ -838,8 +839,8 @@ ins_compl_add(
else else
match->cp_fname = NULL; match->cp_fname = NULL;
match->cp_flags = flags; match->cp_flags = flags;
match->cp_user_abbr_hlattr = extra_hl ? extra_hl[0] : -1; match->cp_user_abbr_hlattr = user_hl ? user_hl[0] : -1;
match->cp_user_kind_hlattr = extra_hl ? extra_hl[1] : -1; match->cp_user_kind_hlattr = user_hl ? user_hl[1] : -1;
if (cptext != NULL) if (cptext != NULL)
{ {
@@ -1233,6 +1234,9 @@ ins_compl_build_pum(void)
unsigned int cur_cot_flags = get_cot_flags(); unsigned int cur_cot_flags = get_cot_flags();
int compl_no_select = (cur_cot_flags & COT_NOSELECT) != 0; int compl_no_select = (cur_cot_flags & COT_NOSELECT) != 0;
int compl_fuzzy_match = (cur_cot_flags & COT_FUZZY) != 0; int compl_fuzzy_match = (cur_cot_flags & COT_FUZZY) != 0;
compl_T *match_head = NULL;
compl_T *match_tail = NULL;
compl_T *match_next = NULL;
// Need to build the popup menu list. // Need to build the popup menu list.
compl_match_arraysize = 0; compl_match_arraysize = 0;
@@ -1249,7 +1253,14 @@ ins_compl_build_pum(void)
&& (compl_leader.string == NULL && (compl_leader.string == NULL
|| ins_compl_equal(compl, compl_leader.string, (int)compl_leader.length) || ins_compl_equal(compl, compl_leader.string, (int)compl_leader.length)
|| (compl_fuzzy_match && compl->cp_score > 0))) || (compl_fuzzy_match && compl->cp_score > 0)))
{
++compl_match_arraysize; ++compl_match_arraysize;
if (match_head == NULL)
match_head = compl;
else
match_tail->cp_match_next = compl;
match_tail = compl;
}
compl = compl->cp_next; compl = compl->cp_next;
} while (compl != NULL && !is_first_match(compl)); } while (compl != NULL && !is_first_match(compl));
@@ -1270,15 +1281,11 @@ ins_compl_build_pum(void)
&& shown_match_ok == FALSE) && shown_match_ok == FALSE)
compl_shown_match = compl_no_select ? compl_first_match compl_shown_match = compl_no_select ? compl_first_match
: compl_first_match->cp_next; : compl_first_match->cp_next;
i = 0; i = 0;
compl = compl_first_match; compl = match_head;
do if (match_tail == match_head)
{ did_find_shown_match = TRUE;
if (!match_at_original_text(compl) while (compl != NULL)
&& (compl_leader.string == NULL
|| ins_compl_equal(compl, compl_leader.string, (int)compl_leader.length)
|| (compl_fuzzy_match && compl->cp_score > 0)))
{ {
if (!shown_match_ok && !compl_fuzzy_match) if (!shown_match_ok && !compl_fuzzy_match)
{ {
@@ -1343,7 +1350,6 @@ ins_compl_build_pum(void)
compl->cp_text[CPT_MENU]; compl->cp_text[CPT_MENU];
else else
compl_match_array[i++].pum_extra = compl->cp_fname; compl_match_array[i++].pum_extra = compl->cp_fname;
}
if (compl == compl_shown_match && !compl_fuzzy_match) if (compl == compl_shown_match && !compl_fuzzy_match)
{ {
@@ -1362,8 +1368,10 @@ ins_compl_build_pum(void)
shown_match_ok = TRUE; shown_match_ok = TRUE;
} }
} }
compl = compl->cp_next; match_next = compl->cp_match_next;
} while (compl != NULL && !is_first_match(compl)); compl->cp_match_next = NULL;
compl = match_next;
}
if (compl_fuzzy_match && compl_leader.string != NULL && compl_leader.length > 0) if (compl_fuzzy_match && compl_leader.string != NULL && compl_leader.length > 0)
{ {
@@ -2893,7 +2901,7 @@ ins_compl_add_tv(typval_T *tv, int dir, int fast)
int status; int status;
char_u *user_abbr_hlname; char_u *user_abbr_hlname;
char_u *user_kind_hlname; char_u *user_kind_hlname;
int extra_hl[2] = { -1, -1 }; int user_hl[2] = { -1, -1 };
user_data.v_type = VAR_UNKNOWN; user_data.v_type = VAR_UNKNOWN;
if (tv->v_type == VAR_DICT && tv->vval.v_dict != NULL) if (tv->v_type == VAR_DICT && tv->vval.v_dict != NULL)
@@ -2905,10 +2913,10 @@ ins_compl_add_tv(typval_T *tv, int dir, int fast)
cptext[CPT_INFO] = dict_get_string(tv->vval.v_dict, "info", FALSE); cptext[CPT_INFO] = dict_get_string(tv->vval.v_dict, "info", FALSE);
user_abbr_hlname = dict_get_string(tv->vval.v_dict, "abbr_hlgroup", FALSE); user_abbr_hlname = dict_get_string(tv->vval.v_dict, "abbr_hlgroup", FALSE);
extra_hl[0] = get_user_highlight_attr(user_abbr_hlname); user_hl[0] = get_user_highlight_attr(user_abbr_hlname);
user_kind_hlname = dict_get_string(tv->vval.v_dict, "kind_hlgroup", FALSE); user_kind_hlname = dict_get_string(tv->vval.v_dict, "kind_hlgroup", FALSE);
extra_hl[1] = get_user_highlight_attr(user_kind_hlname); user_hl[1] = get_user_highlight_attr(user_kind_hlname);
dict_get_tv(tv->vval.v_dict, "user_data", &user_data); dict_get_tv(tv->vval.v_dict, "user_data", &user_data);
if (dict_get_string(tv->vval.v_dict, "icase", FALSE) != NULL if (dict_get_string(tv->vval.v_dict, "icase", FALSE) != NULL
@@ -2933,7 +2941,7 @@ ins_compl_add_tv(typval_T *tv, int dir, int fast)
return FAIL; return FAIL;
} }
status = ins_compl_add(word, -1, NULL, cptext, status = ins_compl_add(word, -1, NULL, cptext,
&user_data, dir, flags, dup, extra_hl); &user_data, dir, flags, dup, user_hl);
if (status != OK) if (status != OK)
clear_tv(&user_data); clear_tv(&user_data);
return status; return status;

View File

@@ -704,6 +704,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
891,
/**/ /**/
890, 890,
/**/ /**/