home *** CD-ROM | disk | FTP | other *** search
- /* commonarrays - Implementation of Common Lisp multi-dimensional */
- /* arrays for xlisp 2.1. */
- /* XLISP-STAT 2.1 Copyright (c) 1990, by Luke Tierney */
- /* Additions to Xlisp 2.1, Copyright (c) 1989 by David Michael Betz */
- /* You may give out copies of this software; for conditions see the */
- /* file COPYING included with this distribution. */
-
- #include <string.h>
- #include <stdio.h>
- #include "xlisp.h"
- #include "osdef.h"
- #ifdef ANSI
- #include "xlproto.h"
- #include "xlsproto.h"
- #include "osproto.h"
- #else
- #include "xlfun.h"
- #include "xlsfun.h"
- #include "osfun.h"
- #endif ANSI
- #include "xlvar.h"
- #include "xlsvar.h"
-
- /* Forward declarations */
- #ifdef ANSI
- LVAL getdim(LVAL,int);
- int rankfordim(LVAL),sizefordim(LVAL),getarraysize(LVAL);
- #else
- LVAL getdim();
- int rankfordim(),sizefordim(),getarraysize();
- #endif
-
- /***************************************************************************/
- /** **/
- /** Utility Functions **/
- /** **/
- /***************************************************************************/
- /* Compute the rank of an array with dimensions given by list or vector dim */
- LOCAL int rankfordim(dim)
- LVAL dim;
- {
- if (listp(dim)) return(llength(dim));
- else if (vectorp(dim)) return(getsize(dim));
- else xlerror("bad dimension specifier", dim);
- }
-
- /* Compute the size of an array with dimensions given by list or vector dim */
- LOCAL int sizefordim(dim)
- LVAL dim;
- {
- int rank, size, i;
-
- if (vectorp(dim)) rank = getsize(dim);
- if (dim == NIL || (vectorp(dim) && rank == 0)) size = 1;
- else
- for (size = 1, i = 0; consp(dim) || (vectorp(dim) && i < rank); i++)
- size *= getfixnum(checknonnegint(getnextelement(&dim, i)));
- return(size);
- }
-
- /* get an array from the argument list */
- LVAL xsgetarray()
- {
- LVAL arg;
- arg = xlgetarg();
- if (! checkarrayp(arg)) xlerror("not an array", arg);
- else return(arg);
- }
-
- /* get and check a displaced array argument */
- LVAL xsgetdisplacedarray()
- {
- LVAL arg;
- arg = xsgetarray();
- if (! displacedarrayp(arg)) xlerror("not a displaced array", arg);
- return(arg);
- }
-
- /***************************************************************************/
- /***************************************************************************/
- /**** ****/
- /**** Internal Representation ****/
- /**** ****/
- /***************************************************************************/
- /***************************************************************************/
-
- /* Multidimensional arrays are implemented as displaced arrays. */
- /* Internally they are represented as a vector of three components. */
- /* The first component is an identifying symbol, s_arrayident. The */
- /* second is the dimension vector and the third is the data vector. */
-
- /***************************************************************************/
- /** **/
- /** Basic Predicates **/
- /** **/
- /***************************************************************************/
-
- /* A displaced array is any vector of length 3 whose first component is */
- /* eq to the symbol s_arrayident. Does not check for consistence of dims. */
- int displacedarrayp(x)
- LVAL x;
- {
- /* return (vectorp(x) && getsize(x) == 3 && getelement(x,0) == s_arrayident);*/
- return((x) && ntype(x) == DISPLACED_ARRAY);
- }
-
- int simplevectorp(x)
- LVAL x;
- {
- return(vectorp(x) && ! displacedarrayp(x));
- }
-
- /* check for consistency of dims in a displaced array. Return TRUE for a */
- /* simple vector, false for a non array. */
- int checkdims(x)
- LVAL x;
- {
- if (displacedarrayp(x))
- return(sizefordim(displacedarraydim(x)) == getsize(arraydata(x)));
- else if vectorp(x) return(TRUE);
- else return(FALSE);
- }
-
- /* check for an array; do not check dimensions */
- int arrayp(x)
- LVAL x;
- {
- return(displacedarrayp(x) || vectorp(x));
- }
-
- /* check for an array; check dimensions if displaced */
- int checkarrayp(x)
- LVAL x;
- {
- return((displacedarrayp(x) && checkdims(x)) || vectorp(x));
- }
-
- /* check if a subscript sequence is in array bounds */
- int inboundsp(x, indices, from_stack)
- LVAL x, indices;
- int from_stack;
- {
- LVAL index;
- int i, rank;
-
- if (simplevectorp(x)) {
- index = getnextarg(&indices, from_stack);
- xllastarg();
- return(fixp(index) && getfixnum(index) >= 0 &&
- getfixnum(index) < getsize(x));
- }
- else if (displacedarrayp(x)) {
- rank = arrayrank(x);
- for (i = 0; i < rank; i++) {
- index = getnextarg(&indices, from_stack);
- if (! fixp(index) || getfixnum(index) < 0
- || getfixnum(index) >= getfixnum(getdim(x, i)))
- return(FALSE);
- }
- xllastarg();
- return(TRUE);
- }
- else xlerror("not an array", x);
- }
-
- /***************************************************************************/
- /** **/
- /** Basic Selectors **/
- /** **/
- /***************************************************************************/
-
- /* Return x if x is a simple vector or the vector x is displaced to if x */
- /* is a displaced array. */
- LVAL arraydata(x)
- LVAL x;
- {
- if (simplevectorp(x)) return(x);
- else if (displacedarrayp(x)) return(getelement(x,2));
- else xlerror("not an array", x);
- }
-
- /* Return the dimension vector of a displaced array. */
- LVAL displacedarraydim(x)
- LVAL x;
- {
- if (displacedarrayp(x)) return(getelement(x,1));
- else xlerror("not a displaced array", x);
- }
-
- /* Size of dimension d; no error checking */
- static LVAL getdim(x, d)
- LVAL x;
- int d;
- {
- return(getelement(getelement(x,1), d));
- }
-
- /* Rank of x; no error checking */
- int arrayrank(x)
- LVAL x;
- {
- return((displacedarrayp(x)) ? getsize(getelement(x,1)) : 1);
- }
-
- /***************************************************************************/
- /** **/
- /** Basic Constructor **/
- /** **/
- /***************************************************************************/
-
- /* Form an array representation from dim sequence and data vector */
- /* Both arguments should be protected from garbage collection */
- LVAL makedisplacedarray(dim, data)
- LVAL dim, data;
- {
- LVAL dimvector, result;
- int rank, size;
-
- rank = rankfordim(dim);
-
- /* Check dim and data for consistency */
- size = sizefordim(dim);
- if (! vectorp(data)) xlerror("bad data argument", data);
- if (size != getsize(data)) xlfail("dimensions do not match data length");
-
- if (rank == 1) {
- result = data;
- }
- else {
- /* protect some pointers */
- xlstkcheck(2);
- xlsave(dimvector);
- xlsave(result);
-
- dimvector = coerce_to_vector(dim);
-
- result = newvector(3);
- result->n_type = DISPLACED_ARRAY;
- setelement(result, 0, s_arrayident);
- setelement(result, 1, dimvector);
- setelement(result, 2, data);
-
- xlpopn(2);
- }
- return(result);
- }
-
- /***************************************************************************/
- /***************************************************************************/
- /**** ****/
- /**** Implementation Independent Part ****/
- /**** ****/
- /***************************************************************************/
- /***************************************************************************/
-
- /***************************************************************************/
- /** **/
- /** Predicates **/
- /** **/
- /***************************************************************************/
-
- /* Common Lisp ARRAYP function */
- LVAL xsarrayp()
- {
- LVAL x;
-
- x = xlgetarg();
- xllastarg();
-
- return((checkarrayp(x)) ? s_true : NIL);
- }
-
- /****************************************************************************/
- /** **/
- /** Selectors **/
- /** **/
- /****************************************************************************/
-
- /* Get array size */
- static int getarraysize(x)
- LVAL x;
- {
- return(getsize(arraydata(x)));
- }
-
- /* Common Lisp ARRAY-DIMENSIONS function */
- LVAL xsarraydimensions()
- {
- LVAL x;
- LVAL result;
-
- x = xsgetarray();
- xllastarg();
-
- xlsave1(result);
- if (simplevectorp(x)) {
- result = cvfixnum((FIXTYPE) getsize(x));
- result = consa(result);
- }
- else
- result = coerce_to_list(displacedarraydim(x));
- xlpop();
- return(result);
- }
-
- /* Common Lisp ARRAY-RANK function */
- LVAL xsarrayrank()
- {
- LVAL x;
-
- x = xsgetarray();
- xllastarg();
-
- if (simplevectorp(x))
- return(cvfixnum((FIXTYPE) 1));
- else
- return(cvfixnum((FIXTYPE) arrayrank(x)));
- }
-
- /* Common Lisp ARRAY-TOTAL-SIZE function */
- LVAL xsarraytotalsize()
- {
- LVAL x;
-
- x = xsgetarray();
- xllastarg();
-
- return(cvfixnum((FIXTYPE) getarraysize(x)));
- }
-
- /* Common Lisp ARRAY-DIMENSION function */
- LVAL xsarraydimension()
- {
- LVAL x, i;
-
- x = xsgetarray();
- i = checknonnegint(xlgafixnum());
- xllastarg();
-
- if (getfixnum(i) >= arrayrank(x)) xlerror("dimension exceeds rank", i);
- else if (simplevectorp(x)) return(cvfixnum((FIXTYPE) getsize(x)));
- else return(getdim(x, (int) getfixnum(i)));
- }
-
- /* Common Lisp ARRAY-IN-BOUNDS-P function */
- LVAL xsarrayinboundsp()
- {
- return((inboundsp(xsgetarray(), NIL, TRUE)) ? s_true : NIL);
- }
-
- /* Compute row major index from indices list or array or from stack args */
- int rowmajorindex(x, indices, from_stack)
- LVAL x, indices;
- int from_stack;
- {
- LVAL dim, index;
- int rank, k, fsize, i;
-
- if (simplevectorp(x)) {
- index = checknonnegint(getnextarg(&indices, from_stack));
- if (getfixnum(index) >= getsize(x))
- xlerror("index out of range", index);
- return(getfixnum(index));
- }
- else if (displacedarrayp(x)) {
-
- dim = displacedarraydim(x);
-
- rank = arrayrank(x);
- for (i = 0, k = 0; i < rank; i++) {
- index = checknonnegint(getnextarg(&indices, from_stack));
- fsize = getfixnum(getelement(dim, i));
- if (getfixnum(index) < 0
- || getfixnum(index) >= getfixnum(getdim(x, i)))
- xlerror("index out of range", index);
- k = fsize * k + getfixnum(index);
- }
- return(k);
- }
- else xlerror("not an array", x);
- }
-
- /* Common Lisp ARRAY-ROW-MAJOR-INDEX function */
- LVAL xsarrayrowmajorindex()
- {
- LVAL x;
-
- x = xlgetarg();
-
- return(cvfixnum((FIXTYPE) rowmajorindex(x, NIL, TRUE)));
- }
-
- /* Common Lisp AREF function */
- LVAL xsaref()
- {
- LVAL x;
-
- x = xsgetarray();
-
- return (getelement(arraydata(x), rowmajorindex(x, NIL, TRUE)));
- }
-
-
- /****************************************************************************/
- /** **/
- /** Constructors **/
- /** **/
- /****************************************************************************/
-
- /* Make a new array of dimension dim with contents specified by the keyword */
- /* argument. */
- LVAL newarray(dim, key, key_arg)
- LVAL dim, key, key_arg;
- {
- LVAL data, contents, result;
- int rank, size, i;
-
- /* protect some pointers */
- xlstkcheck(3);
- xlsave(data);
- xlsave(contents);
- xlsave(result);
-
- /* make the array data vector */
- if (key == NIL)
- data = newvector(sizefordim(dim));
- else if (key == s_ielement) {
- size = sizefordim(dim);
- data = newvector(size);
- for (i = 0; i < size; i++)
- setelement(data, i, key_arg);
- }
- else if (key == s_icontents) {
- rank = rankfordim(dim);
- size = sizefordim(dim);
- contents = nested_list_to_list(key_arg, rank);
- if (llength(contents) != size)
- xlerror("initial contents does not match dimensions", key_arg);
- data = newvector(size);
- for (i = 0; consp(contents); i++, contents = cdr(contents))
- setelement(data, i, car(contents));
- }
- else if (key == s_displacedto)
- data = arraydata(key_arg);
- else
- xlerror("bad keyword", key);
-
- result = makedisplacedarray(dim, data);
-
- /* restore the stack frame */
- xlpopn(3);
-
- return (result);
- }
-
- /* convert nested list to array - used by read macro. Determines dimension */
- /* from first list element, without checking others, then calls newarray. */
- LVAL nested_list_to_array(list, rank)
- LVAL list;
- int rank;
- {
- LVAL next, dim, data, result;
- int i;
-
- /* protect some pointers */
- xlstkcheck(2);
- xlsave(dim);
- xlsave(result);
-
- dim = mklist(rank, NIL);
- for (i = 0, data = list, next = dim; i < rank; i++, next = cdr(next)) {
- rplaca(next, cvfixnum((FIXTYPE) llength(data)));
- if ((i < rank) && (! consp(data)))
- xlerror("data does not match rank", list);
- data = car(data);
- }
-
- result = newarray(dim, s_icontents, list);
-
- /* restore the stack frame */
- xlpopn(2);
-
- return (result);
- }
-
- /* Common Lisp MAKE-ARRAY function. Allows one of the keywords */
- /* :INITIAL-ELEMENT, :INITIAL-CONTENTS, or :DISPLACED-TO */
- LVAL xsmakearray()
- {
- LVAL dim, key = NIL, key_arg = NIL, result;
-
- /* protect some pointes */
- xlstkcheck(2);
- xlsave(dim);
- xlsave(result);
-
- dim = xlgetarg();
- if (xlgetkeyarg(s_ielement, &key_arg)) key = s_ielement;
- else if (xlgetkeyarg(s_icontents, &key_arg)) key = s_icontents;
- else if (xlgetkeyarg(s_displacedto, &key_arg)) key = s_displacedto;
-
- if (fixp(dim)) dim = consa(dim);
- if (! listp(dim)) xlerror("bad dimension argument", dim);
-
- result = newarray(dim, key, key_arg);
-
- /* restore the stack frame */
- xlpopn(2);
-
- return (result);
- }
-
- /*************************************************************************/
- /** **/
- /** Mutators **/
- /** **/
- /*************************************************************************/
-
- /* setf function for aref */
- void evsetarrayelement(place, value)
- LVAL place, value;
- {
- LVAL args, next, x, rest;
-
- /* protect args pointer */
- xlsave1(args);
-
- args = mklist(llength(place), NIL);
- /* rplaca(args, evmatch(VECTOR,&place));*/
- rplaca(args, evarg(&place));
- if (! arrayp(car(args))) xlerror("not an array", car(args));
- for (next = cdr(args); consp(next); next = cdr(next)) {
- rplaca(next, evmatch(FIXNUM,&place));
- }
-
- x = car(args);
- rest = cdr(args);
- if (checkarrayp(x)) {
- setelement(arraydata(x), rowmajorindex(x, rest, FALSE), value);
- }
- else
- xlerror("not an array", x);
-
- xlpop();
- }
-
- /*************************************************************************/
- /** **/
- /** Print Array **/
- /** **/
- /*************************************************************************/
-
- /* Convert to a nested list for printing */
- LVAL array_to_nested_list(array)
- LVAL array;
- {
- int i;
- LVAL alist;
-
- if (! displacedarrayp(array)) xlerror("not a displaced array", array);
-
- /* protect the result pointer */
- xlsave1(alist);
-
- alist = coerce_to_list(arraydata(array));
- if (alist != NIL)
- for (i = arrayrank(array) - 1; i > 0; i--)
- alist = splitlist(alist, (int) getfixnum(getdim(array, i)));
-
- /* restore the stack frame */
- xlpop();
-
- return(alist);
- }
-
- /* print an array */
- void putarray(fptr, array, flag)
- LVAL fptr, array;
- int flag;
- {
- LVAL value;
-
- if (! displacedarrayp(array)) xlerror("not an array", array);
-
- /* protect a pointer */
- xlsave1(value);
-
- xlputc(fptr,'#');
- value = cvfixnum((FIXTYPE) arrayrank(array));
- xlprint(fptr, value, flag);
- xlputc(fptr, (getvalue(s_printcase) == k_downcase) ? 'a' : 'A');
- value = array_to_nested_list(array);
- if (value == NIL) {
- xlputc(fptr,'(');
- xlputc(fptr,')');
- }
- else
- xlprint(fptr, value, flag);
-
- /* restore the stack frame */
- xlpop();
- }
-