+;;; 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)
+ &body forms)
+ (once-only ((n-array array)
+ (n-svalue `(the index ,svalue))
+ (n-evalue `(the (or index null) ,evalue)))
+ `(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 `(length ,n-array))
+ (n-end `(or ,n-evalue ,n-len)))
+ `(if (<= ,n-svalue ,n-end ,n-len)
+ ;; success
+ (values ,n-array ,n-svalue ,n-end 0)
+ ;; failure: Make a NOTINLINE call to
+ ;; %WITH-ARRAY-DATA with our bad data
+ ;; to cause the error to be signalled.
+ (locally
+ (declare (notinline %with-array-data))
+ (%with-array-data ,n-array ,n-svalue ,n-evalue)))))
+ (,(if force-inline '%with-array-data-macro '%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 '*)
+ unsafe?
+ fail-inline?)
+ (let ((size (gensym "SIZE-"))
+ (defaulted-end (gensym "DEFAULTED-END-"))
+ (data (gensym "DATA-"))
+ (cumulative-offset (gensym "CUMULATIVE-OFFSET-")))
+ `(let* ((,size (array-total-size ,array))
+ (,defaulted-end
+ (cond (,end
+ (unless (or ,unsafe? (<= ,end ,size))
+ ,(if fail-inline?
+ `(error "End ~D is greater than total size ~D."
+ ,end ,size)
+ `(failed-%with-array-data ,array ,start ,end)))
+ ,end)
+ (t ,size))))
+ (unless (or ,unsafe? (<= ,start ,defaulted-end))
+ ,(if fail-inline?
+ `(error "Start ~D is greater than end ~D." ,start ,defaulted-end)
+ `(failed-%with-array-data ,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))))))
+
+(deftransform %with-array-data ((array start end)
+ ;; Note: This transform is limited to
+ ;; VECTOR only because I happened to
+ ;; create it in order to get sequence
+ ;; function operations to be more
+ ;; efficient. It might very well be
+ ;; reasonable to allow general ARRAY
+ ;; here, I just haven't tried to
+ ;; understand the performance issues
+ ;; involved. -- WHN
+ (vector index (or index null))
+ *
+ :important t
+ :node node
+ :policy (> speed space))
+ "inline non-SIMPLE-vector-handling logic"
+ (let ((element-type (upgraded-element-type-specifier-or-give-up array)))
+ `(%with-array-data-macro array start end
+ :unsafe? ,(policy node (= safety 0))
+ :element-type ,element-type)))
+\f
+;;;; array accessors
+
+;;; We convert all typed array accessors into AREF and %ASET with type