On 16/08/06, Brad Beveridge <[EMAIL PROTECTED]> wrote:
On 16/08/06, Bram Moolenaar <[EMAIL PROTECTED]> wrote:
>
> Brad -
>
> > As a side note, if I wanted to get really fast char append, how does
> > this method sound:
> > 1) In a structure (not sure if a mem_line or bufT struct), have three
> > new entries
> > uint current_line_num;
> > uchar *current_line_buffer;
> > uint current_line_alloced;
> > 2) current_line_buffer points to the string data for the current line,
> > it starts off at a sane size (say 80, or screen_width), and doubles in
> > alloced size when it is too full.
> > 3) ml_append_char (or whatever I call it), will check the target line
> > number against current_line_number, if the match then
> > - append the char, possibly reallocing the current_line_buffer if we
> > have run out of space
> > ELSE, the edit line number and our "cached line" don't match
> > - trim the size of the current_line_buffer to match the STRLEN of the line
> > - alloc a new oversized line buffer and copy the new edit line into it
> > - append the char as above
>
> Vim caches the last changed line, you could do something with that.
> Start looking at ml_flush_line(), you can find the rest from there.
>
> > Would this kind of optimisation be more widely useful?
>
> Perhaps. Changing the same line several times is not unusual. It
> mostly depends on how much code would need to be changed compared to
> how much we would gain.
>
> - Bram
>
Thanks for the tips, I'll test all this out and see what I can come up
with. I also accidentally posted just to Bram, so I've included the
list in this reply.
Thanks
Brad
I ended up writing a string append function, that has sped up my
output code by a couple of orders of magnitude :) Here it is, does it
look sane?
Cheers
Brad
/*
* Append string to line lnum, with buffering, in current buffer.
*
* Always makes a copy of the incoming string
*
* Check: The caller of this function should probably also call
* changed_lines(), unless update_screen(NOT_VALID) is used.
*
* return FAIL for failure, OK otherwise
*/
int
ml_append_string(lnum, string, slen)
linenr_T lnum;
char_u *string;
int slen;
{
int append_len = 0;
int line_len = 0;
if (slen == -1)
append_len = STRLEN(string);
else
append_len = slen;
if (string == NULL) /* just checking... */
return FAIL;
if (lnum == 0)
ml_append (lnum, string, slen, 0);
/* When starting up, we might still need to create the memfile */
if (curbuf->b_ml.ml_mfp == NULL && open_buffer(FALSE, NULL) == FAIL)
return FAIL;
#ifdef FEAT_NETBEANS_INTG
/*
#error I am 99% sure this is broken
if (usingNetbeans)
{
netbeans_removed(curbuf, lnum, 0, (long)STRLEN(ml_get(lnum)));
netbeans_inserted(curbuf, lnum, 0, string, (int)STRLEN(string));
}
*/
#endif
if (curbuf->b_ml.ml_line_lnum != lnum) /* other line buffered */
{
ml_flush_line(curbuf); /* flush it, this frees
ml_line_ptr */
/* Take a pointer to the existing line, will get re-alloced right
* away below because it is not big enough */
curbuf->b_ml.ml_line_ptr = vim_strsave(ml_get(lnum));
curbuf->b_ml.ml_line_len = STRLEN(curbuf->b_ml.ml_line_ptr);
curbuf->b_ml.ml_line_lnum = lnum;
}
/* By here,
* curbuf->b_ml.ml_line_ptr - is filled with the correct existing line
* curbuf->b_ml.ml_line_len - is the alloced size of the line
*/
line_len = STRLEN(curbuf->b_ml.ml_line_ptr);
if (curbuf->b_ml.ml_line_len < line_len + append_len + 1)
{
int new_len = (curbuf->b_ml.ml_line_len + line_len + 1) * 2;
char_u *new_line;
if (new_len < 80) new_len = 80;
new_line = vim_strnsave(curbuf->b_ml.ml_line_ptr, new_len);
vim_free(curbuf->b_ml.ml_line_ptr);
curbuf->b_ml.ml_line_ptr = new_line;
curbuf->b_ml.ml_line_len = new_len;
}
/* by here:
* ml_line_ptr is allocated to fit the current line + the append
* ml_line_len is the total alloced size of the line
*/
STRCPY (&curbuf->b_ml.ml_line_ptr[line_len], string); /* Append
our string */
curbuf->b_ml.ml_line_ptr[line_len + append_len] = NUL; /* End the line */
curbuf->b_ml.ml_flags = (curbuf->b_ml.ml_flags | ML_LINE_DIRTY) & ~ML_EMPTY;
return OK;
}