length.lisp (1484 bytes)
1 (in-package :cl-user) 2 (defpackage #:len-cmp 3 (:use #:cl) 4 (:export :len)) 5 (in-package :len-cmp) 6 7 ;;;; An attempt to define an efficient length comparator. 8 #+5am (5am:def-suite length-tests :description "Test length functions.") 9 #+5am (5am:in-suite length-tests) 10 11 (in-package :len-cmp) 12 13 (defun null0 (list) 14 "Normalize a list variable to be numeric for length computation." 15 (if (null list) 0 1)) 16 17 #+5am (5am:test null0 (5am:is-true (and (= 1 (null0 '(1))) 18 (= 0 (null0 nil))))) 19 20 (defun len (a b &optional predicate) 21 "Compare length in a variety of efficient ways." 22 (let ((predicate (if predicate predicate #'=))) 23 (if (integerp a) 24 (len-int a b predicate) 25 (len-list a b predicate)))) 26 27 (defun len-int (a b predicate) 28 (declare (integer a) 29 ((or null cons) b)) 30 (if (or (= 0 a) (null b)) 31 (funcall predicate a (null0 b)) 32 (len-int (1- a) (cdr b) predicate))) 33 34 (defun len-list (a b predicate) 35 (declare ((or null cons) a b)) 36 (if (and a b) 37 (len-list (cdr a) (cdr b) predicate) 38 (funcall predicate (null0 a) (null0 b)))) 39 40 #+5am (5am:test len-list (5am:is-true (and (len '(1) '(1 2) #'<) 41 (len '(1) '(1) #'=)))) 42 #+5am (5am:test len-int (5am:is-true (and (len 1 '(1)) 43 (len 0 nil) 44 (not (len 1 '(1 2))) 45 (not (len 1 nil)))))