summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2016-07-10 18:21:50 +0200
committerBram Moolenaar <Bram@vim.org>2016-07-10 18:21:50 +0200
commitb25f9a97e9aad3cbb4bc3fe87cdbd5700f8aa0c6 (patch)
treec51d62bd77521a1de07d989af9a8ca3cd8c8b85a /src
parent8240433f48f7383c281ba2453cc55f10b8ec47d9 (diff)
downloadvim-b25f9a97e9aad3cbb4bc3fe87cdbd5700f8aa0c6.zip
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.
Diffstat (limited to 'src')
-rw-r--r--src/buffer.c115
-rw-r--r--src/proto/buffer.pro2
-rw-r--r--src/quickfix.c8
-rw-r--r--src/structs.h8
-rw-r--r--src/version.c2
5 files changed, 107 insertions, 28 deletions
diff --git a/src/buffer.c b/src/buffer.c
index 586ab3848..8fe2b8a59 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -67,6 +67,9 @@ static char *msg_qflist = N_("[Quickfix List]");
static char *e_auabort = N_("E855: Autocommands caused command to abort");
#endif
+/* 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.
@@ -309,7 +312,29 @@ open_buffer(
}
/*
+ * Store "buf" in "bufref" and set the free count.
+ */
+ void
+set_bufref(bufref_T *bufref, buf_T *buf)
+{
+ bufref->br_buf = buf;
+ bufref->br_buf_free_count = buf_free_count;
+}
+
+/*
+ * Return TRUE if "bufref->br_buf" points to a valid buffer.
+ * Only goes through the buffer list if buf_free_count changed.
+ */
+ int
+bufref_valid(bufref_T *bufref)
+{
+ return bufref->br_buf_free_count == buf_free_count
+ ? TRUE : buf_valid(bufref->br_buf);
+}
+
+/*
* Return TRUE if "buf" points to a valid buffer (in the buffer list).
+ * This can be slow if there are many buffers, prefer using bufref_valid().
*/
int
buf_valid(buf_T *buf)
@@ -351,6 +376,7 @@ close_buffer(
#ifdef FEAT_AUTOCMD
int is_curbuf;
int nwindows;
+ bufref_T bufref;
#endif
int unload_buf = (action != 0);
int del_buf = (action == DOBUF_DEL || action == DOBUF_WIPE);
@@ -395,13 +421,15 @@ close_buffer(
}
#ifdef FEAT_AUTOCMD
+ 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))
+ && !bufref_valid(&bufref))
{
/* Autocommands deleted the buffer. */
aucmd_abort:
@@ -420,7 +448,7 @@ aucmd_abort:
buf->b_closing = TRUE;
if (apply_autocmds(EVENT_BUFHIDDEN, buf->b_fname, buf->b_fname,
FALSE, buf)
- && !buf_valid(buf))
+ && !bufref_valid(&bufref))
/* Autocommands deleted the buffer. */
goto aucmd_abort;
buf->b_closing = FALSE;
@@ -464,7 +492,7 @@ aucmd_abort:
#ifdef FEAT_AUTOCMD
/* Autocommands may have deleted the buffer. */
- if (!buf_valid(buf))
+ if (!bufref_valid(&bufref))
return;
# ifdef FEAT_EVAL
if (aborting()) /* autocmds may abort script processing */
@@ -575,27 +603,32 @@ buf_freeall(buf_T *buf, int flags)
{
#ifdef FEAT_AUTOCMD
int is_curbuf = (buf == curbuf);
+ bufref_T bufref;
buf->b_closing = TRUE;
+ set_bufref(&bufref, buf);
if (buf->b_ml.ml_mfp != NULL)
{
if (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)
{
if (apply_autocmds(EVENT_BUFDELETE, 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_WIPE)
{
if (apply_autocmds(EVENT_BUFWIPEOUT, buf->b_fname, buf->b_fname,
FALSE, buf)
- && !buf_valid(buf)) /* autocommands may delete the buffer */
+ && !bufref_valid(&bufref))
+ /* autocommands deleted the buffer */
return;
}
buf->b_closing = FALSE;
@@ -662,6 +695,7 @@ buf_freeall(buf_T *buf, int flags)
static void
free_buffer(buf_T *buf)
{
+ ++buf_free_count;
free_buffer_stuff(buf, TRUE);
#ifdef FEAT_EVAL
unref_var_dict(buf->b_vars);
@@ -1027,6 +1061,7 @@ empty_curbuf(
{
int retval;
buf_T *buf = curbuf;
+ bufref_T bufref;
if (action == DOBUF_UNLOAD)
{
@@ -1034,13 +1069,12 @@ empty_curbuf(
return FAIL;
}
+ set_bufref(&bufref, buf);
+#ifdef FEAT_WINDOWS
if (close_others)
- {
/* Close any other windows on this buffer, then make it empty. */
-#ifdef FEAT_WINDOWS
close_windows(buf, TRUE);
#endif
- }
setpcmark();
retval = do_ecmd(0, NULL, NULL, NULL, ECMD_ONE,
@@ -1051,7 +1085,7 @@ empty_curbuf(
* 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)
+ if (buf != curbuf && bufref_valid(&bufref) && buf->b_nwindows == 0)
close_buffer(NULL, buf, action, FALSE);
if (!close_others)
need_fileinfo = FALSE;
@@ -1177,6 +1211,11 @@ do_buffer(
if (unload)
{
int forward;
+# if defined(FEAT_AUTOCMD) || defined(FEAT_WINDOWS)
+ bufref_T bufref;
+
+ set_bufref(&bufref, buf);
+# endif
/* When unloading or deleting a buffer that's already unloaded and
* unlisted: fail silently. */
@@ -1190,7 +1229,7 @@ do_buffer(
{
dialog_changed(buf, FALSE);
# ifdef FEAT_AUTOCMD
- if (!buf_valid(buf))
+ if (!bufref_valid(&bufref))
/* Autocommand deleted buffer, oops! It's not changed
* now. */
return FAIL;
@@ -1243,9 +1282,10 @@ do_buffer(
{
#ifdef FEAT_WINDOWS
close_windows(buf, FALSE);
+ if (buf != curbuf && bufref_valid(&bufref))
#endif
- if (buf != curbuf && buf_valid(buf) && buf->b_nwindows <= 0)
- close_buffer(NULL, buf, action, FALSE);
+ if (buf->b_nwindows <= 0)
+ close_buffer(NULL, buf, action, FALSE);
return OK;
}
@@ -1390,9 +1430,14 @@ do_buffer(
#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
if ((p_confirm || cmdmod.confirm) && p_write)
{
+# ifdef FEAT_AUTOCMD
+ bufref_T bufref;
+
+ set_bufref(&bufref, buf);
+# endif
dialog_changed(curbuf, FALSE);
# ifdef FEAT_AUTOCMD
- if (!buf_valid(buf))
+ if (!bufref_valid(&bufref))
/* Autocommand deleted buffer, oops! */
return FAIL;
# endif
@@ -1443,6 +1488,9 @@ set_curbuf(buf_T *buf, int action)
#ifdef FEAT_SYN_HL
long old_tw = curbuf->b_p_tw;
#endif
+#ifdef FEAT_AUTOCMD
+ bufref_T bufref;
+#endif
setpcmark();
if (!cmdmod.keepalt)
@@ -1456,11 +1504,12 @@ set_curbuf(buf_T *buf, int action)
prevbuf = curbuf;
#ifdef FEAT_AUTOCMD
+ set_bufref(&bufref, prevbuf);
if (!apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf)
# ifdef FEAT_EVAL
- || (buf_valid(prevbuf) && !aborting()))
+ || (bufref_valid(&bufref) && !aborting()))
# else
- || buf_valid(prevbuf))
+ || bufref_valid(&bufref))
# endif
#endif
{
@@ -1473,9 +1522,9 @@ set_curbuf(buf_T *buf, int action)
close_windows(prevbuf, FALSE);
#endif
#if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
- if (buf_valid(prevbuf) && !aborting())
+ if (bufref_valid(&bufref) && !aborting())
#else
- if (buf_valid(prevbuf))
+ if (bufref_valid(&bufref))
#endif
{
#ifdef FEAT_WINDOWS
@@ -1496,7 +1545,7 @@ set_curbuf(buf_T *buf, int action)
}
#ifdef FEAT_AUTOCMD
/* An autocommand may have deleted "buf", already entered it (e.g., when
- * it did ":bunload") or aborted the script processing!
+ * it did ":bunload") or aborted the script processing.
* If curwin->w_buffer is null, enter_buffer() will make it valid again */
if ((buf_valid(buf) && buf != curbuf
# ifdef FEAT_EVAL
@@ -1706,12 +1755,16 @@ buflist_new(
if ((flags & BLN_LISTED) && !buf->b_p_bl)
{
+#ifdef FEAT_AUTOCMD
+ bufref_T bufref;
+#endif
buf->b_p_bl = TRUE;
#ifdef FEAT_AUTOCMD
+ 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;
}
#endif
@@ -1887,16 +1940,19 @@ buflist_new(
#ifdef FEAT_AUTOCMD
if (!(flags & BLN_DUMMY))
{
+ bufref_T bufref;
+
/* 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. */
+ 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)
{
if (apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, buf)
- && !buf_valid(buf))
+ && !bufref_valid(&bufref))
return NULL;
}
# ifdef FEAT_EVAL
@@ -4708,10 +4764,15 @@ do_arg_all(
if (!P_HID(buf) && buf->b_nwindows <= 1
&& bufIsChanged(buf))
{
+#ifdef FEAT_AUTOCMD
+ bufref_T bufref;
+
+ set_bufref(&bufref, buf);
+#endif
(void)autowrite(buf, FALSE);
#ifdef FEAT_AUTOCMD
/* check if autocommands removed the window */
- if (!win_valid(wp) || !buf_valid(buf))
+ if (!win_valid(wp) || !bufref_valid(&bufref))
{
wpnext = firstwin; /* start all over... */
continue;
@@ -4993,6 +5054,11 @@ ex_buffer_all(exarg_T *eap)
if (wp == NULL && split_ret == OK)
{
+#ifdef FEAT_AUTOCMD
+ bufref_T bufref;
+
+ set_bufref(&bufref, buf);
+#endif
/* Split the window and put the buffer in it */
p_ea_save = p_ea;
p_ea = TRUE; /* use space from all windows */
@@ -5008,8 +5074,9 @@ ex_buffer_all(exarg_T *eap)
#endif
set_curbuf(buf, DOBUF_GOTO);
#ifdef FEAT_AUTOCMD
- if (!buf_valid(buf)) /* autocommands deleted the buffer!!! */
+ if (!bufref_valid(&bufref))
{
+ /* autocommands deleted the buffer!!! */
#if defined(HAS_SWAP_EXISTS_ACTION)
swap_exists_action = SEA_NONE;
# endif
diff --git a/src/proto/buffer.pro b/src/proto/buffer.pro
index 71217287a..e2adf5c9f 100644
--- a/src/proto/buffer.pro
+++ b/src/proto/buffer.pro
@@ -1,5 +1,7 @@
/* buffer.c */
int open_buffer(int read_stdin, exarg_T *eap, int flags);
+void set_bufref(bufref_T *bufref, buf_T *buf);
+int bufref_valid(bufref_T *bufref);
int buf_valid(buf_T *buf);
void close_buffer(win_T *win, buf_T *buf, int action, int abort_if_last);
void buf_clear_file(buf_T *buf);
diff --git a/src/quickfix.c b/src/quickfix.c
index 065216afe..1e5abc69e 100644
--- a/src/quickfix.c
+++ b/src/quickfix.c
@@ -1487,7 +1487,7 @@ copy_loclist(win_T *from, win_T *to)
* to make this a lot faster if there are multiple matches in the same file.
*/
static char_u *qf_last_bufname = NULL;
-static buf_T *qf_last_buf = NULL;
+static bufref_T qf_last_bufref = {NULL, 0};
/*
* Get buffer number for file "dir.name".
@@ -1536,9 +1536,9 @@ qf_get_fnum(qf_info_T *qi, char_u *directory, char_u *fname)
bufname = fname;
if (qf_last_bufname != NULL && STRCMP(bufname, qf_last_bufname) == 0
- && buf_valid(qf_last_buf))
+ && bufref_valid(&qf_last_bufref))
{
- buf = qf_last_buf;
+ buf = qf_last_bufref.br_buf;
vim_free(ptr);
}
else
@@ -1549,7 +1549,7 @@ qf_get_fnum(qf_info_T *qi, char_u *directory, char_u *fname)
qf_last_bufname = bufname;
else
qf_last_bufname = vim_strsave(bufname);
- qf_last_buf = buf;
+ set_bufref(&qf_last_bufref, buf);
}
if (buf == NULL)
return 0;
diff --git a/src/structs.h b/src/structs.h
index 05f461705..e092e6b2d 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -69,6 +69,14 @@ typedef struct frame_S frame_T;
typedef int scid_T; /* script ID */
typedef struct file_buffer buf_T; /* forward declaration */
+/* Reference to a buffer that stores the value of buf_free_count.
+ * bufref_valid() only needs to check "buf" when the count differs.
+ */
+typedef struct {
+ buf_T *br_buf;
+ int br_buf_free_count;
+} bufref_T;
+
/*
* This is here because regexp.h needs pos_T and below regprog_T is used.
*/
diff --git a/src/version.c b/src/version.c
index 0d39ffa62..7317edf21 100644
--- a/src/version.c
+++ b/src/version.c
@@ -759,6 +759,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 2018,
+/**/
2017,
/**/
2016,