Mercurial > hg > xemacs-beta
changeset 5273:799742b751c8
Accept circular lists where that is useful in #'mapcar*, #'map* and friends.
src/ChangeLog addition:
2010-09-16 Aidan Kehoe <kehoea@parhasard.net>
* fns.c (Flist_length): New, moved here from cl-extra.el, needed
by the next function.
(shortest_length_among_sequences): New.
(Fmapconcat, FmapcarX, Fmapvector, Fmapcan, Fmapc, Fmap)
(Fmap_into, Fsome, Fevery):
Use shortest_length_among_sequences() when working out how many
iterations to do, only giving circular list errors if all
arguments are circular.
author | Aidan Kehoe <kehoea@parhasard.net> |
---|---|
date | Thu, 16 Sep 2010 20:34:49 +0100 |
parents | 66dbef5f8076 |
children | ecdd1daab447 |
files | lisp/cl-extra.el src/ChangeLog src/fns.c |
diffstat | 3 files changed, 87 insertions(+), 84 deletions(-) [+] |
line wrap: on
line diff
--- a/lisp/cl-extra.el Thu Sep 16 18:46:05 2010 +0100 +++ b/lisp/cl-extra.el Thu Sep 16 20:34:49 2010 +0100 @@ -405,13 +405,6 @@ "Equivalent to (nconc (nreverse X) Y)." (nconc (nreverse x) y)) -(defun list-length (list) - "Return the length of LIST. Return nil if LIST is circular." - (if (listp list) - (condition-case nil (length list) (circular-list)) - ;; Error on not-a-list: - (car list))) - (defun tailp (sublist list) "Return true if SUBLIST is a tail of LIST." (while (and (consp list) (not (eq sublist list)))
--- a/src/ChangeLog Thu Sep 16 18:46:05 2010 +0100 +++ b/src/ChangeLog Thu Sep 16 20:34:49 2010 +0100 @@ -1,3 +1,14 @@ +2010-09-16 Aidan Kehoe <kehoea@parhasard.net> + + * fns.c (Flist_length): New, moved here from cl-extra.el, needed + by the next function. + (shortest_length_among_sequences): New. + (Fmapconcat, FmapcarX, Fmapvector, Fmapcan, Fmapc, Fmap) + (Fmap_into, Fsome, Fevery): + Use shortest_length_among_sequences() when working out how many + iterations to do, only giving circular list errors if all + arguments are circular. + 2010-09-16 Aidan Kehoe <kehoea@parhasard.net> * fns.c (Fsubseq):
--- a/src/fns.c Thu Sep 16 18:46:05 2010 +0100 +++ b/src/fns.c Thu Sep 16 20:34:49 2010 +0100 @@ -339,6 +339,29 @@ return make_int (len); } +/* This is almost the above, but is defined by Common Lisp. We need it in C + for shortest_length_among_sequences(), below, for the various sequence + functions that can usefully operate on circular lists. */ + +DEFUN ("list-length", Flist_length, 1, 1, 0, /* +Return the length of LIST. Return nil if LIST is circular. +*/ + (list)) +{ + Lisp_Object hare, tortoise; + Elemcount len; + + for (hare = tortoise = list, len = 0; + CONSP (hare) && (! EQ (hare, tortoise) || len == 0); + hare = XCDR (hare), len++) + { + if (len & 1) + tortoise = XCDR (tortoise); + } + + return EQ (hare, tortoise) && len != 0 ? Qnil : make_int (len); +} + /*** string functions. ***/ DEFUN ("string-equal", Fstring_equal, 2, 2, 0, /* @@ -4458,6 +4481,42 @@ UNGCPRO; } +/* Given NSEQUENCES objects at the address pointed to by SEQUENCES, return + the length of the shortest sequence. Error if all are circular, or if any + one of them is not a sequence. */ +static Elemcount +shortest_length_among_sequences (int nsequences, Lisp_Object *sequences) +{ + Elemcount len = EMACS_INT_MAX; + Lisp_Object length; + int i; + + for (i = 0; i < nsequences; ++i) + { + if (CONSP (sequences[i])) + { + length = Flist_length (sequences[i]); + if (!NILP (length)) + { + len = min (len, XINT (length)); + } + } + else + { + CHECK_SEQUENCE (sequences[i]); + length = Flength (sequences[i]); + len = min (len, XINT (length)); + } + } + + if (NILP (length)) + { + signal_circular_list_error (sequences[0]); + } + + return len; +} + DEFUN ("mapconcat", Fmapconcat, 3, MANY, 0, /* Call FUNCTION on each element of SEQUENCE, and concat results to a string. Between each pair of results, insert SEPARATOR. @@ -4485,11 +4544,7 @@ args[2] = sequence; args[1] = separator; - for (i = 2; i < nargs; ++i) - { - CHECK_SEQUENCE (args[i]); - len = min (len, XINT (Flength (args[i]))); - } + len = shortest_length_among_sequences (nargs - 2, args + 2); if (len == 0) return build_ascstring (""); @@ -4536,15 +4591,8 @@ (int nargs, Lisp_Object *args)) { Lisp_Object function = args[0]; - Elemcount len = EMACS_INT_MAX; + Elemcount len = shortest_length_among_sequences (nargs - 1, args + 1); Lisp_Object *args0; - int i; - - for (i = 1; i < nargs; ++i) - { - CHECK_SEQUENCE (args[i]); - len = min (len, XINT (Flength (args[i]))); - } args0 = alloca_array (Lisp_Object, len); mapcarX (len, args0, Qnil, function, nargs - 1, args + 1, QmapcarX); @@ -4567,18 +4615,10 @@ (int nargs, Lisp_Object *args)) { Lisp_Object function = args[0]; - Elemcount len = EMACS_INT_MAX; - Lisp_Object result; + Elemcount len = shortest_length_among_sequences (nargs - 1, args + 1); + Lisp_Object result = make_vector (len, Qnil); + struct gcpro gcpro1; - int i; - - for (i = 1; i < nargs; ++i) - { - CHECK_SEQUENCE (args[i]); - len = min (len, XINT (Flength (args[i]))); - } - - result = make_vector (len, Qnil); GCPRO1 (result); /* Don't pass result as the lisp_object argument, we want mapcarX to protect a single list argument's elements from being garbage-collected. */ @@ -4602,21 +4642,13 @@ */ (int nargs, Lisp_Object *args)) { - Lisp_Object function = args[0], *result; - Elemcount result_len = EMACS_INT_MAX; - int i; - - for (i = 1; i < nargs; ++i) - { - CHECK_SEQUENCE (args[i]); - result_len = min (result_len, XINT (Flength (args[i]))); - } - - result = alloca_array (Lisp_Object, result_len); - mapcarX (result_len, result, Qnil, function, nargs - 1, args + 1, Qmapcan); + Elemcount len = shortest_length_among_sequences (nargs - 1, args + 1); + Lisp_Object function = args[0], *result = alloca_array (Lisp_Object, len); + + mapcarX (len, result, Qnil, function, nargs - 1, args + 1, Qmapcan); /* #'nconc GCPROs its args in case of signals and error. */ - return Fnconc (result_len, result); + return Fnconc (len, result); } DEFUN ("mapc", Fmapc, 2, MANY, 0, /* @@ -4637,17 +4669,9 @@ */ (int nargs, Lisp_Object *args)) { - Elemcount len = EMACS_INT_MAX; + Elemcount len = shortest_length_among_sequences (nargs - 1, args + 1); Lisp_Object sequence = args[1]; struct gcpro gcpro1; - int i; - - for (i = 1; i < nargs; ++i) - { - CHECK_SEQUENCE (args[i]); - len = min (len, XINT (Flength (args[i]))); - } - /* We need to GCPRO sequence, because mapcarX will modify the elements of the args array handed to it, and this may involve elements of sequence getting garbage collected. */ @@ -4677,16 +4701,9 @@ Lisp_Object function = args[1]; Lisp_Object result = Qnil; Lisp_Object *args0 = NULL; - Elemcount len = EMACS_INT_MAX; - int i; + Elemcount len = shortest_length_among_sequences (nargs - 2, args + 2); struct gcpro gcpro1; - for (i = 2; i < nargs; ++i) - { - CHECK_SEQUENCE (args[i]); - len = min (len, XINT (Flength (args[i]))); - } - if (!NILP (type)) { args0 = alloca_array (Lisp_Object, len); @@ -4742,19 +4759,14 @@ */ (int nargs, Lisp_Object *args)) { - Elemcount len = EMACS_INT_MAX; + Elemcount len; Lisp_Object result_sequence = args[0]; Lisp_Object function = args[1]; - int i; args[0] = function; args[1] = result_sequence; - for (i = 1; i < nargs; ++i) - { - CHECK_SEQUENCE (args[i]); - len = min (len, XINT (Flength (args[i]))); - } + len = shortest_length_among_sequences (nargs - 1, args + 1); mapcarX (len, NULL, result_sequence, function, nargs - 2, args + 2, Qmap_into); @@ -4776,14 +4788,7 @@ { Lisp_Object result = Qnil, result_ptr = STORE_VOID_IN_LISP ((void *) &result); - Elemcount len = EMACS_INT_MAX; - int i; - - for (i = 1; i < nargs; ++i) - { - CHECK_SEQUENCE (args[i]); - len = min (len, XINT (Flength (args[i]))); - } + Elemcount len = shortest_length_among_sequences (nargs - 1, args + 1); mapcarX (len, NULL, result_ptr, args[0], nargs - 1, args +1, Qsome); @@ -4803,14 +4808,7 @@ (int nargs, Lisp_Object *args)) { Lisp_Object result = Qt, result_ptr = STORE_VOID_IN_LISP ((void *) &result); - Elemcount len = EMACS_INT_MAX; - int i; - - for (i = 1; i < nargs; ++i) - { - CHECK_SEQUENCE (args[i]); - len = min (len, XINT (Flength (args[i]))); - } + Elemcount len = shortest_length_among_sequences (nargs - 1, args + 1); mapcarX (len, NULL, result_ptr, args[0], nargs - 1, args +1, Qevery); @@ -6683,6 +6681,7 @@ DEFSUBR (Frandom); DEFSUBR (Flength); DEFSUBR (Fsafe_length); + DEFSUBR (Flist_length); DEFSUBR (Fstring_equal); DEFSUBR (Fcompare_strings); DEFSUBR (Fstring_lessp);