aboutsummaryrefslogtreecommitdiffstats
path: root/src/editfns.c
diff options
context:
space:
mode:
authorPaul Eggert2020-08-24 13:12:51 -0700
committerPaul Eggert2020-08-24 13:17:48 -0700
commite0345b4e86154f42f47a9f7bbbf458a72bf5c06d (patch)
tree6c1b31e29066b2effe859d037a57d5c7c9cf442a /src/editfns.c
parent08a6d14e4116c74284c12dd1319780afbcbbfd1d (diff)
downloademacs-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.c90
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
1907struct context; 1907struct 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. */)
2117static void 2125static void
2118set_bit (unsigned char *a, ptrdiff_t i) 2126set_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
2127static bool 2132static bool
2128bit_is_set (const unsigned char *a, ptrdiff_t i) 2133bit_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