nnn

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit f829afe60bc32c949224d0ec85c590ebf8a9b61c
parent aab5ab53a58347d990dbe8d608e17312e7fcefd8
Author: Arun <engineerarun@gmail.com>
Date:   Sun, 24 Jul 2022 16:14:52 +0530

Merge pull request #1436 from N-R-K/icon_compaction

icons: use a compact array
Diffstat:
Msrc/icons-hash.c | 87++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
Msrc/icons.h | 8+++++---
Msrc/nnn.c | 30+++++++++++++-----------------
3 files changed, 78 insertions(+), 47 deletions(-)

diff --git a/src/icons-hash.c b/src/icons-hash.c @@ -12,21 +12,23 @@ #ifdef ICONS_GENERATE -#define ICONS_PROBE_MAX_ALLOWED 6 -#define ICONS_MATCH_MAX ((size_t)-1) - -#ifdef NDEBUG - #error "NDEBUG" -#endif #include <assert.h> #include <stdio.h> #include <string.h> +#include <limits.h> #include "icons.h" +#ifdef NDEBUG + #error "NDEBUG" +#endif + #define ASSERT(X) assert(X) #define ARRLEN(X) (sizeof(X) / sizeof((X)[0])) #define MAX(A, B) ((A) > (B) ? (A) : (B)) #define HGEN_ITERARATION (1ul << 14) +#define ICONS_PROBE_MAX_ALLOWED 6 +#define ICONS_MATCH_MAX ((size_t)-1) + #if 0 /* enable for debugging */ #define log(...) fprintf(stderr, "[INFO]: " __VA_ARGS__) #else @@ -133,19 +135,9 @@ main(void) assert(found); } - log("hash_start: %u\n", (unsigned)hash_start); - log("hash_mul : %u\n", (unsigned)hash_mul); - log("max_probe : %u\n", max_probe); - - printf("#ifndef INCLUDE_ICONS_GENERATED\n"); - printf("#define INCLUDE_ICONS_GENERATED\n\n"); - - printf("/*\n * NOTE: This file is automatically generated.\n"); - printf(" * DO NOT EDIT THIS FILE DIRECTLY.\n"); - printf(" * Use `icons.h` to customize icons\n */\n\n"); - - printf("#define hash_start %uu\n", hash_start); - printf("#define hash_mul %uu\n\n", hash_mul); + log("hash_start: %6u\n", (unsigned)hash_start); + log("hash_mul : %6u\n", (unsigned)hash_mul); + log("max_probe : %6u\n", max_probe); size_t match_max = 0, icon_max = 0; for (size_t i = 0; i < ARRLEN(icons_name); ++i) { @@ -160,18 +152,59 @@ 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"); + + printf("/*\n * NOTE: This file is automatically generated.\n"); + printf(" * DO NOT EDIT THIS FILE DIRECTLY.\n"); + printf(" * Use `icons.h` to customize icons\n */\n\n"); + + printf("#define hash_start %uu\n", hash_start); + printf("#define hash_mul %uu\n\n", hash_mul); printf("#define ICONS_PROBE_MAX %u\n", max_probe); printf("#define ICONS_MATCH_MAX %zuu\n\n", match_max); 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"); @@ -190,13 +223,13 @@ main(void) static uint16_t icon_ext_hash(const char *str) { - const unsigned int z = 16 - ICONS_TABLE_SIZE; /* 16 == size of `hash` in bits */ - uint16_t hash = hash_start; - for (size_t i = 0; i < ICONS_MATCH_MAX && str[i] != '\0'; ++i) { - hash ^= TOUPPER((unsigned char)str[i]) + i; + uint32_t i, hash = hash_start; + const unsigned int z = (sizeof hash * CHAR_BIT) - ICONS_TABLE_SIZE; + for (i = 0; i < ICONS_MATCH_MAX && str[i] != '\0'; ++i) { + hash ^= TOUPPER((unsigned char)str[i]); hash *= hash_mul; } - hash = (hash >> z) ^ hash; + hash ^= (hash >> z); hash *= GOLDEN_RATIO_16; hash >>= z; ASSERT(hash < ARRLEN(table)); diff --git 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 @@ -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);