# HG changeset patch # User Christian Brabandt # Date 1708979403 -3600 # Node ID 89f9a7925fff3e263a3f301b544ed78f012f52fc # Parent f7438681c79b8cc5cc3537df580507d54ed5617f patch 9.1.0138: too many STRLEN calls when getting a memline Commit: https://github.com/vim/vim/commit/02d7a6c6cfceb3faf9c98fcb7c458760cd50d269 Author: John Marriott Date: Mon Feb 26 21:21:17 2024 +0100 patch 9.1.0138: too many STRLEN calls when getting a memline Problem: too many STRLEN calls when getting a memline Solution: Optimize calls to STRLEN(), add a few functions in memline.c that return the byte length instead of relying on STRLEN() (John Marriott) closes: #14052 Signed-off-by: John Marriott Signed-off-by: Christian Brabandt diff --git a/src/memline.c b/src/memline.c --- a/src/memline.c +++ b/src/memline.c @@ -1754,7 +1754,7 @@ ml_recover(int checkext) for (idx = 1; idx <= lnum; ++idx) { // Need to copy one line, fetching the other one may flush it. - p = vim_strsave(ml_get(idx)); + p = vim_strnsave(ml_get(idx), ml_get_len(idx)); i = STRCMP(p, ml_get(idx + lnum)); vim_free(p); if (i != 0) @@ -2675,6 +2675,37 @@ ml_get_cursor(void) curwin->w_cursor.col); } +// return length (excluding the NUL) of the given line + colnr_T +ml_get_len(linenr_T lnum) +{ + return ml_get_buf_len(curbuf, lnum); +} + +// return length (excluding the NUL) of the cursor line + colnr_T +ml_get_curline_len(void) +{ + return ml_get_buf_len(curbuf, curwin->w_cursor.lnum); +} + +// return length (excluding the NUL) of the cursor position + colnr_T +ml_get_cursor_len(void) +{ + return ml_get_buf_len(curbuf, curwin->w_cursor.lnum) - curwin->w_cursor.col; +} + +// return length (excluding the NUL) of the given line in the given buffer + colnr_T +ml_get_buf_len(buf_T *buf, linenr_T lnum) +{ + if (*ml_get_buf(buf, lnum, FALSE) == NUL) + return 0; + + return buf->b_ml.ml_line_len - 1; +} + /* * Return a pointer to a line in a specific buffer * @@ -2727,7 +2758,6 @@ errorret: if (buf->b_ml.ml_line_lnum != lnum || mf_dont_release) { unsigned start, end; - colnr_T len; int idx; ml_flush_line(buf); @@ -2763,10 +2793,9 @@ errorret: end = dp->db_txt_end; else end = ((dp->db_index[idx - 1]) & DB_INDEX_MASK); - len = end - start; buf->b_ml.ml_line_ptr = (char_u *)dp + start; - buf->b_ml.ml_line_len = len; + buf->b_ml.ml_line_len = end - start; buf->b_ml.ml_line_lnum = lnum; buf->b_ml.ml_flags &= ~(ML_LINE_DIRTY | ML_ALLOCATED); } @@ -3400,10 +3429,10 @@ ml_append_int( #ifdef FEAT_NETBEANS_INTG if (netbeans_active()) { - if (STRLEN(line) > 0) - netbeans_inserted(buf, lnum+1, (colnr_T)0, line, (int)STRLEN(line)); - netbeans_inserted(buf, lnum+1, (colnr_T)STRLEN(line), - (char_u *)"\n", 1); + int line_len = (int)STRLEN(line); + if (line_len > 0) + netbeans_inserted(buf, lnum+1, (colnr_T)0, line, line_len); + netbeans_inserted(buf, lnum+1, (colnr_T)line_len, (char_u *)"\n", 1); } #endif #ifdef FEAT_JOB_CHANNEL @@ -3571,7 +3600,7 @@ ml_replace_len( #ifdef FEAT_NETBEANS_INTG if (netbeans_active()) { - netbeans_removed(curbuf, lnum, 0, (long)STRLEN(ml_get(lnum))); + netbeans_removed(curbuf, lnum, 0, (long)ml_get_len(lnum)); netbeans_inserted(curbuf, lnum, 0, line, (int)STRLEN(line)); } #endif @@ -5192,15 +5221,15 @@ findswapname( { char_u *name; int dialog_result; + size_t len = STRLEN(_("Swap file \"")); name = alloc(STRLEN(fname) - + STRLEN(_("Swap file \"")) + + len + STRLEN(_("\" already exists!")) + 5); if (name != NULL) { STRCPY(name, _("Swap file \"")); - home_replace(NULL, fname, name + STRLEN(name), - 1000, TRUE); + home_replace(NULL, fname, name + len, 1000, TRUE); STRCAT(name, _("\" already exists!")); } dialog_result = do_dialog(VIM_WARNING, diff --git a/src/normal.c b/src/normal.c --- a/src/normal.c +++ b/src/normal.c @@ -3225,8 +3225,7 @@ nv_colon(cmdarg_T *cap) clearop(cap->oap); else if (cap->oap->op_type != OP_NOP && (cap->oap->start.lnum > curbuf->b_ml.ml_line_count - || cap->oap->start.col > - (colnr_T)STRLEN(ml_get(cap->oap->start.lnum)) + || cap->oap->start.col > ml_get_len(cap->oap->start.lnum) || did_emsg )) // The start of the operator has become invalid by the Ex command. @@ -3675,7 +3674,7 @@ get_visual_text( if (VIsual_mode == 'V') { *pp = ml_get_curline(); - *lenp = (int)STRLEN(*pp); + *lenp = (int)ml_get_curline_len(); } else { @@ -4768,7 +4767,6 @@ nv_kundo(cmdarg_T *cap) static void nv_replace(cmdarg_T *cap) { - char_u *ptr; int had_ctrl_v; long n; @@ -4835,9 +4833,8 @@ nv_replace(cmdarg_T *cap) } // Abort if not enough characters to replace. - ptr = ml_get_cursor(); - if (STRLEN(ptr) < (unsigned)cap->count1 - || (has_mbyte && mb_charlen(ptr) < cap->count1)) + if ((size_t)ml_get_cursor_len() < (unsigned)cap->count1 + || (has_mbyte && mb_charlen(ml_get_cursor()) < cap->count1)) { clearopbeep(cap->oap); return; @@ -4917,11 +4914,13 @@ nv_replace(cmdarg_T *cap) } else { + char_u *ptr; + // Replace the characters within one line. for (n = cap->count1; n > 0; --n) { - // Get ptr again, because u_save and/or showmatch() will have - // released the line. This may also happen in ins_copychar(). + // Get ptr again, because ins_copychar() and showmatch() + // will have released the line. // At the same time we let know that the line will be changed. if (cap->nchar == Ctrl_E || cap->nchar == Ctrl_Y) { @@ -4945,6 +4944,7 @@ nv_replace(cmdarg_T *cap) if (netbeans_active()) { colnr_T start = (colnr_T)(curwin->w_cursor.col - cap->count1); + ptr = ml_get_curline(); netbeans_removed(curbuf, curwin->w_cursor.lnum, start, cap->count1); @@ -5130,7 +5130,7 @@ n_swapchar(cmdarg_T *cap) if (did_change) { ptr = ml_get(pos.lnum); - count = (int)STRLEN(ptr) - pos.col; + count = (int)ml_get_len(pos.lnum) - pos.col; netbeans_removed(curbuf, pos.lnum, pos.col, (long)count); // line may have been flushed, get it again @@ -5919,7 +5919,7 @@ nv_gi_cmd(cmdarg_T *cap) { curwin->w_cursor = curbuf->b_last_insert; check_cursor_lnum(); - i = (int)STRLEN(ml_get_curline()); + i = (int)ml_get_curline_len(); if (curwin->w_cursor.col > (colnr_T)i) { if (virtual_active()) @@ -6717,7 +6717,7 @@ unadjust_for_sel(void) else if (pp->lnum > 1) { --pp->lnum; - pp->col = (colnr_T)STRLEN(ml_get(pp->lnum)); + pp->col = ml_get_len(pp->lnum); return TRUE; } } diff --git a/src/proto/memline.pro b/src/proto/memline.pro --- a/src/proto/memline.pro +++ b/src/proto/memline.pro @@ -19,6 +19,10 @@ char_u *ml_get(linenr_T lnum); char_u *ml_get_pos(pos_T *pos); char_u *ml_get_curline(void); char_u *ml_get_cursor(void); +colnr_T ml_get_len(linenr_T lnum); +colnr_T ml_get_curline_len(void); +colnr_T ml_get_cursor_len(void); +colnr_T ml_get_buf_len(buf_T *buf, linenr_T lnum); char_u *ml_get_buf(buf_T *buf, linenr_T lnum, int will_change); int ml_line_alloced(void); int ml_append(linenr_T lnum, char_u *line, colnr_T len, int newfile); diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -705,6 +705,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 138, +/**/ 137, /**/ 136,