changeset 5306:cde1608596d0

Handle bignum N correctly, #'butlast, #'nbutlast. 2010-11-17 Aidan Kehoe <kehoea@parhasard.net> * fns.c (bignum_butlast): New. (Fnbutlast, Fbutlast): Use it. In #'butlast and #'nbutlast, if N is a bignum, we should always return nil. Bug revealed by Paul Dietz' test suite, thank you Paul.
author Aidan Kehoe <kehoea@parhasard.net>
date Wed, 17 Nov 2010 14:37:26 +0000
parents 09fed7053634
children c096d8051f89
files src/ChangeLog src/fns.c
diffstat 2 files changed, 57 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/src/ChangeLog	Wed Nov 17 14:30:03 2010 +0000
+++ b/src/ChangeLog	Wed Nov 17 14:37:26 2010 +0000
@@ -1,3 +1,11 @@
+2010-11-17  Aidan Kehoe  <kehoea@parhasard.net>
+
+	* fns.c (bignum_butlast): New.
+	(Fnbutlast, Fbutlast): Use it.
+	In #'butlast and #'nbutlast, if N is a bignum, we should always
+	return nil. Bug revealed by Paul Dietz' test suite, thank you
+	Paul.
+
 2010-11-15  Aidan Kehoe  <kehoea@parhasard.net>
 
 	* .gdbinit.in: Remove lrecord_type_popup_data,
--- a/src/fns.c	Wed Nov 17 14:30:03 2010 +0000
+++ b/src/fns.c	Wed Nov 17 14:37:26 2010 +0000
@@ -1576,6 +1576,9 @@
   return retval;
 }
 
+static Lisp_Object bignum_butlast (Lisp_Object list, Lisp_Object number,
+                                   Boolint copy);
+
 DEFUN ("nbutlast", Fnbutlast, 1, 2, 0, /*
 Modify LIST to remove the last N (default 1) elements.
 
@@ -1590,6 +1593,11 @@
 
   if (!NILP (n))
     {
+      if (BIGNUMP (n))
+        {
+          return bignum_butlast (list, n, 0);
+        }
+
       CHECK_NATNUM (n);
       int_n = XINT (n);
     }
@@ -1638,6 +1646,11 @@
 
   if (!NILP (n))
     {
+      if (BIGNUMP (n))
+        {
+          return bignum_butlast (list, n, 1);
+        }
+
       CHECK_NATNUM (n);
       int_n = XINT (n);
     }
@@ -1673,6 +1686,42 @@
   return retval;
 }
 
+/* This is sufficient to implement #'butlast and #'nbutlast with bignum N
+   under XEmacs, because #'list-length and #'safe-length can never return a
+   bignum. This means that #'nbutlast never has to modify and #'butlast
+   never has to copy. */
+static Lisp_Object
+bignum_butlast (Lisp_Object list, Lisp_Object number, Boolint copy)
+{
+  Boolint malformed = EQ (Fsafe_length (list), Qzero);
+  Boolint circular = !malformed && EQ (Flist_length (list), Qnil);
+
+  assert (BIGNUMP (number));
+
+#ifdef HAVE_BIGNUM
+
+  if (bignum_sign (XBIGNUM_DATA (number)) < 0)
+    {
+      dead_wrong_type_argument (Qnatnump, number);
+    }
+
+  number = Fcanonicalize_number (number);
+
+  if (INTP (number))
+    {
+      return copy ? Fbutlast (list, number) : Fnbutlast (list, number);
+    }
+
+#endif
+
+  if (circular)
+    {
+      signal_circular_list_error (list);
+    }
+
+  return Qnil;
+}
+
 DEFUN ("member", Fmember, 2, 2, 0, /*
 Return non-nil if ELT is an element of LIST.  Comparison done with `equal'.
 The value is actually the tail of LIST whose car is ELT.