> Milan, did you read the earlier post? It seems to deal with that.

Thank you for the reference, Ian. I made O(n) variant, two patches follows as
attachemnts. Bram, are they OK for you, please?

The first one fasten the join operation, the second one removes do_do_join()
function as it is no longer needed. They are separate to allow to accept just
the first one if API change is not allowed etc.

Milan
--
Milan Vancura, Prague, Czech Republic, Europe

--~--~---------~--~----~------------~-------~--~----~
You received this message from the "vim_dev" maillist.
For more information, visit http://www.vim.org/maillist.php
-~----------~----~----~----~------~----~------~--~---

>From 584f45b5896a80fb06a0774a491cfe97325aa317 Mon Sep 17 00:00:00 2001
From: mvancura <[email protected]>
Date: Tue, 23 Dec 2008 16:57:38 +0100
Subject: [PATCH] New algorithm of joining lines: instead of calling do_join() n-times for n lines,
 new function do_do_join() do the whole work and accepts number of lines to join
 directly.
 That means do_join() function is just a container calling do_do_join() and can be
 deleted in the future.


diff --git a/src/ops.c b/src/ops.c
index 557985c..6ab83fc 100644
--- a/src/ops.c
+++ b/src/ops.c
@@ -4105,135 +4105,118 @@ dis_msg(p, skip_esc)
 /*
  * join 'count' lines (minimal 2), including u_save()
  */
-    void
+    int
 do_do_join(count, insert_space)
     long    count;
     int	    insert_space;
 {
-    colnr_T	col = MAXCOL;
+    char_u	*curr, *cend;
+    char_u	*newp;
+    char_u	*spaces;	/* array of spaces added between lines */
+    int		endcurr1, endcurr2;
+    int		currsize;	/* size of the current line */
+    int		sumsize=0;	/* size of the new (big) line */
+    linenr_T	t;
+    colnr_T	col = 0;
 
     if (u_save((linenr_T)(curwin->w_cursor.lnum - 1),
 		    (linenr_T)(curwin->w_cursor.lnum + count)) == FAIL)
-	return;
-
-    while (--count > 0)
-    {
-	line_breakcheck();
-	if (got_int || do_join(insert_space) == FAIL)
-	{
-	    beep_flush();
-	    break;
-	}
-	if (col == MAXCOL && vim_strchr(p_cpo, CPO_JOINCOL) != NULL)
-	    col = curwin->w_cursor.col;
-    }
+	return FAIL;
 
-    /* Vi compatible: use the column of the first join */
-    if (col != MAXCOL && vim_strchr(p_cpo, CPO_JOINCOL) != NULL)
-	curwin->w_cursor.col = col;
+    spaces=lalloc_clear((long_u)count,TRUE);
+    if(spaces==NUL)
+	return FAIL;
 
-#if 0
     /*
-     * Need to update the screen if the line where the cursor is became too
-     * long to fit on the screen.
+     * Don't move anything, just compute the final line length
+     * and setup the array of space strings lengths
      */
-    update_topline_redraw();
-#endif
-}
-
-/*
- * Join two lines at the cursor position.
- * "redraw" is TRUE when the screen should be updated.
- * Caller must have setup for undo.
- *
- * return FAIL for failure, OK otherwise
- */
-    int
-do_join(insert_space)
-    int		insert_space;
-{
-    char_u	*curr;
-    char_u	*next, *next_start;
-    char_u	*newp;
-    int		endcurr1, endcurr2;
-    int		currsize;	/* size of the current line */
-    int		nextsize;	/* size of the next line */
-    int		spaces;		/* number of spaces to insert */
-    linenr_T	t;
-
-    if (curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count)
-	return FAIL;		/* can't join on last line */
-
-    curr = ml_get_curline();
-    currsize = (int)STRLEN(curr);
-    endcurr1 = endcurr2 = NUL;
-    if (insert_space && currsize > 0)
+    for (t=0;t<count;t++)
     {
-#ifdef FEAT_MBYTE
-	if (has_mbyte)
+	curr = ml_get((linenr_T)(curwin->w_cursor.lnum + t));
+	if (insert_space && t>0)
 	{
-	    next = curr + currsize;
-	    mb_ptr_back(curr, next);
-	    endcurr1 = (*mb_ptr2char)(next);
-	    if (next > curr)
+	    curr = skipwhite(curr);
+	    if (*curr != ')' && currsize != 0 && endcurr1 != TAB
+#ifdef FEAT_MBYTE
+		    && (!has_format_option(FO_MBYTE_JOIN)
+			|| (mb_ptr2char(curr) < 0x100 && endcurr1 < 0x100))
+		    && (!has_format_option(FO_MBYTE_JOIN2)
+			|| mb_ptr2char(curr) < 0x100 || endcurr1 < 0x100)
+#endif
+	       )
 	    {
-		mb_ptr_back(curr, next);
-		endcurr2 = (*mb_ptr2char)(next);
+		/* don't add a space if the line is ending in a space */
+		if (endcurr1 == ' ')
+		    endcurr1 = endcurr2;
+		else
+		    ++spaces[t];
+		/* extra space when 'joinspaces' set and line ends in '.' */
+		if (       p_js
+			&& (endcurr1 == '.'
+			    || (vim_strchr(p_cpo, CPO_JOINSP) == NULL
+				&& (endcurr1 == '?' || endcurr1 == '!'))))
+		    ++spaces[t];
 	    }
 	}
-	else
-#endif
+	currsize = (int)STRLEN(curr);
+	sumsize += currsize + spaces[t];
+	endcurr1 = endcurr2 = NUL;
+	if (insert_space && currsize > 0)
 	{
-	    endcurr1 = *(curr + currsize - 1);
-	    if (currsize > 1)
-		endcurr2 = *(curr + currsize - 2);
-	}
-    }
-
-    next = next_start = ml_get((linenr_T)(curwin->w_cursor.lnum + 1));
-    spaces = 0;
-    if (insert_space)
-    {
-	next = skipwhite(next);
-	if (*next != ')' && currsize != 0 && endcurr1 != TAB
 #ifdef FEAT_MBYTE
-		&& (!has_format_option(FO_MBYTE_JOIN)
-			|| (mb_ptr2char(next) < 0x100 && endcurr1 < 0x100))
-		&& (!has_format_option(FO_MBYTE_JOIN2)
-			|| mb_ptr2char(next) < 0x100 || endcurr1 < 0x100)
-#endif
-		)
-	{
-	    /* don't add a space if the line is ending in a space */
-	    if (endcurr1 == ' ')
-		endcurr1 = endcurr2;
+	    if (has_mbyte)
+	    {
+		cend = curr + currsize;
+		mb_ptr_back(curr, cend);
+		endcurr1 = (*mb_ptr2char)(cend);
+		if (cend > curr)
+		{
+		    mb_ptr_back(curr, cend);
+		    endcurr2 = (*mb_ptr2char)(cend);
+		}
+	    }
 	    else
-		++spaces;
-	    /* extra space when 'joinspaces' set and line ends in '.' */
-	    if (       p_js
-		    && (endcurr1 == '.'
-			|| (vim_strchr(p_cpo, CPO_JOINSP) == NULL
-			    && (endcurr1 == '?' || endcurr1 == '!'))))
-		++spaces;
+#endif
+	    {
+		endcurr1 = *(curr + currsize - 1);
+		if (currsize > 1)
+		    endcurr2 = *(curr + currsize - 2);
+	    }
 	}
     }
-    nextsize = (int)STRLEN(next);
 
-    newp = alloc_check((unsigned)(currsize + nextsize + spaces + 1));
-    if (newp == NULL)
-	return FAIL;
+    /* store the column position before last line */
+    col = sumsize - currsize - spaces[count-1];
+
+    newp = alloc_check((unsigned)(sumsize + 1));
+    cend = newp+sumsize;
+    *cend=0;
 
     /*
-     * Insert the next line first, because we already have that pointer.
-     * Curr has to be obtained again, because getting next will have
-     * invalidated it.
+     * Finally move affected lines to the new long one
      */
-    mch_memmove(newp + currsize + spaces, next, (size_t)(nextsize + 1));
-
-    curr = ml_get_curline();
-    mch_memmove(newp, curr, (size_t)currsize);
-
-    copy_spaces(newp + currsize, (size_t)spaces);
+    for(t=count-1;;t--)
+    {
+	cend -= (currsize + spaces[t]);
+	mch_memmove(cend + spaces[t], curr, (size_t)currsize);
+	if (spaces[t])
+	    copy_spaces(cend, (size_t)(spaces[t]));
+	/*
+	 * Move marks from the deleted line to the joined line, adjusting the
+	 * column.  This is not Vi compatible, but Vi deletes the marks, thus that
+	 * should not really be a problem.
+	 */
+	mark_col_adjust(curwin->w_cursor.lnum + t, (colnr_T)0, (linenr_T)-t,
+				 (long)(cend - newp + spaces[t]));
+	if(t == 0)
+	    break;
+	curr = ml_get((linenr_T)(curwin->w_cursor.lnum + t - 1));
+	if (insert_space && t>1)
+	    curr = skipwhite(curr);
+	currsize = (int)STRLEN(curr);
+    }
+    mch_memmove(cend, curr, (size_t)currsize);
 
     ml_replace(curwin->w_cursor.lnum, newp, FALSE);
 
@@ -4243,34 +4226,55 @@ do_join(insert_space)
 					       curwin->w_cursor.lnum + 1, 0L);
 
     /*
-     * Delete the following line. To do this we move the cursor there
+     * Delete following lines. To do this we move the cursor there
      * briefly, and then move it back. After del_lines() the cursor may
      * have moved up (last line deleted), so the current lnum is kept in t.
-     *
-     * Move marks from the deleted line to the joined line, adjusting the
-     * column.  This is not Vi compatible, but Vi deletes the marks, thus that
-     * should not really be a problem.
      */
     t = curwin->w_cursor.lnum;
-    mark_col_adjust(t + 1, (colnr_T)0, (linenr_T)-1,
-			     (long)(currsize + spaces - (next - next_start)));
     ++curwin->w_cursor.lnum;
-    del_lines(1L, FALSE);
+    del_lines(count - 1, FALSE);
     curwin->w_cursor.lnum = t;
 
     /*
-     * go to first character of the joined line
+     * Cursor column setting
+     * Vi compatible: use the column of the first join
+     * vim: use the column of the last join
      */
-    curwin->w_cursor.col = currsize;
+    curwin->w_cursor.col =
+	( vim_strchr(p_cpo, CPO_JOINCOL) != NULL ? currsize : col );
     check_cursor_col();
+    
 #ifdef FEAT_VIRTUALEDIT
     curwin->w_cursor.coladd = 0;
 #endif
     curwin->w_set_curswant = TRUE;
+#if 0
+    /*
+     * Need to update the screen if the line where the cursor is became too
+     * long to fit on the screen.
+     */
+    update_topline_redraw();
+#endif
+
+    vim_free(spaces);
 
     return OK;
 }
 
+/*
+ * Join two lines at the cursor position.
+ * "redraw" is TRUE when the screen should be updated.
+ * Caller must have setup for undo.
+ *
+ * return FAIL for failure, OK otherwise
+ */
+    int
+do_join(insert_space)
+    int		insert_space;
+{
+    return do_do_join(2,insert_space);
+}
+
 #ifdef FEAT_COMMENTS
 /*
  * Return TRUE if the two comment leaders given are the same.  "lnum" is
diff --git a/src/proto/ops.pro b/src/proto/ops.pro
index 37c3194..1e89509 100644
--- a/src/proto/ops.pro
+++ b/src/proto/ops.pro
@@ -36,7 +36,7 @@ void adjust_cursor_eol __ARGS((void));
 int preprocs_left __ARGS((void));
 int get_register_name __ARGS((int num));
 void ex_display __ARGS((exarg_T *eap));
-void do_do_join __ARGS((long count, int insert_space));
+int do_do_join __ARGS((long count, int insert_space));
 int do_join __ARGS((int insert_space));
 void op_format __ARGS((oparg_T *oap, int keep_cursor));
 void op_formatexpr __ARGS((oparg_T *oap));
>From c461f7789338ae703b9ced7e5b80299081d90a15 Mon Sep 17 00:00:00 2001
From: mvancura <[email protected]>
Date: Tue, 23 Dec 2008 17:15:18 +0100
Subject: [PATCH] The duality do_join() + do_do_join() removed. Only one function do_join
 accepting number of lines to join is here now.


diff --git a/src/edit.c b/src/edit.c
index 714d320..3d82eac 100644
--- a/src/edit.c
+++ b/src/edit.c
@@ -8206,7 +8206,7 @@ ins_del()
 	if (!can_bs(BS_EOL)		/* only if "eol" included */
 		|| u_save((linenr_T)(curwin->w_cursor.lnum - 1),
 		    (linenr_T)(curwin->w_cursor.lnum + 2)) == FAIL
-		|| do_join(FALSE) == FAIL)
+		|| do_join(2,FALSE) == FAIL)
 	    vim_beep();
 	else
 	    curwin->w_cursor.col = temp;
@@ -8386,7 +8386,7 @@ ins_bs(c, mode, inserted_space_p)
 			ptr[len - 1] = NUL;
 		}
 
-		(void)do_join(FALSE);
+		(void)do_join(2,FALSE);
 		if (temp == NUL && gchar_cursor() != NUL)
 		    inc_cursor();
 	    }
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
index b060e63..1fba98e 100644
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -8282,7 +8282,7 @@ ex_join(eap)
 	}
 	++eap->line2;
     }
-    do_do_join(eap->line2 - eap->line1 + 1, !eap->forceit);
+    do_join(eap->line2 - eap->line1 + 1, !eap->forceit);
     beginline(BL_WHITE | BL_FIX);
     ex_may_print(eap);
 }
diff --git a/src/normal.c b/src/normal.c
index 0557833..a7124af 100644
--- a/src/normal.c
+++ b/src/normal.c
@@ -1912,7 +1912,7 @@ do_pending_operator(cap, old_col, gui_yank)
 		beep_flush();
 	    else
 	    {
-		do_do_join(oap->line_count, oap->op_type == OP_JOIN);
+		do_join(oap->line_count, oap->op_type == OP_JOIN);
 		auto_format(FALSE, TRUE);
 	    }
 	    break;
@@ -9082,7 +9082,7 @@ nv_join(cap)
 	{
 	    prep_redo(cap->oap->regname, cap->count0,
 			 NUL, cap->cmdchar, NUL, NUL, cap->nchar);
-	    do_do_join(cap->count0, cap->nchar == NUL);
+	    do_join(cap->count0, cap->nchar == NUL);
 	}
     }
 }
diff --git a/src/ops.c b/src/ops.c
index 6ab83fc..dc4f81d 100644
--- a/src/ops.c
+++ b/src/ops.c
@@ -1919,7 +1919,7 @@ op_delete(oap)
 							    );
 	    curwin->w_cursor = curpos;		/* restore curwin->w_cursor */
 
-	    (void)do_join(FALSE);
+	    (void)do_join(2,FALSE);
 	}
     }
 
@@ -4104,9 +4104,13 @@ dis_msg(p, skip_esc)
 
 /*
  * join 'count' lines (minimal 2), including u_save()
+ * "redraw" is TRUE when the screen should be updated.
+ * Caller must have setup for undo.
+ *
+ * return FAIL for failure, OK otherwise
  */
     int
-do_do_join(count, insert_space)
+do_join(count, insert_space)
     long    count;
     int	    insert_space;
 {
@@ -4261,20 +4265,6 @@ do_do_join(count, insert_space)
     return OK;
 }
 
-/*
- * Join two lines at the cursor position.
- * "redraw" is TRUE when the screen should be updated.
- * Caller must have setup for undo.
- *
- * return FAIL for failure, OK otherwise
- */
-    int
-do_join(insert_space)
-    int		insert_space;
-{
-    return do_do_join(2,insert_space);
-}
-
 #ifdef FEAT_COMMENTS
 /*
  * Return TRUE if the two comment leaders given are the same.  "lnum" is
@@ -4708,7 +4698,7 @@ format_lines(line_count, avoid_fex)
 						      (long)-next_leader_len);
 #endif
 		curwin->w_cursor.lnum--;
-		if (do_join(TRUE) == FAIL)
+		if (do_join(2,TRUE) == FAIL)
 		{
 		    beep_flush();
 		    break;
diff --git a/src/proto/ops.pro b/src/proto/ops.pro
index 1e89509..fc1d471 100644
--- a/src/proto/ops.pro
+++ b/src/proto/ops.pro
@@ -36,8 +36,7 @@ void adjust_cursor_eol __ARGS((void));
 int preprocs_left __ARGS((void));
 int get_register_name __ARGS((int num));
 void ex_display __ARGS((exarg_T *eap));
-int do_do_join __ARGS((long count, int insert_space));
-int do_join __ARGS((int insert_space));
+int do_join __ARGS((long count, int insert_space));
 void op_format __ARGS((oparg_T *oap, int keep_cursor));
 void op_formatexpr __ARGS((oparg_T *oap));
 int fex_format __ARGS((linenr_T lnum, long count, int c));

Raspunde prin e-mail lui