;;; ----------------------------------------------------------------------
;;;
;;; ILTITERE: Runtime for iteration
;;;
;;; ----------------------------------------------------------------------
;;;
;;; This file is part of ILOG Talk.
;;; Inquiries to ILOG S.A.
;;;              9 rue de Verdun, BP 85,
;;;              94253 Gentilly Cedex, France.
;;;
;;; Copyright (c) 1995-1996 by ILOG
;;; ----------------------------------------------------------------------
;;;

(defgeneric .iterator-default-iterator (obj)
  ;; Compute a default iterator for OBJ when none is given explicitly.
  method: (((obj <object>))
	   obj))

(defgeneric .iterator-init-index (iter obj)
  ;; Initialize the index variable for the iteration.
  ;; Default is to do nothing.
  method: (((iter <object>) obj)
	   (ignore iter obj)
	   ()))

(defgeneric .iterator-init-value (iter obj)
  ;; Initialize the loop variable for the iteration.
  ;; Default is to use the object.
  method: (((iter <object>) obj)
	   (ignore iter)
	   obj))

(defgeneric .iterator-done-p (iter obj index)
  ;; Decide whether the loop is finished.
  ;; By default, it is never finished (infinite loop.)
  method: (((iter <object>) obj index)
	   (ignore iter obj index)
	   ()))

(defgeneric .iterator-next-index (iter obj index)
  ;; Choose the next index value.
  ;; By default, just ().
  method: (((iter <object>) obj index)
	   (ignore iter obj index)
	   ()))

(defgeneric .iterator-next-value (iter obj index)
  ;; Compute the next loop variable value.
  ;; By default, just the object.
  method: (((iter <object>) obj index)
	   (ignore iter index)
	   obj))

;;; Example of iteration protocol for vectors, even though we already
;;; have in-vector:
;;; Use:
;;;   (for ((var in-object: <vec>
;;;              [iterator: (.make-viter [from: 0]
;;;                                      [by: 1]
;;;                                      [to: (i- (vlen <vec>) 1)])]))
;;;     ...)

(defstructure .<viter> ()
  ((.from 0)
   (.to ())
   (.by 1)))

(defmethod .iterator-default-iterator ((obj <vector>))
  (.make-viter from: 0 to: (i1- (vlen obj)) by: 1))

(defmethod .iterator-init-index ((iter .<viter>) obj)
  (ignore obj)
  (.viter-from iter))

(defmethod .iterator-init-value ((iter .<viter>) obj)
  (ignore iter obj)
  ())

(defmethod .iterator-done-p ((iter .<viter>) obj index)
  (if (i> index (or (.viter-to iter) (vlen obj))) t ()))

(defmethod .iterator-next-index ((iter .<viter>) obj index)
  (ignore obj)
  (i+ index (.viter-by iter)))

(defmethod .iterator-next-value ((iter .<viter>) obj index)
  (ignore iter)
  (vref obj index))

(defun time-viter ()
  ;; Run this to see why you shouldn't use in-object:...
  (let* ((vec (make-vector 1000 ()))
	 (t1 (timeq (for ((elt in-vector: vec)) ()) 1000))
	 (t2 (timeq (for ((elt in-object: vec)) ()) 1000)))
    (printf "Time for in-vector: %d ms\n" t1)
    (printf "Time for in-object: %d ms\n" t2)))
