diff options
| author | Paul Eggert | 2020-08-24 13:12:51 -0700 |
|---|---|---|
| committer | Paul Eggert | 2020-08-24 13:17:48 -0700 |
| commit | e0345b4e86154f42f47a9f7bbbf458a72bf5c06d (patch) | |
| tree | 6c1b31e29066b2effe859d037a57d5c7c9cf442a /src/editfns.c | |
| parent | 08a6d14e4116c74284c12dd1319780afbcbbfd1d (diff) | |
| download | emacs-e0345b4e86154f42f47a9f7bbbf458a72bf5c06d.tar.gz emacs-e0345b4e86154f42f47a9f7bbbf458a72bf5c06d.zip | |
replace-buffer-contents cleanups
* src/editfns.c (NOTE_DELETE, NOTE_INSERT): Avoid unnecessary parens.
(Freplace_buffer_contents): Check args before returning results.
Avoid integer overflow when computing too_expensive, and work even
if MAX-COSTS is bignum. Call alloca and/or malloc just once, not
three times.
(set_bit, bit_is_set): Simplify micro-optimization by using eassume.
Diffstat (limited to 'src/editfns.c')
| -rw-r--r-- | src/editfns.c | 90 |
1 files changed, 46 insertions, 44 deletions
diff --git a/src/editfns.c b/src/editfns.c index a5368c59dad..7e1e24ef16a 100644 --- a/src/editfns.c +++ b/src/editfns.c | |||
| @@ -1900,8 +1900,8 @@ determines whether case is significant or ignored. */) | |||
| 1900 | sys_jmp_buf jmp; \ | 1900 | sys_jmp_buf jmp; \ |
| 1901 | unsigned short quitcounter; | 1901 | unsigned short quitcounter; |
| 1902 | 1902 | ||
| 1903 | #define NOTE_DELETE(ctx, xoff) set_bit ((ctx)->deletions, (xoff)) | 1903 | #define NOTE_DELETE(ctx, xoff) set_bit ((ctx)->deletions, xoff) |
| 1904 | #define NOTE_INSERT(ctx, yoff) set_bit ((ctx)->insertions, (yoff)) | 1904 | #define NOTE_INSERT(ctx, yoff) set_bit ((ctx)->insertions, yoff) |
| 1905 | #define EARLY_ABORT(ctx) compareseq_early_abort (ctx) | 1905 | #define EARLY_ABORT(ctx) compareseq_early_abort (ctx) |
| 1906 | 1906 | ||
| 1907 | struct context; | 1907 | struct context; |
| @@ -1954,6 +1954,28 @@ nil. */) | |||
| 1954 | if (a == b) | 1954 | if (a == b) |
| 1955 | error ("Cannot replace a buffer with itself"); | 1955 | error ("Cannot replace a buffer with itself"); |
| 1956 | 1956 | ||
| 1957 | ptrdiff_t too_expensive; | ||
| 1958 | if (NILP (max_costs)) | ||
| 1959 | too_expensive = 1000000; | ||
| 1960 | else if (FIXNUMP (max_costs)) | ||
| 1961 | too_expensive = clip_to_bounds (0, XFIXNUM (max_costs), PTRDIFF_MAX); | ||
| 1962 | else | ||
| 1963 | { | ||
| 1964 | CHECK_INTEGER (max_costs); | ||
| 1965 | too_expensive = NILP (Fnatnump (max_costs)) ? 0 : PTRDIFF_MAX; | ||
| 1966 | } | ||
| 1967 | |||
| 1968 | struct timespec time_limit = make_timespec (0, -1); | ||
| 1969 | if (!NILP (max_secs)) | ||
| 1970 | { | ||
| 1971 | struct timespec | ||
| 1972 | tlim = timespec_add (current_timespec (), | ||
| 1973 | lisp_time_argument (max_secs)), | ||
| 1974 | tmax = make_timespec (TYPE_MAXIMUM (time_t), TIMESPEC_HZ - 1); | ||
| 1975 | if (timespec_cmp (tlim, tmax) < 0) | ||
| 1976 | time_limit = tlim; | ||
| 1977 | } | ||
| 1978 | |||
| 1957 | ptrdiff_t min_a = BEGV; | 1979 | ptrdiff_t min_a = BEGV; |
| 1958 | ptrdiff_t min_b = BUF_BEGV (b); | 1980 | ptrdiff_t min_b = BUF_BEGV (b); |
| 1959 | ptrdiff_t size_a = ZV - min_a; | 1981 | ptrdiff_t size_a = ZV - min_a; |
| @@ -1983,36 +2005,24 @@ nil. */) | |||
| 1983 | 2005 | ||
| 1984 | ptrdiff_t count = SPECPDL_INDEX (); | 2006 | ptrdiff_t count = SPECPDL_INDEX (); |
| 1985 | 2007 | ||
| 1986 | /* FIXME: It is not documented how to initialize the contents of the | ||
| 1987 | context structure. This code cargo-cults from the existing | ||
| 1988 | caller in src/analyze.c of GNU Diffutils, which appears to | ||
| 1989 | work. */ | ||
| 1990 | 2008 | ||
| 1991 | ptrdiff_t diags = size_a + size_b + 3; | 2009 | ptrdiff_t diags = size_a + size_b + 3; |
| 2010 | ptrdiff_t del_bytes = size_a / CHAR_BIT + 1; | ||
| 2011 | ptrdiff_t ins_bytes = size_b / CHAR_BIT + 1; | ||
| 1992 | ptrdiff_t *buffer; | 2012 | ptrdiff_t *buffer; |
| 2013 | ptrdiff_t bytes_needed; | ||
| 2014 | if (INT_MULTIPLY_WRAPV (diags, 2 * sizeof *buffer, &bytes_needed) | ||
| 2015 | || INT_ADD_WRAPV (del_bytes + ins_bytes, bytes_needed, &bytes_needed)) | ||
| 2016 | memory_full (SIZE_MAX); | ||
| 1993 | USE_SAFE_ALLOCA; | 2017 | USE_SAFE_ALLOCA; |
| 1994 | SAFE_NALLOCA (buffer, 2, diags); | 2018 | buffer = SAFE_ALLOCA (bytes_needed); |
| 2019 | unsigned char *deletions_insertions = memset (buffer + 2 * diags, 0, | ||
| 2020 | del_bytes + ins_bytes); | ||
| 1995 | 2021 | ||
| 1996 | if (NILP (max_costs)) | 2022 | /* FIXME: It is not documented how to initialize the contents of the |
| 1997 | XSETFASTINT (max_costs, 1000000); | 2023 | context structure. This code cargo-cults from the existing |
| 1998 | else | 2024 | caller in src/analyze.c of GNU Diffutils, which appears to |
| 1999 | CHECK_FIXNUM (max_costs); | 2025 | work. */ |
| 2000 | |||
| 2001 | struct timespec time_limit = make_timespec (0, -1); | ||
| 2002 | if (!NILP (max_secs)) | ||
| 2003 | { | ||
| 2004 | struct timespec | ||
| 2005 | tlim = timespec_add (current_timespec (), | ||
| 2006 | lisp_time_argument (max_secs)), | ||
| 2007 | tmax = make_timespec (TYPE_MAXIMUM (time_t), TIMESPEC_HZ - 1); | ||
| 2008 | if (timespec_cmp (tlim, tmax) < 0) | ||
| 2009 | time_limit = tlim; | ||
| 2010 | } | ||
| 2011 | |||
| 2012 | /* Micro-optimization: Casting to size_t generates much better | ||
| 2013 | code. */ | ||
| 2014 | ptrdiff_t del_bytes = (size_t) size_a / CHAR_BIT + 1; | ||
| 2015 | ptrdiff_t ins_bytes = (size_t) size_b / CHAR_BIT + 1; | ||
| 2016 | struct context ctx = { | 2026 | struct context ctx = { |
| 2017 | .buffer_a = a, | 2027 | .buffer_a = a, |
| 2018 | .buffer_b = b, | 2028 | .buffer_b = b, |
| @@ -2020,16 +2030,14 @@ nil. */) | |||
| 2020 | .beg_b = min_b, | 2030 | .beg_b = min_b, |
| 2021 | .a_unibyte = BUF_ZV (a) == BUF_ZV_BYTE (a), | 2031 | .a_unibyte = BUF_ZV (a) == BUF_ZV_BYTE (a), |
| 2022 | .b_unibyte = BUF_ZV (b) == BUF_ZV_BYTE (b), | 2032 | .b_unibyte = BUF_ZV (b) == BUF_ZV_BYTE (b), |
| 2023 | .deletions = SAFE_ALLOCA (del_bytes), | 2033 | .deletions = deletions_insertions, |
| 2024 | .insertions = SAFE_ALLOCA (ins_bytes), | 2034 | .insertions = deletions_insertions + del_bytes, |
| 2025 | .fdiag = buffer + size_b + 1, | 2035 | .fdiag = buffer + size_b + 1, |
| 2026 | .bdiag = buffer + diags + size_b + 1, | 2036 | .bdiag = buffer + diags + size_b + 1, |
| 2027 | .heuristic = true, | 2037 | .heuristic = true, |
| 2028 | .too_expensive = XFIXNUM (max_costs), | 2038 | .too_expensive = too_expensive, |
| 2029 | .time_limit = time_limit, | 2039 | .time_limit = time_limit, |
| 2030 | }; | 2040 | }; |
| 2031 | memclear (ctx.deletions, del_bytes); | ||
| 2032 | memclear (ctx.insertions, ins_bytes); | ||
| 2033 | 2041 | ||
| 2034 | /* compareseq requires indices to be zero-based. We add BEGV back | 2042 | /* compareseq requires indices to be zero-based. We add BEGV back |
| 2035 | later. */ | 2043 | later. */ |
| @@ -2074,8 +2082,8 @@ nil. */) | |||
| 2074 | 2082 | ||
| 2075 | /* Check whether there is a change (insertion or deletion) | 2083 | /* Check whether there is a change (insertion or deletion) |
| 2076 | before the current position. */ | 2084 | before the current position. */ |
| 2077 | if ((i > 0 && bit_is_set (ctx.deletions, i - 1)) || | 2085 | if ((i > 0 && bit_is_set (ctx.deletions, i - 1)) |
| 2078 | (j > 0 && bit_is_set (ctx.insertions, j - 1))) | 2086 | || (j > 0 && bit_is_set (ctx.insertions, j - 1))) |
| 2079 | { | 2087 | { |
| 2080 | ptrdiff_t end_a = min_a + i; | 2088 | ptrdiff_t end_a = min_a + i; |
| 2081 | ptrdiff_t end_b = min_b + j; | 2089 | ptrdiff_t end_b = min_b + j; |
| @@ -2117,21 +2125,15 @@ nil. */) | |||
| 2117 | static void | 2125 | static void |
| 2118 | set_bit (unsigned char *a, ptrdiff_t i) | 2126 | set_bit (unsigned char *a, ptrdiff_t i) |
| 2119 | { | 2127 | { |
| 2120 | eassert (i >= 0); | 2128 | eassume (0 <= i); |
| 2121 | /* Micro-optimization: Casting to size_t generates much better | 2129 | a[i / CHAR_BIT] |= (1 << (i % CHAR_BIT)); |
| 2122 | code. */ | ||
| 2123 | size_t j = i; | ||
| 2124 | a[j / CHAR_BIT] |= (1 << (j % CHAR_BIT)); | ||
| 2125 | } | 2130 | } |
| 2126 | 2131 | ||
| 2127 | static bool | 2132 | static bool |
| 2128 | bit_is_set (const unsigned char *a, ptrdiff_t i) | 2133 | bit_is_set (const unsigned char *a, ptrdiff_t i) |
| 2129 | { | 2134 | { |
| 2130 | eassert (i >= 0); | 2135 | eassume (0 <= i); |
| 2131 | /* Micro-optimization: Casting to size_t generates much better | 2136 | return a[i / CHAR_BIT] & (1 << (i % CHAR_BIT)); |
| 2132 | code. */ | ||
| 2133 | size_t j = i; | ||
| 2134 | return a[j / CHAR_BIT] & (1 << (j % CHAR_BIT)); | ||
| 2135 | } | 2137 | } |
| 2136 | 2138 | ||
| 2137 | /* Return true if the characters at position POS_A of buffer | 2139 | /* Return true if the characters at position POS_A of buffer |