comparison src/quickfix.c @ 30829:d7066cbac096 v9.0.0749

patch 9.0.0749: alloc/free of buffer for each quickfix entry is inefficient Commit: https://github.com/vim/vim/commit/975a665d4811649a51e2c6a97a6ce096290d87ae Author: Yegappan Lakshmanan <yegappan@yahoo.com> Date: Fri Oct 14 13:11:13 2022 +0100 patch 9.0.0749: alloc/free of buffer for each quickfix entry is inefficient Problem: Alloc/free of buffer for each quickfix entry is inefficient. Solution: Use a shared grow array. (Yegappan Lakshmanan, closes https://github.com/vim/vim/issues/11365)
author Bram Moolenaar <Bram@vim.org>
date Fri, 14 Oct 2022 14:15:03 +0200
parents bba8d0f45cb8
children 86683574317a
comparison
equal deleted inserted replaced
30828:0f439fcdfa1a 30829:d7066cbac096
216 * Looking up a buffer can be slow if there are many. Remember the last one 216 * Looking up a buffer can be slow if there are many. Remember the last one
217 * to make this a lot faster if there are multiple matches in the same file. 217 * to make this a lot faster if there are multiple matches in the same file.
218 */ 218 */
219 static char_u *qf_last_bufname = NULL; 219 static char_u *qf_last_bufname = NULL;
220 static bufref_T qf_last_bufref = {NULL, 0, 0}; 220 static bufref_T qf_last_bufref = {NULL, 0, 0};
221
222 static garray_T qfga;
223
224 /*
225 * Get a growarray to buffer text in. Shared between various commands to avoid
226 * many alloc/free calls.
227 */
228 static garray_T *
229 qfga_get(void)
230 {
231 static int initialized = FALSE;
232
233 if (!initialized)
234 {
235 initialized = TRUE;
236 ga_init2(&qfga, 1, 256);
237 }
238
239 // Retain ga_data from previous use. Reset the length to zero.
240 qfga.ga_len = 0;
241
242 return &qfga;
243 }
221 244
222 /* 245 /*
223 * Maximum number of bytes allowed per line while reading a errorfile. 246 * Maximum number of bytes allowed per line while reading a errorfile.
224 */ 247 */
225 #define LINE_MAXLEN 4096 248 #define LINE_MAXLEN 4096
3284 qfline_T *qf_ptr, 3307 qfline_T *qf_ptr,
3285 buf_T *old_curbuf, 3308 buf_T *old_curbuf,
3286 linenr_T old_lnum) 3309 linenr_T old_lnum)
3287 { 3310 {
3288 linenr_T i; 3311 linenr_T i;
3289 garray_T ga; 3312 garray_T *gap;
3313
3314 gap = qfga_get();
3290 3315
3291 // Update the screen before showing the message, unless the screen 3316 // Update the screen before showing the message, unless the screen
3292 // scrolled up. 3317 // scrolled up.
3293 if (!msg_scrolled) 3318 if (!msg_scrolled)
3294 update_topline_redraw(); 3319 update_topline_redraw();
3295 vim_snprintf((char *)IObuff, IOSIZE, _("(%d of %d)%s%s: "), qf_index, 3320 vim_snprintf((char *)IObuff, IOSIZE, _("(%d of %d)%s%s: "), qf_index,
3296 qf_get_curlist(qi)->qf_count, 3321 qf_get_curlist(qi)->qf_count,
3297 qf_ptr->qf_cleared ? _(" (line deleted)") : "", 3322 qf_ptr->qf_cleared ? _(" (line deleted)") : "",
3298 (char *)qf_types(qf_ptr->qf_type, qf_ptr->qf_nr)); 3323 (char *)qf_types(qf_ptr->qf_type, qf_ptr->qf_nr));
3299 // Add the message, skipping leading whitespace and newlines. 3324 // Add the message, skipping leading whitespace and newlines.
3300 ga_init2(&ga, 1, 256); 3325 ga_concat(gap, IObuff);
3301 ga_concat(&ga, IObuff); 3326 qf_fmt_text(gap, skipwhite(qf_ptr->qf_text));
3302 qf_fmt_text(&ga, skipwhite(qf_ptr->qf_text));
3303 3327
3304 // Output the message. Overwrite to avoid scrolling when the 'O' 3328 // Output the message. Overwrite to avoid scrolling when the 'O'
3305 // flag is present in 'shortmess'; But when not jumping, print the 3329 // flag is present in 'shortmess'; But when not jumping, print the
3306 // whole message. 3330 // whole message.
3307 i = msg_scroll; 3331 i = msg_scroll;
3308 if (curbuf == old_curbuf && curwin->w_cursor.lnum == old_lnum) 3332 if (curbuf == old_curbuf && curwin->w_cursor.lnum == old_lnum)
3309 msg_scroll = TRUE; 3333 msg_scroll = TRUE;
3310 else if (!msg_scrolled && shortmess(SHM_OVERALL)) 3334 else if (!msg_scrolled && shortmess(SHM_OVERALL))
3311 msg_scroll = FALSE; 3335 msg_scroll = FALSE;
3312 msg_attr_keep((char *)ga.ga_data, 0, TRUE); 3336 msg_attr_keep((char *)gap->ga_data, 0, TRUE);
3313 msg_scroll = i; 3337 msg_scroll = i;
3314 ga_clear(&ga);
3315 } 3338 }
3316 3339
3317 /* 3340 /*
3318 * Find a usable window for opening a file from the quickfix/location list. If 3341 * Find a usable window for opening a file from the quickfix/location list. If
3319 * a window is not found then open a new window. If 'newwin' is TRUE, then open 3342 * a window is not found then open a new window. If 'newwin' is TRUE, then open
3574 qf_list_entry(qfline_T *qfp, int qf_idx, int cursel) 3597 qf_list_entry(qfline_T *qfp, int qf_idx, int cursel)
3575 { 3598 {
3576 char_u *fname; 3599 char_u *fname;
3577 buf_T *buf; 3600 buf_T *buf;
3578 int filter_entry; 3601 int filter_entry;
3579 garray_T ga; 3602 garray_T *gap;
3580 3603
3581 fname = NULL; 3604 fname = NULL;
3582 if (qfp->qf_module != NULL && *qfp->qf_module != NUL) 3605 if (qfp->qf_module != NULL && *qfp->qf_module != NUL)
3583 vim_snprintf((char *)IObuff, IOSIZE, "%2d %s", qf_idx, 3606 vim_snprintf((char *)IObuff, IOSIZE, "%2d %s", qf_idx,
3584 (char *)qfp->qf_module); 3607 (char *)qfp->qf_module);
3615 msg_putchar('\n'); 3638 msg_putchar('\n');
3616 msg_outtrans_attr(IObuff, cursel ? HL_ATTR(HLF_QFL) : qfFileAttr); 3639 msg_outtrans_attr(IObuff, cursel ? HL_ATTR(HLF_QFL) : qfFileAttr);
3617 3640
3618 if (qfp->qf_lnum != 0) 3641 if (qfp->qf_lnum != 0)
3619 msg_puts_attr(":", qfSepAttr); 3642 msg_puts_attr(":", qfSepAttr);
3620 ga_init2(&ga, 1, 256); 3643 gap = qfga_get();
3621 if (qfp->qf_lnum == 0) 3644 if (qfp->qf_lnum == 0)
3622 ga_append(&ga, NUL); 3645 ga_append(gap, NUL);
3623 else 3646 else
3624 qf_range_text(&ga, qfp); 3647 qf_range_text(gap, qfp);
3625 ga_concat(&ga, qf_types(qfp->qf_type, qfp->qf_nr)); 3648 ga_concat(gap, qf_types(qfp->qf_type, qfp->qf_nr));
3626 ga_append(&ga, NUL); 3649 ga_append(gap, NUL);
3627 msg_puts_attr((char *)ga.ga_data, qfLineAttr); 3650 msg_puts_attr((char *)gap->ga_data, qfLineAttr);
3628 ga_clear(&ga);
3629 msg_puts_attr(":", qfSepAttr); 3651 msg_puts_attr(":", qfSepAttr);
3630 if (qfp->qf_pattern != NULL) 3652 if (qfp->qf_pattern != NULL)
3631 { 3653 {
3632 qf_fmt_text(&ga, qfp->qf_pattern); 3654 gap = qfga_get();
3633 msg_puts((char *)ga.ga_data); 3655 qf_fmt_text(gap, qfp->qf_pattern);
3634 ga_clear(&ga); 3656 msg_puts((char *)gap->ga_data);
3635 msg_puts_attr(":", qfSepAttr); 3657 msg_puts_attr(":", qfSepAttr);
3636 } 3658 }
3637 msg_puts(" "); 3659 msg_puts(" ");
3638 3660
3639 { 3661 // Remove newlines and leading whitespace from the text. For an
3640 // Remove newlines and leading whitespace from the text. For an 3662 // unrecognized line keep the indent, the compiler may mark a word
3641 // unrecognized line keep the indent, the compiler may mark a word 3663 // with ^^^^.
3642 // with ^^^^. 3664 gap = qfga_get();
3643 qf_fmt_text(&ga, (fname != NULL || qfp->qf_lnum != 0) 3665 qf_fmt_text(gap, (fname != NULL || qfp->qf_lnum != 0)
3644 ? skipwhite(qfp->qf_text) : qfp->qf_text); 3666 ? skipwhite(qfp->qf_text) : qfp->qf_text);
3645 msg_prt_line((char_u *)ga.ga_data, FALSE); 3667 msg_prt_line((char_u *)gap->ga_data, FALSE);
3646 ga_clear(&ga);
3647 }
3648 out_flush(); // show one line at a time 3668 out_flush(); // show one line at a time
3649 } 3669 }
3650 3670
3651 /* 3671 /*
3652 * ":clist": list all errors 3672 * ":clist": list all errors
4591 char_u *dirname, 4611 char_u *dirname,
4592 int first_bufline, 4612 int first_bufline,
4593 char_u *qftf_str) 4613 char_u *qftf_str)
4594 { 4614 {
4595 buf_T *errbuf; 4615 buf_T *errbuf;
4596 garray_T ga; 4616 garray_T *gap;
4597 4617
4598 ga_init2(&ga, 1, 256); 4618 gap = qfga_get();
4599 4619
4600 // If the 'quickfixtextfunc' function returned a non-empty custom string 4620 // If the 'quickfixtextfunc' function returned a non-empty custom string
4601 // for this entry, then use it. 4621 // for this entry, then use it.
4602 if (qftf_str != NULL && *qftf_str != NUL) 4622 if (qftf_str != NULL && *qftf_str != NUL)
4603 ga_concat(&ga, qftf_str); 4623 ga_concat(gap, qftf_str);
4604 else 4624 else
4605 { 4625 {
4606 if (qfp->qf_module != NULL) 4626 if (qfp->qf_module != NULL)
4607 ga_concat(&ga, qfp->qf_module); 4627 ga_concat(gap, qfp->qf_module);
4608 else if (qfp->qf_fnum != 0 4628 else if (qfp->qf_fnum != 0
4609 && (errbuf = buflist_findnr(qfp->qf_fnum)) != NULL 4629 && (errbuf = buflist_findnr(qfp->qf_fnum)) != NULL
4610 && errbuf->b_fname != NULL) 4630 && errbuf->b_fname != NULL)
4611 { 4631 {
4612 if (qfp->qf_type == 1) // :helpgrep 4632 if (qfp->qf_type == 1) // :helpgrep
4613 ga_concat(&ga, gettail(errbuf->b_fname)); 4633 ga_concat(gap, gettail(errbuf->b_fname));
4614 else 4634 else
4615 { 4635 {
4616 // Shorten the file name if not done already. 4636 // Shorten the file name if not done already.
4617 // For optimization, do this only for the first entry in a 4637 // For optimization, do this only for the first entry in a
4618 // buffer. 4638 // buffer.
4621 { 4641 {
4622 if (*dirname == NUL) 4642 if (*dirname == NUL)
4623 mch_dirname(dirname, MAXPATHL); 4643 mch_dirname(dirname, MAXPATHL);
4624 shorten_buf_fname(errbuf, dirname, FALSE); 4644 shorten_buf_fname(errbuf, dirname, FALSE);
4625 } 4645 }
4626 ga_concat(&ga, errbuf->b_fname); 4646 ga_concat(gap, errbuf->b_fname);
4627 } 4647 }
4628 } 4648 }
4629 4649
4630 ga_append(&ga, '|'); 4650 ga_append(gap, '|');
4631 4651
4632 if (qfp->qf_lnum > 0) 4652 if (qfp->qf_lnum > 0)
4633 { 4653 {
4634 qf_range_text(&ga, qfp); 4654 qf_range_text(gap, qfp);
4635 ga_concat(&ga, qf_types(qfp->qf_type, qfp->qf_nr)); 4655 ga_concat(gap, qf_types(qfp->qf_type, qfp->qf_nr));
4636 } 4656 }
4637 else if (qfp->qf_pattern != NULL) 4657 else if (qfp->qf_pattern != NULL)
4638 qf_fmt_text(&ga, qfp->qf_pattern); 4658 qf_fmt_text(gap, qfp->qf_pattern);
4639 ga_append(&ga, '|'); 4659 ga_append(gap, '|');
4640 ga_append(&ga, ' '); 4660 ga_append(gap, ' ');
4641 4661
4642 // Remove newlines and leading whitespace from the text. 4662 // Remove newlines and leading whitespace from the text.
4643 // For an unrecognized line keep the indent, the compiler may 4663 // For an unrecognized line keep the indent, the compiler may
4644 // mark a word with ^^^^. 4664 // mark a word with ^^^^.
4645 qf_fmt_text(&ga, ga.ga_len > 3 ? skipwhite(qfp->qf_text) : qfp->qf_text); 4665 qf_fmt_text(gap, gap->ga_len > 3 ? skipwhite(qfp->qf_text) : qfp->qf_text);
4646 } 4666 }
4647 4667
4648 ga_append(&ga, NUL); 4668 ga_append(gap, NUL);
4649 4669
4650 if (ml_append_buf(buf, lnum, ga.ga_data, ga.ga_len + 1, FALSE) == FAIL) 4670 if (ml_append_buf(buf, lnum, gap->ga_data, gap->ga_len + 1, FALSE) == FAIL)
4651 return FAIL; 4671 return FAIL;
4652
4653 ga_clear(&ga);
4654 4672
4655 return OK; 4673 return OK;
4656 } 4674 }
4657 4675
4658 /* 4676 /*
8374 // current window didn't have a location list associated with it 8392 // current window didn't have a location list associated with it
8375 // before. Associate the new location list now. 8393 // before. Associate the new location list now.
8376 curwin->w_llist = qi; 8394 curwin->w_llist = qi;
8377 } 8395 }
8378 } 8396 }
8397
8398 # if defined(EXITFREE) || defined(PROTO)
8399 void
8400 free_quickfix()
8401 {
8402 win_T *win;
8403 tabpage_T *tab;
8404
8405 qf_free_all(NULL);
8406 // Free all location lists
8407 FOR_ALL_TAB_WINDOWS(tab, win)
8408 qf_free_all(win);
8409
8410 ga_clear(&qfga);
8411 }
8412 # endif
8413
8379 #endif // FEAT_QUICKFIX 8414 #endif // FEAT_QUICKFIX
8380 8415
8381 #if defined(FEAT_EVAL) || defined(PROTO) 8416 #if defined(FEAT_EVAL) || defined(PROTO)
8382 # ifdef FEAT_QUICKFIX 8417 # ifdef FEAT_QUICKFIX
8383 static void 8418 static void