tagtree reduce size of get_tag lookup table

this is not a hot path only runs at start-up and tagnav reload
so speed is not so much of a concern

we can split the data into two separate tables to
remove the padding and allow symbols to be stored in uint8
(highest symbol <128) and do strlen at TOU

use uint16_t for get_clause()

Change-Id: I0f8663d0de9cac102f1d58b43bf200272754c466
This commit is contained in:
William Wilgus 2025-02-09 16:33:58 -05:00 committed by William Wilgus
parent bb84e9def5
commit a29af6e7c6

View file

@ -358,69 +358,66 @@ static int get_token_str(char *buf, int size)
static int get_tag(int *tag) static int get_tag(int *tag)
{ {
#define TAG_MATCH(str, tag) {str, sizeof(str) - 1, tag} #define TAG_TABLE \
struct match {const char* str; uint16_t len; uint16_t symbol;}; TAG_MATCH("lm", tag_virt_length_min) \
static const struct match get_tag_match[] = TAG_MATCH("ls", tag_virt_length_sec) \
TAG_MATCH("pm", tag_virt_playtime_min) \
TAG_MATCH("ps", tag_virt_playtime_sec) \
TAG_MATCH("->", menu_next) \
TAG_MATCH("~>", menu_shuffle_songs) \
TAG_MATCH("==>", menu_load) \
TAG_MATCH("year", tag_year) \
TAG_MATCH("album", tag_album) \
TAG_MATCH("genre", tag_genre) \
TAG_MATCH("title", tag_title) \
TAG_MATCH("%sort", var_sorttype) \
TAG_MATCH("artist", tag_artist) \
TAG_MATCH("length", tag_length) \
TAG_MATCH("rating", tag_rating) \
TAG_MATCH("%limit", var_limit) \
TAG_MATCH("%strip", var_strip) \
TAG_MATCH("bitrate", tag_bitrate) \
TAG_MATCH("comment", tag_comment) \
TAG_MATCH("discnum", tag_discnumber) \
TAG_MATCH("%format", var_format) \
TAG_MATCH("%reload", menu_reload) \
TAG_MATCH("filename", tag_filename) \
TAG_MATCH("basename", tag_virt_basename) \
TAG_MATCH("tracknum", tag_tracknumber) \
TAG_MATCH("composer", tag_composer) \
TAG_MATCH("ensemble", tag_albumartist) \
TAG_MATCH("grouping", tag_grouping) \
TAG_MATCH("entryage", tag_virt_entryage) \
TAG_MATCH("commitid", tag_commitid) \
TAG_MATCH("%include", var_include) \
TAG_MATCH("playcount", tag_playcount) \
TAG_MATCH("autoscore", tag_virt_autoscore) \
TAG_MATCH("lastplayed", tag_lastplayed) \
TAG_MATCH("lastoffset", tag_lastoffset) \
TAG_MATCH("%root_menu", var_rootmenu) \
TAG_MATCH("albumartist", tag_albumartist) \
TAG_MATCH("lastelapsed", tag_lastelapsed) \
TAG_MATCH("%menu_start", var_menu_start) \
TAG_MATCH("%byfirstletter", menu_byfirstletter) \
TAG_MATCH("canonicalartist", tag_virt_canonicalartist) \
/* END OF TAG_TABLE MACRO */
/* build two separate arrays tag strings and symbol map*/
#define TAG_MATCH(str, tag) str,
static const char * const get_tag_match[] =
{ {
TAG_MATCH("lm", tag_virt_length_min), TAG_TABLE
TAG_MATCH("ls", tag_virt_length_sec),
TAG_MATCH("pm", tag_virt_playtime_min),
TAG_MATCH("ps", tag_virt_playtime_sec),
TAG_MATCH("->", menu_next),
TAG_MATCH("~>", menu_shuffle_songs),
TAG_MATCH("==>", menu_load),
TAG_MATCH("year", tag_year),
TAG_MATCH("album", tag_album),
TAG_MATCH("genre", tag_genre),
TAG_MATCH("title", tag_title),
TAG_MATCH("%sort", var_sorttype),
TAG_MATCH("artist", tag_artist),
TAG_MATCH("length", tag_length),
TAG_MATCH("rating", tag_rating),
TAG_MATCH("%limit", var_limit),
TAG_MATCH("%strip", var_strip),
TAG_MATCH("bitrate", tag_bitrate),
TAG_MATCH("comment", tag_comment),
TAG_MATCH("discnum", tag_discnumber),
TAG_MATCH("%format", var_format),
TAG_MATCH("%reload", menu_reload),
TAG_MATCH("filename", tag_filename),
TAG_MATCH("basename", tag_virt_basename),
TAG_MATCH("tracknum", tag_tracknumber),
TAG_MATCH("composer", tag_composer),
TAG_MATCH("ensemble", tag_albumartist),
TAG_MATCH("grouping", tag_grouping),
TAG_MATCH("entryage", tag_virt_entryage),
TAG_MATCH("commitid", tag_commitid),
TAG_MATCH("%include", var_include),
TAG_MATCH("playcount", tag_playcount),
TAG_MATCH("autoscore", tag_virt_autoscore),
TAG_MATCH("lastplayed", tag_lastplayed),
TAG_MATCH("lastoffset", tag_lastoffset),
TAG_MATCH("%root_menu", var_rootmenu),
TAG_MATCH("albumartist", tag_albumartist),
TAG_MATCH("lastelapsed", tag_lastelapsed),
TAG_MATCH("%menu_start", var_menu_start),
TAG_MATCH("%byfirstletter", menu_byfirstletter),
TAG_MATCH("canonicalartist", tag_virt_canonicalartist),
TAG_MATCH("", 0) /* sentinel */
}; };
#undef TAG_MATCH #undef TAG_MATCH
const size_t max_cmd_sz = 32; /* needs to be >= to len of longest tagstr */ #define TAG_MATCH(str, tag) tag,
static const uint8_t get_tag_symbol[]=
{
TAG_TABLE
};
#undef TAG_MATCH
const char *tagstr; const char *tagstr;
uint16_t tagstr_len; ptrdiff_t tagstr_len;
const struct match *match;
/* Find the start. */ /* Find the start. */
while (*strp == ' ' || *strp == '>') while (*strp == ' ' || *strp == '>')
@ -430,24 +427,24 @@ static int get_tag(int *tag)
return 0; return 0;
tagstr = strp; tagstr = strp;
for (tagstr_len = 0; tagstr_len < max_cmd_sz; tagstr_len++) while(*strp != '\0' && *strp != ' ') /* walk to the end of the tag */
{ {
if (*strp == '\0' || *strp == ' ')
break ;
strp++; strp++;
} }
tagstr_len = strp - tagstr;
for (match = get_tag_match; match->len != 0; match++) for (size_t i = 0; i < ARRAYLEN(get_tag_match); i++)
{ {
if (tagstr_len != match->len) const char *match = get_tag_match[i];
continue; if ((ptrdiff_t)strlen(match) == tagstr_len)
else if (strncasecmp(tagstr, match->str, match->len) == 0)
{ {
*tag = match->symbol; if (strncasecmp(tagstr, match, tagstr_len) == 0)
{
*tag = get_tag_symbol[i];
return 1; return 1;
} }
} }
}
logf("NO MATCH: %.*s\n", tagstr_len, tagstr); logf("NO MATCH: %.*s\n", tagstr_len, tagstr);
return -1; return -1;
@ -456,10 +453,10 @@ static int get_tag(int *tag)
static int get_clause(int *condition) static int get_clause(int *condition)
{ {
/* one or two operator conditionals */ /* one or two operator conditionals */
#define OPS2VAL(op1, op2) ((int)op1 << 8 | (int)op2) #define OPS2VAL(op1, op2) ((uint16_t)op1 << 8 | (uint16_t)op2)
#define CLAUSE(op1, op2, symbol) {OPS2VAL(op1, op2), symbol } #define CLAUSE(op1, op2, symbol) {OPS2VAL(op1, op2), symbol }
struct clause_symbol {int value;int symbol;}; struct clause_symbol {uint16_t value;uint16_t symbol;};
const struct clause_symbol *match; const struct clause_symbol *match;
static const struct clause_symbol get_clause_match[] = static const struct clause_symbol get_clause_match[] =
{ {
@ -497,7 +494,7 @@ static int get_clause(int *condition)
if (op2 == '"') /*allow " to end a single op conditional */ if (op2 == '"') /*allow " to end a single op conditional */
op2 = ' '; op2 = ' ';
int value = OPS2VAL(op1, op2); uint16_t value = OPS2VAL(op1, op2);
for (match = get_clause_match; match->value != 0; match++) for (match = get_clause_match; match->value != 0; match++)
{ {