X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fsequence.lisp;h=8d2701b6392cb62f7a4c6bf7eea245a4fd4f6c9c;hb=7b9c47361e1aac31bc78d4627b651b8cc5ee0a7c;hp=e5e7aca90e2bf1a7aed459432de500a4154f5b39;hpb=c2493e3427215081351e8ab6a0e90aebe946c86d;p=jscl.git diff --git a/src/sequence.lisp b/src/sequence.lisp index e5e7aca..8d2701b 100644 --- a/src/sequence.lisp +++ b/src/sequence.lisp @@ -13,56 +13,48 @@ ;; You should have received a copy of the GNU General Public License ;; along with JSCL. If not, see . -(defmacro doseq ((elt seq &optional index) &body body) - (let* ((nseq (gensym "seq")) - (i (or index (gensym "i"))) - (list-body (if index - `(let ((,i -1)) - (dolist (,elt ,nseq) - (incf ,i) - ,@body)) - `(dolist (,elt ,nseq) - ,@body)))) +(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) + (error "`~S' must be a symbol." elt)) `(let ((,nseq ,seq)) (if (listp ,nseq) - ,list-body - (dotimes (,i (length ,nseq)) - (let ((,elt (aref ,nseq ,i))) + ,(if index-p + `(let ((,index -1)) + (dolist (,elt ,nseq) + (incf ,index) + ,@body)) + `(dolist (,elt ,nseq) + ,@body)) + (dotimes (,index (length ,nseq)) + (let ((,elt (aref ,nseq ,index))) ,@body)))))) (defun find (item seq &key key (test #'eql)) (if key - (doseq (x seq) + (do-sequence (x seq) (when (funcall test (funcall key x) item) (return x))) - (doseq (x seq) + (do-sequence (x seq) (when (funcall test x item) (return x))))) -(defun find-if (predicate sequence &key (key #'identity)) - (do-sequence (x sequence) - (when (funcall predicate (funcall key x)) - (return x)))) - -(defun some (function seq) - (do-sequence (elt seq) - (when (funcall function elt) - (return-from some t)))) - -(defun every (function seq) - (do-sequence (elt seq) - (unless (funcall function elt) - (return-from every nil))) - t) - -(defun position (elt sequence) - (let ((pos 0)) - (do-sequence (x seq) - (when (eq elt x) - (return)) - (incf pos)) - pos)) +(defun find-if (predicate sequence &key key) + (if key + (do-sequence (x sequence) + (when (funcall predicate (funcall key x)) + (return x))) + (do-sequence (x sequence) + (when (funcall predicate x) + (return x))))) +(defun position (elt sequence &key (test #'eql)) + (do-sequence (x seq index) + (when (funcall test elt x) + (return index)))) (defun remove (x seq) (cond @@ -71,7 +63,7 @@ ((listp seq) (let* ((head (cons nil nil)) (tail head)) - (doseq (elt seq) + (do-sequence (elt seq) (unless (eql x elt) (let ((new (list elt))) (rplacd tail new) @@ -79,7 +71,7 @@ (cdr head))) (t (let (vector) - (doseq (elt seq index) + (do-sequence (elt seq index) (if (eql x elt) ;; Copy the beginning of the vector only when we find an element ;; that does not match. @@ -92,23 +84,66 @@ (or vector seq))))) -;;; TODO: Support vectors +(defun some (function seq) + (do-sequence (elt seq) + (when (funcall function elt) + (return-from some t)))) -(defun remove-if (func list) +(defun every (function seq) + (do-sequence (elt seq) + (unless (funcall function elt) + (return-from every nil))) + t) + +(defun remove-if (func seq) (cond - ((null list) - nil) - ((funcall func (car list)) - (remove-if func (cdr list))) - (t - ;; - (cons (car list) (remove-if func (cdr list)))))) + ((listp seq) (list-remove-if func seq nil)) + ((arrayp seq) (vector-remove-if func seq nil)) + (t (not-seq-error seq)))) -(defun remove-if-not (func list) +(defun remove-if-not (func seq) (cond - ((null list) - nil) - ((funcall func (car list)) - (cons (car list) (remove-if-not func (cdr list)))) - (t - (remove-if-not func (cdr list))))) + ((listp seq) (list-remove-if func seq t)) + ((arrayp seq) (vector-remove-if func seq t)) + (t (not-seq-error seq)))) + +(defun list-remove-if (func list negate) + (if (endp list) + () + (let ((test (funcall func (car list)))) + (if (if negate (not test) test) + (list-remove-if func (cdr list) negate) + (cons (car list) (list-remove-if func (cdr list) negate)))))) + +(defun vector-remove-if (func vector negate) + (let ((out-vector (make-array 0))) + (do-sequence (element vector i) + (let ((test (funcall func element))) + (when (if negate test (not test)) + (vector-push-extend element out-vector)))) + out-vector)) + +(defun subseq (seq a &optional b) + (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))))