commit 31a6931be9e7a00bc94fb8582ef65c3ecb9f9fca
parent debb288115ed22897c31eb78a1d5326647773678
Author: Benno Schulenberg <bensberg@telfort.nl>
Date: Thu, 8 Apr 2021 11:44:48 +0200
tweaks: elide a call of strlen() for every row
For a normal file (without overlong lines) the strlen() wasn't much
of a problem. But when there are very long lines, it wasted time
counting stuff that wouldn't be displayed on the current row anyway,
and reserved *far* too much memory for the displayable string.
Problem existed since commit cf0eed6c from five years ago that traded
a continuous comparison (of the used space with the reserved space)
against a one-time big reservation up front involving a strlen().
In retrospect that was not a good trade-off when softwrapping.
The extra check (charwidth == 0) is incurred only by characters that
have their high bit set, so the average file (with only ASCII) is not
affected by this -- it just loses an unneeded call of strlen().
Diffstat:
1 file changed, 13 insertions(+), 5 deletions(-)
diff --git a/src/winio.c b/src/winio.c
@@ -1717,8 +1717,12 @@ char *display_string(const char *text, size_t column, size_t span,
/* The index of the first character that the caller wishes to show. */
size_t start_col = wideness(text, start_index);
/* The actual column where that first character starts. */
- char *converted;
- /* The expanded string we will return. */
+ size_t stowaways = 20;
+ /* The number of zero-width characters for which to reserve space. */
+ size_t allocsize = (COLS + stowaways) * MAXCHARLEN + 1;
+ /* The amount of memory to reserve for the displayable string. */
+ char *converted = nmalloc(allocsize);
+ /* The displayable string we will return. */
size_t index = 0;
/* Current position in converted. */
size_t beyond = column + span;
@@ -1726,9 +1730,6 @@ char *display_string(const char *text, size_t column, size_t span,
text += start_index;
- /* Allocate enough space for converting the relevant part of the line. */
- converted = nmalloc(strlen(text) * (MAXCHARLEN + tabsize) + 1);
-
#ifndef NANO_TINY
if (span > HIGHEST_POSITIVE) {
statusline(ALERT, "Span has underflowed -- please report a bug");
@@ -1842,6 +1843,13 @@ char *display_string(const char *text, size_t column, size_t span,
/* Determine whether the character takes zero, one, or two columns. */
charwidth = wcwidth(wc);
+ /* Watch the number of zero-widths, to keep ample memory reserved. */
+ if (charwidth == 0 && --stowaways == 0) {
+ stowaways = 40;
+ allocsize += stowaways * MAXCHARLEN;
+ converted = nrealloc(converted, allocsize);
+ }
+
#ifdef __linux__
/* On a Linux console, skip zero-width characters, as it would show
* them WITH a width, thus messing up the display. See bug #52954. */