diff options
| author | Paul Eggert | 2020-03-08 00:20:57 -0800 |
|---|---|---|
| committer | Paul Eggert | 2020-03-08 00:20:57 -0800 |
| commit | 4415534ef01309417e8f552eb4c075095603f2f3 (patch) | |
| tree | ca55889bb9636c2b2d16e4a29fcc14b2d18e3fdc | |
| parent | e4fb95fa18072cedb021a82f7aa0e79fa6ca387a (diff) | |
| parent | 0a3682a566d5563e3d57defe49359cee236e0274 (diff) | |
| download | emacs-4415534ef01309417e8f552eb4c075095603f2f3.tar.gz emacs-4415534ef01309417e8f552eb4c075095603f2f3.zip | |
Merge from origin/emacs-27
0a3682a566 * src/timefns.c: Add comments.
b16ba4041d ; lisp/emacs-lisp/seq.el: Explain why we don't use cl-lib ...
3cbf4cb796 Eliminate use of cl-concatenate in 'seq' package
363d927086 Fix bug with JIT stealth timers
818333c85a * doc/lispref/os.texi (time-subtract): Doc fix.
| -rw-r--r-- | doc/lispref/os.texi | 5 | ||||
| -rw-r--r-- | lisp/emacs-lisp/cl-extra.el | 6 | ||||
| -rw-r--r-- | lisp/emacs-lisp/seq.el | 10 | ||||
| -rw-r--r-- | lisp/emacs-lisp/timer.el | 2 | ||||
| -rw-r--r-- | src/timefns.c | 32 |
5 files changed, 37 insertions, 18 deletions
diff --git a/doc/lispref/os.texi b/doc/lispref/os.texi index cf4ef52abfb..e72858bbf1a 100644 --- a/doc/lispref/os.texi +++ b/doc/lispref/os.texi | |||
| @@ -1979,10 +1979,9 @@ The result is @code{nil} if either argument is a NaN. | |||
| 1979 | 1979 | ||
| 1980 | @defun time-subtract t1 t2 | 1980 | @defun time-subtract t1 t2 |
| 1981 | This returns the time difference @var{t1} @minus{} @var{t2} between | 1981 | This returns the time difference @var{t1} @minus{} @var{t2} between |
| 1982 | two time values, normally as a Lisp timestamp but as a float | 1982 | two time values, as a Lisp time value. The result is exact and its clock |
| 1983 | if either argument is infinite or a NaN@. | ||
| 1984 | When the result is a timestamp, it is exact and its clock | ||
| 1985 | resolution is no worse than the worse of its two arguments' resolutions. | 1983 | resolution is no worse than the worse of its two arguments' resolutions. |
| 1984 | The result is floating-point only if it is infinite or a NaN. | ||
| 1986 | If you need the difference in units | 1985 | If you need the difference in units |
| 1987 | of elapsed seconds, you can convert it with @code{time-convert} or | 1986 | of elapsed seconds, you can convert it with @code{time-convert} or |
| 1988 | @code{float-time}. @xref{Time Conversion}. | 1987 | @code{float-time}. @xref{Time Conversion}. |
diff --git a/lisp/emacs-lisp/cl-extra.el b/lisp/emacs-lisp/cl-extra.el index e3dabdfcef2..e9bfe8df5f2 100644 --- a/lisp/emacs-lisp/cl-extra.el +++ b/lisp/emacs-lisp/cl-extra.el | |||
| @@ -556,11 +556,7 @@ too large if positive or too small if negative)." | |||
| 556 | (defun cl-concatenate (type &rest sequences) | 556 | (defun cl-concatenate (type &rest sequences) |
| 557 | "Concatenate, into a sequence of type TYPE, the argument SEQUENCEs. | 557 | "Concatenate, into a sequence of type TYPE, the argument SEQUENCEs. |
| 558 | \n(fn TYPE SEQUENCE...)" | 558 | \n(fn TYPE SEQUENCE...)" |
| 559 | (pcase type | 559 | (seq-concatenate type sequences)) |
| 560 | ('vector (apply #'vconcat sequences)) | ||
| 561 | ('string (apply #'concat sequences)) | ||
| 562 | ('list (apply #'append (append sequences '(nil)))) | ||
| 563 | (_ (error "Not a sequence type name: %S" type)))) | ||
| 564 | 560 | ||
| 565 | ;;; List functions. | 561 | ;;; List functions. |
| 566 | 562 | ||
diff --git a/lisp/emacs-lisp/seq.el b/lisp/emacs-lisp/seq.el index 0b946dd7365..e3037a71901 100644 --- a/lisp/emacs-lisp/seq.el +++ b/lisp/emacs-lisp/seq.el | |||
| @@ -58,6 +58,10 @@ | |||
| 58 | 58 | ||
| 59 | (eval-when-compile (require 'cl-generic)) | 59 | (eval-when-compile (require 'cl-generic)) |
| 60 | 60 | ||
| 61 | ;; We used to use some sequence functions from cl-lib, but this | ||
| 62 | ;; dependency was swapped around so that it will be easier to make | ||
| 63 | ;; seq.el preloaded in the future. See also Bug#39761#26. | ||
| 64 | |||
| 61 | (defmacro seq-doseq (spec &rest body) | 65 | (defmacro seq-doseq (spec &rest body) |
| 62 | "Loop over a sequence. | 66 | "Loop over a sequence. |
| 63 | Evaluate BODY with VAR bound to each element of SEQUENCE, in turn. | 67 | Evaluate BODY with VAR bound to each element of SEQUENCE, in turn. |
| @@ -285,7 +289,11 @@ sorted. FUNCTION must be a function of one argument." | |||
| 285 | TYPE must be one of following symbols: vector, string or list. | 289 | TYPE must be one of following symbols: vector, string or list. |
| 286 | 290 | ||
| 287 | \n(fn TYPE SEQUENCE...)" | 291 | \n(fn TYPE SEQUENCE...)" |
| 288 | (apply #'cl-concatenate type (seq-map #'seq-into-sequence sequences))) | 292 | (pcase type |
| 293 | ('vector (apply #'vconcat sequences)) | ||
| 294 | ('string (apply #'concat sequences)) | ||
| 295 | ('list (apply #'append (append sequences '(nil)))) | ||
| 296 | (_ (error "Not a sequence type name: %S" type)))) | ||
| 289 | 297 | ||
| 290 | (cl-defgeneric seq-into-sequence (sequence) | 298 | (cl-defgeneric seq-into-sequence (sequence) |
| 291 | "Convert SEQUENCE into a sequence. | 299 | "Convert SEQUENCE into a sequence. |
diff --git a/lisp/emacs-lisp/timer.el b/lisp/emacs-lisp/timer.el index 74a94957e73..9eb8feed0f1 100644 --- a/lisp/emacs-lisp/timer.el +++ b/lisp/emacs-lisp/timer.el | |||
| @@ -378,7 +378,7 @@ This function returns a timer object which you can use in | |||
| 378 | (decoded-time-year now) | 378 | (decoded-time-year now) |
| 379 | (decoded-time-zone now))))))) | 379 | (decoded-time-zone now))))))) |
| 380 | 380 | ||
| 381 | (or (consp time) | 381 | (or (time-equal-p time time) |
| 382 | (error "Invalid time format")) | 382 | (error "Invalid time format")) |
| 383 | 383 | ||
| 384 | (let ((timer (timer-create))) | 384 | (let ((timer (timer-create))) |
diff --git a/src/timefns.c b/src/timefns.c index 41db1e68759..6dd6e1611a4 100644 --- a/src/timefns.c +++ b/src/timefns.c | |||
| @@ -491,11 +491,14 @@ timespec_mpz (struct timespec t) | |||
| 491 | static Lisp_Object | 491 | static Lisp_Object |
| 492 | timespec_ticks (struct timespec t) | 492 | timespec_ticks (struct timespec t) |
| 493 | { | 493 | { |
| 494 | /* For speed, use intmax_t arithmetic if it will do. */ | ||
| 494 | intmax_t accum; | 495 | intmax_t accum; |
| 495 | if (FASTER_TIMEFNS | 496 | if (FASTER_TIMEFNS |
| 496 | && !INT_MULTIPLY_WRAPV (t.tv_sec, TIMESPEC_HZ, &accum) | 497 | && !INT_MULTIPLY_WRAPV (t.tv_sec, TIMESPEC_HZ, &accum) |
| 497 | && !INT_ADD_WRAPV (t.tv_nsec, accum, &accum)) | 498 | && !INT_ADD_WRAPV (t.tv_nsec, accum, &accum)) |
| 498 | return make_int (accum); | 499 | return make_int (accum); |
| 500 | |||
| 501 | /* Fall back on bignum arithmetic. */ | ||
| 499 | timespec_mpz (t); | 502 | timespec_mpz (t); |
| 500 | return make_integer_mpz (); | 503 | return make_integer_mpz (); |
| 501 | } | 504 | } |
| @@ -505,12 +508,17 @@ timespec_ticks (struct timespec t) | |||
| 505 | static Lisp_Object | 508 | static Lisp_Object |
| 506 | lisp_time_hz_ticks (struct lisp_time t, Lisp_Object hz) | 509 | lisp_time_hz_ticks (struct lisp_time t, Lisp_Object hz) |
| 507 | { | 510 | { |
| 511 | /* For speed, just return TICKS if T is (TICKS . HZ). */ | ||
| 508 | if (FASTER_TIMEFNS && EQ (t.hz, hz)) | 512 | if (FASTER_TIMEFNS && EQ (t.hz, hz)) |
| 509 | return t.ticks; | 513 | return t.ticks; |
| 514 | |||
| 515 | /* Check HZ for validity. */ | ||
| 510 | if (FIXNUMP (hz)) | 516 | if (FIXNUMP (hz)) |
| 511 | { | 517 | { |
| 512 | if (XFIXNUM (hz) <= 0) | 518 | if (XFIXNUM (hz) <= 0) |
| 513 | invalid_hz (hz); | 519 | invalid_hz (hz); |
| 520 | |||
| 521 | /* For speed, use intmax_t arithmetic if it will do. */ | ||
| 514 | intmax_t ticks; | 522 | intmax_t ticks; |
| 515 | if (FASTER_TIMEFNS && FIXNUMP (t.ticks) && FIXNUMP (t.hz) | 523 | if (FASTER_TIMEFNS && FIXNUMP (t.ticks) && FIXNUMP (t.hz) |
| 516 | && !INT_MULTIPLY_WRAPV (XFIXNUM (t.ticks), XFIXNUM (hz), &ticks)) | 524 | && !INT_MULTIPLY_WRAPV (XFIXNUM (t.ticks), XFIXNUM (hz), &ticks)) |
| @@ -520,6 +528,7 @@ lisp_time_hz_ticks (struct lisp_time t, Lisp_Object hz) | |||
| 520 | else if (! (BIGNUMP (hz) && 0 < mpz_sgn (*xbignum_val (hz)))) | 528 | else if (! (BIGNUMP (hz) && 0 < mpz_sgn (*xbignum_val (hz)))) |
| 521 | invalid_hz (hz); | 529 | invalid_hz (hz); |
| 522 | 530 | ||
| 531 | /* Fall back on bignum arithmetic. */ | ||
| 523 | mpz_mul (mpz[0], | 532 | mpz_mul (mpz[0], |
| 524 | *bignum_integer (&mpz[0], t.ticks), | 533 | *bignum_integer (&mpz[0], t.ticks), |
| 525 | *bignum_integer (&mpz[1], hz)); | 534 | *bignum_integer (&mpz[1], hz)); |
| @@ -533,9 +542,13 @@ lisp_time_seconds (struct lisp_time t) | |||
| 533 | { | 542 | { |
| 534 | if (!FASTER_TIMEFNS) | 543 | if (!FASTER_TIMEFNS) |
| 535 | return lisp_time_hz_ticks (t, make_fixnum (1)); | 544 | return lisp_time_hz_ticks (t, make_fixnum (1)); |
| 545 | |||
| 546 | /* For speed, use EMACS_INT arithmetic if it will do. */ | ||
| 536 | if (FIXNUMP (t.ticks) && FIXNUMP (t.hz)) | 547 | if (FIXNUMP (t.ticks) && FIXNUMP (t.hz)) |
| 537 | return make_fixnum (XFIXNUM (t.ticks) / XFIXNUM (t.hz) | 548 | return make_fixnum (XFIXNUM (t.ticks) / XFIXNUM (t.hz) |
| 538 | - (XFIXNUM (t.ticks) % XFIXNUM (t.hz) < 0)); | 549 | - (XFIXNUM (t.ticks) % XFIXNUM (t.hz) < 0)); |
| 550 | |||
| 551 | /* For speed, inline what lisp_time_hz_ticks would do. */ | ||
| 539 | mpz_fdiv_q (mpz[0], | 552 | mpz_fdiv_q (mpz[0], |
| 540 | *bignum_integer (&mpz[0], t.ticks), | 553 | *bignum_integer (&mpz[0], t.ticks), |
| 541 | *bignum_integer (&mpz[1], t.hz)); | 554 | *bignum_integer (&mpz[1], t.hz)); |
| @@ -1122,21 +1135,22 @@ time_arith (Lisp_Object a, Lisp_Object b, bool subtract) | |||
| 1122 | (subtract ? mpz_submul : mpz_addmul) (*iticks, *fa, *nb); | 1135 | (subtract ? mpz_submul : mpz_addmul) (*iticks, *fa, *nb); |
| 1123 | 1136 | ||
| 1124 | /* Normalize iticks/ihz by dividing both numerator and | 1137 | /* Normalize iticks/ihz by dividing both numerator and |
| 1125 | denominator by ig = gcd (iticks, ihz). However, if that | 1138 | denominator by ig = gcd (iticks, ihz). For speed, though, |
| 1126 | would cause the denominator to become less than hzmin, | 1139 | skip this division if ihz = 1. */ |
| 1127 | rescale the denominator upwards from its ordinary value by | ||
| 1128 | multiplying numerator and denominator so that the denominator | ||
| 1129 | becomes at least hzmin. This rescaling avoids returning a | ||
| 1130 | timestamp that is less precise than both a and b, or a | ||
| 1131 | timestamp that looks obsolete when that might be a problem. */ | ||
| 1132 | mpz_t *ig = &mpz[3]; | 1140 | mpz_t *ig = &mpz[3]; |
| 1133 | mpz_gcd (*ig, *iticks, *ihz); | 1141 | mpz_gcd (*ig, *iticks, *ihz); |
| 1134 | |||
| 1135 | if (!FASTER_TIMEFNS || mpz_cmp_ui (*ig, 1) > 0) | 1142 | if (!FASTER_TIMEFNS || mpz_cmp_ui (*ig, 1) > 0) |
| 1136 | { | 1143 | { |
| 1137 | mpz_divexact (*iticks, *iticks, *ig); | 1144 | mpz_divexact (*iticks, *iticks, *ig); |
| 1138 | mpz_divexact (*ihz, *ihz, *ig); | 1145 | mpz_divexact (*ihz, *ihz, *ig); |
| 1139 | 1146 | ||
| 1147 | /* However, if dividing the denominator by ig would cause the | ||
| 1148 | denominator to become less than hzmin, rescale the denominator | ||
| 1149 | upwards by multiplying the normalized numerator and denominator | ||
| 1150 | so that the resulting denominator becomes at least hzmin. | ||
| 1151 | This rescaling avoids returning a timestamp that is less precise | ||
| 1152 | than both a and b, or a timestamp that looks obsolete when that | ||
| 1153 | might be a problem. */ | ||
| 1140 | if (!FASTER_TIMEFNS || mpz_cmp (*ihz, *hzmin) < 0) | 1154 | if (!FASTER_TIMEFNS || mpz_cmp (*ihz, *hzmin) < 0) |
| 1141 | { | 1155 | { |
| 1142 | /* Rescale straightforwardly. Although this might not | 1156 | /* Rescale straightforwardly. Although this might not |
| @@ -1150,6 +1164,8 @@ time_arith (Lisp_Object a, Lisp_Object b, bool subtract) | |||
| 1150 | mpz_mul (*ihz, *ihz, *rescale); | 1164 | mpz_mul (*ihz, *ihz, *rescale); |
| 1151 | } | 1165 | } |
| 1152 | } | 1166 | } |
| 1167 | |||
| 1168 | /* mpz[0] and iticks now correspond to the (HZ . TICKS) pair. */ | ||
| 1153 | hz = make_integer_mpz (); | 1169 | hz = make_integer_mpz (); |
| 1154 | mpz_swap (mpz[0], *iticks); | 1170 | mpz_swap (mpz[0], *iticks); |
| 1155 | ticks = make_integer_mpz (); | 1171 | ticks = make_integer_mpz (); |