[cl-utilities-cvs] CVS update: cl-utilities/extremum.lisp

Peter Scott pscott at common-lisp.net
Tue May 17 19:17:34 UTC 2005


Update of /project/cl-utilities/cvsroot/cl-utilities
In directory common-lisp.net:/tmp/cvs-serv24989

Modified Files:
	extremum.lisp 
Log Message:
Fixed various problems and factored out some very ugly repeated
checking code into a macro. The code is now much cleaner and less
error-prone.

Date: Tue May 17 21:17:34 2005
Author: pscott

Index: cl-utilities/extremum.lisp
diff -u cl-utilities/extremum.lisp:1.4 cl-utilities/extremum.lisp:1.5
--- cl-utilities/extremum.lisp:1.4	Tue May 17 00:06:47 2005
+++ cl-utilities/extremum.lisp	Tue May 17 21:17:34 2005
@@ -31,6 +31,19 @@
 
 (declaim (inline zero-length-p))
 
+;; Checks the length of the subsequence of SEQUENCE specified by START
+;; and END, and if it's 0 then a NO-EXTREMUM error is signalled. This
+;; should only be used in EXTREMUM functions.
+(defmacro with-check-length ((sequence start end) &body body)
+  (once-only (sequence start end)
+    `(if (or (zero-length-p ,sequence)
+	  (>= ,start (or ,end (length ,sequence))))
+      (restart-case (error 'no-extremum)
+	(continue ()
+	  :report "Return NIL instead"
+	  nil))
+      , at body)))
+
 ;; This is an extended version which takes START and END keyword
 ;; arguments. Any spec-compliant use of EXTREMUM will also work with
 ;; this extended version.
@@ -41,26 +54,16 @@
 http://www.cliki.net/EXTREMUM for the full
 specification. Additionally, START and END specify the beginning and
 ending indices of the part of the sequence we should look at."
-  (if (or (zero-length-p sequence)
-	  (>= start (or end (length sequence))))
-      (restart-case (error 'no-extremum)
-	(continue ()
-	  :report "Return NIL instead"
-	  nil))
-      (reduce (comparator predicate key) sequence
-	      :start start :end end)))
+  (with-check-length (sequence start end)
+    (reduce (comparator predicate key) sequence
+	    :start start :end end)))
 
 ;; This optimizes the case where KEY is #'identity
 (define-compiler-macro extremum (&whole whole sequence predicate
 					&key (key #'identity) (start 0) end)
   (if (eql key #'identity)
       (once-only (sequence predicate start end)
-	`(if (or (zero-length-p ,sequence)
-	      (>= ,start (or ,end (length ,sequence))))
-	  (restart-case (error 'no-extremum)
-	    (continue ()
-	      :report "Return NIL instead"
-	      nil))
+	`(with-check-length (,sequence ,start ,end)
 	  (locally (declare (optimize (speed 3) (safety 0) (space 0) (debug 1)))
 	    (reduce (comparator ,predicate) ,sequence
 		    :start ,start :end ,end))))
@@ -72,12 +75,8 @@
   "Returns the element of SEQUENCE that would appear first if the
 sequence were ordered according to SORT using PREDICATE and KEY. See
 http://www.cliki.net/EXTREMUM for the full specification."
-  (if (zero-length-p sequence)
-      (restart-case (error 'no-extremum)
-	(continue ()
-	  :report "Return NIL instead"
-	  nil))
-      (reduce (comparator predicate key) sequence)))
+  (with-check-length (sequence 0 nil)
+    (reduce (comparator predicate key) sequence)))
 
 ;; This is an "optimized" version which calls KEY less. REDUCE is
 ;; already so optimized that this will actually be slower unless KEY
@@ -91,26 +90,21 @@
 if the KEY function is so slow that calling it less often would be a
 significant improvement; ordinarily it's slower."
   (declare (optimize (speed 3) (safety 0) (space 0) (debug 1)))
-  (if (or (zero-length-p sequence)
-	  (>= start (or end (length sequence))))
-      (restart-case (error 'no-extremum)
-	(continue ()
-	  :report "Return NIL instead"
-	  nil))
-      (let* ((smallest (elt sequence 0))
-	     (smallest-key (funcall key smallest))
-	     (current-index 0)
-	     (real-end (or end #.(1- most-positive-fixnum))))
-	(declare (type (integer 0 #.most-positive-fixnum)
-		       current-index real-end start))
-	(map nil #'(lambda (x)
-		     (when (<= start current-index real-end)
-		       (let ((x-key (funcall key x)))
-			 (when (funcall predicate
-					x-key
-					smallest-key)
-			   (setf smallest x)
-			   (setf smallest-key x-key))))
-		     (incf current-index))
-	     sequence)
-	smallest)))
\ No newline at end of file
+  (with-check-length (sequence start end)
+    (let* ((smallest (elt sequence 0))
+	   (smallest-key (funcall key smallest))
+	   (current-index 0)
+	   (real-end (or end #.(1- most-positive-fixnum))))
+      (declare (type (integer 0 #.most-positive-fixnum)
+		     current-index real-end start))
+      (map nil #'(lambda (x)
+		   (when (<= start current-index real-end)
+		     (let ((x-key (funcall key x)))
+		       (when (funcall predicate
+				      x-key
+				      smallest-key)
+			 (setf smallest x)
+			 (setf smallest-key x-key))))
+		   (incf current-index))
+	   sequence)
+      smallest)))
\ No newline at end of file




More information about the Cl-utilities-cvs mailing list