Modify SUBST to:
[jscl.git] / src / sequence.lisp
index e5e7aca..8d2701b 100644 (file)
 ;; You should have received a copy of the GNU General Public License
 ;; along with JSCL.  If not, see <http://www.gnu.org/licenses/>.
 
-(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.
        (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))))