Here is a working version, at least for the last minute or so :-).

diff --git a/grid.c b/grid.c
index aabf66c..7088b79 100644
--- a/grid.c
+++ b/grid.c
@@ -70,6 +70,10 @@ grid_check_y(struct grid *gd, u_int py)
 }
 #endif
 
+void   grid_reflow_join(struct grid *, u_int *, struct grid_line *, u_int);
+void   grid_reflow_split(struct grid *, u_int *, struct grid_line *, u_int);
+void   grid_reflow_move(struct grid *, u_int *, struct grid_line *);
+
 /* Create a new grid. */
 struct grid *
 grid_create(u_int sx, u_int sy, u_int hlimit)
@@ -461,43 +465,147 @@ grid_duplicate_lines(
        }
 }
 
+/* Join line data. */
+void
+grid_reflow_join(struct grid *dst, u_int *py, struct grid_line *src_gl,
+    u_int new_x)
+{
+       struct grid_line        *dst_gl = &dst->linedata[*py];
+       u_int                    left, to_copy, ox, nx;
+
+       /* How much is left on the old line? */
+       left = new_x - dst_gl->cellsize;
+
+       /* Work out how much to append. */
+       to_copy = src_gl->cellsize;
+       if (to_copy > left)
+               to_copy = left;
+       ox = dst_gl->cellsize;
+       nx = ox + to_copy;
+
+       /* Resize the destination line. */
+       dst_gl->celldata = xrealloc(dst_gl->celldata, nx,
+           sizeof *dst_gl->celldata);
+       dst_gl->cellsize = nx;
+
+       /* Append as much as possible. */
+       memcpy(&dst_gl->celldata[ox], &src_gl->celldata[0],
+           to_copy * sizeof src_gl->celldata[0]);
+
+       /* If there is any left in the source, add a new line with it. */
+       if (src_gl->cellsize > to_copy) {
+               (*py)++;
+               if (*py >= dst->hsize + dst->sy)
+                       grid_scroll_history(dst);
+               dst_gl = &dst->linedata[*py];
+
+               memcpy(dst_gl, src_gl, sizeof *dst_gl);
+               dst_gl->flags |= GRID_LINE_WRAPPED;
+
+               dst_gl->cellsize -= to_copy;
+               memmove(&dst_gl->celldata[0], &dst_gl->celldata[to_copy],
+                   dst_gl->cellsize * sizeof dst_gl->celldata[0]);
+       }
+
+       /* Clear source data. */
+       src_gl->celldata = NULL;
+}
+
+/* Split line data. */
+void
+grid_reflow_split(struct grid *dst, u_int *py, struct grid_line *src_gl,
+    u_int new_x)
+{
+       struct grid_line        *dst_gl;
+       u_int                    offset, to_copy;
+
+       /* Loop and copy sections of the source line. */
+       offset = 0;
+       while (src_gl->cellsize > 0)
+       {
+               /* Create new line. */
+               (*py)++;
+               if (*py >= dst->hsize + dst->sy)
+                       grid_scroll_history(dst);
+               dst_gl = &dst->linedata[*py];
+
+               /* How much should we copy? */
+               to_copy = new_x;
+               if (to_copy > src_gl->cellsize)
+                       to_copy = src_gl->cellsize;
+
+               /* Expand destination line. */
+               dst_gl->celldata = xmalloc(to_copy * sizeof *dst_gl->celldata);
+               dst_gl->cellsize = to_copy;
+               dst_gl->flags |= GRID_LINE_WRAPPED;
+
+               /* Copy the data. */
+               memcpy (&dst_gl->celldata[0], &src_gl->celldata[offset],
+                   to_copy * sizeof dst_gl->celldata[0]);
+
+               /* Move offset and reduce old line size. */
+               offset += to_copy;
+               src_gl->cellsize -= to_copy;
+       }
+
+       /* Last line is not wrapped. */
+       dst_gl->flags &= ~GRID_LINE_WRAPPED;
+}
+
+/* Move line data. */
+void
+grid_reflow_move(struct grid *dst, u_int *py, struct grid_line *src_gl)
+{
+       struct grid_line        *dst_gl;
+
+       /* Create new line. */
+       (*py)++;
+       if (*py >= dst->hsize + dst->sy)
+               grid_scroll_history(dst);
+       dst_gl = &dst->linedata[*py];
+
+       /* Copy the old line. */
+       memcpy(dst_gl, src_gl, sizeof *dst_gl);
+       dst_gl->flags &= ~GRID_LINE_WRAPPED;
+
+       /* Clear old line. */
+       src_gl->celldata = NULL;
+}
+
 /*
- * Reflow lines from src grid into dst grid based on width sx. Returns number
- * of lines fewer in the visible area, or zero.
+ * Reflow lines from src grid into dst grid of width new_x. Returns number of
+ * lines fewer in the visible area. The source grid is destroyed.
  */
 u_int
-grid_reflow(struct grid *dst, const struct grid *src, u_int sx)
+grid_reflow(struct grid *dst, struct grid *src, u_int new_x)
 {
-       u_int                    px, py, line, cell;
+       u_int                    py, sy, line;
        int                      previous_wrapped;
-       struct grid_line        *gl;
+       struct grid_line        *src_gl;
+
+       py = 0;
+       sy = src->sy;
 
-       px = py = 0;
        previous_wrapped = 1;
-       for (line = 0; line < src->sy + src->hsize; line++) {
-               gl = src->linedata + line;
+       for (line = 0; line < sy + src->hsize; line++) {
+               src_gl = src->linedata + line;
                if (!previous_wrapped) {
-                       px = 0;
-                       py++;
-                       if (py >= dst->hsize + dst->sy)
-                               grid_scroll_history(dst);
-               }
-               for (cell = 0; cell < gl->cellsize; cell++) {
-                       if (px == sx) {
-                               dst->linedata[py].flags |= GRID_LINE_WRAPPED;
-                               px = 0;
-                               py++;
-                               if (py >= dst->hsize + dst->sy)
-                                       grid_scroll_history(dst);
-                       }
-                       grid_set_cell(dst, px, py, gl->celldata + cell);
-                       px++;
+                       /* Wasn't wrapped. If smaller, move to destination. */
+                       if (src_gl->cellsize < new_x)
+                               grid_reflow_move(dst, &py, src_gl);
+                       else
+                               grid_reflow_split(dst, &py, src_gl, new_x);
+               } else {
+                       /* Previous was wrapped. Try to join. */
+                       grid_reflow_join(dst, &py, src_gl, new_x);
                }
-               previous_wrapped = gl->flags & GRID_LINE_WRAPPED;
+               previous_wrapped = src_gl->flags & GRID_LINE_WRAPPED;
        }
        py++; /* account for final line, which never wraps */
 
-       if (py > src->sy)
+       grid_destroy(src);
+
+       if (py > sy)
                return (0);
-       return (src->sy - py);
+       return (sy - py);
 }
diff --git a/screen.c b/screen.c
index fe0b738..e92c6aa 100644
--- a/screen.c
+++ b/screen.c
@@ -363,15 +363,10 @@ screen_check_selection(struct screen *s, u_int px, u_int 
py)
 
 /* Reflow wrapped lines. */
 void
-screen_reflow(struct screen *s, u_int sx)
+screen_reflow(struct screen *s, u_int new_x)
 {
-       struct grid     *old, *new;
+       struct grid     *old = s->grid;
 
-       old = s->grid;
-       new = grid_create(old->sx, old->sy, old->hlimit);
-
-       s->cy -= grid_reflow(new, old, sx);
-       s->grid = new;
-
-       grid_destroy(old);
+       s->grid = grid_create(old->sx, old->sy, old->hlimit);
+       s->cy -= grid_reflow(s->grid, old, new_x);
 }
diff --git a/tmux.h b/tmux.h
index 1dd11ad..fd67724 100644
--- a/tmux.h
+++ b/tmux.h
@@ -1960,7 +1960,7 @@ void       grid_move_cells(struct grid *, u_int, u_int, 
u_int, u_int);
 char   *grid_string_cells(struct grid *, u_int, u_int, u_int);
 void    grid_duplicate_lines(
             struct grid *, u_int, struct grid *, u_int, u_int);
-u_int   grid_reflow(struct grid *, const struct grid *, u_int);
+u_int   grid_reflow(struct grid *, struct grid *, u_int);
 
 /* grid-cell.c */
 u_int   grid_cell_width(const struct grid_cell *);



On Sun, Feb 10, 2013 at 02:08:21PM +0000, Nicholas Marriott wrote:
> I just made this core so maybe wait for a wee bit first :-).
> 
> 
> On Sun, Feb 10, 2013 at 02:06:12PM +0000, Nicholas Marriott wrote:
> > Hi
> > 
> > The current reflow code is nice and simple but as Thomas has discovered
> > it is pretty slow. Particularly on FreeBSD apparently, my guess would be
> > because it does a lot of realloc and is hitting some suboptimal case in
> > their libc.
> > 
> > So the diff below avoids allocation and does memcpy rather than
> > cell-by-cell copies.
> > 
> > Tests, comments please.
> > 
> > If this doesn't fix the problem then we shall have to think again :-).
> > 
> > 
> > diff --git a/grid.c b/grid.c
> > index aabf66c..cad8187 100644
> > --- a/grid.c
> > +++ b/grid.c
> > @@ -70,6 +70,10 @@ grid_check_y(struct grid *gd, u_int py)
> >  }
> >  #endif
> >  
> > +void       grid_reflow_join(struct grid *, u_int *, struct grid_line *, 
> > u_int);
> > +void       grid_reflow_split(struct grid *, u_int *, struct grid_line *, 
> > u_int);
> > +void       grid_reflow_move(struct grid *, u_int *, struct grid_line *);
> > +
> >  /* Create a new grid. */
> >  struct grid *
> >  grid_create(u_int sx, u_int sy, u_int hlimit)
> > @@ -461,43 +465,147 @@ grid_duplicate_lines(
> >     }
> >  }
> >  
> > +/* Join line data. */
> > +void
> > +grid_reflow_join(struct grid *dst, u_int *py, struct grid_line *src_gl,
> > +    u_int new_x)
> > +{
> > +   struct grid_line        *dst_gl = &dst->linedata[*py];
> > +   u_int                    left, to_copy, ox, nx;
> > +
> > +   /* How much is left on the old line? */
> > +   left = new_x - dst_gl->cellsize;
> > +
> > +   /* Work out how much to append. */
> > +   to_copy = src_gl->cellsize;
> > +   if (to_copy > left)
> > +           to_copy = left;
> > +   ox = dst_gl->cellsize;
> > +   nx = ox + to_copy;
> > +
> > +   /* Resize the destination line. */
> > +   dst_gl->celldata = xrealloc(dst_gl->celldata, nx,
> > +       sizeof *dst_gl->celldata);
> > +   dst_gl->cellsize = nx;
> > +
> > +   /* Append as much as possible. */
> > +   memcpy(&dst_gl->celldata[ox], &src_gl->celldata[0],
> > +       src_gl->cellsize * sizeof src_gl->celldata[0]);
> > +
> > +   /* If there is any left in the source, add a new line with it. */
> > +   if (src_gl->cellsize > to_copy) {
> > +           (*py)++;
> > +           if (*py >= dst->hsize + dst->sy)
> > +                   grid_scroll_history(dst);
> > +           dst_gl = &dst->linedata[*py];
> > +
> > +           memcpy(dst_gl, src_gl, sizeof *dst_gl);
> > +           dst_gl->flags |= GRID_LINE_WRAPPED;
> > +
> > +           dst_gl->cellsize -= to_copy;
> > +           memmove(&dst_gl->celldata[0], &dst_gl->celldata[to_copy],
> > +               dst_gl->cellsize * sizeof dst_gl->celldata[0]);
> > +   }
> > +
> > +   /* Clear source data. */
> > +   src_gl->celldata = NULL;
> > +}
> > +
> > +/* Split line data. */
> > +void
> > +grid_reflow_split(struct grid *dst, u_int *py, struct grid_line *src_gl,
> > +    u_int new_x)
> > +{
> > +   struct grid_line        *dst_gl;
> > +   u_int                    offset, to_copy;
> > +
> > +   /* Loop and copy sections of the source line. */
> > +   offset = 0;
> > +   while (src_gl->cellsize > 0)
> > +   {
> > +           /* Create new line. */
> > +           (*py)++;
> > +           if (*py >= dst->hsize + dst->sy)
> > +                   grid_scroll_history(dst);
> > +           dst_gl = &dst->linedata[*py];
> > +
> > +           /* How much should we copy? */
> > +           to_copy = new_x;
> > +           if (to_copy > src_gl->cellsize)
> > +                   to_copy = src_gl->cellsize;
> > +
> > +           /* Expand destination line. */
> > +           dst_gl->celldata = xmalloc(to_copy * sizeof *dst_gl->celldata);
> > +           dst_gl->cellsize = to_copy;
> > +           dst_gl->flags |= GRID_LINE_WRAPPED;
> > +
> > +           /* Copy the data. */
> > +           memcpy (&dst_gl->celldata[0], &src_gl->celldata[offset],
> > +               to_copy * sizeof dst_gl->celldata[0]);
> > +
> > +           /* Move offset and reduce old line size. */
> > +           offset += to_copy;
> > +           src_gl->cellsize -= to_copy;
> > +   }
> > +
> > +   /* Last line is not wrapped. */
> > +   dst_gl->flags &= ~GRID_LINE_WRAPPED;
> > +}
> > +
> > +/* Move line data. */
> > +void
> > +grid_reflow_move(struct grid *dst, u_int *py, struct grid_line *src_gl)
> > +{
> > +   struct grid_line        *dst_gl;
> > +
> > +   /* Create new line. */
> > +   (*py)++;
> > +   if (*py >= dst->hsize + dst->sy)
> > +           grid_scroll_history(dst);
> > +   dst_gl = &dst->linedata[*py];
> > +
> > +   /* Copy the old line. */
> > +   memcpy(dst_gl, src_gl, sizeof *dst_gl);
> > +   dst_gl->flags &= ~GRID_LINE_WRAPPED;
> > +
> > +   /* Clear old line. */
> > +   src_gl->celldata = NULL;
> > +}
> > +
> >  /*
> > - * Reflow lines from src grid into dst grid based on width sx. Returns 
> > number
> > - * of lines fewer in the visible area, or zero.
> > + * Reflow lines from src grid into dst grid of width new_x. Returns number 
> > of
> > + * lines fewer in the visible area. The source grid is destroyed.
> >   */
> >  u_int
> > -grid_reflow(struct grid *dst, const struct grid *src, u_int sx)
> > +grid_reflow(struct grid *dst, struct grid *src, u_int new_x)
> >  {
> > -   u_int                    px, py, line, cell;
> > +   u_int                    py, sy, line;
> >     int                      previous_wrapped;
> > -   struct grid_line        *gl;
> > +   struct grid_line        *src_gl;
> > +
> > +   py = 0;
> > +   sy = src->sy;
> >  
> > -   px = py = 0;
> >     previous_wrapped = 1;
> > -   for (line = 0; line < src->sy + src->hsize; line++) {
> > -           gl = src->linedata + line;
> > +   for (line = 0; line < sy + src->hsize; line++) {
> > +           src_gl = src->linedata + line;
> >             if (!previous_wrapped) {
> > -                   px = 0;
> > -                   py++;
> > -                   if (py >= dst->hsize + dst->sy)
> > -                           grid_scroll_history(dst);
> > -           }
> > -           for (cell = 0; cell < gl->cellsize; cell++) {
> > -                   if (px == sx) {
> > -                           dst->linedata[py].flags |= GRID_LINE_WRAPPED;
> > -                           px = 0;
> > -                           py++;
> > -                           if (py >= dst->hsize + dst->sy)
> > -                                   grid_scroll_history(dst);
> > -                   }
> > -                   grid_set_cell(dst, px, py, gl->celldata + cell);
> > -                   px++;
> > +                   /* Wasn't wrapped. If smaller, move to destination. */
> > +                   if (src_gl->cellsize < new_x)
> > +                           grid_reflow_move(dst, &py, src_gl);
> > +                   else
> > +                           grid_reflow_split(dst, &py, src_gl, new_x);
> > +           } else {
> > +                   /* Previous was wrapped. Try to join. */
> > +                   grid_reflow_join(dst, &py, src_gl, new_x);
> >             }
> > -           previous_wrapped = gl->flags & GRID_LINE_WRAPPED;
> > +           previous_wrapped = src_gl->flags & GRID_LINE_WRAPPED;
> >     }
> >     py++; /* account for final line, which never wraps */
> >  
> > -   if (py > src->sy)
> > +   grid_destroy(src);
> > +
> > +   if (py > sy)
> >             return (0);
> > -   return (src->sy - py);
> > +   return (sy - py);
> >  }
> > diff --git a/screen.c b/screen.c
> > index fe0b738..e92c6aa 100644
> > --- a/screen.c
> > +++ b/screen.c
> > @@ -363,15 +363,10 @@ screen_check_selection(struct screen *s, u_int px, 
> > u_int py)
> >  
> >  /* Reflow wrapped lines. */
> >  void
> > -screen_reflow(struct screen *s, u_int sx)
> > +screen_reflow(struct screen *s, u_int new_x)
> >  {
> > -   struct grid     *old, *new;
> > +   struct grid     *old = s->grid;
> >  
> > -   old = s->grid;
> > -   new = grid_create(old->sx, old->sy, old->hlimit);
> > -
> > -   s->cy -= grid_reflow(new, old, sx);
> > -   s->grid = new;
> > -
> > -   grid_destroy(old);
> > +   s->grid = grid_create(old->sx, old->sy, old->hlimit);
> > +   s->cy -= grid_reflow(s->grid, old, new_x);
> >  }
> > diff --git a/tmux.h b/tmux.h
> > index 1dd11ad..fd67724 100644
> > --- a/tmux.h
> > +++ b/tmux.h
> > @@ -1960,7 +1960,7 @@ void   grid_move_cells(struct grid *, u_int, u_int, 
> > u_int, u_int);
> >  char       *grid_string_cells(struct grid *, u_int, u_int, u_int);
> >  void        grid_duplicate_lines(
> >          struct grid *, u_int, struct grid *, u_int, u_int);
> > -u_int       grid_reflow(struct grid *, const struct grid *, u_int);
> > +u_int       grid_reflow(struct grid *, struct grid *, u_int);
> >  
> >  /* grid-cell.c */
> >  u_int       grid_cell_width(const struct grid_cell *);
> > 
> > 
> > 

------------------------------------------------------------------------------
Free Next-Gen Firewall Hardware Offer
Buy your Sophos next-gen firewall before the end March 2013 
and get the hardware for free! Learn more.
http://p.sf.net/sfu/sophos-d2d-feb
_______________________________________________
tmux-users mailing list
tmux-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/tmux-users

Reply via email to