;;; Random useful utilities.
;;; Copyright (c) 1993 by Olin Shivers. See file COPYING.

(define (del elt lis)
  (letrec ((del (lambda (lis)
		  (if (pair? lis)
		      (let* ((head (car lis))
			     (tail (cdr lis))
			     (new-tail (del tail)))
			(if (equal? head elt) new-tail
			    (if (eq? tail new-tail) lis
				(cons head new-tail))))
		      '()))))
    (del lis)))

(define (delete pred lis)
  (filter (lambda (x) (not (pred x))) lis))

(define (fold kons knil lis)
  (let lp ((lis lis) (ans knil))
    (if (pair? lis)
	(lp (cdr lis) (kons (car lis) ans))
	ans)))

(define (fold-right kons knil lis)
  (let recur ((lis lis))
    (if (pair? lis)
	(let ((head (car lis)))		; Won't need LIS after RECUR call. 
	  (kons head (recur (cdr lis))))
	knil)))

(define (filter pred list)
  (letrec ((filter (lambda (list)
		     (if (pair? list)
			 (let* ((head (car list))
				(tail (cdr list))
				(new-tail (filter tail)))
			   (if (pred head)
			       (if (eq? tail new-tail) list
				   (cons head new-tail))
			       new-tail))
			 '()))))
    (filter list)))

(define (first pred list)
  (letrec ((lp (lambda (list)
		 (and (pair? list)
		      (let ((head (car list)))
			(if (pred head) head
			    (lp (cdr list))))))))
    (lp list)))

;;; Returns the first true value produced by PRED, not the list element
;;; that satisfied PRED.

(define (first? pred list)
  (letrec ((lp (lambda (list)
		 (and (pair? list)
		      (or (pred (car list))
			  (lp (cdr list)))))))
    (lp list)))

(define any first?)

(define (every pred list)
  (or (not (pair? list))	
      (let lp ((head (car list))  (tail (cdr list)))
	(if (pair? tail)
	    (and (pred head) (lp (car tail) (cdr tail)))
	    (pred head)))))		; Tail-call the last PRED call.


(define (mapv f v)
  (let* ((len (vector-length v))
	 (ans (make-vector len)))
    (do ((i 0 (+ i 1)))
	((>= i len) ans)
      (vector-set! ans i (f (vector-ref v i))))))

(define (mapv! f v)
  (let ((len (vector-length v)))
    (do ((i 0 (+ i 1)))
	((>= i len) v)
      (vector-set! v i (f (vector-ref v i))))))

(define (vector-every? pred v)
  (let lp ((i (- (vector-length v) 1)))
    (or (< i 0)
	(and (pred (vector-ref v i))
	     (lp (- i 1))))))

(define (copy-vector v)
  (let* ((len (vector-length v))
	 (ans (make-vector len)))
    (do ((i (- len 1) (- i 1)))
	((< i 0) ans)
      (vector-set! ans i (vector-ref v i)))))

(define (initialize-vector len init)
  (let ((v (make-vector len)))
    (do ((i (- len 1) (- i 1)))
	((< i 0) v)
      (vector-set! v i (init i)))))

(define (vector-append . vecs)
  (let* ((vlen (fold (lambda (v len) (+ (vector-length v) len)) 0 vecs))
	 (ans (make-vector vlen)))
    (let lp1 ((vecs vecs) (to 0))
      (if (pair? vecs)
	  (let* ((vec (car vecs))
		 (len (vector-length vec)))
	    (let lp2 ((from 0) (to to))
	      (cond ((< from len)
		     (vector-set! ans to (vector-ref vec from))
		     (lp2 (+ from 1) (+ to 1)))
		    (else (lp1 (cdr vecs) to)))))))
    ans))
      

(define (vfold kons knil v)
  (let ((len (vector-length v)))
    (do ((i 0 (+ i 1))
	 (ans knil (kons (vector-ref v i) ans)))
	((>= i len) ans))))

(define (vfold-right kons knil v)
  (do ((i (- (vector-length v) 1) (- i 1))
       (ans knil (kons (vector-ref v i) ans)))
      ((< i 0) ans)))


;;; We loophole the call to ERROR -- the point is that perhaps the
;;; user will interact with a breakpoint, and proceed with a new
;;; value, which we will then pass to a new invocation of CHECK-ARG
;;; for approval.
(define (check-arg pred val caller)
  (if (pred val) val
      (check-arg pred
		 (loophole :value (error "Bad argument" val pred caller))
		 caller)))

(define (conjoin f g)
  (lambda args (and (apply f args) (apply g args))))

(define (disjoin f g)
  (lambda args (or (apply f args) (apply g args))))

(define (negate f) (lambda args (not (apply f args))))

(define (compose f g)
  (lambda args (call-with-values (lambda () (apply g args)) f)))


(define (reverse! lis)
  (let lp ((lis lis) (prev '()))
    (if (not (pair? lis)) prev
	(let ((tail (cdr lis)))
	  (set-cdr! lis prev)
	  (lp tail lis)))))

(define call/cc call-with-current-continuation)

(define (deposit-bit-field bits mask field)
  (bitwise-ior (bitwise-and field mask)
	       (bitwise-and bits  (bitwise-not mask))))


(define (nth lis i)
  (if (< i 0) (error "nth: illegal list index" i)
      (let lp ((l lis) (i i))
	(if (pair? l)
	    (if (zero? i) (car l)
		(lp (cdr l) (- i 1)))
	    (error "nth: index too large" lis i)))))


(define (deprecated-proc proc name . maybe-preferred-msg)
  (let ((warned? #f))
    (lambda args
      (cond ((not warned?)
	     (set! warned? #t)
	     (apply warn
		    "Deprecated procedure (may not be supported in a future release)"
		    name
		    maybe-preferred-msg)))
      (apply proc args))))


(define (real->exact-integer x)
  (let ((f (round x)))
    (if (inexact? f) (inexact->exact f) f)))

