perf(reader): M31 字体路径记忆化(开书字体查找 35 目录 walk → 1 次 stat)+ 「· 读」徽标即时刷新
字体:find_font_rec/resolve_font 从 reader.c 抽到 app/font_resolve.c 并加进程内记忆化。 只缓存成功路径;命中后仍做一次 access() 校验(字库被删即重扫);没找到不缓存, 用户之后拷入的字库下次开书即可找到。顶栏「刷新」额外调 font_cache_invalidate(), 给「新拷入字库、旧字库仍在」一条显式失效路径。宿主实测:35 目录树 walk 0.026~0.54ms (=300+ 次系统调用)vs 命中 0.001ms(1 次 access);开书路径每次省一次完整 walk。 徽标:副题格式化抽成 shelf_fmt_sub()(扫描与「刚读完置顶」共用一份实现), promote_just_read() 改 ts 后立即重算这本的 sub/sub_folder,「· 读」不再等下次全量刷新。 回归:test_reader_core 6846、shelf_group_smoke 63(+8)、font_resolve_smoke 14 全绿; build_reader.sh 0 warning;扫描缓存/进度语义未改。app.json 0.1.3/code4 → 0.1.4/code5。
This commit is contained in:
1 parent
0b30cdbafb
commit
dc9bfdbdaf
12 files changed
+460
-53
No files matched your search
@@ -11,6 +11,8 @@
|
||||
* G7 超上限不静默:truncated=1(含「cap 卡在目录边界」与「恰好装满不误报」两种);
|
||||
* 行数上限(段头 ≤ 书数 ⇒ 2N 必够)
|
||||
* G8 进度不受分组影响:path 不变、rdprog_load 前后同值、ts 两种模式一致
|
||||
* G9 副题格式化的唯一实现 shelf_fmt_sub:扫描与「刚读完置顶」共用
|
||||
* (ts 变化后重算 → 「· 读」立即出现;folder 子路径前缀随 group 重建)
|
||||
*/
|
||||
#include "shelf_model.h"
|
||||
#include "progress.h"
|
||||
@@ -297,6 +299,48 @@ static void test_scan_and_modes(const char *root, const char *tmproot)
|
||||
CHECK(shelf_copy_utf8(dst, 96, ascii) == 95, "ASCII 90+ 字节按 cap-1 截断");
|
||||
}
|
||||
|
||||
/* G9(M31):副题格式化的唯一实现 —— 扫描与「刚读完置顶」共用 shelf_fmt_sub。
|
||||
* 置顶只改 ts 不重算副题时,「· 读」要等一次全量刷新才出现(M30 遗留),这里锁住语义。 */
|
||||
static void test_fmt_sub(void)
|
||||
{
|
||||
shelf_book b;
|
||||
memset(&b, 0, sizeof b);
|
||||
strcpy(b.title, "t");
|
||||
b.fmt = 0; b.size = 5;
|
||||
shelf_fmt_sub(&b);
|
||||
CHECK(strcmp(b.sub, "TXT · 5B") == 0, "无进度副题不含「读」");
|
||||
CHECK(strcmp(b.sub_folder, b.sub) == 0, "根下书两种副题相同");
|
||||
|
||||
/* 刚读完:ts 从 0 变正 → 重算后「· 读」立即出现(不等全量刷新) */
|
||||
b.ts = 100;
|
||||
shelf_fmt_sub(&b);
|
||||
CHECK(strcmp(b.sub, "TXT · 5B · 读") == 0, "ts>0 重算后副题含「· 读」");
|
||||
CHECK(strcmp(b.sub_folder, b.sub) == 0, "根下书重算后两种副题仍相同");
|
||||
|
||||
/* folder 模式:子路径前置,其余与默认副题一致 */
|
||||
shelf_book f;
|
||||
memset(&f, 0, sizeof f);
|
||||
strcpy(f.title, "f");
|
||||
strcpy(f.group, "a/b");
|
||||
f.fmt = 2; f.size = 4 * 1024;
|
||||
shelf_fmt_sub(&f);
|
||||
CHECK(strcmp(f.sub, "EPUB · 4KB") == 0, "folder 书的默认副题不带子路径");
|
||||
CHECK(strcmp(f.sub_folder, "b · EPUB · 4KB") == 0, "folder 副题 = 子路径 · 默认副题");
|
||||
f.ts = 7;
|
||||
shelf_fmt_sub(&f);
|
||||
CHECK(strcmp(f.sub_folder, "b · EPUB · 4KB · 读") == 0,
|
||||
"folder 副题重算后「· 读」出现在末尾");
|
||||
|
||||
/* 一级目录书:rel 无 '/' → 两种副题相同 */
|
||||
shelf_book g;
|
||||
memset(&g, 0, sizeof g);
|
||||
strcpy(g.group, "轻小说");
|
||||
g.fmt = 3; g.size = 100;
|
||||
shelf_fmt_sub(&g);
|
||||
CHECK(strcmp(g.sub, "MOBI · 100B") == 0 && strcmp(g.sub_folder, g.sub) == 0,
|
||||
"一级目录书无子路径前缀");
|
||||
}
|
||||
|
||||
static void test_progress_stability(const char *root)
|
||||
{
|
||||
/* G8:写一份进度,切换分组模式前后 rdprog_load 必须同值,path 不变。 */
|
||||
@@ -382,6 +426,7 @@ int main(void)
|
||||
mkdirs(root);
|
||||
|
||||
test_scan_and_modes(root, tmp);
|
||||
test_fmt_sub();
|
||||
test_progress_stability(root);
|
||||
test_conf_default(tmp);
|
||||
|
||||
|
||||
Reference in new issue
Block a user