+;;; Given any ARRAY, bind DATA-VAR to the array's data vector and
+;;; START-VAR and END-VAR to the start and end of the designated
+;;; portion of the data vector. SVALUE and EVALUE are any start and
+;;; end specified to the original operation, and are factored into the
+;;; bindings of START-VAR and END-VAR. OFFSET-VAR is the cumulative
+;;; offset of all displacements encountered, and does not include
+;;; SVALUE.
+;;;
+;;; When FORCE-INLINE is set, the underlying %WITH-ARRAY-DATA form is
+;;; forced to be inline, overriding the ordinary judgment of the
+;;; %WITH-ARRAY-DATA DEFTRANSFORMs. Ordinarily the DEFTRANSFORMs are
+;;; fairly picky about their arguments, figuring that if you haven't
+;;; bothered to get all your ducks in a row, you probably don't care
+;;; that much about speed anyway! But in some cases it makes sense to
+;;; do type testing inside %WITH-ARRAY-DATA instead of outside, and
+;;; the DEFTRANSFORM can't tell that that's going on, so it can make
+;;; sense to use FORCE-INLINE option in that case.
+(def!macro with-array-data (((data-var array &key offset-var)
+ (start-var &optional (svalue 0))
+ (end-var &optional (evalue nil))
+ &key force-inline check-fill-pointer)
+ &body forms
+ &environment env)
+ (once-only ((n-array array)
+ (n-svalue `(the index ,svalue))
+ (n-evalue `(the (or index null) ,evalue)))
+ (let ((check-bounds (policy env (plusp insert-array-bounds-checks))))
+ `(multiple-value-bind (,data-var
+ ,start-var
+ ,end-var
+ ,@(when offset-var `(,offset-var)))
+ (if (not (array-header-p ,n-array))
+ (let ((,n-array ,n-array))
+ (declare (type (simple-array * (*)) ,n-array))
+ ,(once-only ((n-len (if check-fill-pointer
+ `(length ,n-array)
+ `(array-total-size ,n-array)))
+ (n-end `(or ,n-evalue ,n-len)))
+ (if check-bounds
+ `(if (<= 0 ,n-svalue ,n-end ,n-len)
+ (values ,n-array ,n-svalue ,n-end 0)
+ ,(if check-fill-pointer
+ `(sequence-bounding-indices-bad-error ,n-array ,n-svalue ,n-evalue)
+ `(array-bounding-indices-bad-error ,n-array ,n-svalue ,n-evalue)))
+ `(values ,n-array ,n-svalue ,n-end 0))))
+ ,(if force-inline
+ `(%with-array-data-macro ,n-array ,n-svalue ,n-evalue
+ :check-bounds ,check-bounds
+ :check-fill-pointer ,check-fill-pointer)
+ (if check-fill-pointer
+ `(%with-array-data/fp ,n-array ,n-svalue ,n-evalue)
+ `(%with-array-data ,n-array ,n-svalue ,n-evalue))))
+ ,@forms))))
+
+;;; This is the fundamental definition of %WITH-ARRAY-DATA, for use in
+;;; DEFTRANSFORMs and DEFUNs.
+(def!macro %with-array-data-macro (array
+ start
+ end
+ &key
+ (element-type '*)
+ check-bounds
+ check-fill-pointer)
+ (with-unique-names (size defaulted-end data cumulative-offset)
+ `(let* ((,size ,(if check-fill-pointer
+ `(length ,array)
+ `(array-total-size ,array)))
+ (,defaulted-end (or ,end ,size)))
+ ,@(when check-bounds
+ `((unless (<= ,start ,defaulted-end ,size)
+ ,(if check-fill-pointer
+ `(sequence-bounding-indices-bad-error ,array ,start ,end)
+ `(array-bounding-indices-bad-error ,array ,start ,end)))))
+ (do ((,data ,array (%array-data-vector ,data))
+ (,cumulative-offset 0
+ (+ ,cumulative-offset
+ (%array-displacement ,data))))
+ ((not (array-header-p ,data))
+ (values (the (simple-array ,element-type 1) ,data)
+ (the index (+ ,cumulative-offset ,start))
+ (the index (+ ,cumulative-offset ,defaulted-end))
+ (the index ,cumulative-offset)))
+ (declare (type index ,cumulative-offset))))))
+
+(defun transform-%with-array-data/muble (array node check-fill-pointer)
+ (let ((element-type (upgraded-element-type-specifier-or-give-up array))
+ (type (lvar-type array))
+ (check-bounds (policy node (plusp insert-array-bounds-checks))))
+ (if (and (array-type-p type)
+ (not (array-type-complexp type))
+ (listp (array-type-dimensions type))
+ (not (null (cdr (array-type-dimensions type)))))
+ ;; If it's a simple multidimensional array, then just return
+ ;; its data vector directly rather than going through
+ ;; %WITH-ARRAY-DATA-MACRO. SBCL doesn't generally generate
+ ;; code that would use this currently, but we have encouraged
+ ;; users to use WITH-ARRAY-DATA and we may use it ourselves at
+ ;; some point in the future for optimized libraries or
+ ;; similar.
+ (if check-bounds
+ `(let* ((data (truly-the (simple-array ,element-type (*))
+ (%array-data-vector array)))
+ (len (length data))
+ (real-end (or end len)))
+ (unless (<= 0 start data-end lend)
+ (sequence-bounding-indices-bad-error array start end))
+ (values data 0 real-end 0))
+ `(let ((data (truly-the (simple-array ,element-type (*))
+ (%array-data-vector array))))
+ (values data 0 (or end (length data)) 0)))
+ `(%with-array-data-macro array start end
+ :check-fill-pointer ,check-fill-pointer
+ :check-bounds ,check-bounds
+ :element-type ,element-type))))
+
+;; It might very well be reasonable to allow general ARRAY here, I
+;; just haven't tried to understand the performance issues involved.
+;; -- WHN, and also CSR 2002-05-26
+(deftransform %with-array-data ((array start end)
+ ((or vector simple-array) index (or index null) t)
+ *
+ :node node
+ :policy (> speed space))
+ "inline non-SIMPLE-vector-handling logic"
+ (transform-%with-array-data/muble array node nil))
+(deftransform %with-array-data/fp ((array start end)
+ ((or vector simple-array) index (or index null) t)
+ *
+ :node node
+ :policy (> speed space))
+ "inline non-SIMPLE-vector-handling logic"
+ (transform-%with-array-data/muble array node t))
+\f
+;;;; array accessors
+
+;;; We convert all typed array accessors into AREF and %ASET with type