aboutsummaryrefslogtreecommitdiffstats
path: root/src/editfns.c
diff options
context:
space:
mode:
authorPaul Eggert2017-06-01 16:03:12 -0700
committerPaul Eggert2017-06-01 16:06:38 -0700
commit178d0cb5f530e6d7eb36eb9987ff405c854ccdb3 (patch)
treed5c8c63dc97ed4635b354bb16803cbfd1d953470 /src/editfns.c
parent53247108411a1e9d1aa5352c231fa049f3f918aa (diff)
downloademacs-178d0cb5f530e6d7eb36eb9987ff405c854ccdb3.tar.gz
emacs-178d0cb5f530e6d7eb36eb9987ff405c854ccdb3.zip
Improve performance by avoiding strtoumax
This made (string-to-number "10") 20% faster on my old desktop, an AMD Phenom II X4 910e running Fedora 25 x86-64. * admin/merge-gnulib (GNULIB_MODULES): Remove strtoumax. * lib/gnulib.mk.in, m4/gnulib-comp.m4: Regenerate. * lib/strtoul.c, lib/strtoull.c, lib/strtoumax.c, m4/strtoull.m4: * m4/strtoumax.m4: Remove. * src/editfns.c (str2num): New function. (styled_format): Use it instead of strtoumax. Use ptrdiff_t instead of uintmax_t. Check for integer overflow. * src/lread.c (LEAD_INT, DOT_CHAR, TRAIL_INT, E_EXP): Move to private scope and make them enums. (string_to_number): Compute integer value directly during first pass instead of revisiting it with strtoumax later.
Diffstat (limited to 'src/editfns.c')
-rw-r--r--src/editfns.c43
1 files changed, 31 insertions, 12 deletions
diff --git a/src/editfns.c b/src/editfns.c
index 98187df5d97..1dbae8f5d4b 100644
--- a/src/editfns.c
+++ b/src/editfns.c
@@ -3851,6 +3851,23 @@ usage: (propertize STRING &rest PROPERTIES) */)
3851 return string; 3851 return string;
3852} 3852}
3853 3853
3854/* Convert the prefix of STR from ASCII decimal digits to a number.
3855 Set *STR_END to the address of the first non-digit. Return the
3856 number, or PTRDIFF_MAX on overflow. Return 0 if there is no number.
3857 This is like strtol for ptrdiff_t and base 10 and C locale,
3858 except without negative numbers or errno. */
3859
3860static ptrdiff_t
3861str2num (char *str, char **str_end)
3862{
3863 ptrdiff_t n = 0;
3864 for (; c_isdigit (*str); str++)
3865 if (INT_MULTIPLY_WRAPV (n, 10, &n) || INT_ADD_WRAPV (n, *str - '0', &n))
3866 n = PTRDIFF_MAX;
3867 *str_end = str;
3868 return n;
3869}
3870
3854DEFUN ("format", Fformat, Sformat, 1, MANY, 0, 3871DEFUN ("format", Fformat, Sformat, 1, MANY, 0,
3855 doc: /* Format a string out of a format-string and arguments. 3872 doc: /* Format a string out of a format-string and arguments.
3856The first argument is a format control string. 3873The first argument is a format control string.
@@ -4057,17 +4074,16 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
4057 digits to print after the '.' for floats, or the max. 4074 digits to print after the '.' for floats, or the max.
4058 number of chars to print from a string. */ 4075 number of chars to print from a string. */
4059 4076
4060 uintmax_t num; 4077 ptrdiff_t num;
4061 char *num_end; 4078 char *num_end;
4062 if (c_isdigit (*format)) 4079 if (c_isdigit (*format))
4063 { 4080 {
4064 num = strtoumax (format, &num_end, 10); 4081 num = str2num (format, &num_end);
4065 if (*num_end == '$') 4082 if (*num_end == '$')
4066 { 4083 {
4067 if (num == 0) 4084 if (num == 0)
4068 error ("Invalid format field number 0"); 4085 error ("Invalid format field number 0");
4069 n = min (num, PTRDIFF_MAX); 4086 n = num - 1;
4070 n--;
4071 format = num_end + 1; 4087 format = num_end + 1;
4072 } 4088 }
4073 } 4089 }
@@ -4095,15 +4111,15 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
4095 space_flag &= ! plus_flag; 4111 space_flag &= ! plus_flag;
4096 zero_flag &= ! minus_flag; 4112 zero_flag &= ! minus_flag;
4097 4113
4098 num = strtoumax (format, &num_end, 10); 4114 num = str2num (format, &num_end);
4099 if (max_bufsize <= num) 4115 if (max_bufsize <= num)
4100 string_overflow (); 4116 string_overflow ();
4101 ptrdiff_t field_width = num; 4117 ptrdiff_t field_width = num;
4102 4118
4103 bool precision_given = *num_end == '.'; 4119 bool precision_given = *num_end == '.';
4104 uintmax_t precision = (precision_given 4120 ptrdiff_t precision = (precision_given
4105 ? strtoumax (num_end + 1, &num_end, 10) 4121 ? str2num (num_end + 1, &num_end)
4106 : UINTMAX_MAX); 4122 : PTRDIFF_MAX);
4107 format = num_end; 4123 format = num_end;
4108 4124
4109 if (format == end) 4125 if (format == end)
@@ -4176,7 +4192,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
4176 /* handle case (precision[n] >= 0) */ 4192 /* handle case (precision[n] >= 0) */
4177 4193
4178 ptrdiff_t prec = -1; 4194 ptrdiff_t prec = -1;
4179 if (precision_given && precision <= TYPE_MAXIMUM (ptrdiff_t)) 4195 if (precision_given)
4180 prec = precision; 4196 prec = precision;
4181 4197
4182 /* lisp_string_width ignores a precision of 0, but GNU 4198 /* lisp_string_width ignores a precision of 0, but GNU
@@ -4424,8 +4440,9 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
4424 padding and excess precision. Deal with excess precision 4440 padding and excess precision. Deal with excess precision
4425 first. This happens only when the format specifies 4441 first. This happens only when the format specifies
4426 ridiculously large precision. */ 4442 ridiculously large precision. */
4427 uintmax_t excess_precision = precision - prec; 4443 ptrdiff_t excess_precision
4428 uintmax_t leading_zeros = 0, trailing_zeros = 0; 4444 = precision_given ? precision - prec : 0;
4445 ptrdiff_t leading_zeros = 0, trailing_zeros = 0;
4429 if (excess_precision) 4446 if (excess_precision)
4430 { 4447 {
4431 if (float_conversion) 4448 if (float_conversion)
@@ -4451,7 +4468,9 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
4451 4468
4452 /* Compute the total bytes needed for this item, including 4469 /* Compute the total bytes needed for this item, including
4453 excess precision and padding. */ 4470 excess precision and padding. */
4454 uintmax_t numwidth = sprintf_bytes + excess_precision; 4471 ptrdiff_t numwidth;
4472 if (INT_ADD_WRAPV (sprintf_bytes, excess_precision, &numwidth))
4473 numwidth = PTRDIFF_MAX;
4455 ptrdiff_t padding 4474 ptrdiff_t padding
4456 = numwidth < field_width ? field_width - numwidth : 0; 4475 = numwidth < field_width ? field_width - numwidth : 0;
4457 if (max_bufsize - sprintf_bytes <= excess_precision 4476 if (max_bufsize - sprintf_bytes <= excess_precision