unofficial mirror of bug-guile@gnu.org 
 help / color / mirror / Atom feed
From: David Kastrup <dak@gnu.org>
To: 17485@debbugs.gnu.org
Cc: David Kastrup <dak@gnu.org>
Subject: bug#17485: [PATCH 2/3] Rewrite take-right, drop-right, drop-right!
Date: Tue,  3 Jun 2014 20:56:17 +0200	[thread overview]
Message-ID: <1401821778-19972-2-git-send-email-dak@gnu.org> (raw)
In-Reply-To: <1401821778-19972-1-git-send-email-dak@gnu.org>

* module/srfi/srfi-1.scm (take-right, drop-right, drop-right!): The
  definitions tended to be overly complicate and/or rely on pushing
  material on the VM stack, detrimental to scalability for Guile 2.0 and
  also worse for performance.

  The changed definitions lead to different, more accurate exceptions
  being raised.  They rely on length+ returning the length of dotted
  lists, behavior that is not specified by the SRFI-1 definition but
  available in GUILE.

Signed-off-by: David Kastrup <dak@gnu.org>
---
 module/srfi/srfi-1.scm       | 44 ++++++++++++++++++++------------------------
 test-suite/tests/srfi-1.test | 24 ++++++++++++------------
 2 files changed, 32 insertions(+), 36 deletions(-)

diff --git a/module/srfi/srfi-1.scm b/module/srfi/srfi-1.scm
index bc72048..73d164a 100644
--- a/module/srfi/srfi-1.scm
+++ b/module/srfi/srfi-1.scm
@@ -363,21 +363,24 @@ end-of-list checking in contexts where dotted lists are allowed."
 (define take list-head)
 (define drop list-tail)
 
-;;; TAKE-RIGHT and DROP-RIGHT work by getting two pointers into the list, 
-;;; off by K, then chasing down the list until the lead pointer falls off
-;;; the end.  Note that they diverge for circular lists.
+;;; TAKE-RIGHT and DROP-RIGHT make use of this implementation's length+
+;;; being defined for dotted lists.  They error out for circular lists.
 
 (define (take-right lis k)
-  (let lp ((lag lis)  (lead (drop lis k)))
-    (if (pair? lead)
-	(lp (cdr lag) (cdr lead))
-	lag)))
+  (let ((len (length+ lis)))
+    (if len
+        (if (<= 0 k len)
+            (drop lis (- len k))
+            (out-of-range 'take-right k))
+        (wrong-type-arg 'take-right lis))))
 
 (define (drop-right lis k)
-  (let recur ((lag lis) (lead (drop lis k)))
-    (if (pair? lead)
-	(cons (car lag) (recur (cdr lag) (cdr lead)))
-	'())))
+  (let ((len (length+ lis)))
+    (if len
+        (if (<= 0 k len)
+            (take lis (- len k))
+            (out-of-range 'drop-right k))
+        (wrong-type-arg 'drop-right lis))))
 
 (define (take! lst i)
   "Linear-update variant of `take'."
@@ -389,19 +392,12 @@ end-of-list checking in contexts where dotted lists are allowed."
 
 (define (drop-right! lst i)
   "Linear-update variant of `drop-right'."
-  (let ((tail (drop lst i)))
-    (if (null? tail)
-        '()
-        (let loop ((prev lst)
-                   (tail (cdr tail)))
-          (if (null? tail)
-              (if (pair? prev)
-                  (begin
-                    (set-cdr! prev '())
-                    lst)
-                  lst)
-              (loop (cdr prev)
-                    (cdr tail)))))))
+  (let ((len (length+ lst)))
+    (if len
+        (if (<= 0 i len)
+            (take! lst (- len i))
+            (out-of-range 'drop-right! i))
+        (wrong-type-arg 'drop-right! lst))))
 
 (define (split-at lst i)
   "Return two values, a list of the elements before index I in LST, and
diff --git a/test-suite/tests/srfi-1.test b/test-suite/tests/srfi-1.test
index 9364ea2..032bfa4 100644
--- a/test-suite/tests/srfi-1.test
+++ b/test-suite/tests/srfi-1.test
@@ -877,14 +877,14 @@
   (pass-if-exception "() -1" exception:out-of-range
     (drop-right '() -1))
   (pass-if (equal? '() (drop-right '() 0)))
-  (pass-if-exception "() 1" exception:wrong-type-arg
+  (pass-if-exception "() 1" exception:out-of-range
     (drop-right '() 1))
 
   (pass-if-exception "(1) -1" exception:out-of-range
     (drop-right '(1) -1))
   (pass-if (equal? '(1) (drop-right '(1) 0)))
   (pass-if (equal? '() (drop-right '(1) 1)))
-  (pass-if-exception "(1) 2" exception:wrong-type-arg
+  (pass-if-exception "(1) 2" exception:out-of-range
     (drop-right '(1) 2))
 
   (pass-if-exception "(4 5) -1" exception:out-of-range
@@ -892,7 +892,7 @@
   (pass-if (equal? '(4 5) (drop-right '(4 5) 0)))
   (pass-if (equal? '(4) (drop-right '(4 5) 1)))
   (pass-if (equal? '() (drop-right '(4 5) 2)))
-  (pass-if-exception "(4 5) 3" exception:wrong-type-arg
+  (pass-if-exception "(4 5) 3" exception:out-of-range
     (drop-right '(4 5) 3))
 
   (pass-if-exception "(4 5 6) -1" exception:out-of-range
@@ -901,7 +901,7 @@
   (pass-if (equal? '(4 5) (drop-right '(4 5 6) 1)))
   (pass-if (equal? '(4) (drop-right '(4 5 6) 2)))
   (pass-if (equal? '() (drop-right '(4 5 6) 3)))
-  (pass-if-exception "(4 5 6) 4" exception:wrong-type-arg
+  (pass-if-exception "(4 5 6) 4" exception:out-of-range
     (drop-right '(4 5 6) 4))
 
   (pass-if "(a b . c) 0"
@@ -918,14 +918,14 @@
   (pass-if-exception "() -1" exception:out-of-range
     (drop-right! '() -1))
   (pass-if (equal? '() (drop-right! '() 0)))
-  (pass-if-exception "() 1" exception:wrong-type-arg
+  (pass-if-exception "() 1" exception:out-of-range
     (drop-right! '() 1))
 
   (pass-if-exception "(1) -1" exception:out-of-range
     (drop-right! (list 1) -1))
   (pass-if (equal? '(1) (drop-right! (list 1) 0)))
   (pass-if (equal? '() (drop-right! (list 1) 1)))
-  (pass-if-exception "(1) 2" exception:wrong-type-arg
+  (pass-if-exception "(1) 2" exception:out-of-range
     (drop-right! (list 1) 2))
 
   (pass-if-exception "(4 5) -1" exception:out-of-range
@@ -933,7 +933,7 @@
   (pass-if (equal? '(4 5) (drop-right! (list 4 5) 0)))
   (pass-if (equal? '(4) (drop-right! (list 4 5) 1)))
   (pass-if (equal? '() (drop-right! (list 4 5) 2)))
-  (pass-if-exception "(4 5) 3" exception:wrong-type-arg
+  (pass-if-exception "(4 5) 3" exception:out-of-range
     (drop-right! (list 4 5) 3))
 
   (pass-if-exception "(4 5 6) -1" exception:out-of-range
@@ -942,7 +942,7 @@
   (pass-if (equal? '(4 5) (drop-right! (list 4 5 6) 1)))
   (pass-if (equal? '(4) (drop-right! (list 4 5 6) 2)))
   (pass-if (equal? '() (drop-right! (list 4 5 6) 3)))
-  (pass-if-exception "(4 5 6) 4" exception:wrong-type-arg
+  (pass-if-exception "(4 5 6) 4" exception:out-of-range
     (drop-right! (list 4 5 6) 4)))
 
 ;;
@@ -2603,14 +2603,14 @@
   (pass-if-exception "() -1" exception:out-of-range
     (take-right '() -1))
   (pass-if (equal? '() (take-right '() 0)))
-  (pass-if-exception "() 1" exception:wrong-type-arg
+  (pass-if-exception "() 1" exception:out-of-range
     (take-right '() 1))
 
   (pass-if-exception "(1) -1" exception:out-of-range
     (take-right '(1) -1))
   (pass-if (equal? '() (take-right '(1) 0)))
   (pass-if (equal? '(1) (take-right '(1) 1)))
-  (pass-if-exception "(1) 2" exception:wrong-type-arg
+  (pass-if-exception "(1) 2" exception:out-of-range
     (take-right '(1) 2))
 
   (pass-if-exception "(4 5) -1" exception:out-of-range
@@ -2618,7 +2618,7 @@
   (pass-if (equal? '() (take-right '(4 5) 0)))
   (pass-if (equal? '(5) (take-right '(4 5) 1)))
   (pass-if (equal? '(4 5) (take-right '(4 5) 2)))
-  (pass-if-exception "(4 5) 3" exception:wrong-type-arg
+  (pass-if-exception "(4 5) 3" exception:out-of-range
     (take-right '(4 5) 3))
 
   (pass-if-exception "(4 5 6) -1" exception:out-of-range
@@ -2627,7 +2627,7 @@
   (pass-if (equal? '(6) (take-right '(4 5 6) 1)))
   (pass-if (equal? '(5 6) (take-right '(4 5 6) 2)))
   (pass-if (equal? '(4 5 6) (take-right '(4 5 6) 3)))
-  (pass-if-exception "(4 5 6) 4" exception:wrong-type-arg
+  (pass-if-exception "(4 5 6) 4" exception:out-of-range
     (take-right '(4 5 6) 4))
 
   (pass-if "(a b . c) 0"
-- 
1.9.1






  reply	other threads:[~2014-06-03 18:56 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-05-13 10:47 bug#17485: (srfi srfi-1) reduce-right does not scale, version 2.0.9 David Kastrup
2014-06-01 23:41 ` Mark H Weaver
2014-06-02  7:59   ` David Kastrup
2014-06-03 18:56 ` bug#17485: [PATCH 1/3] Let length+ return the length of dotted lists rather than #f David Kastrup
2014-06-03 18:56   ` David Kastrup [this message]
2014-06-04  3:29     ` bug#17485: [PATCH 2/3] Rewrite take-right, drop-right, drop-right! Mark H Weaver
2014-06-04  3:45     ` Mark H Weaver
2014-09-20 14:56     ` Mark H Weaver
2014-09-20 15:15       ` David Kastrup
2014-09-22 17:15         ` Mark H Weaver
2014-09-22 18:40           ` David Kastrup
2014-06-03 18:56   ` bug#17485: [PATCH 3/3] Reimplement reduce-right in srfi-1 David Kastrup
2014-06-04  3:30     ` Mark H Weaver
2014-06-04  3:42   ` bug#17485: [PATCH 1/3] Let length+ return the length of dotted lists rather than #f Mark H Weaver
2014-06-04  4:57     ` David Kastrup
2014-06-04 10:09       ` David Kastrup
2014-06-05 13:57         ` David Kastrup
2016-06-21 14:42 ` bug#17485: (srfi srfi-1) reduce-right does not scale, version 2.0.9 Andy Wingo
2016-06-21 15:31   ` David Kastrup
2016-07-12  7:07     ` Andy Wingo
2016-07-12  7:43 ` bug#17485: Ugh, well David Kastrup
2016-07-12 13:54   ` Andy Wingo

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/guile/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1401821778-19972-2-git-send-email-dak@gnu.org \
    --to=dak@gnu.org \
    --cc=17485@debbugs.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).