Mercurial > vim
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 |