Mercurial > hg > xemacs-beta
changeset 5432:46491edfd94a
Merge with trunk.
author | Mats Lidell <matsl@xemacs.org> |
---|---|
date | Sun, 07 Nov 2010 00:22:33 +0100 |
parents | 5cddeeeb25bb (current diff) 9f738305f80f (diff) |
children | 863f16484873 |
files | src/bytecode.c src/fns.c tests/automated/lisp-tests.el |
diffstat | 7 files changed, 247 insertions(+), 53 deletions(-) [+] |
line wrap: on
line diff
--- a/man/ChangeLog Sun Nov 07 00:15:08 2010 +0100 +++ b/man/ChangeLog Sun Nov 07 00:22:33 2010 +0100 @@ -1,3 +1,9 @@ +2010-11-06 Aidan Kehoe <kehoea@parhasard.net> + + * lispref/lists.texi (Rearrangement, Building Lists): + Document that #'nreverse and #'reverse now accept sequences, not + just lists, in this file. + 2010-09-02 Aidan Kehoe <kehoea@parhasard.net> * lispref/os.texi (Time Conversion):
--- a/man/lispref/lists.texi Sun Nov 07 00:15:08 2010 +0100 +++ b/man/lispref/lists.texi Sun Nov 07 00:22:33 2010 +0100 @@ -655,9 +655,9 @@ (@pxref{String Conversion}). @end defun -@defun reverse list -This function creates a new list whose elements are the elements of -@var{list}, but in reverse order. The original argument @var{list} is +@defun reverse sequence +This function creates a new sequence whose elements are the elements of +@var{sequence}, but in reverse order. The original argument @var{sequence} is @emph{not} altered. @example @@ -998,13 +998,14 @@ @end smallexample @end defun -@defun nreverse list +@defun nreverse sequence @cindex reversing a list - This function reverses the order of the elements of @var{list}. -Unlike @code{reverse}, @code{nreverse} alters its argument by reversing -the @sc{cdr}s in the cons cells forming the list. The cons cell that -used to be the last one in @var{list} becomes the first cell of the -value. +@cindex reversing a sequence + This function reverses the order of the elements of @var{sequence}. +Unlike @code{reverse}, @code{nreverse} alters its argument. If +@var{sequence} is a list, it does this by reversing the @sc{cdr}s in the +cons cells forming the sequence. The cons cell that used to be the last +one in @var{sequence} becomes the first cell of the value. For example: @@ -1027,7 +1028,7 @@ @end example To avoid confusion, we usually store the result of @code{nreverse} -back in the same variable which held the original list: +back in the same variable which held the original sequence: @example (setq x (nreverse x))
--- a/src/ChangeLog Sun Nov 07 00:15:08 2010 +0100 +++ b/src/ChangeLog Sun Nov 07 00:22:33 2010 +0100 @@ -1,3 +1,15 @@ +2010-11-06 Aidan Kehoe <kehoea@parhasard.net> + + * bytecode.c (bytecode_nreverse): Call Fnreverse() if SEQUENCE is + not a cons in this function. + (Fnreverse, Freverse): + Accept sequences, not just lists, in these functions. + +2010-11-06 Aidan Kehoe <kehoea@parhasard.net> + + * fns.c (Flist_length): Error if LIST is dotted in this function; + document this behaviour. + 2010-10-25 Aidan Kehoe <kehoea@parhasard.net> * specifier.c (specifier_instance_from_inst_list):
--- a/src/bytecode.c Sun Nov 07 00:15:08 2010 +0100 +++ b/src/bytecode.c Sun Nov 07 00:22:33 2010 +0100 @@ -249,21 +249,28 @@ } static Lisp_Object -bytecode_nreverse (Lisp_Object list) +bytecode_nreverse (Lisp_Object sequence) { - REGISTER Lisp_Object prev = Qnil; - REGISTER Lisp_Object tail = list; - - while (!NILP (tail)) + if (LISTP (sequence)) { - REGISTER Lisp_Object next; - CHECK_CONS (tail); - next = XCDR (tail); - XCDR (tail) = prev; - prev = tail; - tail = next; + REGISTER Lisp_Object prev = Qnil; + REGISTER Lisp_Object tail = sequence; + + while (!NILP (tail)) + { + REGISTER Lisp_Object next; + CHECK_CONS (tail); + next = XCDR (tail); + XCDR (tail) = prev; + prev = tail; + tail = next; + } + return prev; } - return prev; + else + { + return Fnreverse (sequence); + } }
--- a/src/fns.c Sun Nov 07 00:15:08 2010 +0100 +++ b/src/fns.c Sun Nov 07 00:22:33 2010 +0100 @@ -343,6 +343,7 @@ DEFUN ("list-length", Flist_length, 1, 1, 0, /* Return the length of LIST. Return nil if LIST is circular. +Error if LIST is dotted. */ (list)) { @@ -357,6 +358,11 @@ tortoise = XCDR (tortoise); } + if (!LISTP (hare)) + { + signal_malformed_list_error (list); + } + return EQ (hare, tortoise) && len != 0 ? Qnil : make_int (len); } @@ -2084,43 +2090,161 @@ } DEFUN ("nreverse", Fnreverse, 1, 1, 0, /* -Reverse LIST by destructively modifying cdr pointers. -Return the beginning of the reversed list. -Also see: `reverse'. +Reverse SEQUENCE, destructively. + +Return the beginning of the reversed sequence, which will be a distinct Lisp +object if SEQUENCE is a list with length greater than one. See also +`reverse', the non-destructive version of this function. */ - (list)) -{ - struct gcpro gcpro1, gcpro2; - Lisp_Object prev = Qnil; - Lisp_Object tail = list; - - /* We gcpro our args; see `nconc' */ - GCPRO2 (prev, tail); - while (!NILP (tail)) - { - REGISTER Lisp_Object next; - CONCHECK_CONS (tail); - next = XCDR (tail); - XCDR (tail) = prev; - prev = tail; - tail = next; - } - UNGCPRO; - return prev; + (sequence)) +{ + CHECK_SEQUENCE (sequence); + + if (CONSP (sequence)) + { + struct gcpro gcpro1, gcpro2; + Lisp_Object prev = Qnil; + Lisp_Object tail = sequence; + + /* We gcpro our args; see `nconc' */ + GCPRO2 (prev, tail); + while (!NILP (tail)) + { + REGISTER Lisp_Object next; + CONCHECK_CONS (tail); + next = XCDR (tail); + XCDR (tail) = prev; + prev = tail; + tail = next; + } + UNGCPRO; + return prev; + } + else if (VECTORP (sequence)) + { + Elemcount length = XVECTOR_LENGTH (sequence), ii = length; + Elemcount half = length / 2; + Lisp_Object swap = Qnil; + + while (ii > half) + { + swap = XVECTOR_DATA (sequence) [length - ii]; + XVECTOR_DATA (sequence) [length - ii] + = XVECTOR_DATA (sequence) [ii - 1]; + XVECTOR_DATA (sequence) [ii - 1] = swap; + --ii; + } + } + else if (STRINGP (sequence)) + { + Elemcount length = XSTRING_LENGTH (sequence); + Ibyte *staging = alloca_ibytes (length), *staging_end = staging + length; + Ibyte *cursor = XSTRING_DATA (sequence), *endp = cursor + length; + + while (cursor < endp) + { + staging_end -= itext_ichar_len (cursor); + itext_copy_ichar (cursor, staging_end); + INC_IBYTEPTR (cursor); + } + + assert (staging == staging_end); + + memcpy (XSTRING_DATA (sequence), staging, length); + init_string_ascii_begin (sequence); + bump_string_modiff (sequence); + sledgehammer_check_ascii_begin (sequence); + } + else if (BIT_VECTORP (sequence)) + { + Lisp_Bit_Vector *bv = XBIT_VECTOR (sequence); + Elemcount length = bit_vector_length (bv), ii = length; + Elemcount half = length / 2; + int swap = 0; + + while (ii > half) + { + swap = bit_vector_bit (bv, length - ii); + set_bit_vector_bit (bv, length - ii, bit_vector_bit (bv, ii - 1)); + set_bit_vector_bit (bv, ii - 1, swap); + --ii; + } + } + else + { + assert (NILP (sequence)); + } + + return sequence; } DEFUN ("reverse", Freverse, 1, 1, 0, /* -Reverse LIST, copying. Return the beginning of the reversed list. +Reverse SEQUENCE, copying. Return the reversed sequence. See also the function `nreverse', which is used more often. */ - (list)) -{ - Lisp_Object reversed_list = Qnil; - EXTERNAL_LIST_LOOP_2 (elt, list) - { - reversed_list = Fcons (elt, reversed_list); - } - return reversed_list; + (sequence)) +{ + Lisp_Object result = Qnil; + + CHECK_SEQUENCE (sequence); + + if (CONSP (sequence)) + { + EXTERNAL_LIST_LOOP_2 (elt, sequence) + { + result = Fcons (elt, result); + } + } + else if (VECTORP (sequence)) + { + Elemcount length = XVECTOR_LENGTH (sequence), ii = length; + Lisp_Object *staging = alloca_array (Lisp_Object, length); + + while (ii > 0) + { + staging[length - ii] = XVECTOR_DATA (sequence) [ii - 1]; + --ii; + } + + result = Fvector (length, staging); + } + else if (STRINGP (sequence)) + { + Elemcount length = XSTRING_LENGTH (sequence); + Ibyte *staging = alloca_ibytes (length), *staging_end = staging + length; + Ibyte *cursor = XSTRING_DATA (sequence), *endp = cursor + length; + + while (cursor < endp) + { + staging_end -= itext_ichar_len (cursor); + itext_copy_ichar (cursor, staging_end); + INC_IBYTEPTR (cursor); + } + + assert (staging == staging_end); + + result = make_string (staging, length); + } + else if (BIT_VECTORP (sequence)) + { + Lisp_Bit_Vector *bv = XBIT_VECTOR (sequence), *res; + Elemcount length = bit_vector_length (bv), ii = length; + + result = make_bit_vector (length, Qzero); + res = XBIT_VECTOR (result); + + while (ii > 0) + { + set_bit_vector_bit (res, length - ii, bit_vector_bit (bv, ii - 1)); + --ii; + } + } + else + { + assert (NILP (sequence)); + } + + return result; } static Lisp_Object
--- a/tests/ChangeLog Sun Nov 07 00:15:08 2010 +0100 +++ b/tests/ChangeLog Sun Nov 07 00:22:33 2010 +0100 @@ -1,3 +1,14 @@ +2010-11-06 Aidan Kehoe <kehoea@parhasard.net> + + * automated/lisp-tests.el (list-nreverse): + Check that #'reverse and #'nreverse handle non-list sequences + properly. + +2010-11-06 Aidan Kehoe <kehoea@parhasard.net> + + * automated/lisp-tests.el (malformed-list): Check that #'mapcar, + #'map and #'list-length throw this error when appropriate. + 2010-10-25 Aidan Kehoe <kehoea@parhasard.net> * automated/lisp-tests.el:
--- a/tests/automated/lisp-tests.el Sun Nov 07 00:15:08 2010 +0100 +++ b/tests/automated/lisp-tests.el Sun Nov 07 00:22:33 2010 +0100 @@ -1038,6 +1038,12 @@ 1) "checking multiple values are correctly discarded in mapcar") +(let ((malformed-list '(1 2 3 4 hi there . tail))) + (Check-Error malformed-list (mapcar #'identity malformed-list)) + (Check-Error malformed-list (map nil #'eq [1 2 3 4] + malformed-list)) + (Check-Error malformed-list (list-length malformed-list))) + ;;----------------------------------------------------- ;; Test vector functions ;;----------------------------------------------------- @@ -2476,4 +2482,31 @@ (Assert (equal expected (merge 'list list '(1) #'<)) "checking merge's circularity checks are sane")) +(flet ((list-nreverse (list) + (do ((list1 list (cdr list1)) + (list2 nil (prog1 list1 (setcdr list1 list2)))) + ((atom list1) list2)))) + (let* ((integers (loop for i from 0 to 6000 collect i)) + (characters (mapcan #'(lambda (integer) + (if (char-int-p integer) + (list (int-char integer)))) integers)) + (fourth-bit #'(lambda (integer) (ash (logand #x10 integer) -4))) + (bits (mapcar fourth-bit integers)) + (vector (vconcat integers)) + (string (concat characters)) + (bit-vector (bvconcat bits))) + (Assert (equal (reverse vector) + (vconcat (list-nreverse (copy-list integers))))) + (Assert (eq vector (nreverse vector))) + (Assert (equal vector (vconcat (list-nreverse (copy-list integers))))) + (Assert (equal (reverse string) + (concat (list-nreverse (copy-list characters))))) + (Assert (eq string (nreverse string))) + (Assert (equal string (concat (list-nreverse (copy-list characters))))) + (Assert (eq bit-vector (nreverse bit-vector))) + (Assert (equal (bvconcat (list-nreverse (copy-list bits))) bit-vector)) + (Assert (not (equal bit-vector + (mapcar fourth-bit + (loop for i from 0 to 6000 collect i))))))) + ;;; end of lisp-tests.el