From 4be63ed8cd2eb1c4861f0ab287f24ea695fd671e Mon Sep 17 00:00:00 2001 From: Berke Güzel Date: Wed, 14 Oct 2026 14:36:22 +0300 Subject: Optimize term_feed scalar dispatch, branchless range search, and invalid subparts --- src/text.c | 158 +++++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 95 insertions(+), 63 deletions(-) (limited to 'src/text.c') diff --git a/src/text.c b/src/text.c index 80c4914..88b23a5 100644 --- a/src/text.c +++ b/src/text.c @@ -23,7 +23,7 @@ static void dispatch_c1_control(struct term *t, uint32_t cp) term_escape_byte(t, (unsigned char)ch); } -static inline void emit_codepoint(struct term *t, uint32_t cp, int klass) +static inline void emit_codepoint(struct term *t, uint32_t cp, int klass, uint16_t flags) { static const uint32_t dec_graphics[] = { 0x00a0, @@ -39,14 +39,14 @@ static inline void emit_codepoint(struct term *t, uint32_t cp, int klass) cp = dec_graphics[cp - '_']; klass = -1; } - term_sc_print_glyph(t, cp, klass, term_current_flags(t)); + sc_print_cell(t, cp, klass, flags); } -static inline void emit_decoded(struct term *t, uint32_t cp) +static inline void emit_decoded(struct term *t, uint32_t cp, uint16_t flags) { int klass = term_text_class(cp); if (!term_sc_extend_cluster(t, cp, klass)) - emit_codepoint(t, cp, klass); + emit_codepoint(t, cp, klass, flags); } /* A byte that cannot continue a UTF-8 sequence ends it: the unfinished @@ -56,13 +56,13 @@ void term_text_utf8_interrupt(struct term *t) if (TERM_EXPECT(t->utf8_state == UTF8_ACCEPT, 1)) return; t->utf8_state = UTF8_ACCEPT; - emit_decoded(t, 0xFFFD); + emit_decoded(t, 0xFFFD, term_current_flags(t)); } void term_text_ground(struct term *t, unsigned char ch) { if (ch >= 0x20 && ch < 0x7f && t->utf8_state == UTF8_ACCEPT) { - emit_codepoint(t, ch, 1); + emit_codepoint(t, ch, 1, term_current_flags(t)); return; } @@ -94,10 +94,10 @@ void term_text_ground(struct term *t, unsigned char ch) uint32_t before = t->utf8_state; uint32_t st = utf8_decode(&t->utf8_state, &t->utf8_codep, ch); if (st == UTF8_ACCEPT) { - emit_decoded(t, t->utf8_codep); + emit_decoded(t, t->utf8_codep, term_current_flags(t)); } else if (st == UTF8_REJECT) { t->utf8_state = UTF8_ACCEPT; - emit_decoded(t, 0xFFFD); + emit_decoded(t, 0xFFFD, term_current_flags(t)); /* The byte that ended an unfinished sequence starts anew. */ if (before != UTF8_ACCEPT) term_text_ground(t, ch); @@ -131,15 +131,15 @@ static inline bool try_text_run(struct term *t, const char *buf, size_t len, ((unsigned char)buf[i] < 0xc2 || (unsigned char)buf[i] > 0xf4)) || t->last_char == 0x200D || grapheme_is_handle(t->last_char)) return false; + if (t->cursor_x != 0 && + t->cursor_x != term_row(t, t->cursor_y)->len) + return false; if ((unsigned char)buf[i] >= 0x80) { uint32_t cp; int bytes = utf8_decode_one(buf + i, len - i, &cp); if (!bytes || term_text_class(cp) <= 0) return false; } - if (t->cursor_x != 0 && - t->cursor_x != term_row(t, t->cursor_y)->len) - return false; struct text_pen pen = term_text_pen(t); bool wrote = false; do { @@ -201,6 +201,7 @@ static void term_feed_inner(struct term *t, const char *buf, size_t len, unsigne if (!t || !buf || len == 0) return; t->transport_newline = (flags & TERM_FEED_ONLCR) != 0; + uint16_t cur_flags = term_current_flags(t); for (size_t i = 0; i < len; i++) { while (t->state != ST_GROUND) { @@ -210,6 +211,7 @@ static void term_feed_inner(struct term *t, const char *buf, size_t len, unsigne i += term_escape_str(t, buf + i, len - i); else term_escape_byte(t, (unsigned char)buf[i++]); + cur_flags = term_current_flags(t); if (i == len) return; } @@ -220,7 +222,10 @@ static void term_feed_inner(struct term *t, const char *buf, size_t len, unsigne int avail = t->pending_wrap ? t->cols : t->cols - t->cursor_x; int rem = (int)(len - i); if (rem > avail) rem = avail; - int run = scan_ascii_run(buf + i, rem); + int run = 1; + if (rem > 1 && (unsigned char)buf[i + 1] >= 0x20 && + (unsigned char)buf[i + 1] < 0x7f) + run += scan_ascii_run(buf + i + 1, rem - 1); if (TERM_EXPECT(can_stream_bottom(t), 1) && (run == t->cols || (i + (size_t)run < len && @@ -260,70 +265,97 @@ static void term_feed_inner(struct term *t, const char *buf, size_t len, unsigne continue; } - if ((ch < 0x20 || ch == 0x7f) && t->state == ST_GROUND) - term_text_utf8_interrupt(t); - - if (TERM_EXPECT(ch < 0x20 && t->state == ST_GROUND && - ch != 0x1b && ch != '\n' && ch != '\r' && ch != '\b' && ch != '\t' && - ch != 0x0e && ch != 0x0f && ch != 0x07 && ch != 0x0b && - ch != 0x0c, 0)) { - continue; - } - - if (TERM_EXPECT(ch == 0x1b && t->state == ST_GROUND && - t->utf8_state == UTF8_ACCEPT && i + 1 < len && - buf[i + 1] == '[' && !t->insert_mode && - !t->lr_margin_mode && !t->graphics, 0)) { - int fast = term_try_fast_csi(t, buf + i + 2, len - i - 2); - if (fast > 0) { - i += 1 + (size_t)fast; + if (TERM_EXPECT(ch >= 0x80, 1)) { + if (TERM_EXPECT(t->state == ST_GROUND && + t->utf8_state == UTF8_ACCEPT && !t->graphics, 1)) { + if (ch >= 0xc2 && ch <= 0xf4 && + (i + 1 == len || ((unsigned char)buf[i + 1] & 0xc0) == 0x80)) { + if (!t->insert_mode && !t->lr_margin_mode && + try_text_run(t, buf, len, &i)) + continue; + } else { + if (TERM_EXPECT(t->last_char != 0x200D && !grapheme_is_handle(t->last_char), 1)) + sc_print_cell(t, 0xFFFD, 1, cur_flags); + else + emit_decoded(t, 0xFFFD, cur_flags); + continue; + } + uint32_t cp; + int cp_len = decode_ground_utf8(t, buf + i, len - i, &cp); + if (cp) + emit_decoded(t, cp, cur_flags); + i += (size_t)(cp_len - 1); continue; } - t->state = ST_CSI; - csi_parser_reset(&t->csi_parser); - i += 1 + term_escape_csi(t, buf + i + 2, len - i - 2); - continue; - } - - if (TERM_EXPECT(t->state == ST_GROUND && ch == '\n', 0)) { - size_t end = i + 1 + scan_byte_run(buf + i + 1, len - i - 1, '\n'); - if (term_lnm(t)) sc_cr(t); - sc_linefeed(t, end - i); - i = end - 1; - continue; - } - - if (TERM_EXPECT(t->state == ST_GROUND && ch == '\r' && - i + 1 < len && buf[i + 1] == '\n', 0)) { - size_t end = i + 2 + scan_crlf_pairs(buf + i + 2, len - i - 2); - sc_cr(t); - sc_linefeed(t, (end - i) / 2); - i = end - 1; + if (TERM_EXPECT(t->state == ST_GROUND, 1)) + term_text_ground(t, ch); + else + term_escape_byte(t, ch); continue; } - if (TERM_EXPECT(ch == '\r' && t->state == ST_GROUND, 0)) { - sc_cr(t); - continue; - } + if (TERM_EXPECT(ch < 0x20 || ch == 0x7f, 0)) { + if (t->state == ST_GROUND) { + term_text_utf8_interrupt(t); + if (ch == 0x7f || ((1u << ch) & 0x0800FF80u) == 0) + continue; - if (TERM_EXPECT(ch >= 0x80 && t->state == ST_GROUND && - t->utf8_state == UTF8_ACCEPT && !t->graphics, 1)) { - if (!t->insert_mode && !t->lr_margin_mode && - try_text_run(t, buf, len, &i)) + switch (ch) { + case '\n': + case 0x0b: + case 0x0c: { + size_t end = i + 1 + scan_byte_run(buf + i + 1, len - i - 1, '\n'); + if (term_lnm(t)) sc_cr(t); + sc_linefeed(t, end - i); + i = end - 1; + continue; + } + case '\r': + if (i + 1 < len && buf[i + 1] == '\n') { + size_t end = i + 2 + scan_crlf_pairs(buf + i + 2, len - i - 2); + sc_cr(t); + sc_linefeed(t, (end - i) / 2); + i = end - 1; + } else { + sc_cr(t); + } + continue; + case 0x1b: + if (t->utf8_state == UTF8_ACCEPT && i + 1 < len && + buf[i + 1] == '[' && !t->insert_mode && + !t->lr_margin_mode && !t->graphics) { + int fast = term_try_fast_csi(t, buf + i + 2, len - i - 2); + if (fast > 0) { + cur_flags = term_current_flags(t); + i += 1 + (size_t)fast; + continue; + } + t->state = ST_CSI; + csi_parser_reset(&t->csi_parser); + i += 1 + term_escape_csi(t, buf + i + 2, len - i - 2); + cur_flags = term_current_flags(t); + continue; + } + term_text_ground(t, ch); + cur_flags = term_current_flags(t); + continue; + default: + term_text_ground(t, ch); + cur_flags = term_current_flags(t); + continue; + } + } else { + term_escape_byte(t, ch); + cur_flags = term_current_flags(t); continue; - uint32_t cp; - int cp_len = decode_ground_utf8(t, buf + i, len - i, &cp); - if (cp) - emit_decoded(t, cp); - i += (size_t)(cp_len - 1); - continue; + } } if (TERM_EXPECT(t->state == ST_GROUND, 1)) term_text_ground(t, ch); else term_escape_byte(t, ch); + cur_flags = term_current_flags(t); } } -- cgit v1.2.3