diff options
author | Marco Hinz <mh.codebro@gmail.com> | 2017-01-09 02:03:03 +0100 |
---|---|---|
committer | James McCoy <jamessan@jamessan.com> | 2017-02-04 17:55:29 -0500 |
commit | e177226d51feb99e159773eebe6a773732fc89e9 (patch) | |
tree | dece7dd4cbc637b940393e19d5e117b323594a5c /src/nvim/buffer.c | |
parent | 951dd1571cbb57b41274c0e515e2b3c789305bad (diff) | |
download | rneovim-e177226d51feb99e159773eebe6a773732fc89e9.tar.gz rneovim-e177226d51feb99e159773eebe6a773732fc89e9.tar.bz2 rneovim-e177226d51feb99e159773eebe6a773732fc89e9.zip |
vim-patch:7.4.2018
Problem: buf_valid() can be slow when there are many buffers.
Solution: Add bufref_valid(), only go through the buffer list
when a buffer was freed.
https://github.com/vim/vim/commit/b25f9a97e9aad3cbb4bc3fe87cdbd5700f8aa0c6
Diffstat (limited to 'src/nvim/buffer.c')
-rw-r--r-- | src/nvim/buffer.c | 154 |
1 files changed, 107 insertions, 47 deletions
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 53fb43f549..3b18bf5366 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -78,6 +78,9 @@ static char *msg_loclist = N_("[Location List]"); static char *msg_qflist = N_("[Quickfix List]"); static char *e_auabort = N_("E855: Autocommands caused command to abort"); +// Number of times free_buffer() was called. +static int buf_free_count = 0; + /* * Open current buffer, that is: open the memfile and read the file into * memory. @@ -267,7 +270,31 @@ open_buffer ( return retval; } -/// Check that "buf" points to a valid buffer (in the buffer list). +/// Store "buf" in "bufref" and set the free count. +/// +/// @param bufref Reference to be used for the buffer. +/// @param buf The buffer to reference. +void set_bufref(bufref_T *bufref, buf_T *buf) { + bufref->br_buf = buf; + bufref->br_buf_free_count = buf_free_count; +} + +/// Check if "bufref" points to a valid buffer. +/// +/// Only goes through the buffer list if buf_free_count changed. +/// +/// @param bufref Buffer reference to check for. +bool bufref_valid(bufref_T *bufref) { + return bufref->br_buf_free_count == buf_free_count + ? true + : buf_valid(bufref->br_buf); +} + +/// Check that "buf" points to a valid buffer in the buffer list. +/// +/// Can be slow if there are many buffers, prefer using bufref_valid(). +/// +/// @param buf The buffer to check for. bool buf_valid(buf_T *buf) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { @@ -365,11 +392,14 @@ void close_buffer(win_T *win, buf_T *buf, int action, int abort_if_last) win->w_cursor.col, TRUE); } + bufref_T bufref; + set_bufref(&bufref, buf); + /* When the buffer is no longer in a window, trigger BufWinLeave */ if (buf->b_nwindows == 1) { buf->b_closing = true; if (apply_autocmds(EVENT_BUFWINLEAVE, buf->b_fname, buf->b_fname, false, - buf) && !buf_valid(buf)) { + buf) && !bufref_valid(&bufref)) { // Autocommands deleted the buffer. EMSG(_(e_auabort)); return; @@ -386,7 +416,7 @@ void close_buffer(win_T *win, buf_T *buf, int action, int abort_if_last) if (!unload_buf) { buf->b_closing = true; if (apply_autocmds(EVENT_BUFHIDDEN, buf->b_fname, buf->b_fname, false, - buf) && !buf_valid(buf)) { + buf) && !bufref_valid(&bufref)) { // Autocommands deleted the buffer. EMSG(_(e_auabort)); return; @@ -431,11 +461,14 @@ void close_buffer(win_T *win, buf_T *buf, int action, int abort_if_last) buf_freeall(buf, (del_buf ? BFA_DEL : 0) + (wipe_buf ? BFA_WIPE : 0)); - /* Autocommands may have deleted the buffer. */ - if (!buf_valid(buf)) + if (!bufref_valid(&bufref)) { + // Autocommands may have deleted the buffer. return; - if (aborting()) /* autocmds may abort script processing */ + } + if (aborting()) { + // Autocmds may abort script processing. return; + } /* * It's possible that autocommands change curbuf to the one being deleted. @@ -535,23 +568,27 @@ void buf_freeall(buf_T *buf, int flags) // Make sure the buffer isn't closed by autocommands. buf->b_closing = true; + + bufref_T bufref; + set_bufref(&bufref, buf); + if ((buf->b_ml.ml_mfp != NULL) && apply_autocmds(EVENT_BUFUNLOAD, buf->b_fname, buf->b_fname, false, buf) - && !buf_valid(buf)) { - // Autocommands may delete the buffer. + && !bufref_valid(&bufref)) { + // Autocommands deleted the buffer. return; } if ((flags & BFA_DEL) && buf->b_p_bl && apply_autocmds(EVENT_BUFDELETE, buf->b_fname, buf->b_fname, false, buf) - && !buf_valid(buf)) { + && !bufref_valid(&bufref)) { // Autocommands may delete the buffer. return; } if ((flags & BFA_WIPE) && apply_autocmds(EVENT_BUFWIPEOUT, buf->b_fname, buf->b_fname, false, buf) - && !buf_valid(buf)) { + && !bufref_valid(&bufref)) { // Autocommands may delete the buffer. return; } @@ -606,7 +643,8 @@ void buf_freeall(buf_T *buf, int flags) static void free_buffer(buf_T *buf) { handle_unregister_buffer(buf); - free_buffer_stuff(buf, TRUE); + buf_free_count++; + free_buffer_stuff(buf, true); unref_var_dict(buf->b_vars); aubuflocal_remove(buf); buf_hashtab_remove(buf); @@ -882,6 +920,9 @@ static int empty_curbuf(int close_others, int forceit, int action) return FAIL; } + bufref_T bufref; + set_bufref(&bufref, buf); + if (close_others) { /* Close any other windows on this buffer, then make it empty. */ close_windows(buf, TRUE); @@ -891,15 +932,17 @@ static int empty_curbuf(int close_others, int forceit, int action) retval = do_ecmd(0, NULL, NULL, NULL, ECMD_ONE, forceit ? ECMD_FORCEIT : 0, curwin); - /* - * do_ecmd() may create a new buffer, then we have to delete - * the old one. But do_ecmd() may have done that already, check - * if the buffer still exists. - */ - if (buf != curbuf && buf_valid(buf) && buf->b_nwindows == 0) - close_buffer(NULL, buf, action, FALSE); - if (!close_others) - need_fileinfo = FALSE; + // do_ecmd() may create a new buffer, then we have to delete + // the old one. But do_ecmd() may have done that already, check + // if the buffer still exists. + if (buf != curbuf && bufref_valid(&bufref) && buf->b_nwindows == 0) { + close_buffer(NULL, buf, action, false); + } + + if (!close_others) { + need_fileinfo = false; + } + return retval; } /* @@ -1001,6 +1044,8 @@ do_buffer ( */ if (unload) { int forward; + bufref_T bufref; + set_bufref(&bufref, buf); /* When unloading or deleting a buffer that's already unloaded and * unlisted: fail silently. */ @@ -1009,15 +1054,16 @@ do_buffer ( if (!forceit && (buf->terminal || bufIsChanged(buf))) { if ((p_confirm || cmdmod.confirm) && p_write && !buf->terminal) { - dialog_changed(buf, FALSE); - if (!buf_valid(buf)) - /* Autocommand deleted buffer, oops! It's not changed - * now. */ + dialog_changed(buf, false); + if (!bufref_valid(&bufref)) { + // Autocommand deleted buffer, oops! It's not changed now. return FAIL; - /* If it's still changed fail silently, the dialog already - * mentioned why it fails. */ - if (bufIsChanged(buf)) + } + // If it's still changed fail silently, the dialog already + // mentioned why it fails. + if (bufIsChanged(buf)) { return FAIL; + } } else { if (buf->terminal) { EMSG2(_("E89: %s will be killed(add ! to override)"), @@ -1061,9 +1107,10 @@ do_buffer ( * If the buffer to be deleted is not the current one, delete it here. */ if (buf != curbuf) { - close_windows(buf, FALSE); - if (buf != curbuf && buf_valid(buf) && buf->b_nwindows <= 0) - close_buffer(NULL, buf, action, FALSE); + close_windows(buf, false); + if (buf != curbuf && bufref_valid(&bufref) && buf->b_nwindows <= 0) { + close_buffer(NULL, buf, action, false); + } return OK; } @@ -1186,10 +1233,13 @@ do_buffer ( */ if (action == DOBUF_GOTO && !can_abandon(curbuf, forceit)) { if ((p_confirm || cmdmod.confirm) && p_write) { - dialog_changed(curbuf, FALSE); - if (!buf_valid(buf)) - /* Autocommand deleted buffer, oops! */ + bufref_T bufref; + set_bufref(&bufref, buf); + dialog_changed(curbuf, false); + if (!bufref_valid(&bufref)) { + // Autocommand deleted buffer, oops! return FAIL; + } } if (bufIsChanged(curbuf)) { EMSG(_(e_nowrtmsg)); @@ -1237,16 +1287,18 @@ void set_curbuf(buf_T *buf, int action) /* close_windows() or apply_autocmds() may change curbuf */ prevbuf = curbuf; + bufref_T bufref; + set_bufref(&bufref, prevbuf); if (!apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, false, curbuf) - || (buf_valid(prevbuf) && !aborting())) { + || (bufref_valid(&bufref) && !aborting())) { if (prevbuf == curwin->w_buffer) { reset_synblock(curwin); } if (unload) { close_windows(prevbuf, false); } - if (buf_valid(prevbuf) && !aborting()) { + if (bufref_valid(&bufref) && !aborting()) { win_T *previouswin = curwin; if (prevbuf == curbuf) u_sync(FALSE); @@ -1423,10 +1475,12 @@ buf_T * buflist_new(char_u *ffname, char_u *sfname, linenr_T lnum, int flags) buf_copy_options(buf, 0); } if ((flags & BLN_LISTED) && !buf->b_p_bl) { - buf->b_p_bl = TRUE; + buf->b_p_bl = true; + bufref_T bufref; + set_bufref(&bufref, buf); if (!(flags & BLN_DUMMY)) { if (apply_autocmds(EVENT_BUFADD, NULL, NULL, false, buf) - && !buf_valid(buf)) { + && !bufref_valid(&bufref)) { return NULL; } } @@ -1560,13 +1614,15 @@ buf_T * buflist_new(char_u *ffname, char_u *sfname, linenr_T lnum, int flags) // Tricky: these autocommands may change the buffer list. They could also // split the window with re-using the one empty buffer. This may result in // unexpectedly losing the empty buffer. + bufref_T bufref; + set_bufref(&bufref, buf); if (apply_autocmds(EVENT_BUFNEW, NULL, NULL, false, buf) - && !buf_valid(buf)) { + && !bufref_valid(&bufref)) { return NULL; } if ((flags & BLN_LISTED) && apply_autocmds(EVENT_BUFADD, NULL, NULL, false, buf) - && !buf_valid(buf)) { + && !bufref_valid(&bufref)) { return NULL; } if (aborting()) { @@ -4235,12 +4291,13 @@ do_arg_all ( || !bufIsChanged(buf)) { /* If the buffer was changed, and we would like to hide it, * try autowriting. */ - if (!P_HID(buf) && buf->b_nwindows <= 1 - && bufIsChanged(buf)) { - (void)autowrite(buf, FALSE); - /* check if autocommands removed the window */ - if (!win_valid(wp) || !buf_valid(buf)) { - wpnext = firstwin; /* start all over... */ + if (!P_HID(buf) && buf->b_nwindows <= 1 && bufIsChanged(buf)) { + bufref_T bufref; + set_bufref(&bufref, buf); + (void)autowrite(buf, false); + // Check if autocommands removed the window. + if (!win_valid(wp) || !bufref_valid(&bufref)) { + wpnext = firstwin; // Start all over... continue; } } @@ -4454,7 +4511,9 @@ void ex_buffer_all(exarg_T *eap) } if (wp == NULL && split_ret == OK) { - /* Split the window and put the buffer in it */ + bufref_T bufref; + set_bufref(&bufref, buf); + // Split the window and put the buffer in it. p_ea_save = p_ea; p_ea = true; /* use space from all windows */ split_ret = win_split(0, WSP_ROOM | WSP_BELOW); @@ -4466,7 +4525,8 @@ void ex_buffer_all(exarg_T *eap) /* Open the buffer in this window. */ swap_exists_action = SEA_DIALOG; set_curbuf(buf, DOBUF_GOTO); - if (!buf_valid(buf)) { /* autocommands deleted the buffer!!! */ + if (!bufref_valid(&bufref)) { + // Autocommands deleted the buffer. swap_exists_action = SEA_NONE; break; } |