diff src/normal.c @ 27447:4050f0554902 v8.2.4252

patch 8.2.4252: generating the normal command table at runtime is inefficient Commit: https://github.com/vim/vim/commit/4dc0dd869972ddafc7d9ee5ea765645b818a6dc9 Author: Yegappan Lakshmanan <yegappan@yahoo.com> Date: Sat Jan 29 13:06:40 2022 +0000 patch 8.2.4252: generating the normal command table at runtime is inefficient Problem: Generating the normal command table at runtime is inefficient. Solution: Generate the table with a Vim script and put it in a header file. (Yegappan Lakshmanan, closes #9648)
author Bram Moolenaar <Bram@vim.org>
date Sat, 29 Jan 2022 14:15:04 +0100
parents 3f8a57b8c7d8
children ee1019e59bef
line wrap: on
line diff
--- a/src/normal.c
+++ b/src/normal.c
@@ -19,7 +19,6 @@ static int	VIsual_mode_orig = NUL;		// s
 #ifdef FEAT_EVAL
 static void	set_vcount_ca(cmdarg_T *cap, int *set_prevcount);
 #endif
-static int	nv_compare(const void *s1, const void *s2);
 static void	unshift_special(cmdarg_T *cap);
 #ifdef FEAT_CMDL_INFO
 static void	del_from_showcmd(int);
@@ -128,6 +127,34 @@ static void	nv_drop(cmdarg_T *cap);
 #endif
 static void	nv_cursorhold(cmdarg_T *cap);
 
+#ifdef FEAT_GUI
+#define NV_VER_SCROLLBAR	nv_ver_scrollbar
+#define NV_HOR_SCROLLBAR	nv_hor_scrollbar
+#else
+#define NV_VER_SCROLLBAR nv_error
+#define NV_HOR_SCROLLBAR nv_error
+#endif
+
+#ifdef FEAT_GUI_TABLINE
+#define NV_TABLINE	nv_tabline
+#define NV_TABMENU	nv_tabmenu
+#else
+#define NV_TABLINE	nv_error
+#define NV_TABMENU	nv_error
+#endif
+
+#ifdef FEAT_NETBEANS_INTG
+#define NV_NBCMD	nv_nbcmd
+#else
+#define NV_NBCMD	nv_error
+#endif
+
+#ifdef FEAT_DND
+#define NV_DROP		nv_drop
+#else
+#define NV_DROP		nv_error
+#endif
+
 /*
  * Function to be called for a Normal or Visual mode command.
  * The argument is a cmdarg_T.
@@ -159,8 +186,14 @@ typedef void (*nv_func_T)(cmdarg_T *cap)
 
 /*
  * This table contains one entry for every Normal or Visual mode command.
- * The order doesn't matter, init_normal_cmds() will create a sorted index.
+ * The order doesn't matter, this will be sorted by the create_nvcmdidx.vim
+ * script to generate the nv_cmd_idx[] lookup table.
  * It is faster when all keys from zero to '~' are present.
+ *
+ * After changing the "nv_cmds" table:
+ * 1. Build Vim with "make"
+ * 2. Run "make nvcmdidxs" to re-generate the nv_cmdidxs.h file.
+ * 3. Build Vim with "make" to use the newly generated index table.
  */
 static const struct nv_cmd
 {
@@ -193,8 +226,6 @@ static const struct nv_cmd
     {Ctrl_T,	nv_tagpop,	NV_NCW,			0},
     {Ctrl_U,	nv_halfpage,	0,			0},
     {Ctrl_V,	nv_visual,	0,			FALSE},
-    {'V',	nv_visual,	0,			FALSE},
-    {'v',	nv_visual,	0,			FALSE},
     {Ctrl_W,	nv_window,	0,			0},
     {Ctrl_X,	nv_addsub,	0,			0},
     {Ctrl_Y,	nv_scroll_line,	0,			FALSE},
@@ -258,6 +289,7 @@ static const struct nv_cmd
     {'S',	nv_subst,	NV_KEEPREG,		0},
     {'T',	nv_csearch,	NV_NCH_ALW|NV_LANG,	BACKWARD},
     {'U',	nv_Undo,	0,			0},
+    {'V',	nv_visual,	0,			FALSE},
     {'W',	nv_wordcmd,	0,			TRUE},
     {'X',	nv_abbrev,	NV_KEEPREG,		0},
     {'Y',	nv_abbrev,	NV_KEEPREG,		0},
@@ -289,6 +321,7 @@ static const struct nv_cmd
     {'s',	nv_subst,	NV_KEEPREG,		0},
     {'t',	nv_csearch,	NV_NCH_ALW|NV_LANG,	FORWARD},
     {'u',	nv_undo,	0,			0},
+    {'v',	nv_visual,	0,			FALSE},
     {'w',	nv_wordcmd,	0,			FALSE},
     {'x',	nv_abbrev,	NV_KEEPREG,		0},
     {'y',	nv_operator,	0,			0},
@@ -356,20 +389,12 @@ static const struct nv_cmd
     {K_F1,	nv_help,	NV_NCW,			0},
     {K_XF1,	nv_help,	NV_NCW,			0},
     {K_SELECT,	nv_select,	0,			0},
-#ifdef FEAT_GUI
-    {K_VER_SCROLLBAR, nv_ver_scrollbar, 0,		0},
-    {K_HOR_SCROLLBAR, nv_hor_scrollbar, 0,		0},
-#endif
-#ifdef FEAT_GUI_TABLINE
-    {K_TABLINE, nv_tabline,	0,			0},
-    {K_TABMENU, nv_tabmenu,	0,			0},
-#endif
-#ifdef FEAT_NETBEANS_INTG
-    {K_F21,	nv_nbcmd,	NV_NCH_ALW,		0},
-#endif
-#ifdef FEAT_DND
-    {K_DROP,	nv_drop,	NV_STS,			0},
-#endif
+    {K_VER_SCROLLBAR, NV_VER_SCROLLBAR, 0,		0},
+    {K_HOR_SCROLLBAR, NV_HOR_SCROLLBAR, 0,		0},
+    {K_TABLINE, NV_TABLINE,	0,			0},
+    {K_TABMENU, NV_TABMENU,	0,			0},
+    {K_F21,	NV_NBCMD,	NV_NCH_ALW,		0},
+    {K_DROP,	NV_DROP,	NV_STS,			0},
     {K_CURSORHOLD, nv_cursorhold, NV_KEEPREG,		0},
     {K_PS,	nv_edit,	0,			0},
     {K_COMMAND,	nv_colon,	0,			0},
@@ -379,55 +404,42 @@ static const struct nv_cmd
 // Number of commands in nv_cmds[].
 #define NV_CMDS_SIZE ARRAY_LENGTH(nv_cmds)
 
-#ifndef PROTO  // cproto doesn't like this
-// Sorted index of commands in nv_cmds[].
-static short nv_cmd_idx[NV_CMDS_SIZE];
-#endif
-
-// The highest index for which
-// nv_cmds[idx].cmd_char == nv_cmd_idx[nv_cmds[idx].cmd_char]
-static int nv_max_linear;
-
-/*
- * Compare functions for qsort() below, that checks the command character
- * through the index in nv_cmd_idx[].
- */
-    static int
-nv_compare(const void *s1, const void *s2)
-{
-    int		c1, c2;
-
-    // The commands are sorted on absolute value.
-    c1 = nv_cmds[*(const short *)s1].cmd_char;
-    c2 = nv_cmds[*(const short *)s2].cmd_char;
-    if (c1 < 0)
-	c1 = -c1;
-    if (c2 < 0)
-	c2 = -c2;
-    return c1 - c2;
-}
-
-/*
- * Initialize the nv_cmd_idx[] table.
+// Include the lookuptable generated by create_nvcmdidx.vim.
+#include "nv_cmdidxs.h"
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * Return the command character for the given command index. This function is
+ * used to auto-generate nv_cmd_idx[].
  */
     void
-init_normal_cmds(void)
-{
-    int		i;
-
-    // Fill the index table with a one to one relation.
-    for (i = 0; i < (int)NV_CMDS_SIZE; ++i)
-	nv_cmd_idx[i] = i;
-
-    // Sort the commands by the command character.
-    qsort((void *)&nv_cmd_idx, (size_t)NV_CMDS_SIZE, sizeof(short), nv_compare);
-
-    // Find the first entry that can't be indexed by the command character.
-    for (i = 0; i < (int)NV_CMDS_SIZE; ++i)
-	if (i != nv_cmds[nv_cmd_idx[i]].cmd_char)
-	    break;
-    nv_max_linear = i - 1;
-}
+f_internal_get_nv_cmdchar(typval_T *argvars, typval_T *rettv)
+{
+    int	idx;
+    int	cmd_char;
+
+    rettv->v_type = VAR_NUMBER;
+    rettv->vval.v_number = -1;
+
+    if (check_for_number_arg(argvars, 0) == FAIL)
+	return;
+
+    idx = tv_get_number(&argvars[0]);
+    if (idx < 0 || idx >= (int)NV_CMDS_SIZE)
+	return;
+
+    cmd_char = nv_cmds[idx].cmd_char;
+
+    // We use the absolute value of the character.  Special keys have a
+    // negative value, but are sorted on their absolute value.
+    if (cmd_char < 0)
+	cmd_char = -cmd_char;
+
+    rettv->vval.v_number = cmd_char;
+
+    return;
+}
+#endif
 
 /*
  * Search for a command in the commands table.