mdview2: снять рудиментные merge-гварды (11→10с)
После полной миграции на merge флаги g_cur_merged/g_next_merged всегда равны 1 (все типы блоков строит форвард-сканер). Убраны сами флаги и ~30 гвардов `if (g_cur_merged)` в горячем посимвольном цикле — это и небольшое ускорение (ветка на символ), и чистка. Проверено замером: инлайн gc_put (макрос/inline) в этот регистро-нагруженный цикл, наоборот, ЗАМЕДЛЯЕТ (~11→13с) из-за роста спиллов — оставлен функцией. Вывод: per-char микрооптимизации здесь исчерпаны (asm-fb не помог, инлайн навредил, снятие гвардов дало ~1с). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+31
-41
@@ -780,15 +780,16 @@ static uint8_t marker_visible_col(uint8_t kind, uint32_t p_start, uint32_t conte
|
||||
* по файлу — без отдельного второго скана. На каждом emit_seg ячейки
|
||||
* ПРЕДЫДУЩего сегмента флашатся в кэш (lag-1: к этому моменту сегмент уже
|
||||
* полностью просканирован); последний сегмент флашится после цикла index_lines.
|
||||
* g_cur_merged переживает переносы внутри одного параграфа; g_next_merged
|
||||
* выставляет index_lines перед блоком (рудимент эпохи поэтапной миграции —
|
||||
* сейчас все типы строит merge, так что флаг всегда 1). */
|
||||
* g_ncells_at_space — снимок длины на последнем пробеле для усечения буфера
|
||||
* при переносе строки (отбрасываем уехавшее за границу слово). */
|
||||
static uint8_t g_cells[MAX_CACHE_LINE_LEN * 2];
|
||||
static uint8_t g_ncells = 0; /* ячеек в текущем сегменте */
|
||||
static uint8_t g_ncells_at_space = 0; /* снимок g_ncells на последнем пробеле (для усечения при переносе) */
|
||||
static uint8_t g_cur_merged = 0; /* строящийся сегмент построен merge'ем (всегда 1) */
|
||||
static uint8_t g_next_merged = 0; /* статус следующего сегмента (ставит index_lines) */
|
||||
|
||||
/* Пишет одну (char,attr)-ячейку в g_cells, молча игнорируя переполнение
|
||||
* MAX_CACHE_LINE_LEN. Оставлена ФУНКЦИЕЙ намеренно: инлайн в сильно
|
||||
* регистро-нагруженный скан-цикл на Z80/SDCC увеличивает спиллы и замедляет
|
||||
* (проверено замером — макро-инлайн дал регрессию ~11→13с). */
|
||||
static void gc_put(char ch, uint8_t attr)
|
||||
{
|
||||
if (g_ncells < MAX_CACHE_LINE_LEN) {
|
||||
@@ -838,7 +839,6 @@ static void emit_seg(uint32_t off, uint8_t style, uint8_t ckind, uint8_t cont)
|
||||
n_lines++;
|
||||
/* Флаш ячеек ПРЕДЫДУЩего сегмента (lag-1): он полностью собран форвард-сканером. */
|
||||
if (n_lines >= 2) seg_commit_cells((uint16_t)(n_lines - 2));
|
||||
g_cur_merged = g_next_merged; /* статус нового сегмента (сейчас всегда 1) */
|
||||
g_ncells = 0; /* буфер ячеек под новый сегмент */
|
||||
g_ncells_at_space = 0;
|
||||
}
|
||||
@@ -929,7 +929,7 @@ static uint8_t inline_scan(uint32_t q, uint32_t q_end, uint8_t col,
|
||||
if (ch == '`') {
|
||||
if (line_style == INIT_STYLE_PLAIN) { line_style = INIT_STYLE_CODE; q++; continue; }
|
||||
if (line_style == INIT_STYLE_CODE) { line_style = INIT_STYLE_PLAIN; q++; continue; }
|
||||
if (g_cur_merged) gc_put('`', emph_to_attr(line_style, base));
|
||||
gc_put('`', emph_to_attr(line_style, base));
|
||||
seg_col++; q++; prev_ch = '`'; continue;
|
||||
}
|
||||
if (ch == '*' && (q + 1) < q_end && fb(q + 1) == '*') {
|
||||
@@ -941,7 +941,7 @@ static uint8_t inline_scan(uint32_t q, uint32_t q_end, uint8_t col,
|
||||
line_style = INIT_STYLE_PLAIN; q += 2; continue;
|
||||
}
|
||||
}
|
||||
if (g_cur_merged) { gc_put('*', emph_to_attr(line_style, base)); gc_put('*', emph_to_attr(line_style, base)); }
|
||||
{ gc_put('*', emph_to_attr(line_style, base)); gc_put('*', emph_to_attr(line_style, base)); }
|
||||
seg_col += 2; q += 2; prev_ch = '*'; continue;
|
||||
}
|
||||
if (ch == '~' && (q + 1) < q_end && fb(q + 1) == '~') {
|
||||
@@ -953,7 +953,7 @@ static uint8_t inline_scan(uint32_t q, uint32_t q_end, uint8_t col,
|
||||
line_style = INIT_STYLE_PLAIN; q += 2; continue;
|
||||
}
|
||||
}
|
||||
if (g_cur_merged) { gc_put('~', emph_to_attr(line_style, base)); gc_put('~', emph_to_attr(line_style, base)); }
|
||||
{ gc_put('~', emph_to_attr(line_style, base)); gc_put('~', emph_to_attr(line_style, base)); }
|
||||
seg_col += 2; q += 2; prev_ch = '~'; continue;
|
||||
}
|
||||
if (ch == '*' || ch == '_') {
|
||||
@@ -967,7 +967,7 @@ static uint8_t inline_scan(uint32_t q, uint32_t q_end, uint8_t col,
|
||||
line_style = INIT_STYLE_PLAIN; q++; continue;
|
||||
}
|
||||
}
|
||||
if (g_cur_merged) gc_put(ch, emph_to_attr(line_style, base));
|
||||
gc_put(ch, emph_to_attr(line_style, base));
|
||||
seg_col++; q++; prev_ch = ch; continue;
|
||||
}
|
||||
if (ch == '\t') {
|
||||
@@ -975,17 +975,17 @@ static uint8_t inline_scan(uint32_t q, uint32_t q_end, uint8_t col,
|
||||
uint8_t tgt_full = (uint8_t)((seg_col & (uint8_t)~(TAB_STOP - 1)) + TAB_STOP);
|
||||
uint8_t tgt = tgt_full;
|
||||
if (tgt > SCREEN_W) tgt = SCREEN_W;
|
||||
if (g_cur_merged) gc_fill(' ', emph_to_attr(line_style, base), (uint8_t)(tgt_full - old_sc));
|
||||
gc_fill(' ', emph_to_attr(line_style, base), (uint8_t)(tgt_full - old_sc));
|
||||
seg_col = tgt; q++; prev_ch = ' '; continue;
|
||||
}
|
||||
if (ch == ' ') {
|
||||
if (g_cur_merged) gc_put(' ', emph_to_attr(line_style, base));
|
||||
gc_put(' ', emph_to_attr(line_style, base));
|
||||
last_space = q + 1;
|
||||
last_space_style = line_style;
|
||||
if (g_cur_merged) g_ncells_at_space = g_ncells;
|
||||
g_ncells_at_space = g_ncells;
|
||||
seg_col++; q++; prev_ch = ' ';
|
||||
} else {
|
||||
if (g_cur_merged) gc_put(ch, emph_to_attr(line_style, base));
|
||||
gc_put(ch, emph_to_attr(line_style, base));
|
||||
seg_col++; q++; prev_ch = ch;
|
||||
}
|
||||
if (!nowrap && seg_col >= SCREEN_W) {
|
||||
@@ -993,7 +993,7 @@ static uint8_t inline_scan(uint32_t q, uint32_t q_end, uint8_t col,
|
||||
uint32_t wrap_at = use_ls ? last_space : q;
|
||||
if (wrap_at >= q_end || wrap_at == cur_seg_off) break;
|
||||
uint8_t wrap_style = use_ls ? last_space_style : line_style;
|
||||
if (g_cur_merged && use_ls) g_ncells = g_ncells_at_space;
|
||||
if (use_ls) g_ncells = g_ncells_at_space;
|
||||
emit_seg(wrap_at, wrap_style, ckind, 1);
|
||||
base = ATTR_TEXT; /* continuation заголовка → PLAIN */
|
||||
seg_col = col; last_space = 0xFFFFFFFFu; prev_ch = ' '; q = wrap_at;
|
||||
@@ -1147,7 +1147,7 @@ static uint32_t scan_join_stream(uint32_t q, uint32_t para_start, uint8_t col,
|
||||
if (!soft_break) q++;
|
||||
continue;
|
||||
}
|
||||
if (g_cur_merged) gc_put('`', styles_map[line_style]);
|
||||
gc_put('`', styles_map[line_style]);
|
||||
seg_col++;
|
||||
if (!soft_break) q++; else q++;
|
||||
prev_ch = '`';
|
||||
@@ -1166,7 +1166,7 @@ static uint32_t scan_join_stream(uint32_t q, uint32_t para_start, uint8_t col,
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (g_cur_merged) { gc_put('*', styles_map[line_style]); gc_put('*', styles_map[line_style]); }
|
||||
{ gc_put('*', styles_map[line_style]); gc_put('*', styles_map[line_style]); }
|
||||
seg_col += 2;
|
||||
if (!soft_break) q += 2; else q++;
|
||||
prev_ch = '*';
|
||||
@@ -1185,7 +1185,7 @@ static uint32_t scan_join_stream(uint32_t q, uint32_t para_start, uint8_t col,
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (g_cur_merged) { gc_put('~', styles_map[line_style]); gc_put('~', styles_map[line_style]); }
|
||||
{ gc_put('~', styles_map[line_style]); gc_put('~', styles_map[line_style]); }
|
||||
seg_col += 2;
|
||||
if (!soft_break) q += 2; else q++;
|
||||
prev_ch = '~';
|
||||
@@ -1206,7 +1206,7 @@ static uint32_t scan_join_stream(uint32_t q, uint32_t para_start, uint8_t col,
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (g_cur_merged) gc_put(ch, styles_map[line_style]);
|
||||
gc_put(ch, styles_map[line_style]);
|
||||
seg_col++;
|
||||
if (!soft_break) q++; else q++;
|
||||
prev_ch = ch;
|
||||
@@ -1218,14 +1218,14 @@ static uint32_t scan_join_stream(uint32_t q, uint32_t para_start, uint8_t col,
|
||||
uint8_t tgt = tgt_full;
|
||||
if (tgt > SCREEN_W) tgt = SCREEN_W;
|
||||
/* render заполняет до НЕкапнутого tgt_full (по cc); для plain cc==seg_col */
|
||||
if (g_cur_merged) gc_fill(' ', styles_map[line_style], (uint8_t)(tgt_full - old_sc));
|
||||
gc_fill(' ', styles_map[line_style], (uint8_t)(tgt_full - old_sc));
|
||||
seg_col = tgt;
|
||||
if (!soft_break) q++; else q++;
|
||||
prev_ch = ' ';
|
||||
continue;
|
||||
}
|
||||
if (ch == ' ') {
|
||||
if (g_cur_merged) gc_put(' ', styles_map[line_style]);
|
||||
gc_put(' ', styles_map[line_style]);
|
||||
if (soft_break) {
|
||||
last_space = q;
|
||||
last_space_style = line_style;
|
||||
@@ -1236,10 +1236,10 @@ static uint32_t scan_join_stream(uint32_t q, uint32_t para_start, uint8_t col,
|
||||
seg_col++;
|
||||
q++;
|
||||
}
|
||||
if (g_cur_merged) g_ncells_at_space = g_ncells; /* снимок для усечения */
|
||||
g_ncells_at_space = g_ncells; /* снимок для усечения */
|
||||
prev_ch = ' ';
|
||||
} else {
|
||||
if (g_cur_merged) gc_put(ch, styles_map[line_style]);
|
||||
gc_put(ch, styles_map[line_style]);
|
||||
seg_col++;
|
||||
if (!soft_break) q++; else q++;
|
||||
prev_ch = ch;
|
||||
@@ -1249,13 +1249,13 @@ static uint32_t scan_join_stream(uint32_t q, uint32_t para_start, uint8_t col,
|
||||
uint32_t wrap_at = use_ls ? last_space : q;
|
||||
if (wrap_at >= file_size || wrap_at == cur_seg_off) break;
|
||||
uint8_t wrap_style = use_ls ? last_space_style : line_style;
|
||||
if (g_cur_merged && use_ls) g_ncells = g_ncells_at_space; /* усечь до пробела */
|
||||
if (use_ls) g_ncells = g_ncells_at_space; /* усечь до пробела */
|
||||
emit_seg(wrap_at, wrap_style, ckind, 1);
|
||||
/* Префикс continuation-сегмента (как render в cont-блоке): список —
|
||||
* col пробелов; цитата — отступ + маркер 0xB3 + пробел; plain — без префикса. */
|
||||
if (g_cur_merged && ckind == CK_LIST) {
|
||||
if (ckind == CK_LIST) {
|
||||
gc_fill(' ', ATTR_TEXT, col);
|
||||
} else if (g_cur_merged && ckind == CK_QUOTE) {
|
||||
} else if (ckind == CK_QUOTE) {
|
||||
uint32_t content_off2 = para_start + col;
|
||||
uint8_t qsp = 0;
|
||||
while (qsp + 2 < content_off2 && qsp < SCREEN_W && fb(para_start + qsp) == ' ') qsp++;
|
||||
@@ -1293,7 +1293,6 @@ static void index_lines(void)
|
||||
uint32_t p = 0;
|
||||
while (p < file_size && n_lines < max_lines) {
|
||||
|
||||
g_next_merged = 0; /* по умолчанию блок не мигрирован → render; мигрированные типы выставят 1 */
|
||||
|
||||
if ((n_lines & 15) == 0)
|
||||
spinner_tick();
|
||||
@@ -1305,7 +1304,6 @@ static void index_lines(void)
|
||||
if (p < file_size) p++;
|
||||
/* Серия пустых строк схлопывается в одну визуальную строку. */
|
||||
if (n_lines == 0 || !(cur_rec.flags & IF_BLANK)) {
|
||||
g_next_merged = 1; /* S5: blank — пустой буфер (len 0) */
|
||||
emit_seg(p, INIT_STYLE_PLAIN, CK_PLAIN, 0);
|
||||
set_blank_cur();
|
||||
}
|
||||
@@ -1315,7 +1313,6 @@ static void index_lines(void)
|
||||
/* ---- fenced code-блок (граница или тело) ---- */
|
||||
if (is_fence_raw(p)) {
|
||||
in_block = !in_block;
|
||||
g_next_merged = 1; /* S5: граница ``` — пустой буфер (len 0) */
|
||||
emit_seg(p, INIT_STYLE_PLAIN, CK_OTHER, 0);
|
||||
set_nowrap_cur();
|
||||
while (p < file_size && fb(p) != '\n') p++;
|
||||
@@ -1323,12 +1320,11 @@ static void index_lines(void)
|
||||
continue;
|
||||
}
|
||||
if (in_block) {
|
||||
g_next_merged = 1; /* S5: тело кода — verbatim ATTR_TEXT_CODE */
|
||||
emit_seg(p, INIT_STYLE_PLAIN, CK_OTHER, 0);
|
||||
set_nowrap_cur();
|
||||
set_code_cur();
|
||||
set_hscroll_cur(); /* код скроллится целым блоком */
|
||||
if (g_cur_merged) {
|
||||
{
|
||||
uint8_t ccx = 0;
|
||||
uint32_t pp = p;
|
||||
while (pp < file_size && fb(pp) != '\n') {
|
||||
@@ -1352,10 +1348,9 @@ static void index_lines(void)
|
||||
|
||||
/* ---- горизонтальный разделитель ---- */
|
||||
if (is_hr_raw(p)) {
|
||||
g_next_merged = 1; /* S5: HR — 80×0xC4 ATTR_HR */
|
||||
emit_seg(p, INIT_STYLE_PLAIN, CK_OTHER, 0);
|
||||
set_nowrap_cur();
|
||||
if (g_cur_merged) gc_fill(0xC4, ATTR_HR, SCREEN_W);
|
||||
gc_fill(0xC4, ATTR_HR, SCREEN_W);
|
||||
while (p < file_size && fb(p) != '\n') p++;
|
||||
if (p < file_size) p++;
|
||||
continue;
|
||||
@@ -1363,11 +1358,10 @@ static void index_lines(void)
|
||||
|
||||
/* ---- строка таблицы (| ... |): один nowrap-сегмент на исходную строку ---- */
|
||||
if (is_table_raw(p)) {
|
||||
g_next_merged = 1; /* S5: таблица — inline-парсинг без переноса */
|
||||
emit_seg(p, INIT_STYLE_PLAIN, CK_OTHER, 0);
|
||||
set_nowrap_cur();
|
||||
set_hscroll_cur(); /* таблица скроллится целым блоком */
|
||||
if (g_cur_merged) {
|
||||
{
|
||||
uint32_t line_end = p;
|
||||
while (line_end < file_size && fb(line_end) != '\n') line_end++;
|
||||
(void)inline_scan(p, line_end, 0, CK_OTHER, INIT_STYLE_PLAIN, ATTR_TEXT, 1);
|
||||
@@ -1390,7 +1384,6 @@ static void index_lines(void)
|
||||
case LK_H3: hbase = ATTR_TEXT_TITLE3; break;
|
||||
default: hbase = ATTR_TEXT_TITLE4; break;
|
||||
}
|
||||
g_next_merged = 1; /* S2: заголовки строит merge */
|
||||
emit_seg(p, INIT_STYLE_PLAIN, CK_OTHER, 0);
|
||||
uint32_t line_end = content_off;
|
||||
while (line_end < file_size && fb(line_end) != '\n') line_end++;
|
||||
@@ -1406,10 +1399,9 @@ static void index_lines(void)
|
||||
uint8_t line_style = INIT_STYLE_PLAIN;
|
||||
uint32_t q = content_off;
|
||||
|
||||
g_next_merged = 1; /* S3: списки строит merge */
|
||||
emit_seg(p, line_style, CK_LIST, 0);
|
||||
/* Префикс ПЕРВОГО сегмента: отступ + маркер + пробел (как render). */
|
||||
if (g_cur_merged) {
|
||||
{
|
||||
uint32_t qq = p, qmax = p + SCREEN_W;
|
||||
if (kind == LK_ULIST) {
|
||||
while (qq + 2 < content_off && qq < qmax && fb(qq) == ' ') qq++;
|
||||
@@ -1462,10 +1454,9 @@ static void index_lines(void)
|
||||
uint8_t line_style = INIT_STYLE_PLAIN;
|
||||
uint32_t q = content_off;
|
||||
|
||||
g_next_merged = 1; /* S4: цитаты строит merge */
|
||||
emit_seg(p, line_style, CK_QUOTE, 0);
|
||||
/* Префикс ПЕРВОГО сегмента: отступ + маркер 0xB3 + пробел (как render LK_QUOTE). */
|
||||
if (g_cur_merged) {
|
||||
{
|
||||
uint32_t qq = p, qmax = p + SCREEN_W;
|
||||
while (qq + 1 < content_off && qq < qmax && fb(qq) == ' ') qq++;
|
||||
gc_fill(' ', ATTR_TEXT, (uint8_t)(qq - p));
|
||||
@@ -1483,7 +1474,6 @@ static void index_lines(void)
|
||||
/* ---- Обычный текстовый параграф: склейка через soft-break ---- */
|
||||
{
|
||||
uint8_t line_style = INIT_STYLE_PLAIN;
|
||||
g_next_merged = 1; /* S1: параграфы строит merge */
|
||||
emit_seg(p, line_style, CK_PLAIN, 0);
|
||||
|
||||
uint32_t q = p;
|
||||
|
||||
Reference in New Issue
Block a user