From: NRK Date: Sun, 24 Jul 2022 10:10:28 +0000 (+0600) Subject: icons: use a compact array X-Git-Tag: v4.6~5^2 X-Git-Url: http://www.git.stargrave.org/?a=commitdiff_plain;h=fe9c1bbb3a51543b83eab9df08030fb66c2e5553;p=nnn.git icons: use a compact array a lot of the extension use the same icon. this can be exploited via having an array with all the unique icons and then storing a single byte index into the unique array. when using `O_EMOJI` this results in around ~1.7KiB drop in the total table size. `O_NERD` and `O_ICONS` get roughly ~0.5KiB savings. --- diff --git a/src/icons-hash.c b/src/icons-hash.c index f422b225..b001f311 100644 --- a/src/icons-hash.c +++ b/src/icons-hash.c @@ -152,6 +152,28 @@ main(void) icon_max = MAX(icon_max, strlen(exec_icon.icon) + 1); icon_max = MAX(icon_max, strlen(file_icon.icon) + 1); + const char *uniq[ARRLEN(icons_ext)] = {0}; + size_t uniq_head = 0; + for (size_t i = 0; i < ARRLEN(icons_ext); ++i) { + if (icons_ext[i].icon[0] == 0) continue; + int isuniq = 1; + for (size_t k = 0; k < uniq_head; ++k) { + if (strcmp(uniq[k], icons_ext[i].icon) == 0) { + isuniq = 0; + break; + } + } + if (isuniq) { + assert(uniq_head < ARRLEN(uniq)); + uniq[uniq_head++] = icons_ext[i].icon; + } + } + assert(uniq_head < (unsigned char)-1); + + log("uniq icons: %6zu\n", uniq_head); + log("no-compact: %6zu bytes\n", ARRLEN(table) * icon_max); + log("compaction: %6zu bytes\n", uniq_head * icon_max + ARRLEN(table)); + printf("#ifndef INCLUDE_ICONS_GENERATED\n"); printf("#define INCLUDE_ICONS_GENERATED\n\n"); @@ -167,12 +189,22 @@ main(void) printf("struct icon_pair { const char match[%zu]; const char icon[%zu]; unsigned char color; };\n\n", match_max, icon_max); - printf("static const struct icon_pair icons_ext[%zu] = {\n", ARRLEN(table)); + printf("static const char icons_ext_uniq[%zu][%zu] = {\n", uniq_head, icon_max); + for (size_t i = 0; i < uniq_head; ++i) + printf("\t\"%s\",\n", uniq[i]); + printf("};\n\n"); + + printf("static const struct {\n\tconst char match[%zu];" + "\n\tunsigned char idx;\n\tunsigned char color;\n} icons_ext[%zu] = {\n", + match_max, ARRLEN(table)); for (size_t i = 0; i < ARRLEN(table); ++i) { if (table[i].icon == NULL || table[i].icon[0] == '\0') /* skip empty entries */ continue; - printf("\t[%zu] = {\"%s\", \"%s\", %hhu },\n", i, - table[i].match, table[i].icon, table[i].color); + int k; + for (k = 0; k < uniq_head; ++k) if (strcmp(table[i].icon, uniq[k]) == 0) break; + assert(k < uniq_head); + printf("\t[%3zu] = {\"%s\", %d, %hhu },\n", + i, table[i].match, k, table[i].color); } printf("};\n\n"); diff --git a/src/icons.h b/src/icons.h index 7049e738..fa3c27c0 100644 --- a/src/icons.h +++ b/src/icons.h @@ -167,9 +167,11 @@ static const unsigned char init_colors[] = { COLOR_LIST }; struct icon_pair { const char *match; const char *icon; unsigned char color; }; #endif -static const struct icon_pair dir_icon = {"", ICON_DIRECTORY, 0}; -static const struct icon_pair file_icon = {"", ICON_FILE, 0}; -static const struct icon_pair exec_icon = {"", ICON_EXEC, 0}; +struct icon { const char *icon; unsigned char color; }; + +static const struct icon dir_icon = {ICON_DIRECTORY, 0}; +static const struct icon file_icon = {ICON_FILE, 0}; +static const struct icon exec_icon = {ICON_EXEC, 0}; static const struct icon_pair icons_name[] = { {".git", ICON_GIT, 0}, diff --git a/src/nnn.c b/src/nnn.c index 0d7e9d2f..6a1b6287 100644 --- a/src/nnn.c +++ b/src/nnn.c @@ -3961,16 +3961,14 @@ static char *get_lsperms(mode_t mode) } #ifdef ICONS_ENABLED -static const struct icon_pair *get_icon(const struct entry *ent) +static struct icon get_icon(const struct entry *ent) { - ushort_t i = 0; - - for (; i < ELEMENTS(icons_name); ++i) + for (size_t i = 0; i < ELEMENTS(icons_name); ++i) if (strcasecmp(ent->name, icons_name[i].match) == 0) - return &icons_name[i]; + return (struct icon){ icons_name[i].icon, icons_name[i].color }; if (ent->flags & DIR_OR_DIRLNK) - return &dir_icon; + return dir_icon; char *tmp = xextension(ent->name, ent->nlen); @@ -3979,29 +3977,27 @@ static const struct icon_pair *get_icon(const struct entry *ent) for (k = 0; k < ICONS_PROBE_MAX; ++k) { z = (h + k) % ELEMENTS(icons_ext); if (strcasecmp(tmp, icons_ext[z].match) == 0) - return &icons_ext[z]; + return (struct icon){ icons_ext_uniq[icons_ext[z].idx], icons_ext[z].color }; } } /* If there's no match and the file is executable, icon that */ if (ent->mode & 0100) - return &exec_icon; - - return &file_icon; + return exec_icon; + return file_icon; } static void print_icon(const struct entry *ent, const int attrs) { - const struct icon_pair *picon = get_icon(ent); - + const struct icon icon = get_icon(ent); addstr(ICON_PADDING_LEFT); - if (picon->color) - attron(COLOR_PAIR(C_UND + 1 + picon->color)); + if (icon.color) + attron(COLOR_PAIR(C_UND + 1 + icon.color)); else if (attrs) attron(attrs); - addstr(picon->icon); - if (picon->color) - attroff(COLOR_PAIR(C_UND + 1 + picon->color)); + addstr(icon.icon); + if (icon.color) + attroff(COLOR_PAIR(C_UND + 1 + icon.color)); else if (attrs) attroff(attrs); addstr(ICON_PADDING_RIGHT);