X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fsequence.lisp;h=6ac3ebfbe1e73bf3f5ec7b76739a127adad69fea;hb=c90c7de3efcd6934c6dfd217c64def71bc611d54;hp=4b5a7598864d9712de43d150cf9d7ee055fc2770;hpb=74f21cdb986001f15a889011698350de1dd51fe2;p=jscl.git diff --git a/src/sequence.lisp b/src/sequence.lisp index 4b5a759..6ac3ebf 100644 --- a/src/sequence.lisp +++ b/src/sequence.lisp @@ -13,6 +13,9 @@ ;; You should have received a copy of the GNU General Public License ;; along with JSCL. If not, see . +(defun not-seq-error (thing) + (error "`~S' is not of type SEQUENCE" thing)) + (defmacro do-sequence ((elt seq &optional (index (gensym "i") index-p)) &body body) (let ((nseq (gensym "seq"))) (unless (symbolp elt) @@ -30,14 +33,11 @@ (let ((,elt (aref ,nseq ,index))) ,@body)))))) -(defun find (item seq &key key (test #'eql)) - (if key - (do-sequence (x seq) - (when (funcall test (funcall key x) item) - (return x))) - (do-sequence (x seq) - (when (funcall test x item) - (return x))))) +(defun find (item seq &key key (test #'eql testp) (test-not #'eql test-not-p)) + (do-sequence (x seq) + (when (satisfies-test-p item x :key key :test test :testp testp + :test-not test-not :test-not-p test-not-p) + (return x)))) (defun find-if (predicate sequence &key key) (if key @@ -48,12 +48,14 @@ (when (funcall predicate x) (return x))))) -(defun position (elt sequence &key (test #'eql)) - (do-sequence (x seq index) - (when (funcall test elt x) +(defun position (elt sequence &key key (test #'eql testp) + (test-not #'eql test-not-p)) + (do-sequence (x sequence index) + (when (satisfies-test-p elt x :key key :test test :testp testp + :test-not test-not :test-not-p test-not-p ) (return index)))) -(defun remove (x seq) +(defun remove (x seq &key key (test #'eql testp) (test-not #'eql test-not-p)) (cond ((null seq) nil) @@ -61,7 +63,8 @@ (let* ((head (cons nil nil)) (tail head)) (do-sequence (elt seq) - (unless (eql x elt) + (unless (satisfies-test-p x elt :key key :test test :testp testp + :test-not test-not :test-not-p test-not-p) (let ((new (list elt))) (rplacd tail new) (setq tail new)))) @@ -69,7 +72,8 @@ (t (let (vector) (do-sequence (elt seq index) - (if (eql x elt) + (if (satisfies-test-p x elt :key key :test test :testp testp + :test-not test-not :test-not-p test-not-p) ;; Copy the beginning of the vector only when we find an element ;; that does not match. (unless vector @@ -96,13 +100,13 @@ (cond ((listp seq) (list-remove-if func seq nil)) ((arrayp seq) (vector-remove-if func seq nil)) - (t (error "`~S' is not of type SEQUENCE" seq)))) + (t (not-seq-error seq)))) (defun remove-if-not (func seq) (cond ((listp seq) (list-remove-if func seq t)) ((arrayp seq) (vector-remove-if func seq t)) - (t (error "`~S' is not of type SEQUENCE" seq)))) + (t (not-seq-error seq)))) (defun list-remove-if (func list negate) (if (endp list) @@ -120,9 +124,27 @@ (vector-push-extend element out-vector)))) out-vector)) -;;; TODO: Support both List and vectors in the following functions - (defun subseq (seq a &optional b) - (if b - (slice seq a b) - (slice seq a))) + (cond + ((listp seq) + (if b + (let ((diff (- b a))) + (cond + ((zerop diff) ()) + ((minusp diff) + (error "Start index must be smaller than end index")) + (t + (let* ((drop-a (copy-list (nthcdr a seq))) + (pointer drop-a)) + (dotimes (_ (1- diff)) + (setq pointer (cdr pointer)) + (when (null pointer) + (error "Ending index larger than length of list"))) + (rplacd pointer ()) + drop-a)))) + (copy-list (nthcdr a seq)))) + ((arrayp seq) + (if b + (slice seq a b) + (slice seq a))) + (t (not-seq-error seq))))