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
[email protected]
https://lists.sourceforge.net/lists/listinfo/tmux-users