mirror of
https://github.com/neovim/neovim.git
synced 2026-04-02 05:39:26 +00:00
vim-patch:partial:9.2.0096: has() function is slow due to linear feature scan (#38135)
Problem: The has() function is slow because it performs a linear scan
of the feature list for every call.
Solution: Move common runtime checks and the patch-version parser to the
beginning of the f_has() function (Yasuhiro Matsumoto).
closes: vim/vim#19550
327e0e34c9
Co-authored-by: Yasuhiro Matsumoto <mattn.jp@gmail.com>
This commit is contained in:
@@ -2784,70 +2784,89 @@ static void f_has(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
|||||||
"nvim",
|
"nvim",
|
||||||
};
|
};
|
||||||
|
|
||||||
// XXX: eval_has_provider() may shell out :(
|
bool x = false;
|
||||||
const int save_shell_error = (int)get_vim_var_nr(VV_SHELL_ERROR);
|
|
||||||
bool n = false;
|
bool n = false;
|
||||||
const char *const name = tv_get_string(&argvars[0]);
|
const char *const name = tv_get_string(&argvars[0]);
|
||||||
for (size_t i = 0; i < ARRAY_SIZE(has_list); i++) {
|
|
||||||
if (STRICMP(name, has_list[i]) == 0) {
|
// Fast-path: check features not in has_list[] first to avoid the full
|
||||||
n = true;
|
// linear scan for very common queries like has('patch-...').
|
||||||
break;
|
if (STRNICMP(name, "patch", 5) == 0) {
|
||||||
|
x = true;
|
||||||
|
if (name[5] == '-'
|
||||||
|
&& strlen(name) >= 11
|
||||||
|
&& (name[6] >= '1' && name[6] <= '9')) {
|
||||||
|
char *end;
|
||||||
|
|
||||||
|
// This works for patch-8.1.2, patch-9.0.3, patch-10.0.4, etc.
|
||||||
|
// Not for patch-9.10.5.
|
||||||
|
int major = (int)strtoul(name + 6, &end, 10);
|
||||||
|
if (*end == '.' && ascii_isdigit(end[1])
|
||||||
|
&& end[2] == '.' && ascii_isdigit(end[3])) {
|
||||||
|
int minor = atoi(end + 1);
|
||||||
|
|
||||||
|
// Expect "patch-9.9.01234".
|
||||||
|
n = has_vim_patch(atoi(end + 3), major * 100 + minor);
|
||||||
|
}
|
||||||
|
} else if (ascii_isdigit(name[5])) {
|
||||||
|
n = has_vim_patch(atoi(name + 5), 0);
|
||||||
|
}
|
||||||
|
} else if (STRNICMP(name, "nvim-", 5) == 0) {
|
||||||
|
x = true;
|
||||||
|
// Expect "nvim-x.y.z"
|
||||||
|
n = has_nvim_version(name + 5);
|
||||||
|
} else if (STRICMP(name, "vim_starting") == 0) {
|
||||||
|
x = true;
|
||||||
|
n = (starting != 0);
|
||||||
|
} else if (STRICMP(name, "ttyin") == 0) {
|
||||||
|
x = true;
|
||||||
|
n = stdin_isatty;
|
||||||
|
} else if (STRICMP(name, "ttyout") == 0) {
|
||||||
|
x = true;
|
||||||
|
n = stdout_isatty;
|
||||||
|
} else if (STRICMP(name, "multi_byte_encoding") == 0) {
|
||||||
|
x = true;
|
||||||
|
n = true;
|
||||||
|
} else if (STRICMP(name, "gui_running") == 0) {
|
||||||
|
x = true;
|
||||||
|
n = ui_gui_attached();
|
||||||
|
} else if (STRICMP(name, "syntax_items") == 0) {
|
||||||
|
x = true;
|
||||||
|
n = syntax_present(curwin);
|
||||||
|
} else if (STRICMP(name, "wsl") == 0) {
|
||||||
|
x = true;
|
||||||
|
n = has_wsl();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look up in has_list[] only if not already handled above.
|
||||||
|
if (!x) {
|
||||||
|
for (size_t i = 0; i < ARRAY_SIZE(has_list); i++) {
|
||||||
|
if (STRICMP(name, has_list[i]) == 0) {
|
||||||
|
x = true;
|
||||||
|
n = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!n) {
|
if (!x) {
|
||||||
if (STRNICMP(name, "gui_running", 11) == 0) {
|
// XXX: eval_has_provider() may shell out :(
|
||||||
n = ui_gui_attached();
|
const int save_shell_error = (int)get_vim_var_nr(VV_SHELL_ERROR);
|
||||||
} else if (STRNICMP(name, "patch", 5) == 0) {
|
|
||||||
if (name[5] == '-'
|
|
||||||
&& strlen(name) >= 11
|
|
||||||
&& (name[6] >= '1' && name[6] <= '9')) {
|
|
||||||
char *end;
|
|
||||||
|
|
||||||
// This works for patch-8.1.2, patch-9.0.3, patch-10.0.4, etc.
|
if (STRICMP(name, "clipboard_working") == 0) {
|
||||||
// Not for patch-9.10.5.
|
|
||||||
int major = (int)strtoul(name + 6, &end, 10);
|
|
||||||
if (*end == '.' && ascii_isdigit(end[1])
|
|
||||||
&& end[2] == '.' && ascii_isdigit(end[3])) {
|
|
||||||
int minor = atoi(end + 1);
|
|
||||||
|
|
||||||
// Expect "patch-9.9.01234".
|
|
||||||
n = has_vim_patch(atoi(end + 3), major * 100 + minor);
|
|
||||||
}
|
|
||||||
} else if (ascii_isdigit(name[5])) {
|
|
||||||
n = has_vim_patch(atoi(name + 5), 0);
|
|
||||||
}
|
|
||||||
} else if (STRNICMP(name, "nvim-", 5) == 0) {
|
|
||||||
// Expect "nvim-x.y.z"
|
|
||||||
n = has_nvim_version(name + 5);
|
|
||||||
} else if (STRICMP(name, "vim_starting") == 0) {
|
|
||||||
n = (starting != 0);
|
|
||||||
} else if (STRICMP(name, "ttyin") == 0) {
|
|
||||||
n = stdin_isatty;
|
|
||||||
} else if (STRICMP(name, "ttyout") == 0) {
|
|
||||||
n = stdout_isatty;
|
|
||||||
} else if (STRICMP(name, "multi_byte_encoding") == 0) {
|
|
||||||
n = true;
|
|
||||||
} else if (STRICMP(name, "syntax_items") == 0) {
|
|
||||||
n = syntax_present(curwin);
|
|
||||||
} else if (STRICMP(name, "clipboard_working") == 0) {
|
|
||||||
n = eval_has_provider("clipboard", true);
|
n = eval_has_provider("clipboard", true);
|
||||||
} else if (STRICMP(name, "pythonx") == 0) {
|
|
||||||
n = eval_has_provider("python3", true);
|
|
||||||
} else if (STRICMP(name, "wsl") == 0) {
|
|
||||||
n = has_wsl();
|
|
||||||
#ifdef UNIX
|
#ifdef UNIX
|
||||||
} else if (STRICMP(name, "unnamedplus") == 0) {
|
} else if (STRICMP(name, "unnamedplus") == 0) {
|
||||||
n = eval_has_provider("clipboard", true);
|
n = eval_has_provider("clipboard", true);
|
||||||
#endif
|
#endif
|
||||||
|
} else if (STRICMP(name, "pythonx") == 0) {
|
||||||
|
n = eval_has_provider("python3", true);
|
||||||
|
} else if (eval_has_provider(name, true)) {
|
||||||
|
n = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set_vim_var_nr(VV_SHELL_ERROR, save_shell_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!n && eval_has_provider(name, true)) {
|
|
||||||
n = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
set_vim_var_nr(VV_SHELL_ERROR, save_shell_error);
|
|
||||||
rettv->vval.v_number = n;
|
rettv->vval.v_number = n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user