aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert2017-02-05 13:25:37 -0800
committerPaul Eggert2017-02-05 13:30:28 -0800
commitb7fa6b1f1cee9d1b71553fa665843774d2e5cf3d (patch)
tree3a6df68a8377005aec8872de00df48b2cbf9f714 /src
parent5e222f673717718cd0ee209487cc06637bd142fc (diff)
downloademacs-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.c6
-rw-r--r--src/fns.c16
-rw-r--r--src/lisp.h34
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
173void
174circular_list (Lisp_Object list)
175{
176 xsignal1 (Qcircular_list, list);
177}
178
173 179
174/* Data type predicates. */ 180/* Data type predicates. */
175 181
diff --git a/src/fns.c b/src/fns.c
index ac7c1f265a4..4de74a5967f 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -1544,25 +1544,23 @@ list.
1544Write `(setq foo (delq element foo))' to be sure of correctly changing 1544Write `(setq foo (delq element foo))' to be sure of correctly changing
1545the value of a list `foo'. See also `remq', which does not modify the 1545the value of a list `foo'. See also `remq', which does not modify the
1546argument. */) 1546argument. */)
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 *);
3317extern _Noreturn void args_out_of_range (Lisp_Object, Lisp_Object); 3317extern _Noreturn void args_out_of_range (Lisp_Object, Lisp_Object);
3318extern _Noreturn void args_out_of_range_3 (Lisp_Object, Lisp_Object, 3318extern _Noreturn void args_out_of_range_3 (Lisp_Object, Lisp_Object,
3319 Lisp_Object); 3319 Lisp_Object);
3320extern _Noreturn void circular_list (Lisp_Object);
3320extern Lisp_Object do_symval_forwarding (union Lisp_Fwd *); 3321extern Lisp_Object do_symval_forwarding (union Lisp_Fwd *);
3321enum Set_Internal_Bind { 3322enum 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