mirror of
https://github.com/vim/vim.git
synced 2025-09-30 04:44:14 -04:00
updated for version 7.0051
This commit is contained in:
186
src/undo.c
186
src/undo.c
@@ -41,24 +41,33 @@
|
||||
* curbuf->b_u_curhead points to the header of the last undo (the next redo),
|
||||
* or is NULL if nothing has been undone.
|
||||
*
|
||||
* All data is allocated with u_alloc_line(), thus it will be freed as soon as
|
||||
* we switch files!
|
||||
* All data is allocated with U_ALLOC_LINE(), it will be freed as soon as the
|
||||
* buffer is unloaded.
|
||||
*/
|
||||
|
||||
#include "vim.h"
|
||||
|
||||
/* See below: use malloc()/free() for memory management. */
|
||||
#define U_USE_MALLOC 1
|
||||
|
||||
static u_entry_T *u_get_headentry __ARGS((void));
|
||||
static void u_getbot __ARGS((void));
|
||||
static int u_savecommon __ARGS((linenr_T, linenr_T, linenr_T));
|
||||
static void u_doit __ARGS((int count));
|
||||
static void u_undoredo __ARGS((void));
|
||||
static void u_undo_end __ARGS((void));
|
||||
static void u_freelist __ARGS((struct u_header *));
|
||||
static void u_freelist __ARGS((buf_T *buf, struct u_header *));
|
||||
static void u_freeentry __ARGS((u_entry_T *, long));
|
||||
|
||||
static char_u *u_blockalloc __ARGS((long_u));
|
||||
static void u_free_line __ARGS((char_u *, int keep));
|
||||
static char_u *u_alloc_line __ARGS((unsigned));
|
||||
#ifdef U_USE_MALLOC
|
||||
# define U_FREE_LINE(ptr) vim_free(ptr)
|
||||
# define U_ALLOC_LINE(size) lalloc((long_u)((size) + 1), FALSE)
|
||||
#else
|
||||
static void u_free_line __ARGS((char_u *ptr, int keep));
|
||||
static char_u *u_alloc_line __ARGS((unsigned size));
|
||||
# define U_FREE_LINE(ptr) u_free_line((ptr), FALSE)
|
||||
# define U_ALLOC_LINE(size) u_alloc_line(size)
|
||||
#endif
|
||||
static char_u *u_save_line __ARGS((linenr_T));
|
||||
|
||||
static long u_newcount, u_oldcount;
|
||||
@@ -227,13 +236,13 @@ u_savecommon(top, bot, newbot)
|
||||
* including curbuf->b_u_curhead
|
||||
*/
|
||||
while (curbuf->b_u_curhead != NULL)
|
||||
u_freelist(curbuf->b_u_newhead);
|
||||
u_freelist(curbuf, curbuf->b_u_newhead);
|
||||
|
||||
/*
|
||||
* free headers to keep the size right
|
||||
*/
|
||||
while (curbuf->b_u_numhead > p_ul && curbuf->b_u_oldhead != NULL)
|
||||
u_freelist(curbuf->b_u_oldhead);
|
||||
u_freelist(curbuf, curbuf->b_u_oldhead);
|
||||
|
||||
if (p_ul < 0) /* no undo at all */
|
||||
{
|
||||
@@ -244,7 +253,7 @@ u_savecommon(top, bot, newbot)
|
||||
/*
|
||||
* make a new header entry
|
||||
*/
|
||||
uhp = (struct u_header *)u_alloc_line((unsigned)
|
||||
uhp = (struct u_header *)U_ALLOC_LINE((unsigned)
|
||||
sizeof(struct u_header));
|
||||
if (uhp == NULL)
|
||||
goto nomem;
|
||||
@@ -364,7 +373,7 @@ u_savecommon(top, bot, newbot)
|
||||
/*
|
||||
* add lines in front of entry list
|
||||
*/
|
||||
uep = (u_entry_T *)u_alloc_line((unsigned)sizeof(u_entry_T));
|
||||
uep = (u_entry_T *)U_ALLOC_LINE((unsigned)sizeof(u_entry_T));
|
||||
if (uep == NULL)
|
||||
goto nomem;
|
||||
|
||||
@@ -384,9 +393,9 @@ u_savecommon(top, bot, newbot)
|
||||
curbuf->b_u_newhead->uh_getbot_entry = uep;
|
||||
}
|
||||
|
||||
if (size)
|
||||
if (size > 0)
|
||||
{
|
||||
if ((uep->ue_array = (char_u **)u_alloc_line(
|
||||
if ((uep->ue_array = (char_u **)U_ALLOC_LINE(
|
||||
(unsigned)(sizeof(char_u *) * size))) == NULL)
|
||||
{
|
||||
u_freeentry(uep, 0L);
|
||||
@@ -609,9 +618,9 @@ u_undoredo()
|
||||
empty_buffer = FALSE;
|
||||
|
||||
/* delete the lines between top and bot and save them in newarray */
|
||||
if (oldsize)
|
||||
if (oldsize > 0)
|
||||
{
|
||||
if ((newarray = (char_u **)u_alloc_line(
|
||||
if ((newarray = (char_u **)U_ALLOC_LINE(
|
||||
(unsigned)(sizeof(char_u *) * oldsize))) == NULL)
|
||||
{
|
||||
do_outofmem_msg((long_u)(sizeof(char_u *) * oldsize));
|
||||
@@ -654,9 +663,9 @@ u_undoredo()
|
||||
ml_replace((linenr_T)1, uep->ue_array[i], TRUE);
|
||||
else
|
||||
ml_append(lnum, uep->ue_array[i], (colnr_T)0, FALSE);
|
||||
u_free_line(uep->ue_array[i], FALSE);
|
||||
U_FREE_LINE(uep->ue_array[i]);
|
||||
}
|
||||
u_free_line((char_u *)uep->ue_array, FALSE);
|
||||
U_FREE_LINE((char_u *)uep->ue_array);
|
||||
}
|
||||
|
||||
/* adjust marks */
|
||||
@@ -870,7 +879,8 @@ u_getbot()
|
||||
* u_freelist: free one entry list and adjust the pointers
|
||||
*/
|
||||
static void
|
||||
u_freelist(uhp)
|
||||
u_freelist(buf, uhp)
|
||||
buf_T *buf;
|
||||
struct u_header *uhp;
|
||||
{
|
||||
u_entry_T *uep, *nuep;
|
||||
@@ -881,21 +891,21 @@ u_freelist(uhp)
|
||||
u_freeentry(uep, uep->ue_size);
|
||||
}
|
||||
|
||||
if (curbuf->b_u_curhead == uhp)
|
||||
curbuf->b_u_curhead = NULL;
|
||||
if (buf->b_u_curhead == uhp)
|
||||
buf->b_u_curhead = NULL;
|
||||
|
||||
if (uhp->uh_next == NULL)
|
||||
curbuf->b_u_oldhead = uhp->uh_prev;
|
||||
buf->b_u_oldhead = uhp->uh_prev;
|
||||
else
|
||||
uhp->uh_next->uh_prev = uhp->uh_prev;
|
||||
|
||||
if (uhp->uh_prev == NULL)
|
||||
curbuf->b_u_newhead = uhp->uh_next;
|
||||
buf->b_u_newhead = uhp->uh_next;
|
||||
else
|
||||
uhp->uh_prev->uh_next = uhp->uh_next;
|
||||
|
||||
u_free_line((char_u *)uhp, FALSE);
|
||||
--curbuf->b_u_numhead;
|
||||
U_FREE_LINE((char_u *)uhp);
|
||||
--buf->b_u_numhead;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -907,8 +917,8 @@ u_freeentry(uep, n)
|
||||
long n;
|
||||
{
|
||||
while (n)
|
||||
u_free_line(uep->ue_array[--n], FALSE);
|
||||
u_free_line((char_u *)uep, FALSE);
|
||||
U_FREE_LINE(uep->ue_array[--n]);
|
||||
U_FREE_LINE((char_u *)uep);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -955,7 +965,7 @@ u_clearline()
|
||||
{
|
||||
if (curbuf->b_u_line_ptr != NULL)
|
||||
{
|
||||
u_free_line(curbuf->b_u_line_ptr, FALSE);
|
||||
U_FREE_LINE(curbuf->b_u_line_ptr);
|
||||
curbuf->b_u_line_ptr = NULL;
|
||||
curbuf->b_u_line_lnum = 0;
|
||||
}
|
||||
@@ -993,7 +1003,7 @@ u_undoline()
|
||||
}
|
||||
ml_replace(curbuf->b_u_line_lnum, curbuf->b_u_line_ptr, TRUE);
|
||||
changed_bytes(curbuf->b_u_line_lnum, 0);
|
||||
u_free_line(curbuf->b_u_line_ptr, FALSE);
|
||||
U_FREE_LINE(curbuf->b_u_line_ptr);
|
||||
curbuf->b_u_line_ptr = oldp;
|
||||
|
||||
t = curbuf->b_u_line_colnr;
|
||||
@@ -1004,7 +1014,40 @@ u_undoline()
|
||||
}
|
||||
|
||||
/*
|
||||
* storage allocation for the undo lines and blocks of the current file
|
||||
* There are two implementations of the memory management for undo:
|
||||
* 1. Use the standard malloc()/free() functions.
|
||||
* This should be fast for allocating memory, but when a buffer is
|
||||
* abandoned every single allocated chunk must be freed, which may be slow.
|
||||
* 2. Allocate larger blocks of memory and keep track of chunks ourselves.
|
||||
* This is fast for abandoning, but the use of linked lists is slow for
|
||||
* finding a free chunk. Esp. when a lot of lines are changed or deleted.
|
||||
* A bit of profiling showed that the first method is faster, especially when
|
||||
* making a large number of changes, under the condition that malloc()/free()
|
||||
* is implemented efficiently.
|
||||
*/
|
||||
#ifdef U_USE_MALLOC
|
||||
/*
|
||||
* Version of undo memory allocation using malloc()/free()
|
||||
*
|
||||
* U_FREE_LINE() and U_ALLOC_LINE() are macros that invoke vim_free() and
|
||||
* lalloc() directly.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Free all allocated memory blocks for the buffer 'buf'.
|
||||
*/
|
||||
void
|
||||
u_blockfree(buf)
|
||||
buf_T *buf;
|
||||
{
|
||||
while (buf->b_u_newhead != NULL)
|
||||
u_freelist(buf, buf->b_u_newhead);
|
||||
}
|
||||
|
||||
#else
|
||||
/*
|
||||
* Storage allocation for the undo lines and blocks of the current file.
|
||||
* Version where Vim keeps track of the available memory.
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -1071,6 +1114,8 @@ u_undoline()
|
||||
# define M_OFFSET (sizeof(short_u))
|
||||
#endif
|
||||
|
||||
static char_u *u_blockalloc __ARGS((long_u));
|
||||
|
||||
/*
|
||||
* Allocate a block of memory and link it in the allocated block list.
|
||||
*/
|
||||
@@ -1092,6 +1137,7 @@ u_blockalloc(size)
|
||||
;
|
||||
p->mb_next = next; /* link in block list */
|
||||
p->mb_size = size;
|
||||
p->mb_maxsize = 0; /* nothing free yet */
|
||||
mp->mb_next = p;
|
||||
p->mb_info.m_next = NULL; /* clear free list */
|
||||
p->mb_info.m_size = 0;
|
||||
@@ -1135,6 +1181,7 @@ u_free_line(ptr, keep)
|
||||
minfo_T *mp;
|
||||
mblock_T *nextb;
|
||||
mblock_T *prevb;
|
||||
long_u maxsize;
|
||||
|
||||
if (ptr == NULL || ptr == IObuff)
|
||||
return; /* illegal address can happen in out-of-memory situations */
|
||||
@@ -1212,11 +1259,13 @@ u_free_line(ptr, keep)
|
||||
}
|
||||
else
|
||||
mp->m_next = next;
|
||||
maxsize = mp->m_size;
|
||||
|
||||
/* if *curr and *mp are concatenated, join them */
|
||||
if (prev != NULL && (char_u *)curr + curr->m_size == (char_u *)mp)
|
||||
{
|
||||
curr->m_size += mp->m_size;
|
||||
maxsize = curr->m_size;
|
||||
curr->m_next = mp->m_next;
|
||||
curbuf->b_m_search = prev;
|
||||
}
|
||||
@@ -1244,6 +1293,8 @@ u_free_line(ptr, keep)
|
||||
curbuf->b_mb_current = NULL;
|
||||
curbuf->b_m_search = NULL;
|
||||
}
|
||||
else if (curbuf->b_mb_current->mb_maxsize < maxsize)
|
||||
curbuf->b_mb_current->mb_maxsize = maxsize;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1282,48 +1333,56 @@ u_alloc_line(size)
|
||||
curbuf->b_m_search = &(curbuf->b_block_head.mb_info);
|
||||
}
|
||||
|
||||
/* search for space in free list */
|
||||
mprev = curbuf->b_m_search;
|
||||
/* Search for a block with enough space. */
|
||||
mbp = curbuf->b_mb_current;
|
||||
mp = curbuf->b_m_search->m_next;
|
||||
if (mp == NULL)
|
||||
while (mbp->mb_maxsize < size_align)
|
||||
{
|
||||
if (mbp->mb_next)
|
||||
if (mbp->mb_next != NULL)
|
||||
mbp = mbp->mb_next;
|
||||
else
|
||||
mbp = &curbuf->b_block_head;
|
||||
mp = curbuf->b_m_search = &(mbp->mb_info);
|
||||
}
|
||||
while (mp->m_size < size)
|
||||
{
|
||||
if (mp == curbuf->b_m_search) /* back where we started in free
|
||||
chunk list */
|
||||
if (mbp == curbuf->b_mb_current)
|
||||
{
|
||||
if (mbp->mb_next)
|
||||
mbp = mbp->mb_next;
|
||||
else
|
||||
mbp = &curbuf->b_block_head;
|
||||
mp = curbuf->b_m_search = &(mbp->mb_info);
|
||||
if (mbp == curbuf->b_mb_current) /* back where we started in
|
||||
block list */
|
||||
{
|
||||
int n = (size_align > (MEMBLOCKSIZE / 4)
|
||||
? size_align : MEMBLOCKSIZE);
|
||||
int n = (size_align > (MEMBLOCKSIZE / 4)
|
||||
? size_align : MEMBLOCKSIZE);
|
||||
|
||||
mp = (minfo_T *)u_blockalloc((long_u)n);
|
||||
if (mp == NULL)
|
||||
return (NULL);
|
||||
mp->m_size = n;
|
||||
u_free_line((char_u *)mp + M_OFFSET, TRUE);
|
||||
mp = curbuf->b_m_search;
|
||||
mbp = curbuf->b_mb_current;
|
||||
}
|
||||
/* Back where we started in block list: need to add a new block
|
||||
* with enough space. */
|
||||
mp = (minfo_T *)u_blockalloc((long_u)n);
|
||||
if (mp == NULL)
|
||||
return (NULL);
|
||||
mp->m_size = n;
|
||||
u_free_line((char_u *)mp + M_OFFSET, TRUE);
|
||||
mbp = curbuf->b_mb_current;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (mbp != curbuf->b_mb_current)
|
||||
curbuf->b_m_search = &(mbp->mb_info);
|
||||
|
||||
/* In this block find a chunk with enough space. */
|
||||
mprev = curbuf->b_m_search;
|
||||
mp = curbuf->b_m_search->m_next;
|
||||
while (1)
|
||||
{
|
||||
if (mp == NULL) /* at end of the list */
|
||||
mp = &(mbp->mb_info); /* wrap around to begin */
|
||||
if (mp->m_size >= size)
|
||||
break;
|
||||
if (mp == curbuf->b_m_search)
|
||||
{
|
||||
/* back where we started in free chunk list: "cannot happen" */
|
||||
EMSG2(_(e_intern2), "u_alloc_line()");
|
||||
return NULL;
|
||||
}
|
||||
mprev = mp;
|
||||
if ((mp = mp->m_next) == NULL) /* at end of the list */
|
||||
mp = &(mbp->mb_info); /* wrap around to begin */
|
||||
mp = mp->m_next;
|
||||
}
|
||||
|
||||
/* when using the largest chunk adjust mb_maxsize */
|
||||
if (mp->m_size >= mbp->mb_maxsize)
|
||||
mbp->mb_maxsize = 0;
|
||||
|
||||
/* if the chunk we found is large enough, split it up in two */
|
||||
if ((long)mp->m_size - size_align >= (long)(sizeof(minfo_T) + 1))
|
||||
{
|
||||
@@ -1340,11 +1399,18 @@ u_alloc_line(size)
|
||||
curbuf->b_m_search = mprev;
|
||||
curbuf->b_mb_current = mbp;
|
||||
|
||||
/* If using the largest chunk need to find the new largest chunk */
|
||||
if (mbp->mb_maxsize == 0)
|
||||
for (mp2 = &(mbp->mb_info); mp2 != NULL; mp2 = mp2->m_next)
|
||||
if (mbp->mb_maxsize < mp2->m_size)
|
||||
mbp->mb_maxsize = mp2->m_size;
|
||||
|
||||
mp = (minfo_T *)((char_u *)mp + M_OFFSET);
|
||||
*(char_u *)mp = NUL; /* set the first byte to NUL */
|
||||
|
||||
return ((char_u *)mp);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* u_save_line(): allocate memory with u_alloc_line() and copy line 'lnum'
|
||||
@@ -1360,7 +1426,7 @@ u_save_line(lnum)
|
||||
|
||||
src = ml_get(lnum);
|
||||
len = (unsigned)STRLEN(src);
|
||||
if ((dst = u_alloc_line(len)) != NULL)
|
||||
if ((dst = U_ALLOC_LINE(len)) != NULL)
|
||||
mch_memmove(dst, src, (size_t)(len + 1));
|
||||
return (dst);
|
||||
}
|
||||
|
Reference in New Issue
Block a user