+;;
+;; array.l -[Tue Jul 5 23:51:48 1983 by layer]-
+;;
+;; maclisp compatible array package. This implements maclisp
+;; compatible arrays.
+;;
+;; features of the new package:
+;; Most array will be notype arrays. This is because they are the most
+;; efficient in Franz. What used to be fixnum and flonums arrays are
+;; now fixnum-block and flonum-block arrays.
+;; The array access functions are more specialized and much faster now.
+;; The array access functions have different semantics. Now they are
+;; responsible for both accessing and storing in an array.
+;; When an access function is asked to access a value, it will be given
+;; the subscripts already evaluated and the array object. These will
+;; be stacked, so the array access function should be a lexpr to read them.
+;; When an access function is asked to store a value that value will be
+;; the first argument, the subscripts will follow and finally there will
+;; be the array object.
+;; It is up to the access function to determine if it is being asked to
+;; store or retrieve a value, and this determination will probably
+;; be made by looking at the number of arguments.
+
+
+(setq rcs-array-
+ "$Header: array.l 1.5 83/07/05 23:51:58 layer Exp $")
+
+(declare (special gcdisable)
+ (macros t))
+
+(def array
+ (macro ($lis$)
+ `(*array ',(cadr $lis$) ',(caddr $lis$) ,@(cdddr $lis$))))
+
+(def *array
+ (lexpr (nargs)
+ (prog (name type rtype dims size tname numdims)
+
+ (cond ((lessp (setq numdims (- nargs 2)) 1)
+ (error "no bounds to array declaration ")))
+
+ (setq name (arg 1)
+ type (arg 2)
+ rtype (cond ((memq type '(t nil fixnum flonum))
+ 'value)
+ ((eq type 'fixnum-block)
+ 'fixnum)
+ ((eq type 'flonum-block)
+ 'flonum)
+ (t (error "array: bad type: " type)))
+ dims (do ((i nargs (1- i))
+ (res nil (cons (arg i) res)))
+ ((eq i 2) res))
+
+ size (apply 'times dims))
+
+ (cond ((null type) (setq type 'unmarked_array)))
+
+ ; we disable gc during the next calculation since
+ ; the data returned from small-segment is unprotected
+ ; and a gc would cause its data to be put on the
+ ; free list.
+ (let ((gcdisable t))
+ (setq tname
+ (marray (small-segment rtype size)
+ (cond ((eq rtype 'value)
+ (cond ((eq numdims 1)
+ (getd 'arrac-oneD))
+ ((eq numdims 2)
+ (getd 'arrac-twoD))
+ (t (getd 'arrac-nD))))
+ (t (getd 'arrac-nD)))
+ (cons type dims)
+ size
+ (sizeof rtype))))
+ ; if type is fixnum or flonum
+ ; we must intialize to 0 or 0.0
+ (cond ((or (and (eq 'fixnum type)
+ (setq rtype 0))
+ (and (eq 'flonum type)
+ (setq rtype 0.0))
+ (and (or (status feature 68k)
+ (status feature for-68k))
+ (progn (setq rtype nil) t)))
+ (do ((i size))
+ ((zerop i))
+ (set (arrayref tname (setq i (1- i))) rtype))))
+
+ (cond (name (putd name tname)))
+ (return tname))))
+
+(defmacro arraycall (type array &rest indexes)
+ `(funcall ,array ,@indexes))
+
+;--- array-type :: return type of array
+;
+(defun array-type (arr)
+ (cond ((not (arrayp arr)) (error "array-type: non array passed " arr))
+ (t (car (getaux arr)))))
+
+; this is used by the old array scheme. Keep this around until
+; everything is recompiled
+
+(defun ev-arraycall (type array indexes)
+ (apply array indexes))
+
+
+;;;---- array access functions.
+
+; we first define a macro to evaluate a value cell. In compiled code cdr
+; is the fastest way to do this, in interpreted code the type checker
+; would not let us use cdr so we have to use eval.
+(eval-when (compile)
+ (defmacro value-eval (x) `(cdr ,x)) ; one level of indirection
+ (defmacro simple-arrayref (arr ind) `(offset-cxr ,ind (getdata ,arr))))
+
+(eval-when (eval)
+ (defun value-eval (x) (eval x))
+ (defun simple-arrayref (arr ind) (arrayref arr ind)))
+
+;- one dimensional
+(defun arrac-oneD n
+ (cond ((eq n 2) (value-eval (simple-arrayref (arg 2) (arg 1))))
+ ((eq n 3) (set (simple-arrayref (arg 3) (arg 2)) (arg 1)))
+ (t (error " wrong number of subscripts to array: " (arg n)))))
+
+(defun arrac-twoD n
+ (let ((aux (getaux (arg n))))
+ (cond ((eq n 3)
+ (value-eval (simple-arrayref
+ (arg n)
+ (+ (* (arg 1) (caddr aux)) (arg 2)))))
+ ((eq n 4)
+ (set (simple-arrayref (arg n)
+ (+ (* (arg 2) (caddr aux)) (arg 3)))
+ (arg 1)))
+ (t (error " wrong number of subscripts to array: " (arg n))))))
+
+;-- n dimensional array access function.
+(defun arrac-nD n
+ (let ((aux (getaux (arg n)))
+ firstsub subs
+ store
+ (index 0))
+
+ (setq subs (length (cdr aux)))
+ (cond ((eq n (1+ subs))
+ (setq firstsub 1))
+ ((eq n (+ 2 subs))
+ (setq firstsub 2 store t))
+ (t (error "wrong number of subscripts to array: " (arg n))))
+
+ (setq index (arg firstsub))
+ (do ((bounds (cddr aux) (cdr bounds))
+ (i firstsub))
+ ((null bounds))
+ (setq index (+ (* index (car bounds)) (arg (setq i (1+ i))))))
+
+ (setq subs (arrayref (arg n) index)) ; get cell requested
+ (cond ((memq (car aux) '(fixnum-block flonum-block))
+ (cond (store (replace subs (arg 1)))
+ (t (cpy1 subs))))
+ (t (cond (store (set subs (arg 1)))
+ (t (value-eval subs)))))))
+
+
+(defmacro store ( (arrname . indexes) value)
+ (do ((fnd))
+ (nil)
+ (cond ((eq 'funcall arrname)
+ (return `(funcall ,(car indexes) ,value . ,(cdr indexes))))
+ ((eq 'apply arrname)
+ (return `(apply ,(car indexes) (cons ,value ,@(cdr indexes)))))
+ ((eq 'arraycall arrname)
+ (return `(funcall ,(cadr indexes) ,value ,@(cddr indexes))))
+ ((arrayp arrname)
+ (return `(funcall ',arrname ,value ,@indexes))))
+ (setq fnd (getd arrname))
+ (cond ((or (and (dtpr fnd) (eq 'macro (car fnd)))
+ (and (bcdp fnd) (eq 'macro (getdisc fnd))))
+ (setq fnd (apply arrname (cons arrname indexes)))
+ (setq arrname (car fnd)
+ indexes (cdr fnd)))
+ (t (return `(,arrname ,value . ,indexes))))))
+
+;-- storeintern - there may be residual calls to storeintern from
+; old code, we handle it here. this routine can be eliminated when
+; code is recompiled
+
+(defun storeintern (arrnam value indexes)
+ (apply arrnam (cons value indexes)))
+
+;--- small segment storage allocators.
+
+; this function allocates segments of storage and attempt to use the whole
+; block instead of throwing away what isnt used
+;
+
+(declare (special gcdisable))
+
+(defun small-segment (type n)
+ (prog (lastseg retv elementsize itemsperpage-1 gcdisable tmp)
+ (setq gcdisable t) ; its not a good idea to gc while we are
+ ; handling pointers to things segment returns.
+ (desetq (elementsize . itemsperpage-1) (get 'segment-sizes type))
+ (cond ((null elementsize) (error "small-segment: bad type " type)))
+ (setq lastseg (get 'segment-types type))
+ (cond ((and lastseg (not (lessp (car lastseg) n))))
+ (t ; must allocate a block of storage, want to the least number of
+ ; pages which includes n elements
+ ; there are elementsize elements per page, and
+ ; itemsperpage-1 is the number of elements on a page minus 1
+ (setq retv (boole 4
+ (+ n itemsperpage-1)
+ itemsperpage-1)) ; 4 is x & ~y
+ (setq lastseg (cons retv (maknum (segment type retv))))))
+ (setq retv (cdr lastseg))
+ (rplaca lastseg (- (car lastseg) n))
+ (rplacd lastseg (+ (cdr lastseg) (* elementsize n)))
+ (cond ((greaterp (car lastseg) 0)
+ (putprop 'segment-types lastseg type)
+ (cond ((null (setq tmp (get 'segment-arrays type)))
+ (putprop 'segment-arrays
+ (setq tmp (marray nil nil nil nil nil))
+ type)))
+ (putdata tmp (fake (cdr lastseg)))
+ (putlength tmp (car lastseg))
+ (putdelta tmp elementsize))
+ (t ; remove all counters since we no longer have any space
+ ; left and we can't have a zero length array
+ (remprop 'segment-types type)
+ (remprop 'segment-arrays type)))
+ (return (fake retv))))
+
+; data base for small-segment
+(putprop 'segment-sizes '( 4 . 127) 'value)
+(putprop 'segment-sizes '( 4 . 127) 'fixnum)
+(putprop 'segment-sizes '( 8 . 63) 'flonum)
+
+
+(def arraydims (lambda (arg) (cond ((symbolp arg) (getaux (getd arg)))
+ ((arrayp arg) (getaux arg))
+ (t (break '"non array arg to arraydims")))))
+
+; fill array from list or array
+
+(def fillarray
+ (lambda (arr lis)
+ (prog (maxv typept)
+ (cond ((symbolp arr) (setq arr (getd arr))))
+
+ (cond ((symbolp lis)
+ (setq lis (getd lis))
+ (return (fillarrayarray arr lis)))
+
+ ((arrayp lis) (return (fillarrayarray arr lis))))
+
+ (setq maxv (1- (getlength arr))
+ typept (cond ((memq (car (getaux arr))
+ '(t fixnum flonum unmarked_array))
+ t)
+ (t nil)))
+ (do ((ls lis)
+ (i 0 (1+ i)))
+ ((>& i maxv))
+
+ (cond (typept (set (arrayref arr i) (car ls)))
+ (t (replace (arrayref arr i) (car ls))))
+
+ (cond ((cdr ls) (setq ls (cdr ls))))))))
+
+(def fillarrayarray
+ (lambda (arrto arrfrom)
+ (prog (maxv)
+ (setq maxv (1- (min (getlength arrto)
+ (getlength arrfrom))))
+ (do ((i 0 (1+ i)))
+ ((>& i maxv))
+ (replace (arrayref arrto i) (arrayref arrfrom i))))))
+
+(def listarray
+ (lexpr (n)
+ (prog (arr size typ ret newv)
+ (setq arr (arg 1))
+ (cond ((arrayp arr))
+ ((and (symbolp arr) (arrayp (setq arr (getd arr)))))
+ (t (error "Non array to listarray " arr)))
+ (setq size (cond ((eq n 2) (arg 2))
+ (t (apply '* (cdr (arraydims arr))))))
+ (setq typ (car (getaux arr)))
+ (cond ((memq typ '(t fixnum flonum unmarked_array))
+ (setq typ t))
+ (t (setq typ nil)))
+ (do ((i (1- size) (1- i)))
+ ((lessp i 0))
+ (setq newv (arrayref arr i))
+ (setq ret (cons (cond (typ (eval newv))
+ (t (cpy1 newv)))
+ ret)))
+ (return ret))))