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().
This commit is contained in:
Benno Schulenberg 2021-04-08 11:44:48 +02:00
parent debb288115
commit 31a6931be9
1 changed files with 13 additions and 5 deletions

View File

@ -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. */