From d88bea5e22330c36c241ae0d441279799ac5897f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Fri, 16 Jun 2023 16:26:13 +0200 Subject: [PATCH] vt: split up action_param() to three separate functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We’re already switching on the next VT input byte in the state machine; no need to if...else if in action_param() too. That is, split up action_param() into three: * action_param_new() * action_param_new_subparam() * action_param() This makes the code cleaner, and hopefully slightly faster. Next, to improve performance further, only check for (sub)parameter overflow in action_param_new() and action_param_subparam(). Add pointers to the VT struct that points to the currently active parameter and sub-parameter. When the number of parameters (or sub-parameters) overflow, warn, and then point the parameter pointer to a "dummy" value in the VT struct. This way, we don’t have to check anything in action_param(). --- terminal.h | 8 +++- vt.c | 135 +++++++++++++++++++++++++++-------------------------- 2 files changed, 75 insertions(+), 68 deletions(-) diff --git a/terminal.h b/terminal.h index d2762a5a..abedf44d 100644 --- a/terminal.h +++ b/terminal.h @@ -180,8 +180,10 @@ struct grid { }; struct vt_subparams { - unsigned value[16]; uint8_t idx; + unsigned *cur; + unsigned value[16]; + unsigned dummy; }; struct vt_param { @@ -197,8 +199,10 @@ struct vt { #endif char32_t utf8; struct { - struct vt_param v[16]; uint8_t idx; + struct vt_param *cur; + struct vt_param v[16]; + struct vt_param dummy; } params; uint32_t private; /* LSB=priv0, MSB=priv3 */ diff --git a/vt.c b/vt.c index 91f00e6f..2ee2dbaf 100644 --- a/vt.c +++ b/vt.c @@ -294,74 +294,31 @@ action_print(struct terminal *term, uint8_t c) } static void -action_param(struct terminal *term, uint8_t c) +action_param_lazy_init(struct terminal *term) { if (term->vt.params.idx == 0) { struct vt_param *param = &term->vt.params.v[0]; + + term->vt.params.cur = param; param->value = 0; param->sub.idx = 0; + param->sub.cur = NULL; term->vt.params.idx = 1; } +} - xassert(term->vt.params.idx > 0); +static void +action_param_new(struct terminal *term, uint8_t c) +{ + xassert(c == ';'); + action_param_lazy_init(term); const size_t max_params = sizeof(term->vt.params.v) / sizeof(term->vt.params.v[0]); - const size_t max_sub_params - = sizeof(term->vt.params.v[0].sub.value) / sizeof(term->vt.params.v[0].sub.value[0]); - /* New parameter */ - if (c == ';') { - if (unlikely(term->vt.params.idx >= max_params)) - goto excess_params; + struct vt_param *param; - struct vt_param *param = &term->vt.params.v[term->vt.params.idx++]; - param->value = 0; - param->sub.idx = 0; - } - - /* New sub-parameter */ - else if (c == ':') { - if (unlikely(term->vt.params.idx - 1 >= max_params)) - goto excess_params; - - struct vt_param *param = &term->vt.params.v[term->vt.params.idx - 1]; - if (unlikely(param->sub.idx >= max_sub_params)) - goto excess_sub_params; - - param->sub.value[param->sub.idx++] = 0; - } - - /* New digit for current parameter/sub-parameter */ - else { - if (unlikely(term->vt.params.idx - 1 >= max_params)) - goto excess_params; - - struct vt_param *param = &term->vt.params.v[term->vt.params.idx - 1]; - unsigned *value; - - if (param->sub.idx > 0) { - if (unlikely(param->sub.idx - 1 >= max_sub_params)) - goto excess_sub_params; - value = ¶m->sub.value[param->sub.idx - 1]; - } else - value = ¶m->value; - - *value *= 10; - *value += c - '0'; - } - -#if defined(_DEBUG) - /* The rest of the code assumes 'idx' *never* points outside the array */ - xassert(term->vt.params.idx <= max_params); - for (size_t i = 0; i < term->vt.params.idx; i++) - xassert(term->vt.params.v[i].sub.idx <= max_sub_params); -#endif - - return; - -excess_params: - { + if (unlikely(term->vt.params.idx >= max_params)) { static bool have_warned = false; if (!have_warned) { have_warned = true; @@ -370,11 +327,29 @@ excess_params: "(will not warn again)", sizeof(term->vt.params.v) / sizeof(term->vt.params.v[0])); } - } - return; + param = &term->vt.params.dummy; + } else + param = &term->vt.params.v[term->vt.params.idx++]; -excess_sub_params: - { + term->vt.params.cur = param; + param->value = 0; + param->sub.idx = 0; + param->sub.cur = NULL; +} + +static void +action_param_new_subparam(struct terminal *term, uint8_t c) +{ + xassert(c == ':'); + action_param_lazy_init(term); + + const size_t max_sub_params + = sizeof(term->vt.params.v[0].sub.value) / sizeof(term->vt.params.v[0].sub.value[0]); + + struct vt_param *param = term->vt.params.cur; + unsigned *sub_param_value; + + if (unlikely(param->sub.idx >= max_sub_params)) { static bool have_warned = false; if (!have_warned) { have_warned = true; @@ -383,8 +358,33 @@ excess_sub_params: "(will not warn again)", sizeof(term->vt.params.v[0].sub.value) / sizeof(term->vt.params.v[0].sub.value[0])); } - } - return; + + sub_param_value = ¶m->sub.dummy; + } else + sub_param_value = ¶m->sub.value[param->sub.idx++]; + + param->sub.cur = sub_param_value; + *sub_param_value = 0; +} + +static void +action_param(struct terminal *term, uint8_t c) +{ + action_param_lazy_init(term); + xassert(term->vt.params.cur != NULL); + + struct vt_param *param = term->vt.params.cur; + unsigned *value; + + if (unlikely(param->sub.cur != NULL)) + value = param->sub.cur; + else + value = ¶m->value; + + unsigned v = *value; + v *= 10; + v += c - '0'; + *value = v; } static void @@ -1024,7 +1024,9 @@ state_csi_entry_switch(struct terminal *term, uint8_t data) case 0x20 ... 0x2f: action_collect(term, data); return STATE_CSI_INTERMEDIATE; case 0x30 ... 0x39: action_param(term, data); return STATE_CSI_PARAM; - case 0x3a ... 0x3b: action_param(term, data); return STATE_CSI_PARAM; + case 0x3a: action_param_new_subparam(term, data); return STATE_CSI_PARAM; + case 0x3b: action_param_new(term, data); return STATE_CSI_PARAM; + case 0x3c ... 0x3f: action_collect(term, data); return STATE_CSI_PARAM; case 0x40 ... 0x7e: action_csi_dispatch(term, data); return STATE_GROUND; case 0x7f: action_ignore(term); return STATE_CSI_ENTRY; @@ -1044,8 +1046,9 @@ state_csi_param_switch(struct terminal *term, uint8_t data) case 0x20 ... 0x2f: action_collect(term, data); return STATE_CSI_INTERMEDIATE; - case 0x30 ... 0x39: - case 0x3a ... 0x3b: action_param(term, data); return STATE_CSI_PARAM; + case 0x30 ... 0x39: action_param(term, data); return STATE_CSI_PARAM; + case 0x3a: action_param_new_subparam(term, data); return STATE_CSI_PARAM; + case 0x3b: action_param_new(term, data); return STATE_CSI_PARAM; case 0x3c ... 0x3f: return STATE_CSI_IGNORE; case 0x40 ... 0x7e: action_csi_dispatch(term, data); return STATE_GROUND; @@ -1126,7 +1129,7 @@ state_dcs_entry_switch(struct terminal *term, uint8_t data) case 0x20 ... 0x2f: action_collect(term, data); return STATE_DCS_INTERMEDIATE; case 0x30 ... 0x39: action_param(term, data); return STATE_DCS_PARAM; case 0x3a: return STATE_DCS_IGNORE; - case 0x3b: action_param(term, data); return STATE_DCS_PARAM; + case 0x3b: action_param_new(term, data); return STATE_DCS_PARAM; case 0x3c ... 0x3f: action_collect(term, data); return STATE_DCS_PARAM; case 0x40 ... 0x7e: action_hook(term, data); return STATE_DCS_PASSTHROUGH; case 0x7f: action_ignore(term); return STATE_DCS_ENTRY; @@ -1147,7 +1150,7 @@ state_dcs_param_switch(struct terminal *term, uint8_t data) case 0x20 ... 0x2f: action_collect(term, data); return STATE_DCS_INTERMEDIATE; case 0x30 ... 0x39: action_param(term, data); return STATE_DCS_PARAM; case 0x3a: return STATE_DCS_IGNORE; - case 0x3b: action_param(term, data); return STATE_DCS_PARAM; + case 0x3b: action_param_new(term, data); return STATE_DCS_PARAM; case 0x3c ... 0x3f: return STATE_DCS_IGNORE; case 0x40 ... 0x7e: action_hook(term, data); return STATE_DCS_PASSTHROUGH; case 0x7f: action_ignore(term); return STATE_DCS_PARAM;