diff options
author | Paul Eggert <eggert@Penguin.CS.UCLA.EDU> | 2020-01-17 23:59:51 -0800 |
---|---|---|
committer | Paul Eggert <eggert@cs.ucla.edu> | 2020-01-18 00:02:12 -0800 |
commit | c1b6d5c5b9f8eee8aa3a8071292e8b3281ecf28a (patch) | |
tree | f484fd77b1eec8659d17531c39e1bff1301c5b33 /src/alloc.c | |
parent | bce3d89a6042da8830199d912c3b26aefaf7288c (diff) | |
download | emacs-c1b6d5c5b9f8eee8aa3a8071292e8b3281ecf28a.tar.gz |
Improve performance when a string's byte count changes
* src/alloc.c (allocate_string_data): Now static.
Remove code for when Faset calls this function when S
already has data assigned, as that can no longer happen.
(resize_string_data): New function, which avoids relocation in
more cases than the old code did, by not bothering to relocate
when the size changes falls within the alignment slop.
* src/data.c (Faset): Use resize_string_data.
Change a while to a do-while since it must iterate at least once.
Diffstat (limited to 'src/alloc.c')
-rw-r--r-- | src/alloc.c | 63 |
1 files changed, 46 insertions, 17 deletions
diff --git a/src/alloc.c b/src/alloc.c index 7eb37bb12da..9dc6ef79e39 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -1786,13 +1786,12 @@ allocate_string (void) If CLEARIT, also clear the other bytes of S->u.s.data. */ -void +static void allocate_string_data (struct Lisp_String *s, EMACS_INT nchars, EMACS_INT nbytes, bool clearit) { - sdata *data, *old_data; + sdata *data; struct sblock *b; - ptrdiff_t old_nbytes; if (STRING_BYTES_MAX < nbytes) string_overflow (); @@ -1800,13 +1799,6 @@ allocate_string_data (struct Lisp_String *s, /* Determine the number of bytes needed to store NBYTES bytes of string data. */ ptrdiff_t needed = sdata_size (nbytes); - if (s->u.s.data) - { - old_data = SDATA_OF_STRING (s); - old_nbytes = STRING_BYTES (s); - } - else - old_data = NULL; MALLOC_BLOCK_INPUT; @@ -1875,16 +1867,53 @@ allocate_string_data (struct Lisp_String *s, GC_STRING_OVERRUN_COOKIE_SIZE); #endif - /* Note that Faset may call to this function when S has already data - assigned. In this case, mark data as free by setting it's string - back-pointer to null, and record the size of the data in it. */ - if (old_data) + tally_consing (needed); +} + +/* Reallocate the data for STRING when a single character is replaced. + The character is at byte offset CIDX_BYTE in the string. + The character being replaced is CLEN bytes long, + and the character that will replace it is NEW_CLEN bytes long. + Return the address of where the caller should store the + the new character. */ + +unsigned char * +resize_string_data (Lisp_Object string, ptrdiff_t cidx_byte, + int clen, int new_clen) +{ + sdata *old_sdata = SDATA_OF_STRING (XSTRING (string)); + ptrdiff_t nchars = SCHARS (string); + ptrdiff_t nbytes = SBYTES (string); + ptrdiff_t new_nbytes = nbytes + (new_clen - clen); + unsigned char *data = SDATA (string); + unsigned char *new_charaddr; + + if (sdata_size (nbytes) == sdata_size (new_nbytes)) + { + /* No need to reallocate, as the size change falls within the + alignment slop. */ + new_charaddr = data + cidx_byte; + memmove (new_charaddr + new_clen, new_charaddr + clen, + nbytes - (cidx_byte + (clen - 1))); + } + else { - SDATA_NBYTES (old_data) = old_nbytes; - old_data->string = NULL; + allocate_string_data (XSTRING (string), nchars, new_nbytes, false); + unsigned char *new_data = SDATA (string); + new_charaddr = new_data + cidx_byte; + memcpy (new_charaddr + new_clen, data + cidx_byte + clen, + nbytes - (cidx_byte + clen)); + memcpy (new_data, data, cidx_byte); + + /* Mark old string data as free by setting its string back-pointer + to null, and record the size of the data in it. */ + SDATA_NBYTES (old_sdata) = nbytes; + old_sdata->string = NULL; } - tally_consing (needed); + clear_string_char_byte_cache (); + + return new_charaddr; } |