;;; -*- Mode:LISP; Package:ARRAY; Base:10; Readtable:CL -*-

(export '(aref
	  aset
	  array-element-type
	  array-rank
	  array-dimension
	  array-dimensions
	  array-total-size
	  array-in-bounds-p
	  array-total-size
	  array-row-major-index
	  adjustable-array-p
	  array-has-fill-pointer-p
	  make-array
	  fill-pointer
	  vector-pop
	  vector-push
	  bit-vector-p
	  simple-bit-vector-p
	  vector))
	
	  
(defun ARRAY-ELEMENT-TYPE (array)
  (let* ((header (read-and-lock-array-header array))
         (type (hw:ldb header %%sv-art 0))
         (loc (hw:dpb vinc:$$dtp-locative vinc::%%data-type array))
	 (info nil))
    (when (= type art-hard)
      (hw:vma-start-read-vma-boxed-md-boxed (hw:24+ -1 loc))
      (setq type (hw:ldb (hw:read-md) %%array-type 0)))
    (setq info (dispatch (byte 5. 0.) type
      (art-q t)
      (art-1b   '(unsigned-byte 1.))
      (art-2b   '(unsigned-byte 2.))
      (art-4b   '(unsigned-byte 4.))
      (art-8b   '(unsigned-byte 8.))
      (art-16b  '(unsigned-byte 16.))
      (art-32b  '(unsigned-byte 32.))
      (art-2bs  '(signed-byte 2.))
      (art-4bs  '(signed-byte 4.))
      (art-8bs  '(signed-byte 8.))
      (art-16bs '(signed-byte 16.))
      (art-32bs '(signed-byte 32.))
      (art-string 'string-char)
      (art-fat-string 'character)
      (art-single-float 'single-float)
      (art-double-float 'double-float)
      (t (li:error "Bad array type used in header" ))))
    (unlock-array)
    info))


(defun ARRAY-RANK (array)
  (let ((rank
	  (if (= art-hard (hw:ldb (read-and-lock-array-header array) %%sv-art 0))
	      (progn
		(hw:vma-start-read-vma-boxed-md-boxed
		  (hw:32-1- (hw:dpb vinc:$$dtp-locative vinc:%%data-type array)))
		(hw:ldb (hw:read-md) %%dimensions 0))
	    1.)))
    (unlock-array)
    rank))

(defun ARRAY-DIMENSION (array dim-arg)
  (let* ((header (read-and-lock-array-header array))
	 (dim
	   (cond
	     ((= art-hard (hw:ldb header %%sv-art 0))
	      (let* ((loc (hw:dpb vinc:$$dtp-locative vinc:%%data-type array))
		     (dims (hw:ldb (progn
				     (hw:vma-start-read-vma-boxed-md-boxed (hw:32-1- loc))
				     (hw:read-md))
				   %%dimensions 0)))
		(cond
		  ((or (>= dim-arg dims) (minusp dim-arg))
		   (li:error "Bad dimension argument"))
		  ((zerop dim-arg)
		   (hw:ldb header %%bounds 0))
		  (t
		   (hw:vma-start-read-vma-boxed-md-boxed (hw:24+ (- -1 dims) array))
		   (1+ (hw:ldb (hw:read-md) %%bounds 0))))))
	     ((zerop dim-arg)
	      (1+ (hw:ldb header %%bounds 0)))
	     (t
	      (li:error "Bad dimension argument")))))
    (unlock-array)
    dim))

(defun ARRAY-DIMENSIONS (array)
  (let* ((header (read-and-lock-array-header array))
	 (array-rank (if (= art-hard (hw:ldb header %%sv-art 0))
			 (hw:ldb (%VM-READ (hw:24+ -1 array)) %%dimensions 0)
		       1)))
    (prog1 (cond ((zerop array-rank)
		  nil)
		 ((= array-rank 1)
		  (cons:cons (hw:ldb header %%bounds 0) nil))
		 (t
		  (do ((rank (- array-rank) (1+ rank))
		       (dims () (cons:cons (cons:contents-offset array rank) dims)))
		      ((>= rank -1) (cons:cons (hw:ldb header %%bounds 0) dims)))
		  )
		 )
	   (unlock-array))
    )
  )


(defun ARRAY-TOTAL-SIZE (array)
  (let* ((header (read-and-lock-array-header array))
	 (array-rank (if (= art-hard (hw:ldb header %%sv-art 0))
			 (hw:ldb (%VM-READ (hw:24+ -1 array)) %%dimensions 0)
		       1)))
    (prog1 (cond ((zerop array-rank)
		  1)
		 ((= array-rank 1)
		  (hw:ldb header %%bounds 0))
		 (t
		  (do ((rank (- array-rank) (1+ rank))
		       (array-total-size
			 (hw:ldb header %%bounds 0)
			 (new-math:multiply-fixnum array-total-size (cons:contents-offset array rank))))
		      ((>= rank -1) array-total-size))))
	   (unlock-array))
    )
  )

(defun array-in-bounds-p-internal (array subscripts)
  (let* ((header (read-and-lock-array-header array))
	 (array-rank (if (= art-hard (hw:ldb header %%sv-art 0))
			 (hw:ldb (%VM-READ (hw:24+ -1 array)) %%dimensions 0)
		       1)))
    (prog1 (cond ((zerop array-rank)
		  (unless (null subscripts)
		    (li:error "Wrong number of subscripts passed to array-in-bounds-p"))
		  T)
		 (t
		  (do* ((tail-subscripts subscripts (cons:cdr tail-subscripts))
			(subscript (cons:car subscripts) (cons:car tail-subscripts))
			(n -2 (1- n))
			(array-rank array-rank (1- array-rank))
			(in-bounds T)
			(check-range-bound
			  (hw:ldb header %%bounds 0)
			  use-this-bound)
			(use-this-bound (hw:ldb (%VM-READ (hw:24+ n array)) %%bounds 0)
					(hw:ldb (%VM-READ (hw:24+ n array)) %%bounds 0))
			)
		       ((or (= array-rank 1)
			    (null subscript))
			(progn
			  ;; check number of subscripts vs array rank.
			  (when (or (null subscript)
				    (cons:cdr tail-subscripts))
			    (li:error "Wrong number of subscripts passed to array-in-bounds-p"))
			  ;; must be a fixnum
			  (unless (vinc:%fixnump subscript)
			    (li:error "Bad subscript passed to array-in-bounds-p"))
			  ;; check for subscript error range.
			  (when (or (minusp subscript) (>= subscript check-range-bound))
			    (setq in-bounds nil))
			  in-bounds))
		    (when in-bounds
		      ;; must be a fixnum.
		      (unless (vinc:%fixnump subscript)
			(li:error "Bad subscript passed to array-in-bounds-p"))
		      ;; check for subscript error range.
		      (when (or (minusp subscript) (>= subscript check-range-bound))
			(setq in-bounds nil))))))
	   (unlock-array))
    )
  )

(defun ARRAY-IN-BOUNDS-P (array &rest subscripts)
  (array-in-bounds-p-internal array subscripts)
  )

(defun ARRAY-ROW-MAJOR-INDEX (array &rest subscripts)
  (let* ((header (read-and-lock-array-header array))
	 (array-rank (if (= art-hard (hw:ldb header %%sv-art 0))
			 (hw:ldb (%VM-READ (hw:24+ -1 array)) %%dimensions 0)
		       1)))
    (prog1
      (compute-linearized-index (cons:make-pointer vinc:$$dtp-unboxed-locative array)
				header array-rank subscripts)
      (unlock-array))
    )
  )

(defun ADJUSTABLE-ARRAY-P (array)
  (let ((flag
	  (and (= art-hard (hw:ldb (read-and-lock-array-header array) %%sv-art 0))
	       (progn
		 (hw:vma-start-read-vma-boxed-md-boxed
		   (hw:32-1- (hw:dpb vinc:$$dtp-locative vinc:%%data-type array)))
		 (not (zerop (hw:ldb (hw:read-md) %%adjustable-p 0)))))))
    (unlock-array)
    flag))

(defun ARRAY-HAS-FILL-POINTER-P (array)
  (let ((flag
	  (and (= art-hard (hw:ldb (read-and-lock-array-header array) %%sv-art 0))
	       (progn
		 (hw:vma-start-read-vma-boxed-md-boxed
		   (hw:32-1- (hw:dpb vinc:$$dtp-locative vinc:%%data-type array)))
		 (not (zerop (hw:ldb (hw:read-md) %%fill-pointer-p 0)))))))
    (unlock-array)
    flag))

(defun LOCK-ARRAY-AND-GET-FILL-POINTER-LOC (array)
  ;; Non Common Lisp.
  (if (= art-hard (hw:ldb (read-and-lock-array-header array) %%sv-art 0))
      (let ((loc (hw:dpb vinc:$$dtp-locative vinc:%%data-type array))
	    extension-header)
	(hw:vma-start-read-vma-boxed-md-boxed (hw:32-1- loc))
	(setq extension-header (hw:read-md))
	(unless (hw:ldb extension-header %%fill-pointer-p 0)
	  (li:error "No fill pointer"))
	(hw:24+ (- 1 (hw:ldb extension-header %%leader-offset 0)) loc))
    (li:error "No fill pointer"))
  )

(defun INC-FILL-POINTER (array inc)
  ;; Non Common Lisp.
  (hw:vma-start-read-will-write-vma-boxed-md-boxed
    (lock-array-and-get-fill-pointer-loc array))
  (let ((new-val (+ inc (hw:read-md))))
    (when (minusp new-val)
      (li:error "Fill pointer cannot be negative."))
    (hw:md-start-write-boxed new-val)
    (unlock-array)
    new-val)
  )

(defun FILL-POINTER (array)
  (hw:vma-start-read-vma-boxed-md-boxed
    (lock-array-and-get-fill-pointer-loc array))
  (unlock-array)
  (hw:read-md))

(defun SET-FILL-POINTER (array data)
  (hw:vma-start-read-will-write-vma-boxed-md-boxed
    (lock-array-and-get-fill-pointer-loc array))
  (hw:read-md)
  (hw:md-start-write-boxed data)
  (unlock-array)
  data)

;(defsetf fill-pointer set-fill-pointer)

(defun VECTOR-POP (array)
  (svref array (inc-fill-pointer array -1))
  )

(defun VECTOR-PUSH (data array)
  (svset array (1- (inc-fill-pointer array 1)) data)
  )

;;; fix this up
(defun vector-push-extend (data array)
  (vector-push data array))

;*******************************************************************************

(defun decode-1d-displaced-array (array offset)
  (let* (array-pointer array-length array-type array-offset array-rank array-data)
    (multiple-value-setq (array-pointer array-length array-offset array-data array-rank array-type)
      (decode-array array))
    ;; hum, may be we should include some type of check to see if displaced-array fits in displaced-to array.
    (values array-data (+ array-offset offset))
    )
  )


(defun decode-2d-displaced-array (array s1 s0)
  )


(defun compute-Linearized-index (array header array-rank subscript-or-list)
  (cond ((vinc:%fixnump subscript-or-list)
	 (if (or (>= subscript-or-list (hw:ldb header %%bounds 0))
		 (minusp subscript-or-list))
	     (li:error "Subscript out of range")
	   subscript-or-list))
	(t
	 (do* ((subscripts subscript-or-list (cons:cdr subscripts))
	       (subscript (cons:car subscript-or-list) (cons:car subscripts))
	       (n -2 (1- n))
	       (array-offset 0)
	       (array-rank array-rank (1- array-rank))
	       (check-range-bound
		 (hw:ldb header %%bounds 0)
		 use-this-bound)
	       (use-this-bound (hw:ldb (%VM-READ (hw:24+ n array)) %%bounds 0)
			       (hw:ldb (%VM-READ (hw:24+ n array)) %%bounds 0))
	       )
	      ((or (= array-rank 1)
		   (null subscript))
	       (progn
		 ;; check on number of subscripts vs array rank.
		 (when (or (null subscript)
			   (cons:cdr subscripts))
		   (li:error "Wrong number of subscripts"))
		 ;; must be a fixnum
		 (li:%trap-if-not-both-fixnum subscript subscript)
		 ;; check for subscript error range.
		 (when (or (minusp subscript) (>= subscript check-range-bound))
		   (li:error "subscript out of range"))
		 ;; compute linearized index.
		 (setq array-offset (+ array-offset subscript))))
	   ;; must be a fixnum.
	   (li:%trap-if-not-both-fixnum subscript subscript)
	   ;; check for subscript error range.
	   (when (or (minusp subscript) (>= subscript check-range-bound))
	     (li:error "subscript out of range"))
	   ;; compute linearized index.
	   (setq array-offset (new-math:multiply-fixnum (+ array-offset subscript) use-this-bound))))
	)
  )

(defun decode-array (array)
  ;; function to decode an array. If the argument passed is not an array
  ;; a trap occurs. Returns multiple values that describe array:
  ;;        array-pointer :locative to array
  ;;        array-length : number of element in array
  ;;        array-offset : 0 or offset if array is displaced
  ;;        array-data : locative to first element of array
  ;;        array-rank : number of dimensions of the array
  ;;        array-type : array element type.
  ;;
  (let* ((header (read-and-lock-array-header array))
	 (array-type (hw:ldb header %%sv-art 0))
	 (header2 (hw:dpb array-type
			  %%array-type 
			  (hw:unboxed-constant
			    (lisp:logior (lisp:ash 1 (byte-position %%dimensions))
					 (lisp:ash vinc:$$dtp-array-header-extension
						   (byte-position vinc:%%data-type))))))
	 array-pointer array-length array-offset array-data array-rank)
    (setq array-pointer (cons:make-pointer vinc:$$dtp-unboxed-locative (hw:read-vma)))
    (when (= art-hard array-type)
      (setq header2 (%vm-read (hw:32-1- array)))
      (setq array-type (hw:ldb header2 %%array-type 0))
      (when (= array-type art-error)
	(li:error "Array is ART-ERROR")))
    (setq array-rank (hw:ldb header2 %%dimensions 0))
    ;; compute array length
    (setq array-length (cond ((zerop array-rank) 1)
			     ((= array-rank 1) (hw:ldb header %%bounds 0))
			     (t
			      (do ((rank (- array-rank) (1+ rank))
				   (array-total-size
				     (hw:ldb header %%bounds 0)
				     (new-math:multiply-fixnum array-total-size (cons:contents-offset array rank))))
				  ((>= rank -1) array-total-size)))))

;    (if (= 1 array-rank)
;	(setq array-length (hw:ldb header %%bounds 0))
;      (do ((n array-rank (1- n)))
;	  ((= 1 n)
;	   (setq array-length (new-math:multiply-fixnum array-length (hw:ldb header %%bounds 0))))
;	(setq array-length (new-math:multiply-fixnum
;			     array-length
;			     (hw:ldb (%vm-read (hw:24+ (- -1 n) array)) %%bounds 0)))))

    (if  (zerop (hw:ldb header2 %%displaced-p 0))
	 (setq array-data (cons:make-pointer vinc:$$dtp-unboxed-locative (hw:24+ 1 array-pointer))
	       array-offset 0)
      ;; compute offset to array
      ;; compute locative pointer to data.
      (if (zerop (hw:ldb header2 %%displaced-2d-p 0))
	  ;; usual displaced-array
	  (let ((displaced-to (%VM-READ (hw:24+ (- -1 array-rank) array-pointer))))
	    (setq array-offset (%VM-READ (hw:24+ -1 (hw:READ-VMA))))
	    (if (= (hw:ldb displaced-to vinc:%%data-type 0) vinc:$$dtp-array)
		(multiple-value-setq (array-data array-offset)
		  (decode-1d-displaced-array displaced-to array-offset))
	      (setq array-data displaced-to))
	    ;; new two-dimensional displaced-array
	    ;; to be yet written.
	    )))
    (values array-pointer array-length array-offset array-data array-rank array-type))
  )

(defun aloc-hard (array subscript-list)
  (let* ((header (read-and-lock-array-header array))
	 (array-type (hw:ldb header %%sv-art 0))
	 (header2 (hw:dpb array-type
			  %%array-type 
			  (hw:unboxed-constant
			    (lisp:logior (lisp:ash 1 (byte-position %%dimensions))
					 (lisp:ash vinc:$$dtp-array-header-extension
						   (byte-position vinc:%%data-type))))))
	 (array-offset 0)
	 array-data array-rank)
    (setq array (cons:make-pointer vinc:$$dtp-unboxed-locative (hw:read-vma)))
    (when (= art-hard array-type)
      (setq header2 (%vm-read (hw:32-1- array)))
      (setq array-type (hw:ldb header2 %%array-type 0))
      (when (= array-type art-error)
	(li:error "Array is ART-ERROR")))
    (setq array-rank (hw:ldb header2 %%dimensions 0))
    (if (zerop array-rank)
	(setq array-offset 0)
      ;; compute linearized index
      (setq array-offset (compute-linearized-index array header array-rank subscript-list)))
    (if (not (hw:32logbitp (byte-position %%displaced-p) header2))
	(setq array-data (hw:24+ 1 (cons:make-pointer vinc:$$dtp-unboxed-locative array)))
      ;; compute locative pointer to data.
      (if (not (hw:32logbitp (byte-position %%displaced-2d-p) header2))
	  ;; usual displaced-array
	  (let ((displaced-to (%VM-READ (hw:24+ (- -1 array-rank) array))))
	    (setq array-offset (+ array-offset (%VM-READ (hw:24+ -1 (hw:READ-VMA)))))
	    (if (= (hw:ldb displaced-to vinc:%%data-type 0) vinc:$$dtp-array)
		(multiple-value-setq (array-data array-offset)
		  (decode-1d-displaced-array displaced-to array-offset))
	      (setq array-data displaced-to))
	    ;; new two-dimensional displaced-array
	    ;; to be yet written.
	    )))
    (values array-offset array-data array-type))
  )

(defun decode-2d-array (array s1 s0)
  (li:%trap-if-not-both-fixnum s1 s0)
  (let* ((header (read-and-lock-array-header array))
	 (array-type (hw:ldb header %%sv-art 0))
	 (header2)
	 (array-offset)
	 array-data array-rank dimension-s1 dimension-s0)
    (setq array (cons:make-pointer vinc:$$dtp-unboxed-locative (hw:read-vma)))
    (when (not (= array-type art-hard))
	(li:error "Array is a not two dimensional"))
    (setq header2 (%vm-read (hw:32-1- array)))
    (setq array-type (hw:ldb header2 %%array-type 0))
    (and (= array-type art-error)
	 (li:error "Array is ART-ERROR"))
    (setq array-rank (hw:ldb header2 %%dimensions 0))
    (or (= array-rank 2) (li:error "Array is not two-Dimensional"))
    ;; return these for bitblt purposes.
    (setq dimension-s0 (%VM-READ (hw:24+ -1 (hw:read-vma))))
    (setq dimension-s1 (hw:ldb header %%bounds 0))
    ;; check for bounds errors
    (when (or (minusp s0) (>= s0 dimension-s0))
      (li:error "Subscript range error"))
    (when (or (minusp s1) (>= s1 dimension-s1))
      (li:error "Subscript range error"))
    ;; compute linearized index here
    (setq array-offset (+ (new-math:multiply-fixnum s1 dimension-s0) s0))
    ;; now displaced-stuff
    (if (not (hw:32logbitp (byte-position %%displaced-p) header2))
	(setq array-data (hw:24+ 1 (cons:make-pointer vinc:$$dtp-unboxed-locative array)))
      ;; compute locative pointer to data.
      (if (not (hw:32logbitp (byte-position %%displaced-2d-p) header2))
	  ;; usual displaced-array
	  (let ((displaced-to (%VM-READ (hw:24+ -3 array))))
	    (setq array-offset (+ array-offset (%VM-READ (hw:24+ -4 array))))
	    (if (= (hw:ldb displaced-to vinc:%%data-type 0) vinc:$$dtp-array)
		(multiple-value-setq (array-data array-offset)
		  (decode-1d-displaced-array displaced-to array-offset))
	      (setq array-data displaced-to))
	    ;; new two-dimensional displaced-array
	    ;; to be yet written.
	    )))
    (values array-offset array-data array-type dimension-s1 dimension-s0)
    )
  )

(defafun aref-2 (array s1 s0)
  (move o0 a0 ch-open)
  (move o1 a1)
  (call (decode-2d-array 3) a0 (o2 a2))
  (alu load-status-r nop ignore gr:*data-type* bw-16 unboxed)
  (movea r1 (svref-dispatch 1) boxed)
  (alu l+r r1 r1 gr:*return-1* boxed)
  (alu r-1 vma gr:*return-0* gr:*return-0* boxed-vma)
  (alu l-r nop gr:*zero* gr:*one* bw-24 next-pc-dispatch)
  )

(defafun ASET-2 (data array s1 s0)
  (move o0 a1 ch-open)
  (move o1 a2)
  (call (decode-2d-array 3) a1 (o2 a3))
  (alu load-status-r nop ignore gr:*data-type* bw-16 unboxed)
  (movea r1 (svset-dispatch 2) boxed)
  (alu l+r r1 r1 gr:*return-1* boxed)
  (alu r-1 vma gr:*return-0* gr:*return-0* boxed-vma)
  (alu l-r nop gr:*zero* gr:*one* bw-24 next-pc-dispatch)
 )

(defafun AREF-HARD (array subscript-list)
  (move o0 a0 ch-open)
  (call (aloc-hard 2) a0 (o1 a1))
  (alu load-status-r nop ignore gr:*data-type* bw-16 unboxed)
  (movea r1 (svref-dispatch 1) boxed)
  (alu l+r nop r1 gr:*return-1*)
  (alu r-1 vma gr:*return-0* gr:*return-0* boxed-vma)
  (alu l-r nop gr:*zero* gr:*one* bw-24 next-pc-dispatch)
 )

(defafun ASET-HARD (data array subscript-list)
  (move o0 a1 ch-open)
  (call (aloc-hard 2) a1 (o1 a2))
  (alu load-status-r nop ignore gr:*data-type* bw-16 unboxed)
  (movea r1 (svset-dispatch 2) boxed)
  (alu l+r nop r1 gr:*return-1*)
  (alu r-1 vma gr:*return-0* gr:*return-0* boxed-vma)
  (alu l-r nop gr:*zero* gr:*one* bw-24 next-pc-dispatch)
 )

(defun aref-n (array &rest subscripts)
  (aref-hard array subscripts)
  )

(defun aset-n (value array &rest subscripts)
  (aset-hard value array subscripts)
  )

(defafun aref-linear-dangerously (array index array-type)
  (alu load-status-r nop ignore gr:*data-type* bw-16)
  (move vma a0 boxed-vma)
  (movea r0 (svref-dispatch 1) boxed)
  (alu l+r r0 a2 r0 bw-24 boxed-right)
  (alu r+1 gr:*allow-sequence-break* gr:*allow-sequence-break* gr:*allow-sequence-break* boxed-right)
  (move a0 a1 next-pc-dispatch)
 )

(defafun aset-linear-dangerously (array index array-type data)
  (alu load-status-r nop ignore gr:*data-type* bw-16)
  (move vma a0 boxed-vma)
  (movea r0 (svset-dispatch 2) boxed)
  (alu l+r r0 a2 r0 bw-24 boxed-right)
  (alu r+1 gr:*allow-sequence-break* gr:*allow-sequence-break* gr:*allow-sequence-break* boxed-right)
  (move a0 a3 next-pc-dispatch)
 )

(defrewrite aref (&whole form array &rest subscripts)
  (lisp:case (lisp:length subscripts)
    (1 `(AREF-1  ,array . ,subscripts))
    (2 `(AREF-2  ,array . ,subscripts))
    (t form)))

(defun aref (array &rest subscripts)
  (aref-hard array subscripts)
  )

(defrewrite aset (&whole form value array &rest subscripts)
  (lisp:case (lisp:length subscripts)
    (1 `(ASET-1 ,value ,array . ,subscripts))
    (2 `(ASET-2 ,value ,array . ,subscripts))
    (t form)))

(defun aset (value array &rest subscripts)
  (aset-hard value array subscripts)
  )

(defsetf aref (array &rest subscripts) (value)
  `(aset ,value ,array . ,subscripts))

(defun bit-vector-p (x)
  (array-test x
    #'(lambda (header1)
	  (or
	    (hw:field=
	      (hw:unboxed-constant #.(lisp:ash art-1b (byte-position %%sv-art)))
	      header1 %%sv-art)
	    (and
	      (hw:field= (hw:unboxed-constant #.(lisp:ash $$dtp-array-header-multiple 26.)) header1 vinc:%%data-type)
	      (let ((header2 (progn
			       (hw:vma-start-read-vma-unboxed-md-boxed (hw:32-1- x))
			       (hw:read-md))))
		(and
		  (= 1 (hw:ldb header2 %%dimensions 0))
		  (hw:field=
		    (hw:unboxed-constant #.(lisp:ash art-1b (byte-position %%array-type)))
		    header1 %%array-type))))))))

(defun simple-bit-vector-p (x)
  (array-test x
    #'(lambda (header1)
	(hw:field=
	  (vinc:dpb-multiple-unboxed
	      art-1b    		%%sv-art
	      $$dtp-array-header-single vinc:%%data-type
	      0)
	    x (byte 11. 21.)))))


;;;; MAKE-ARRAY 

;;;;
;;;;
;;;; From file dj:l.sys;qrand.lisp

;(defconstant array-boxed-words-per-element
;	     `((,art-error . 0)
;	       (,art-1b . 0)
;	       (,art-2bs . 0)
;	       (,art-2b . 0)
;	       (,art-4bs . 0)
;	       (,art-4b . 0)
;	       (,art-8bs . 0)
;	       (,art-8b . 0)
;	       (,art-16bs . 0)
;	       (,art-16b . 0)
;	       (,art-32bs . 0)
;	       (,art-32b . 0)
;	       (,art-q . 1)
;	       (,art-string . 0)
;	       (,art-special-pdl . 1)
;	       (,art-single-float . 0)
;	       (,art-double-float . 0)
;	       (,art-fat-string . 0)
;;	       (,art-complex-float . 4)
;;	       (,art-complex . 2)
;	       )
;  )

;(defun array-boxed-words-per-element (type)
;  (let ((words-per-element (cons:cdr (cons:assoc type Array-boxed-words-per-element))))
;    (unless words-per-element
;      (li:error "~S is not a known array element type" type))
;    words-per-element
;    )
;  )

(defun array-boxed-words-per-element (type)
  (if (= type art-q) 1 0))

(defun array-total-data-size (array-type index-length)
  (dispatch (byte 5 0) array-type
	    (art-q	index-length)
	    (art-1b	(hw:ldb (+ 31. index-length) (byte 19. 5.) 0))
	    ((art-2b art-2bs) (hw:ldb (+ 15. index-length) (byte 20. 4.) 0))
	    ((art-4b art-4bs) (hw:ldb (+ 7. index-length) (byte 21. 3.) 0))
	    ((art-8b art-8bs) (hw:ldb (+ 3. index-length) (byte 22. 2.) 0))
	    ((art-16b art-16bs) (hw:ldb (+ 1. index-length) (byte 23. 1.) 0))
	    ((art-32b art-32bs) index-length)
	    (art-string (hw:ldb (+ 3. index-length) (byte 22. 2.) 0))
	    (art-fat-string (hw:ldb (+ 1. index-length) (byte 23. 1.) 0))
	    ))

(eval-when (load compile eval)

(defun array-type-from-element-type (type)
  (cond
    ((li:consp type)
     (let ((first (cons:car type))
	   (second (cons:cadr type)))
       (cond
	 ((eq first 'li:signed-byte)
	  (cond
	    ((<= second 2) art-2bs)
	    ((<= second 4) art-4bs)
	    ((<= second 8.) art-8bs)
	    ((= second 16.) art-16bs)
	    ((<= second 32.) art-32bs)
	    (t art-q)))
	 ((eq first 'li:unsigned-byte)
	  (cond
	    ((<= second 1) art-1b)
	    ((<= second 2) art-2b)
	    ((<= second 4) art-4b)
	    ((<= second 8.) art-8b)
	    ((<= second 16.) art-16b)
	    ((<= second 32.) art-32b)
	    (t art-q)))
	 (t art-q))))
    ((eq type 'li:string-char) art-string)
    ((eq type 'li:fat-string) art-fat-string)
    (t art-q))
  )

)


;(DEFMACRO ARRAY-TOTAL-DATA-SIZE (ARRAY-TYPE INDEX-LENGTH)
;  `(Let ((ELEMENTS-PER-WORD (AREF #'ARRAY-ELEMENTS-PER-Q ,ARRAY-TYPE)))
;     (IF (PLUSP ELEMENTS-PER-WORD)
;	 (CEILING ,INDEX-LENGTH ELEMENTS-PER-WORD)
;       (* ,INDEX-LENGTH (- ELEMENTS-PER-WORD)))))

;(DEFMACRO ARRAY-ELEMENTS-FOR-GIVEN-DATA-SIZE (ARRAY-TYPE WORDS)
;  `(LET ((ELEMENTS-PER-WORD (AREF #'ARRAY-ELEMENTS-PER-Q ,ARRAY-TYPE)))
;     (IF (PLUSP ELEMENTS-PER-WORD)
;	 (* ,WORDS ELEMENTS-PER-WORD)
;       (CEILING ,WORDS (- ELEMENTS-PER-WORD)))))

;(DEFMACRO ARRAY-BOXED-DATA-SIZE (ARRAY-TYPE INDEX-LENGTH)
;  `(* ,INDEX-LENGTH (AREF #'ARRAY-BOXED-WORDS-PER-ELEMENT ,ARRAY-TYPE)))

;;;;;
;;;;;

;;; Internal

(defun Array-dimensions-and-data-length-in-q-s (dimensions type)
  (let (numb-of-dimensions array-length-in-elements)
    ;; error checking on the dimensions. Returns the length of the data area of the array in elements
    ;; if every thing is ok.
    (cond ((and (vinc:%fixnump dimensions)
		(>= dimensions 0))
	   (unless (< dimensions array-dimension-limit)
	     (li:error "Array too large---- Cannot make it."))
	   (setq numb-of-dimensions 1)
	   (setq array-length-in-elements dimensions))
	  ((li:consp dimensions)
	   (setq array-length-in-elements (cons:car dimensions))
	   (do ((i 1 (1+ i))
		(dims (cons:cdr dimensions) (cons:cdr dims)))
	       ((null dims)
		(progn
		  (setq numb-of-dimensions i)
		  (when (>= i array-rank-limit)
		    (li:error "Arrays may have at most ~D dimensions, not ~S" i array-rank-limit))
		  (unless (vinc:%fixnump array-length-in-elements)
		    (li:error "Array too large-- Cannot make it."))))
	     (let ((dim (cons:car dims)))
	       (or (and (vinc:%fixnump dim)
			(>= dim 0)
			(< dim array-dimension-limit))
		   (li:error "~dth dimension, ~S, is not a fixnum" i dim))
	       (setq array-length-in-elements (new-math:multiply-fixnum array-length-in-elements dim))
	       (li:%trap-if-not-both-fixnum array-length-in-elements array-length-in-elements))))
	  ((null dimensions)
	   (setq numb-of-dimensions 0)
	   (setq array-length-in-elements 1))
	  (t (li:error "~S is not a valid array dimension specification." dimensions)))
    (values numb-of-dimensions (array-total-data-size type array-length-in-elements) array-length-in-elements)
    )
  )


(defun Get-array-and-array-header (number-of-dimensions
				   dimension-0
				   type
				   displaced-to
				   2d-displaced
				   fill-pointer
				   adjustable
				   leader-length
				   index-length-in-q-s
				   area)
  ;; Returns the number of boxed qs to be used in the header-block. and the values to store in headers
  (let ((main-array-header (vinc::dpb-multiple-boxed
			     dimension-0 			%%bounds
			     type 				%%sv-art
			     vinc:$$dtp-array-header-single 	vinc:%%data-type
			     0))
	(array-header-extension nil)
	(indirect (arrayp displaced-to))
	(array-leader-header nil)
	(header-block-length 0)
	array)
    (when (> number-of-dimensions 1) (setq header-block-length (1- number-of-dimensions)))
    (when fill-pointer               (setq header-block-length (1+ header-block-length)))
    (when displaced-to               (setq header-block-length (+  header-block-length 2))
	  ;; silly displaced array do not have any data area.
	  (setq index-length-in-q-s 0))
    (when 2d-displaced               (setq header-block-length (1+ header-block-length)))
    (when (and leader-length (not (zerop leader-length)))
      (setq header-block-length (+ header-block-length leader-length 1))
      (setq array-leader-header t))
    (if (or (not (= number-of-dimensions 1))
	    fill-pointer
	    adjustable
	    displaced-to)
	(progn
	  (setq header-block-length (+ header-block-length 3))
	  (setq array-header-extension t))
      (setq header-block-length (1+ header-block-length)))
    ;; Allocate the array block now.
    (setq array (cond ((zerop (array-boxed-words-per-element type))
		       (if area
			   (cons:allocate-structure-in-area
			     header-block-length
			     index-length-in-q-s
			     vinc:$$dtp-unboxed-locative nil
			     area)
			 (cons:allocate-structure
			   header-block-length
			   index-length-in-q-s
			   vinc:$$dtp-unboxed-locative
			   nil)))
		      (t
		       (if area
			   (cons:allocate-structure-in-area
			     (+ header-block-length
				index-length-in-q-s)
			     0
			     vinc:$$dtp-unboxed-locative nil
			     area)
			 (cons:allocate-structure
			   (+ header-block-length
			      index-length-in-q-s)
			   0
			   vinc:$$dtp-unboxed-locative
			   nil)))))
    
    (build-array-headers number-of-dimensions
			 type
			 displaced-to
			 2d-displaced
			 indirect
			 fill-pointer
			 adjustable
			 leader-length
			 index-length-in-q-s
			 header-block-length
			 main-array-header
			 array-header-extension
			 array-leader-header
			 array
			 )
    )
  )
    
(defun build-array-headers (number-of-dimensions
			    type
			    displaced-to
			    2d-displaced
			    indirect
			    fill-pointer
			    adjustable
			    leader-length
			    index-length-in-q-s
			    header-block-length
			    main-array-header
			    array-header-extension
			    array-leader-header
			    array
			    )
  ;; Compute what each header has to be and store it.
  (when array-header-extension
    (hw:write-md-boxed (cons:make-header vinc:$$dtp-array-header-extension (1- header-block-length)))
    (hw:vma-start-write-boxed array)
    (let ((temp (1+ number-of-dimensions)))
      (setq main-array-header (hw:dpb-boxed vinc:$$dtp-array-header-multiple vinc:%%data-type main-array-header))
      (setq main-array-header (hw:dpb-boxed art-hard %%sv-art main-array-header))
      (when displaced-to
	(if 2d-displaced
	    (setq temp (+ temp 3))
	  (setq temp (+ temp 2))))
      (when fill-pointer (setq temp (1+ temp)))
      (setq array-header-extension (hw:dpb-boxed temp %%leader-offset 0))
;				     (+ number-of-dimensions
;					(if displaced-to (if 2d-displaced 3 2) 0)
;					(if fill-pointer 1 0))
;						 %%leader-offset 0))
      (when fill-pointer (setq array-header-extension (hw:dpb-boxed 1 %%fill-pointer-p array-header-extension)))
      (when (and leader-length (not (zerop leader-length)))
	(setq array-header-extension (hw:dpb-boxed 1 %%leader-p array-header-extension)))
      (when 2d-displaced (setq array-header-extension (hw:dpb-boxed 1 %%displaced-2d-p array-header-extension)))
      (when indirect (setq array-header-extension (hw:dpb-boxed 1 %%indirect-p array-header-extension)))
      (when displaced-to (setq array-header-extension (hw:dpb-boxed 1 %%displaced-p array-header-extension)))
      (setq array-header-extension (hw:dpb-boxed type %%array-type array-header-extension))
      (setq array-header-extension (hw:dpb-boxed number-of-dimensions %%dimensions array-header-extension))
      (when adjustable (setq array-header-extension (hw:dpb-boxed 1 %%adjustable-p array-header-extension)))
      ;; now store it in right spot.
      (setq temp (- header-block-length 2))
      (hw:write-md-boxed array-header-extension)
      (hw:vma-start-write-boxed (hw:24+ temp array))
      (when array-leader-header
	(setq array-leader-header (hw:dpb-boxed leader-length	%%leader-length 0))
	(setq temp (1+ leader-length))
	(hw:write-md-boxed array-leader-header)
	(hw:vma-start-write-boxed (hw:24+ temp array)))))
  (setq array (hw:24+ (1- header-block-length) array))
  (values array main-array-header)
  )

(defun check-displaced-legality (type array-length-in-elements displaced-to
				 displaced-index-offset-1
				 displaced-2d displaced-index-offset-2)
  ;; at some point, should decide on this displaced-2d stuff.
  (cond ((hw:field= (hw:dpb-unboxed vinc:$$dtp-array vinc:%%data-type 0)
		    displaced-to vinc:%%data-type)
	 (if (> (+ array-length-in-elements displaced-index-offset-1) (array-total-size displaced-to))
	     (li:error "Cannot fit in specified displaced to array")
	   )
	 )
	((hw:field= (hw:dpb-unboxed vinc:$$dtp-unboxed-locative vinc:%%data-type 0)
		    displaced-to vinc:%%data-type)
	 )
	(t (li:error "Not a valid thing to displaced to.")))
  )



(defun make-array-internal (dimensions type adjustable fill-pointer
			    displaced-to 2d-displaced displaced-index-offset-1
			    displaced-index-offset-2 leader-length area)
  (let (number-of-dimensions
	array-data-length-in-q-s
	main-array-header
	array temp)
    (multiple-value-setq (number-of-dimensions array-data-length-in-q-s temp)
      (array-dimensions-and-data-length-in-q-s dimensions type))
    (when displaced-to
      (check-displaced-legality type temp	; temp has array length in elements
				displaced-to displaced-index-offset-1 2d-displaced
				displaced-index-offset-2))
    (when fill-pointer
      (and (eq fill-pointer t) (setq fill-pointer 0))
      (if (vinc:%fixnump fill-pointer)
	  (unless (= number-of-dimensions 1)
	    (li:error "Only one dimensional array can have fill-pointers"))
	(li:error "~S is a bad fill-pointer specification" fill-pointer)))
    (setq gr::*allow-sequence-break* (1+ gr::*allow-sequence-break*))
    (multiple-value-setq (array main-array-header)
      (Get-array-and-array-header
	number-of-dimensions
	(cond
	  ((li:consp dimensions) (cons:car dimensions))
	  ((vinc:%fixnump dimensions) dimensions)
	  (t 0))
	type displaced-to 2d-displaced
	fill-pointer adjustable leader-length array-data-length-in-q-s area))
    (setq temp (hw:24+ -2 array))
    ;; fill in dimensions and displaced-stuff
    (when (> number-of-dimensions 1)
      (do* ((dim (cons:cdr dimensions) (cons:cdr dim)))
	   ((null dim))
	(hw:write-md-boxed (cons:car dim))
	(hw:vma-start-write-boxed temp)
	(setq temp (hw:24+ -1 temp))))
    ;; temp is pointing to the next empty spot.
    ;; now displaced-suff
    (when displaced-to
      (hw:write-md-boxed displaced-to)
      (hw:vma-start-write-boxed temp)
      (hw:memory-wait)
      (hw:write-md-boxed displaced-index-offset-1)
      (hw:vma-start-write-boxed (hw:32-1- temp))
      (setq temp (hw:24+ -2 temp))
      (when 2d-displaced
	(hw:write-md-boxed displaced-index-offset-2)
	(hw:vma-start-write-boxed temp)
	(setq temp (hw:24+ -1 temp))))
    (when fill-pointer
      (hw:write-md-boxed fill-pointer)
      (hw:vma-start-write-boxed temp)
      (hw:memory-wait))
    (hw:write-md-boxed main-array-header)
    (hw:vma-start-write-boxed array)
    (setq gr::*allow-sequence-break* (1- gr::*allow-sequence-break*))
    (cons:make-pointer vinc:$$dtp-array array)
    )
  )

(defun simple-error-checks (type? element-type? initial-contents? initial-element? displaced-to?)
  (when (and element-type? type?)
    (li:error "Cannot supecify both element-type and type parameters"))
  (when (and initial-contents? initial-element?)
    (li:error "initial-contents and initial-element cannot be specified at the same time"))
  (when (or (and initial-contents? displaced-to?)
	    (and initial-element? displaced-to?))
    (li:error "Initial-contents or initial-element cannot be specified when displaced-to is specified"))
  )

;(defun zl-make-array (dimensions &key (element-type t element-type-p) (type t type-p)
;		      (initial-element nil initial-element-p) (initial-contents nil initial-contents-p)
;		      adjustable fill-pointer (displaced-to nil displaced-to-p) displaced-index-offset-1
;		      displaced-index-offset-2 leader-length leader-list area)
;  (simple-error-checks type-p element-type-p initial-element-p initial-contents-p displaced-to-p)
;  ;; error checks and setup of length of leader.
;  (cond ((null leader-length) (setq leader-length 0))
;	((and (vinc:%fixnump leader-length)
;	      (>= leader-length 0)))
;	(t (li:error "~S is not a valid leader-length specification" leader-length)))
;;  (typecase leader-length
;;	    (null (Setq leader-length 0))
;;	    ((fixnum 0))
;;	    (otherwise
;;	     (li:error "~S is not a valid leader-length specification" leader-length)))
;  (cond ((null leader-list))
;	((li:consp leader-list)
;	 (setq leader-length (max (length leader-list) leader-length)))
;	(t (li:error "~S is not a valid leader-list specification" leader-list)))
;;  (typecase leader-list
;;	    (null)
;;	    (cons (setq leader-length (max (length leader-list) leader-length)))
;;	    (otherwise
;;	     (li:error "~S is not a valid leader-list specification" leader-list)))
;  (make-array-internal
;    dimensions
;    (if element-type-p (array-type-from-element-type element-type) type)
;    adjustable fill-pointer displaced-to displaced-index-offset-1 displaced-index-offset-2
;    leader-length area)
;  )

;; Commonlisp 

(defun make-array (dimensions &key (element-type t element-type-p)
		   (initial-element nil initial-element-p)
		   (initial-contents nil initial-contents-p)
		   adjustable fill-pointer
		   (displaced-to nil displaced-to-p)
		   (displaced-index-offset 0)
		   )
  (simple-error-checks nil element-type-p initial-contents-p initial-element-p displaced-to-p)
  (when displaced-to-p
;    (unless (arrayp displaced-to)
;      (li:error "Supplied displaced-to ~S must be an array" displaced-to))
    ;; ask about types.
;    (when element-type-p
;      (li:error "Cannot specify a type for a displaced array"))
    )
  (make-array-internal
    dimensions (array-type-from-element-type element-type)
    adjustable fill-pointer
    displaced-to nil displaced-index-offset
    nil nil nil)
  )

(defun make-easy-array (dimensions &optional (type ART-Q))
  (make-array-internal dimensions type nil nil nil nil 0 nil nil nil))

(defun make-easy-array-with-element-type (dimensions element-type)
  (make-array-internal dimensions (array-type-from-element-type element-type) nil nil nil nil 0 nil nil nil))

(defrewrite make-array (&whole form dimensions &rest options &key (element-type t element-type-p))
  (cond
    ((null options)
     (cond ((numberp dimensions)
	    `(MAKE-VECTOR ,dimensions))
	   (t
	    `(MAKE-EASY-ARRAY ,dimensions))))
    ((and element-type-p
	  (null (lisp:cddr options)))
     (let ((type ;; do something clever with constantp here
	     (or (eq element-type t)
		 (and (lisp:consp element-type)
		      (eq (lisp:car element-type) 'QUOTE)
		      (lisp:cadr element-type)))))
       (if type
	   (let ((array-type (array-type-from-element-type type)))
	     (if (numberp dimensions)
		 (cond ((= array-type art-q)
			`(MAKE-VECTOR ,dimensions))
		       ((= array-type art-string)
			`(MAKE-STRING ,dimensions))
		       (t
			`(MAKE-1D-ARRAY ,dimensions ,array-type)))		   
	       `(MAKE-EASY-ARRAY ,dimensions ,array-type)))
	 `(MAKE-EASY-ARRAY-WITH-ELEMENT-TYPE ,dimensions ,element-type))))
    (t form)))
	     
	    

(defun vector (&rest objects)
  (let ((vector (make-vector (length objects))))
    (do ((i 0 (1+ i))
	 (tail objects (cdr tail)))
	((null tail) vector)
      (svset vector i (car tail))))
  )
	    




