perf(highlight): use a hashtable for highlight group names

syn_name2id and syn_check_group go brr.

Note: this has impact mostly when using multiple filetypes,
as the old syn_name2id was optimized to return latest
added groups quickly (which will be the latest filetype)
This commit is contained in:
Björn Linse 2021-08-18 17:05:28 +02:00
parent fca52f5f32
commit bb4b4d79a8
4 changed files with 31 additions and 19 deletions

View File

@ -166,6 +166,7 @@ void early_init(mparm_T *paramp)
init_path(argv0 ? argv0 : "nvim"); init_path(argv0 ? argv0 : "nvim");
init_normal_cmds(); // Init the table of Normal mode commands. init_normal_cmds(); // Init the table of Normal mode commands.
highlight_init(); highlight_init();
syntax_init();
#ifdef WIN32 #ifdef WIN32
OSVERSIONINFO ovi; OSVERSIONINFO ovi;

View File

@ -194,6 +194,7 @@ static inline bool ColorKey_eq(ColorKey ae1, ColorKey ae2)
MAP_IMPL(int, int, DEFAULT_INITIALIZER) MAP_IMPL(int, int, DEFAULT_INITIALIZER)
MAP_IMPL(cstr_t, ptr_t, DEFAULT_INITIALIZER) MAP_IMPL(cstr_t, ptr_t, DEFAULT_INITIALIZER)
MAP_IMPL(cstr_t, int, DEFAULT_INITIALIZER)
MAP_IMPL(ptr_t, ptr_t, DEFAULT_INITIALIZER) MAP_IMPL(ptr_t, ptr_t, DEFAULT_INITIALIZER)
MAP_IMPL(uint64_t, ptr_t, DEFAULT_INITIALIZER) MAP_IMPL(uint64_t, ptr_t, DEFAULT_INITIALIZER)
MAP_IMPL(uint64_t, ssize_t, SSIZE_INITIALIZER) MAP_IMPL(uint64_t, ssize_t, SSIZE_INITIALIZER)

View File

@ -36,6 +36,7 @@
// //
MAP_DECLS(int, int) MAP_DECLS(int, int)
MAP_DECLS(cstr_t, ptr_t) MAP_DECLS(cstr_t, ptr_t)
MAP_DECLS(cstr_t, int)
MAP_DECLS(ptr_t, ptr_t) MAP_DECLS(ptr_t, ptr_t)
MAP_DECLS(uint64_t, ptr_t) MAP_DECLS(uint64_t, ptr_t)
MAP_DECLS(uint64_t, ssize_t) MAP_DECLS(uint64_t, ssize_t)

View File

@ -53,9 +53,9 @@ static bool did_syntax_onoff = false;
/// Structure that stores information about a highlight group. /// Structure that stores information about a highlight group.
/// The ID of a highlight group is also called group ID. It is the index in /// The ID of a highlight group is also called group ID. It is the index in
/// the highlight_ga array PLUS ONE. /// the highlight_ga array PLUS ONE.
struct hl_group { typedef struct hl_group {
char_u *sg_name; ///< highlight group name char_u *sg_name; ///< highlight group name
char_u *sg_name_u; ///< uppercase of sg_name char *sg_name_u; ///< uppercase of sg_name
bool sg_cleared; ///< "hi clear" was used bool sg_cleared; ///< "hi clear" was used
int sg_attr; ///< Screen attr @see ATTR_ENTRY int sg_attr; ///< Screen attr @see ATTR_ENTRY
int sg_link; ///< link to this highlight group ID int sg_link; ///< link to this highlight group ID
@ -80,7 +80,7 @@ struct hl_group {
char *sg_rgb_sp_name; ///< RGB special color name char *sg_rgb_sp_name; ///< RGB special color name
int sg_blend; ///< blend level (0-100 inclusive), -1 if unset int sg_blend; ///< blend level (0-100 inclusive), -1 if unset
}; } HlGroup;
/// \addtogroup SG_SET /// \addtogroup SG_SET
/// @{ /// @{
@ -91,6 +91,7 @@ struct hl_group {
// builtin |highlight-groups| // builtin |highlight-groups|
static garray_T highlight_ga = GA_EMPTY_INIT_VALUE; static garray_T highlight_ga = GA_EMPTY_INIT_VALUE;
Map(cstr_t, int) *highlight_unames;
static inline struct hl_group * HL_TABLE(void) static inline struct hl_group * HL_TABLE(void)
{ {
@ -384,6 +385,11 @@ static int current_line_id = 0; // unique number for current line
static int syn_time_on = FALSE; static int syn_time_on = FALSE;
# define IF_SYN_TIME(p) (p) # define IF_SYN_TIME(p) (p)
void syntax_init(void)
{
highlight_unames = map_new(cstr_t, int)();
}
// Set the timeout used for syntax highlighting. // Set the timeout used for syntax highlighting.
// Use NULL to reset, no timeout. // Use NULL to reset, no timeout.
void syn_set_timeout(proftime_T *tm) void syn_set_timeout(proftime_T *tm)
@ -7113,6 +7119,7 @@ void free_highlight(void)
xfree(HL_TABLE()[i].sg_name_u); xfree(HL_TABLE()[i].sg_name_u);
} }
ga_clear(&highlight_ga); ga_clear(&highlight_ga);
map_free(cstr_t, int)(highlight_unames);
} }
#endif #endif
@ -7474,7 +7481,6 @@ int syn_name2id(const char_u *name)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_ALL
{ {
return syn_name2id_len(name, STRLEN(name)); return syn_name2id_len(name, STRLEN(name));
} }
/// Lookup a highlight group name and return its ID. /// Lookup a highlight group name and return its ID.
@ -7484,25 +7490,22 @@ int syn_name2id(const char_u *name)
int syn_name2id_len(const char_u *name, size_t len) int syn_name2id_len(const char_u *name, size_t len)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_ALL
{ {
int i; char name_u[201];
char_u name_u[201];
if (len == 0 || len > 200) { if (len == 0 || len > 200) {
// ID names over 200 chars don't deserve to be found!
return 0; return 0;
} }
// Avoid using stricmp() too much, it's slow on some systems */ // Avoid using stricmp() too much, it's slow on some systems */
// Avoid alloc()/free(), these are slow too. ID names over 200 chars // Avoid alloc()/free(), these are slow too.
// don't deserve to be found!
memcpy(name_u, name, len); memcpy(name_u, name, len);
name_u[len] = '\0'; name_u[len] = '\0';
vim_strup(name_u); vim_strup((char_u *)name_u);
// TODO(bfredl): what is a hash table?
for (i = highlight_ga.ga_len; --i >= 0; ) // map_get(..., int) returns 0 when no key is present, which is
if (HL_TABLE()[i].sg_name_u != NULL // the expected value for missing highlight group.
&& STRCMP(name_u, HL_TABLE()[i].sg_name_u) == 0) return map_get(cstr_t, int)(highlight_unames, name_u);
break;
return i + 1;
} }
/// Lookup a highlight group name and return its attributes. /// Lookup a highlight group name and return its attributes.
@ -7592,7 +7595,7 @@ static int syn_add_group(char_u *name)
return 0; return 0;
} }
char_u *const name_up = vim_strsave_up(name); char *const name_up = (char *)vim_strsave_up(name);
// Append another syntax_highlight entry. // Append another syntax_highlight entry.
struct hl_group* hlgp = GA_APPEND_VIA_PTR(struct hl_group, &highlight_ga); struct hl_group* hlgp = GA_APPEND_VIA_PTR(struct hl_group, &highlight_ga);
@ -7604,7 +7607,11 @@ static int syn_add_group(char_u *name)
hlgp->sg_blend = -1; hlgp->sg_blend = -1;
hlgp->sg_name_u = name_up; hlgp->sg_name_u = name_up;
return highlight_ga.ga_len; /* ID is index plus one */ int id = highlight_ga.ga_len; // ID is index plus one
map_put(cstr_t, int)(highlight_unames, name_up, id);
return id;
} }
/// When, just after calling syn_add_group(), an error is discovered, this /// When, just after calling syn_add_group(), an error is discovered, this
@ -7612,8 +7619,10 @@ static int syn_add_group(char_u *name)
static void syn_unadd_group(void) static void syn_unadd_group(void)
{ {
highlight_ga.ga_len--; highlight_ga.ga_len--;
xfree(HL_TABLE()[highlight_ga.ga_len].sg_name); HlGroup *item = &HL_TABLE()[highlight_ga.ga_len];
xfree(HL_TABLE()[highlight_ga.ga_len].sg_name_u); map_del(cstr_t, int)(highlight_unames, item->sg_name_u);
xfree(item->sg_name);
xfree(item->sg_name_u);
} }