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.
Files:      src/structs.h, src/buffer.c, src/quickfix.c, src/proto/buffer.pro


*** ../vim-7.4.2017/src/structs.h       2016-07-03 17:47:21.858812593 +0200
--- src/structs.h       2016-07-10 17:03:56.106490100 +0200
***************
*** 69,74 ****
--- 69,82 ----
  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.
   */
*** ../vim-7.4.2017/src/buffer.c        2016-07-10 17:00:33.313537282 +0200
--- src/buffer.c        2016-07-10 18:18:04.572170378 +0200
***************
*** 67,72 ****
--- 67,75 ----
  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,315 ****
--- 312,340 ----
  }
  
  /*
+  * 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,356 ****
--- 376,382 ----
  #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,407 ****
      }
  
  #ifdef FEAT_AUTOCMD
      /* 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))
        {
            /* Autocommands deleted the buffer. */
  aucmd_abort:
--- 421,435 ----
      }
  
  #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)
!               && !bufref_valid(&bufref))
        {
            /* Autocommands deleted the buffer. */
  aucmd_abort:
***************
*** 420,426 ****
            buf->b_closing = TRUE;
            if (apply_autocmds(EVENT_BUFHIDDEN, buf->b_fname, buf->b_fname,
                                                                  FALSE, buf)
!                   && !buf_valid(buf))
                /* Autocommands deleted the buffer. */
                goto aucmd_abort;
            buf->b_closing = FALSE;
--- 448,454 ----
            buf->b_closing = TRUE;
            if (apply_autocmds(EVENT_BUFHIDDEN, buf->b_fname, buf->b_fname,
                                                                  FALSE, buf)
!                   && !bufref_valid(&bufref))
                /* Autocommands deleted the buffer. */
                goto aucmd_abort;
            buf->b_closing = FALSE;
***************
*** 464,470 ****
  
  #ifdef FEAT_AUTOCMD
      /* Autocommands may have deleted the buffer. */
!     if (!buf_valid(buf))
        return;
  # ifdef FEAT_EVAL
      if (aborting())       /* autocmds may abort script processing */
--- 492,498 ----
  
  #ifdef FEAT_AUTOCMD
      /* Autocommands may have deleted the buffer. */
!     if (!bufref_valid(&bufref))
        return;
  # ifdef FEAT_EVAL
      if (aborting())       /* autocmds may abort script processing */
***************
*** 575,601 ****
  {
  #ifdef FEAT_AUTOCMD
      int               is_curbuf = (buf == curbuf);
  
      buf->b_closing = TRUE;
      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 */
            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 */
            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 */
            return;
      }
      buf->b_closing = FALSE;
--- 603,634 ----
  {
  #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)
!               && !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)
!               && !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)
!               && !bufref_valid(&bufref))
!           /* autocommands deleted the buffer */
            return;
      }
      buf->b_closing = FALSE;
***************
*** 662,667 ****
--- 695,701 ----
      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,1032 ****
--- 1061,1067 ----
  {
      int           retval;
      buf_T   *buf = curbuf;
+     bufref_T bufref;
  
      if (action == DOBUF_UNLOAD)
      {
***************
*** 1034,1046 ****
        return FAIL;
      }
  
      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,
--- 1069,1080 ----
        return FAIL;
      }
  
+     set_bufref(&bufref, buf);
+ #ifdef FEAT_WINDOWS
      if (close_others)
        /* Close any other windows on this buffer, then make it empty. */
        close_windows(buf, TRUE);
  #endif
  
      setpcmark();
      retval = do_ecmd(0, NULL, NULL, NULL, ECMD_ONE,
***************
*** 1051,1057 ****
       * 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;
--- 1085,1091 ----
       * 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;
***************
*** 1177,1182 ****
--- 1211,1221 ----
      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,1196 ****
            {
                dialog_changed(buf, FALSE);
  # ifdef FEAT_AUTOCMD
!               if (!buf_valid(buf))
                    /* Autocommand deleted buffer, oops!  It's not changed
                     * now. */
                    return FAIL;
--- 1229,1235 ----
            {
                dialog_changed(buf, FALSE);
  # ifdef FEAT_AUTOCMD
!               if (!bufref_valid(&bufref))
                    /* Autocommand deleted buffer, oops!  It's not changed
                     * now. */
                    return FAIL;
***************
*** 1243,1251 ****
        {
  #ifdef FEAT_WINDOWS
            close_windows(buf, FALSE);
  #endif
!           if (buf != curbuf && buf_valid(buf) && buf->b_nwindows <= 0)
!               close_buffer(NULL, buf, action, FALSE);
            return OK;
        }
  
--- 1282,1291 ----
        {
  #ifdef FEAT_WINDOWS
            close_windows(buf, FALSE);
+           if (buf != curbuf && bufref_valid(&bufref))
  #endif
!               if (buf->b_nwindows <= 0)
!                   close_buffer(NULL, buf, action, FALSE);
            return OK;
        }
  
***************
*** 1390,1398 ****
  #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
        if ((p_confirm || cmdmod.confirm) && p_write)
        {
            dialog_changed(curbuf, FALSE);
  # ifdef FEAT_AUTOCMD
!           if (!buf_valid(buf))
                /* Autocommand deleted buffer, oops! */
                return FAIL;
  # endif
--- 1430,1443 ----
  #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 (!bufref_valid(&bufref))
                /* Autocommand deleted buffer, oops! */
                return FAIL;
  # endif
***************
*** 1443,1448 ****
--- 1488,1496 ----
  #ifdef FEAT_SYN_HL
      long      old_tw = curbuf->b_p_tw;
  #endif
+ #ifdef FEAT_AUTOCMD
+     bufref_T  bufref;
+ #endif
  
      setpcmark();
      if (!cmdmod.keepalt)
***************
*** 1456,1466 ****
      prevbuf = curbuf;
  
  #ifdef FEAT_AUTOCMD
      if (!apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf)
  # ifdef FEAT_EVAL
!           || (buf_valid(prevbuf) && !aborting()))
  # else
!           || buf_valid(prevbuf))
  # endif
  #endif
      {
--- 1504,1515 ----
      prevbuf = curbuf;
  
  #ifdef FEAT_AUTOCMD
+     set_bufref(&bufref, prevbuf);
      if (!apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf)
  # ifdef FEAT_EVAL
!           || (bufref_valid(&bufref) && !aborting()))
  # else
!           || bufref_valid(&bufref))
  # endif
  #endif
      {
***************
*** 1473,1481 ****
            close_windows(prevbuf, FALSE);
  #endif
  #if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
!       if (buf_valid(prevbuf) && !aborting())
  #else
!       if (buf_valid(prevbuf))
  #endif
        {
  #ifdef FEAT_WINDOWS
--- 1522,1530 ----
            close_windows(prevbuf, FALSE);
  #endif
  #if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
!       if (bufref_valid(&bufref) && !aborting())
  #else
!       if (bufref_valid(&bufref))
  #endif
        {
  #ifdef FEAT_WINDOWS
***************
*** 1496,1502 ****
      }
  #ifdef FEAT_AUTOCMD
      /* An autocommand may have deleted "buf", already entered it (e.g., when
!      * 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
--- 1545,1551 ----
      }
  #ifdef FEAT_AUTOCMD
      /* An autocommand may have deleted "buf", already entered it (e.g., when
!      * 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,1717 ****
  
        if ((flags & BLN_LISTED) && !buf->b_p_bl)
        {
            buf->b_p_bl = TRUE;
  #ifdef FEAT_AUTOCMD
            if (!(flags & BLN_DUMMY))
            {
                if (apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, buf)
!                       && !buf_valid(buf))
                    return NULL;
            }
  #endif
--- 1755,1770 ----
  
        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)
!                       && !bufref_valid(&bufref))
                    return NULL;
            }
  #endif
***************
*** 1887,1902 ****
  #ifdef FEAT_AUTOCMD
      if (!(flags & BLN_DUMMY))
      {
        /* 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. */
        if (apply_autocmds(EVENT_BUFNEW, NULL, NULL, FALSE, buf)
!               && !buf_valid(buf))
            return NULL;
        if (flags & BLN_LISTED)
        {
            if (apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, buf)
!                   && !buf_valid(buf))
                return NULL;
        }
  # ifdef FEAT_EVAL
--- 1940,1958 ----
  #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)
!               && !bufref_valid(&bufref))
            return NULL;
        if (flags & BLN_LISTED)
        {
            if (apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, buf)
!                   && !bufref_valid(&bufref))
                return NULL;
        }
  # ifdef FEAT_EVAL
***************
*** 4708,4717 ****
                    if (!P_HID(buf) && buf->b_nwindows <= 1
                                                         && bufIsChanged(buf))
                    {
                        (void)autowrite(buf, FALSE);
  #ifdef FEAT_AUTOCMD
                        /* check if autocommands removed the window */
!                       if (!win_valid(wp) || !buf_valid(buf))
                        {
                            wpnext = firstwin;  /* start all over... */
                            continue;
--- 4764,4778 ----
                    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) || !bufref_valid(&bufref))
                        {
                            wpnext = firstwin;  /* start all over... */
                            continue;
***************
*** 4993,4998 ****
--- 5054,5064 ----
  
        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,5015 ****
  #endif
            set_curbuf(buf, DOBUF_GOTO);
  #ifdef FEAT_AUTOCMD
!           if (!buf_valid(buf))        /* autocommands deleted the buffer!!! */
            {
  #if defined(HAS_SWAP_EXISTS_ACTION)
                swap_exists_action = SEA_NONE;
  # endif
--- 5074,5082 ----
  #endif
            set_curbuf(buf, DOBUF_GOTO);
  #ifdef FEAT_AUTOCMD
!           if (!bufref_valid(&bufref))
            {
+               /* autocommands deleted the buffer!!! */
  #if defined(HAS_SWAP_EXISTS_ACTION)
                swap_exists_action = SEA_NONE;
  # endif
*** ../vim-7.4.2017/src/quickfix.c      2016-07-10 17:00:33.317537221 +0200
--- src/quickfix.c      2016-07-10 17:16:38.511074061 +0200
***************
*** 1487,1493 ****
   * 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;
  
  /*
   * Get buffer number for file "dir.name".
--- 1487,1493 ----
   * to make this a lot faster if there are multiple matches in the same file.
   */
  static char_u *qf_last_bufname = NULL;
! static bufref_T  qf_last_bufref = {NULL, 0};
  
  /*
   * Get buffer number for file "dir.name".
***************
*** 1536,1544 ****
        bufname = fname;
  
      if (qf_last_bufname != NULL && STRCMP(bufname, qf_last_bufname) == 0
!           && buf_valid(qf_last_buf))
      {
!       buf = qf_last_buf;
        vim_free(ptr);
      }
      else
--- 1536,1544 ----
        bufname = fname;
  
      if (qf_last_bufname != NULL && STRCMP(bufname, qf_last_bufname) == 0
!           && bufref_valid(&qf_last_bufref))
      {
!       buf = qf_last_bufref.br_buf;
        vim_free(ptr);
      }
      else
***************
*** 1549,1555 ****
            qf_last_bufname = bufname;
        else
            qf_last_bufname = vim_strsave(bufname);
!       qf_last_buf = buf;
      }
      if (buf == NULL)
        return 0;
--- 1549,1555 ----
            qf_last_bufname = bufname;
        else
            qf_last_bufname = vim_strsave(bufname);
!       set_bufref(&qf_last_bufref, buf);
      }
      if (buf == NULL)
        return 0;
*** ../vim-7.4.2017/src/proto/buffer.pro        2016-01-19 13:21:55.833334420 
+0100
--- src/proto/buffer.pro        2016-07-10 17:11:50.255384426 +0200
***************
*** 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);
*** ../vim-7.4.2017/src/version.c       2016-07-10 17:00:33.321537162 +0200
--- src/version.c       2016-07-10 17:04:51.681655986 +0200
***************
*** 760,761 ****
--- 760,763 ----
  {   /* Add new patch number below this line */
+ /**/
+     2018,
  /**/

-- 
hundred-and-one symptoms of being an internet addict:
264. You turn to the teletext page "surfing report" and are surprised that it
     is about sizes of waves and a weather forecast for seaside resorts.

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\  an exciting new programming language -- http://www.Zimbu.org        ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Raspunde prin e-mail lui