;;; -*- Mode:LISP; Package:ARRAY; Base:10; Readtable:CL -*- ;(defun adjust-array (array new-dimensions ; &key (element-type t element-type-p) ; (initial-element nil initial-element-p) ; (initial-contents nil initial-contents-p) ; (fill-pointer 0 fill-pointer-p) ; (displaced-to nil displaced-to-p) ; (displaced-index-offset 0 displaced-index-offset-p) ; &aux array-rank) ;; (unless (adjustable-array-p array) ;; (li:error "~S is not an adjustable array.")) ;; (unless (= (setq array-rank (array-rank array)) (length new-dimensions)) ;; (li:error "New array rank ~D is different from old array rank ~D")) ;; (let ((args (li:list :adjustable T)) ;; (old-element-type (array-type-from-element-type (array-element-type array))) ;; (leader-length (array-leader-length array)) ;; new-array ;; ) ;; (when element-type-p ;; (unless (= old-element-type (array-type-from-element-type element-type)) ;; (li:error "Old element type ~S, and new element type ~S do not match in adjust-array" ;; old-element-type element-type))) ;; ;; in any case it should be one of the arguments. ;; (li:push old-element-type args) ;; (li:push :element-type args) ;; (when initial-element-p ;; (li:push initial-element args) ;; (li:push :initial-element args)) ;; (when :initial-contents-p ;; (li:push initial-contents args) ;; (li:push :initial-contents args)) ;; (when fill-pointer-p ;; ;; check to see if old array had a fill-pointer. If not then it is an error. ;; (unless (array-has-fill-pointer-p array) ;; (li:error "~S has no Fill pointer. Cannot specify it for its adjustment." array)) ;; (li:push fill-pointer args) ;; (li:push :fill-pointer args)) ;; (when displaced-to-p ;; (li:push displaced-to args) ;; (li:push :displaced-to args)) ;; (when displaced-index-offset-p ;; (li:push displaced-index-offset args) ;; (li:push :displaced-index-offset args)) ;; ;; put the dimensions in the argument list ;; (li:push new-dimensions args) ;; ;; builds new array with everything in header set. ; (setq new-array ; (if (zerop leader-length) ; (li:apply #'make-array args) ; (progn ; (li:push leader-length args) ; (li:push :LEADER-LENGTH args) ; (li:push (array-leader-list array) args) ; (li:push :LEADER-LIST args) ; (li:apply #'zl-make-array args)))) ; ;; should not interrupt this piece of code since we are going to start screwing with pointers. ; (setq gr::*allow-sequence-break* (1+ gr::*allow-sequence-break*)) ; ;; copy elements from old array to new array. ; (unless (or initial-contents-p displaced-to-p) ; (let ((index (li:make-list array-rank :initial-element 0)) ; (old-dimensions (array-dimensions array)) ; array-index) ; (dotimes (i (array-total-size array)) ; (setq array-index (li:list-reverse index)) ; (when (array-in-bounds-p-internal new-array array-index) ; (aset-hard (aref-hard array array-index) new-array array-index)) ; (when (= old-element-type art-q) ; ;; put a body forward pointer in current cell of old array to corresponding cell in new array. ; (aset-hard (cons:make-pointer vinc:$$dtp-body-forward array) ; array array-index)) ; ;; increment index. ; (labels ; ((increment-index (index base) ; (if (null index) ; ;; should never see this, but does not hurt to have. ; nil ; (let* ((current-index (cons:car index)) ; (current-base (cons:car base)) ; (new-index (1+ current-index))) ; (if (< new-index current-base) ; (cons:rplaca index new-index) ; (progn ; (cons:rplaca index 0) ; (increment-index (cons:cdr index) (cons:cdr base)))))))) ; ;; increment index ; (increment-index index old-dimensions)) ; ) ; ) ; ) ; ;; forward leader if it exists. Leader contents should have been already copied if it existed before. ; (unless (zerop leader-length) ; (do ((i 0 (1+ i)) ; (new-leader-address (hw:24+ (- (ldb (hw:vm-read (hw:24+ new-array -1)) %%leader-offset 0)) new-array) ; (hw:24+ new-leader-address -1)) ; (old-leader-address (hw:24+ (- (ldb (hw:vm-read (hw:24+ array -1)) %%leader-offset 0)) array) ; (hw:24+ old-leader-address -1))) ; ((= i leader-length)) ; (%vm-write old-leader-address (cons:make-pointer vinc:$$dtp-body-forward array))) ; ) ; ;; forward header of old array to new one. ; (%vm-write array (cons:make-pointer vinc:$$dtp-header-forward new-array)) ; (setq gr::*allow-sequence-break* (1- gr::*allow-sequence-break*)) ; new-array ; ) ; ) (defun adjust-array (array new-dimensions &rest options) ;; allowed options are the following key arguments ;; element-type ;; initial-element ;; initial-contents ;; fill-pointer ;; displaced-to ;; displaced-index-offset (let (new-array array-rank array-type dimensions array-length leader-length displaced initial-contents-p displaced-p args fill-pointer) (multiple-value-setq (array-type array-rank dimensions array-length leader-length fill-pointer displaced) (decode-array-for-adjusting array)) (unless (= array-rank (length new-dimensions)) (li:error "New array rank ~D is different from old array rank ~D")) (multiple-value-setq (args initial-contents-p displaced-p) (li:apply #'build-arg-list-for-adjust-array (cons:cons array ; Silly but must print error message with it in called function. (cons:cons new-dimensions ; dimensions of new array. (cons:cons fill-pointer ; for checking existence of fill pointer in old array (cons:cons array-type options)))))) ; elment type checking. (setq new-array (if (zerop leader-length) (li:apply #'make-array args) (progn (li:push leader-length args) (li:push :LEADER-LENGTH args) (li:push (array-leader-list array) args) (li:push :LEADER-LIST args) (li:apply #'zl-make-array args)))) ;; should not interrupt this piece of code since we are going to start screwing with pointers. (setq gr::*allow-sequence-break* (1+ gr::*allow-sequence-break*)) ;; copy elements from old array to new array. (unless (or initial-contents-p displaced-p) (forward-element-of-adjusted-array array new-array array-type array-rank array-length dimensions displaced)) (forward-header-of-adjusted-array array new-array leader-length array-rank fill-pointer displaced) (setq gr::*allow-sequence-break* (1- gr::*allow-sequence-break*)) new-array ) ) (defun forward-element-of-adjusted-array (array new-array array-type array-rank array-length dimensions displaced) ;; array-length and dimensions are those of the forworded array. (let ((index (li:make-list array-rank :initial-element 0)) (pointer-to-write (cons:make-pointer vinc:$$dtp-body-forward array)) array-index) ;; first, copyt the elements of array into new-array. Put forward pointers if the array is of type art-q (dotimes (i array-length) (setq array-index (li:list-reverse index)) (when (array-in-bounds-p-internal new-array array-index) (aset-hard (aref-hard array array-index) new-array array-index)) (when (and (not displaced) (= array-type art-q)) ;; put a body forward pointer in current cell of old array to corresponding cell in new array. (aset-hard pointer-to-write array array-index)) ;; increment index. (labels ((increment-index (index base) (if (null index) ;; should never see this, but does not hurt to have. nil (let* ((current-index (cons:car index)) (current-base (cons:car base)) (new-index (1+ current-index))) (if (< new-index current-base) (cons:rplaca index new-index) (progn (cons:rplaca index 0) (increment-index (cons:cdr index) (cons:cdr base)))))))) ;; increment index (increment-index index dimensions)) ) ) ) (defun forward-header-of-adjusted-array (array new-array leader-length array-rank fill-pointer? displaced-to? &aux (pointer-to-write (cons:make-pointer vinc:$$dtp-body-forward array))) ;; Copy and forward leader if it exists. (unless (zerop leader-length) (do ((i 0 (1+ i)) (new-leader-address (hw:24+ (- (ldb (hw:vm-read (hw:24+ -1 new-array)) %%leader-offset 0)) new-array) (hw:24+ new-leader-address -1)) (old-leader-address (hw:24+ (- (ldb (hw:vm-read (hw:24+ -1 array)) %%leader-offset 0)) array) (hw:24+ old-leader-address -1))) ((= i leader-length)) (%vm-write new-leader-address (%vm-read old-leader-address)) (%vm-write old-leader-address pointer-to-write)) ;; forward header word (%vm-write (hw:24+ -2 new-array) pointer-to-write) ) ;; displaced-stuff (when displaced-to? (%vm-write (hw:24+ (- -1 array-rank) array) pointer-to-write) (%vm-write (hw:24+ (- -2 array-rank) array) pointer-to-write) ) ;; dimensions (unless (or (zerop array-rank) (= 1 array-rank)) (do ((rank (- array-rank) (1+ rank))) ((>= rank -1)) (%vm-write (hw:24+ rank array) pointer-to-write)) ) ;; fill-pointer? (when fill-pointer? (%vm-write (hw:24+ (- (ldb (hw:vm-read (hw:24+ array -1)) %%leader-offset 0)) array) pointer-to-write) ) ;; the array is adjustable, then it has an extended header at least. (%vm-write (hw:24+ -1 array) pointer-to-write) ;; forward header of old array to new one. (%vm-write array (cons:make-pointer vinc:$$dtp-header-forward new-array)) ) (defun decode-array-for-adjusting (array) ;; should return the type, the old-dimensions, the rank, adjustable-flag, leader-length, ;; total-size, displaced?, fill-pointer. (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)))))) (fill-pointer nil) (dimensions nil) array-pointer array-length array-rank (leader-length 0) displaced) (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-pointer))) (setq array-type (hw:ldb header2 %%array-type 0)) (when (= array-type art-error) (li:error "Array is ART-ERROR"))) (unless (= 1 (hw:ldb header2 %%adjustable-p 0)) (li:error "~S is not an adjustable array.")) (setq array-rank (hw:ldb header2 %%dimensions 0)) ;; compute array length and dimensions (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-pointer rank)))) ((>= rank -1) array-total-size))))) (setq dimensions (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))) ))) (when (= (hw:ldb header2 %%fill-pointer-p 0) 1) (setq fill-pointer (%vm-read (hw:24- (- (hw:ldb header2 %%leader-offset 0)) array-pointer)))) (setq displaced (= 1 (hw:ldb header2 %%displaced-p 0))) (when (= 1 (hw:ldb header2 %%leader-p 0)) (setq leader-length (hw:ldb (%vm-read (hw:24+ -2 array-pointer)) %%leader-length 0))) (unlock-array) (values array-type array-rank dimensions array-length leader-length fill-pointer displaced) ) ) (defun build-arg-list-for-adjust-array (array dimensions old-fill-pointer old-element-type &key (element-type t element-type-p) (initial-element nil initial-element-p) (initial-contents nil initial-contents-p) (fill-pointer 0 fill-pointer-p) (displaced-to nil displaced-to-p) (displaced-index-offset 0 displaced-index-offset-p)) (let ((args (li:list :adjustable T))) (when element-type-p (unless (= old-element-type (array-type-from-element-type element-type)) (li:error "Old element type ~S, and new element type ~S do not match in adjust-array" old-element-type element-type))) (li:push (dispatch (byte 5. 0.) old-element-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"))) args) (li:push :element-type args) (when initial-element-p (li:push initial-element args) (li:push :initial-element args)) (when :initial-contents-p (li:push initial-contents args) (li:push :initial-contents args)) ;; if old array has a fill pointer and we are not supplied with a new one, copy it. (when old-fill-pointer (unless fill-pointer-p (setq fill-pointer old-fill-pointer fill-pointer-p T))) (when fill-pointer-p ;; check to see if old array had a fill-pointer. If not then it is an error. (unless old-fill-pointer (li:error "~S has no Fill pointer. Cannot specify it for its adjustment." array)) (li:push fill-pointer args) (li:push :fill-pointer args)) (when displaced-to-p (li:push displaced-to args) (li:push :displaced-to args)) (when displaced-index-offset-p (li:push displaced-index-offset args) (li:push :displaced-index-offset args)) ;; put the dimensions in the argument list (li:push dimensions args) (values args initial-contents-p displaced-to-p) ) ) ;;; I gess, I should do a version that will be used in vector-push-extend. (defun test-adjust-array (x y k) (setq k 0) (li:boot-stack-groups) (setq x (make-array '(4 4) :element-type t :adjustable t)) (dotimes (i 4) (dotimes (j 4) (setf (aref x i j) k) (setq k (1+ k)))) (setq y (adjust-array x '(10 10))) (loop) )