]> Sergey Matveev's repositories - nnn.git/commitdiff
icons: use a compact array
authorNRK <nrk@disroot.org>
Sun, 24 Jul 2022 10:10:28 +0000 (16:10 +0600)
committerNRK <nrk@disroot.org>
Sun, 24 Jul 2022 10:24:11 +0000 (16:24 +0600)
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.

src/icons-hash.c
src/icons.h
src/nnn.c

index f422b2251b5384a6342640e6ed52e9e28d39bd7f..b001f311dd435d67ee4c6fa0771d57819c942c44 100644 (file)
@@ -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");
 
index 7049e7382da517e35a0be74b4adfedb7ff8171f2..fa3c27c0bba90e82a052f0420c47e78058ddc479 100644 (file)
@@ -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},
index 0d7e9d2ff1d55a813a2386e1ce2c0be42a4b0f4a..6a1b6287bd9f2e254a3f8d57d8e50ef605574e6a 100644 (file)
--- 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);