diff options
| author | Paul Eggert | 2017-02-05 13:25:37 -0800 |
|---|---|---|
| committer | Paul Eggert | 2017-02-05 13:30:28 -0800 |
| commit | b7fa6b1f1cee9d1b71553fa665843774d2e5cf3d (patch) | |
| tree | 3a6df68a8377005aec8872de00df48b2cbf9f714 /src | |
| parent | 5e222f673717718cd0ee209487cc06637bd142fc (diff) | |
| download | emacs-b7fa6b1f1cee9d1b71553fa665843774d2e5cf3d.tar.gz emacs-b7fa6b1f1cee9d1b71553fa665843774d2e5cf3d.zip | |
Simplify use of FOR_EACH_TAIL
* src/data.c (circular_list): New function.
* src/lisp.h (FOR_EACH_TAIL): Use Brent’s algorithm and C99 for-loop
decl, to eliminate the need for the args TAIL, TORTOISE and N, and
to speed things up a bit on typical hosts with optimization.
All uses changed (Bug#25605).
Diffstat (limited to 'src')
| -rw-r--r-- | src/data.c | 6 | ||||
| -rw-r--r-- | src/fns.c | 16 | ||||
| -rw-r--r-- | src/lisp.h | 34 |
3 files changed, 33 insertions, 23 deletions
diff --git a/src/data.c b/src/data.c index 8e07bf01b44..12dc2df0bac 100644 --- a/src/data.c +++ b/src/data.c | |||
| @@ -170,6 +170,12 @@ args_out_of_range_3 (Lisp_Object a1, Lisp_Object a2, Lisp_Object a3) | |||
| 170 | xsignal3 (Qargs_out_of_range, a1, a2, a3); | 170 | xsignal3 (Qargs_out_of_range, a1, a2, a3); |
| 171 | } | 171 | } |
| 172 | 172 | ||
| 173 | void | ||
| 174 | circular_list (Lisp_Object list) | ||
| 175 | { | ||
| 176 | xsignal1 (Qcircular_list, list); | ||
| 177 | } | ||
| 178 | |||
| 173 | 179 | ||
| 174 | /* Data type predicates. */ | 180 | /* Data type predicates. */ |
| 175 | 181 | ||
| @@ -1544,25 +1544,23 @@ list. | |||
| 1544 | Write `(setq foo (delq element foo))' to be sure of correctly changing | 1544 | Write `(setq foo (delq element foo))' to be sure of correctly changing |
| 1545 | the value of a list `foo'. See also `remq', which does not modify the | 1545 | the value of a list `foo'. See also `remq', which does not modify the |
| 1546 | argument. */) | 1546 | argument. */) |
| 1547 | (register Lisp_Object elt, Lisp_Object list) | 1547 | (Lisp_Object elt, Lisp_Object list) |
| 1548 | { | 1548 | { |
| 1549 | Lisp_Object tail, tortoise, prev = Qnil; | 1549 | Lisp_Object prev = Qnil; |
| 1550 | bool skip; | ||
| 1551 | 1550 | ||
| 1552 | FOR_EACH_TAIL (tail, list, tortoise, skip) | 1551 | FOR_EACH_TAIL (list) |
| 1553 | { | 1552 | { |
| 1554 | Lisp_Object tem = XCAR (tail); | 1553 | Lisp_Object tem = XCAR (li.tail); |
| 1555 | if (EQ (elt, tem)) | 1554 | if (EQ (elt, tem)) |
| 1556 | { | 1555 | { |
| 1557 | if (NILP (prev)) | 1556 | if (NILP (prev)) |
| 1558 | list = XCDR (tail); | 1557 | list = XCDR (li.tail); |
| 1559 | else | 1558 | else |
| 1560 | Fsetcdr (prev, XCDR (tail)); | 1559 | Fsetcdr (prev, XCDR (li.tail)); |
| 1561 | } | 1560 | } |
| 1562 | else | 1561 | else |
| 1563 | prev = tail; | 1562 | prev = li.tail; |
| 1564 | } | 1563 | } |
| 1565 | CHECK_LIST_END (tail, list); | ||
| 1566 | return list; | 1564 | return list; |
| 1567 | } | 1565 | } |
| 1568 | 1566 | ||
diff --git a/src/lisp.h b/src/lisp.h index a9011b4a8be..102e8bd70ef 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -3317,6 +3317,7 @@ extern struct Lisp_Symbol *indirect_variable (struct Lisp_Symbol *); | |||
| 3317 | extern _Noreturn void args_out_of_range (Lisp_Object, Lisp_Object); | 3317 | extern _Noreturn void args_out_of_range (Lisp_Object, Lisp_Object); |
| 3318 | extern _Noreturn void args_out_of_range_3 (Lisp_Object, Lisp_Object, | 3318 | extern _Noreturn void args_out_of_range_3 (Lisp_Object, Lisp_Object, |
| 3319 | Lisp_Object); | 3319 | Lisp_Object); |
| 3320 | extern _Noreturn void circular_list (Lisp_Object); | ||
| 3320 | extern Lisp_Object do_symval_forwarding (union Lisp_Fwd *); | 3321 | extern Lisp_Object do_symval_forwarding (union Lisp_Fwd *); |
| 3321 | enum Set_Internal_Bind { | 3322 | enum Set_Internal_Bind { |
| 3322 | SET_INTERNAL_SET, | 3323 | SET_INTERNAL_SET, |
| @@ -4585,20 +4586,25 @@ enum | |||
| 4585 | Lisp_String)) \ | 4586 | Lisp_String)) \ |
| 4586 | : make_unibyte_string (str, len)) | 4587 | : make_unibyte_string (str, len)) |
| 4587 | 4588 | ||
| 4588 | /* Loop over all tails of a list, checking for cycles. | 4589 | /* Loop over tails of LIST, checking for dotted lists and cycles. |
| 4589 | FIXME: Make tortoise and n internal declarations. | 4590 | In the loop body, ‘li.tail’ is the current cons; the name ‘li’ is |
| 4590 | FIXME: Unroll the loop body so we don't need `n'. */ | 4591 | short for “list iterator”. The expression LIST may be evaluated |
| 4591 | #define FOR_EACH_TAIL(hare, list, tortoise, n) \ | 4592 | more than once, and so should not have side effects. The loop body |
| 4592 | for ((tortoise) = (hare) = (list), (n) = true; \ | 4593 | should not modify the list’s top level structure other than by |
| 4593 | CONSP (hare); \ | 4594 | perhaps deleting the current cons. |
| 4594 | (hare = XCDR (hare), (n) = !(n), \ | 4595 | |
| 4595 | ((n) \ | 4596 | Use Brent’s teleporting tortoise-hare algorithm. See: |
| 4596 | ? (EQ (hare, tortoise) \ | 4597 | Brent RP. BIT. 1980;20(2):176-84. doi:10.1007/BF01933190 |
| 4597 | ? xsignal1 (Qcircular_list, list) \ | 4598 | http://maths-people.anu.edu.au/~brent/pd/rpb051i.pdf */ |
| 4598 | : (void) 0) \ | 4599 | |
| 4599 | /* Move tortoise before the next iteration, in case */ \ | 4600 | #define FOR_EACH_TAIL(list) \ |
| 4600 | /* the next iteration does an Fsetcdr. */ \ | 4601 | for (struct { Lisp_Object tail, tortoise; intptr_t n, max; } li \ |
| 4601 | : (void) ((tortoise) = XCDR (tortoise))))) | 4602 | = { list, list, 2, 2 }; \ |
| 4603 | CONSP (li.tail) || (CHECK_LIST_END (li.tail, list), false); \ | ||
| 4604 | (li.tail = XCDR (li.tail), \ | ||
| 4605 | (li.n-- == 0 \ | ||
| 4606 | ? (void) (li.n = li.max <<= 1, li.tortoise = li.tail) \ | ||
| 4607 | : EQ (li.tail, li.tortoise) ? circular_list (list) : (void) 0))) | ||
| 4602 | 4608 | ||
| 4603 | /* Do a `for' loop over alist values. */ | 4609 | /* Do a `for' loop over alist values. */ |
| 4604 | 4610 | ||