nano

nano with my custom patches
git clone git://bsandro.tech/nano
Log | Files | Refs | README | LICENSE

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:
Msrc/winio.c | 18+++++++++++++-----
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. */