[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: C-g while exiting the minibuffer
From: |
Stefan Monnier |
Subject: |
Re: C-g while exiting the minibuffer |
Date: |
Sun, 01 Dec 2013 17:13:12 -0500 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/24.3.50 (gnu/linux) |
>> But the problem remains of what to do with a C-g interrupting a unwind
>> form: in the case of an Fset_window_configuration in an unwind form, the
>> intention is to make that "no matter what happens, we end up recovering
>> the original state", but a C-g at the wrong time will break this promise.
> I'm afraid that C-g at the wrong time might produce an inconsistent
> state which IMO seems more fatal than a non-original state.
An inconsistent state would also be a non-original state, so yes, an
inconsistent would also break the promise.
>> - checking cycles here gives us no guarantee since the caller can do
>> (set-window-prev-buffers w bufs)
>> (setcdr bufs bufs)
>> and you again end up with a cycle in your window-prev-buffers.
> Right. So we'd need a safe implementation of delq and I wouldn't know
> how to do that reasonably via DOLIST.
Indeed, the FOREACH macro was designed for "read-only" traversals, just
like the DOLIST macro. I don't think the hare/tortoise trick is
inapplicable, tho: it just requires more care (since the deletions of
Fdelq might give the tortoise shortcuts that risk making the tortoise
catch up with the hare). See patch below.
> I'd rather use a simple routine to find out whether the original
> argument list of delq is infinite (if we think this could be a real
> problem).
I think the hare/tortoise is a "simple routine to find out if the list is
infinite".
Stefan
=== modified file 'src/fns.c'
--- src/fns.c 2013-11-29 19:47:58 +0000
+++ src/fns.c 2013-12-01 22:02:46 +0000
@@ -1537,15 +1537,12 @@
the value of a list `foo'. */)
(register Lisp_Object elt, Lisp_Object list)
{
- register Lisp_Object tail, prev;
- register Lisp_Object tem;
+ Lisp_Object tail, tortoise, prev = Qnil;
+ bool skip;
- tail = list;
- prev = Qnil;
- while (CONSP (tail))
+ FOR_EACH_TAIL (tail, list, tortoise, skip)
{
- CHECK_LIST_CONS (tail, list);
- tem = XCAR (tail);
+ Lisp_Object tem = XCAR (tail);
if (EQ (elt, tem))
{
if (NILP (prev))
@@ -1555,8 +1552,6 @@
}
else
prev = tail;
- tail = XCDR (tail);
- QUIT;
}
return list;
}
=== modified file 'src/lisp.h'
--- src/lisp.h 2013-11-30 09:25:31 +0000
+++ src/lisp.h 2013-12-01 22:05:02 +0000
@@ -4443,6 +4443,20 @@
memory_full (SIZE_MAX); \
} while (0)
+/* Loop over all tails of a list, checking for cycles.
+ FIXME: Make tortoise and n internal declarations.
+ FIXME: Unroll the loop body so we don't need `n'. */
+#define FOR_EACH_TAIL(hare, list, tortoise, n) \
+ for (tortoise = hare = (list), n = true; \
+ CONSP (hare); \
+ (hare = XCDR (hare), n = !n, \
+ (n \
+ ? ((EQ (hare, tortoise) \
+ && (xsignal1 (Qcircular_list, (list)), 0))) \
+ /* Move tortoise before the next iteration, in case */ \
+ /* the next iteration does an Fsetcdr. */ \
+ : (tortoise = XCDR (tortoise), 0))))
+
/* Do a `for' loop over alist values. */
#define FOR_EACH_ALIST_VALUE(head_var, list_var, value_var) \
- Re: C-g while exiting the minibuffer,
Stefan Monnier <=