368 lines · 11.7 KB · C
RawDownload
/* -------------------------------------------------------------------------- * Haskell array primitives. * * The Hugs 98 system is Copyright (c) Mark P Jones, Alastair Reid, the * Yale Haskell Group, and the OGI School of Science & Engineering at OHSU, * 1994-2003, All rights reserved.  It is distributed as free software under * the license in the file "License", which is included in the distribution. * * $RCSfile: array.c,v $ * $Revision: 1.10 $ * $Date: 2004/01/06 10:02:51 $ * ------------------------------------------------------------------------*/ static Name nameEltUndef;		/* undefined element in array	   */ PROTO_PRIM(primArray);PROTO_PRIM(primUpdate);PROTO_PRIM(primAccum);PROTO_PRIM(primAccumArray);PROTO_PRIM(primAmap);PROTO_PRIM(primSubscript);PROTO_PRIM(primBounds);PROTO_PRIM(primElems);PROTO_PRIM(primEltUndef);#if IO_MONADPROTO_PRIM(primIONewArr);PROTO_PRIM(primIOReadArr);PROTO_PRIM(primIOWriteArr);PROTO_PRIM(primIOFreeze);PROTO_PRIM(primIOArrEq);#endif static struct primitive arrayPrimTable[] = {  {"primArray",		3, primArray},  {"primUpdate",	2, primUpdate},  {"primAccum",		3, primAccum},  {"primAccumArray",	5, primAccumArray},  {"primAmap",		2, primAmap},  {"primSubscript",	2, primSubscript},  {"primBounds",	1, primBounds},  {"primElems",		1, primElems},  {"eltUndef",		0, primEltUndef},#if IO_MONAD  {"IONewArr",		3+IOArity, primIONewArr},  {"IOReadArr",		2+IOArity, primIOReadArr},  {"IOWriteArr",	3+IOArity, primIOWriteArr},  {"IOFreeze",		1+IOArity, primIOFreeze},  {"IOBounds",	        1, primBounds},  {"IOArrEq",	        2, primIOArrEq},#endif  {0,			0, 0}}; static Void outOfBounds Args((void));static void outOfBounds() {    throwException(ap(nameArrayException, ap(nameIndexOutOfBounds, nameNil)));} /* -------------------------------------------------------------------------- * Array control: * ------------------------------------------------------------------------*/ static Void arrayControl Args((Int));static Void arrayControl(what)Int what; {    switch (what) {	case INSTALL : 		       setCurrModule(modulePrelude);#define pFun(n,s,t)    addPrim(0,n=newName(findText(s),NIL),t,modulePrelude,NIL)		       pFun(nameEltUndef,  "_undefined_array_element",							"eltUndef");#undef pFun		       break;    }} static struct primInfo arrayPrims = { arrayControl, arrayPrimTable, 0 }; /*-------------------------------------------------------------------------*/ /* The implementation of arrays is heavily parameterized to allow the * use of different implementations.  Non-conservative GC is also an * important goal, which is also why so much of this was originally done * using macros rather than procedures.  As it happens, this probably could * have been avoided, but there don't seem to be sufficiently good reasons * to warrant changing it. * * The result, however, is a torture-test for the C preprocessor! * * A description of the various `parameters' follows: * * Primitives that build a new array use the macro: * declArr;		Allocate slot on stack to hold a freshly created *			array that will be seen by the garbage collector. *			The value of the array can subsequently be referred *			to using the `arr' macro.  The declArr macro also *			declares a local Int variable, alen, to hold the *			length of the array. * * There are four methods for creating a new array, all of which return * the intermediate array in arr and its length in alen: * * aNewSet(b,s,v);	Allocate new array with bounds b and size s. *			Data elements set to v. * aNewNil(b,s);	Equivalent to aNewSet(b,s,NIL), treated separately *			because it is possible to use more efficient code *			for this special case in some implementations. * aNewCopy(a);		Builds an exact copy of array a, which can then be *			modified destructively, without changing a. *			Note that this forces evaluation of a. * aNewLike(a,v);	Builds an array of the same size and bounds as a *			with each element initialized to v. *			Note that this forces evaluation of a. * * All four of these methods are implemented using macros; the b, r, a * parameters are integers, identifying particular primArg(x) slots. * The v parameters should be constants, unmovable by GC, or primArg(x) * references that can be safely modified during GC. * * Other functions are: * * aEvalModel(a);	Evaluate model array primArg(a), and overwrite it *			on stack with an indirection free pointer to the *			resulting array. * aAssocs(as,p);	Move list of assocs -- (offset,value) pairs -- from *			primArg(as) (which is NIL'd to prevent space leak) *			to top of stack and evaluate, in sequence, until all *			assocs have been processed.  For each pair, we *			run procedure p with the offset in whnfInt and the *			associated value in top(), to be popped before p is *			done. * aSetElt;		To be used with aAssocs: if arr[whnfInt] is NIL, *			set it to top(), otherwise set to undefined. * aAddElt(f);		To be used with aAssocs: replace whnfInt element e *			of arr with ap(ap(primArg(f),e),top()) * aNullElts;		Set any null elements in arr to nameEltUndef. * aCopyNull(a);	Replace any null elements in arr with corresponding *			values in array primArg(a). * aMapElts(f);		Replace every element e in arr with ap(primArg(f),e). * aGetElt(a);		Push value of whnfInt'th element of primArg(a). * aPutElt(a,v);	Put v into whnfInt'th slot of primArg(a). * aElems(a);		Evaluate array at primArg(a), and return its list of *			elements on top of stack in reverse order, backed onto *			NIL (ready for revOnto(top(),nameNil)). * aBounds()		Extract bounds from arr. * aGetBounds(a)	Extract bounds from primArg(a). * * There is no guarantee that the representation used for arr will be the * same as for any other array.  The following methods do however ensure * that the standard representation is used when a value is finally returned: * * updarrRoot();	Updates root of redex with array represented by arr. *			(Should also reset arr to avoid space leaks.) * aRetForIO();		Update root to return an array from IO monad; *			i.e. pass arr to the continuation. */ #define declArr		StackPtr arrPos=sp+1; Int alen; push(NIL)#define arr		stack(arrPos) #define aNewNil(b,s)	aNewSet(b,s,NIL)#define aNewSet(b,s,v)	{   Int i;				\			    eval(primArg(s));			\			    alen = (whnfInt>0)?whnfInt:0;	\			    for (arr=NIL, i=alen; i>0; i--)	\				arr = ap(v,arr);		\			    arr = ap(primArg(b),arr);		\			}#define aNewCopy(a)	{   Cell es = snd(primArg(a));		\			    for (arr=ap(hd(es),NIL), alen=0;	\				 nonNull(es=tl(es)); ++alen)	\				arr = ap(hd(es),arr);		\			    arr = rev(arr);			\			}#define aNewLike(a,v)	{   Cell es = snd(primArg(a));		\			    for (arr=ap(hd(es),NIL), alen=0;	\				 nonNull(es=tl(es)); ++alen)	\				arr = ap(v,arr);		\			    arr = rev(arr);			\			}#define aEvalModel(a)	eval(primArg(a)); primArg(a)=whnfHead#define aSetElt		{   List us = snd(arr);			\			    for (; 0<whnfInt--; us=tl(us));	\			    hd(us) = isNull(hd(us))?top():nameEltUndef;\			    drop();				\			}#define aAddElt(f)	{   List us = snd(arr);			\			    for (; 0<whnfInt--; us=tl(us));	\			    hd(us) = ap(primArg(f),hd(us));	\			    hd(us) = ap(hd(us),pop());		\			}#define aNullElts	{   List us = snd(arr);			\			    for (; nonNull(us); us=tl(us))	\				if (isNull(hd(us)))		\				    hd(us) = nameEltUndef;	\			}#define aCopyNull(a)	{   List us = snd(snd(primArg(a)));	\			    List vs = snd(arr);			\			    for (; nonNull(vs); vs=tl(vs), us=tl(us))\				if (isNull(hd(vs)))		\				    hd(vs) = hd(us);		\			}#define aMapElts(f)	{   List us = snd(arr);			\			    for (; nonNull(us); us=tl(us))	\				hd(us) = ap(primArg(f),hd(us));	\			}#define aGetElt(a)	{   List es = snd(snd(primArg(a)));	\			    while (0<whnfInt--)			\				es = tl(es);			\			    push(hd(es));			\			}#define aPutElt(a,v)	{   List es = snd(snd(primArg(a)));	\			    while (0<whnfInt--)			\				es = tl(es);			\			    hd(es) = v;				\			}#define aElems(a)	{   List us;				\			    eval(primArg(a));			\			    us = snd(snd(primArg(a)));		\			    chkStack(2); onto(NIL); onto(NIL);	\			    for(; nonNull(us); us=tl(us)) {	\				top()     = ap(nameCons,hd(us));\				pushed(1) = ap(top(),pushed(1));\			    }					\			    drop();				\			}#define aBounds()	fst(arr)#define aGetBounds(a)	fst(snd(primArg(a)))#define updarrRoot()	updapRoot(ARRAY,arr); arr=NIL#define aRetForIO()	arr = ap(ARRAY,arr);			\			updapRoot(primArg(1),arr);		\			arr = NIL; /* The implementation of aAssocs(as,p) should be independent of the * representation for arrays: */#define aAssocs(as,p)	push(primArg(as)); primArg(as)=NIL;	\			eval(pop());				\			while (whnfHead==nameCons) {		\			    eval(pop());			\			    eval(top());			\			    if (whnfInt<0 || whnfInt>=alen)	\				outOfBounds();			\			    drop(); p; eval(pop());		\			} /* Finally, we come to the implementation of the Haskell array primitives: */ primFun(primArray) {			/* :: (a,a)			   */    declArr;				/*    -> Int			   */    aNewNil(3,2);			/*	 -> [(Int,b)]		   */    aAssocs(1,aSetElt);			/*	    -> Array a b	   */    aNullElts;    updarrRoot();} primFun(primUpdate) {			/* :: [(Int,b)]			   */    declArr;				/*    -> Array a b		   */    aEvalModel(1);			/*       -> Array a b		   */    aNewLike(1,NIL);    aAssocs(2,aSetElt);    aCopyNull(1);    updarrRoot();} primFun(primAccum) {			/* :: [(Int,c)] -> Array a b	   */    declArr;				/*    -> (b -> c -> b)		   */    aEvalModel(2);			/*	 -> Array a b		   */    aNewCopy(2);    aAssocs(3,aAddElt(1));    updarrRoot();} primFun(primAccumArray) {		/* :: (a,a) -> Int		   */    declArr;				/*    -> (b -> c -> b) -> b	   */    aNewSet(5,4,primArg(2));		/*	 -> [(Int,c)]		   */    aAssocs(1,aAddElt(3));		/*	    -> Array a b	   */    updarrRoot();} primFun(primAmap) {			/* :: (a -> b)			   */    declArr;				/*    -> Array c a		   */    aEvalModel(1);			/*       -> Array c b		   */    aNewCopy(1);    aMapElts(2);    updarrRoot();} primFun(primSubscript) {		/* :: Array a b -> Int -> b        */    aEvalModel(2);    eval(primArg(1));    aGetElt(2);    updateRoot(top());} primFun(primBounds) {			/* :: Array a b -> (a,a)	   */    aEvalModel(1);    updateRoot(aGetBounds(1));} primFun(primElems) {			/* :: Array a b -> [b]		   */    aEvalModel(1);    aElems(1);    updateRoot(revOnto(top(),nameNil));} primFun(primEltUndef) {    throwException(ap(nameArrayException, ap(nameUndefinedElement, nameNil)));} #if IO_MONADprimFun(primIONewArr) {			/* :: (a,a)			   */    declArr;				/*    -> Int			   */    aNewSet(3+IOArity,2+IOArity,IOArg(1));/*	 -> b			   */    aRetForIO();			/*	    -> IO (IOArray a b)	   */} primFun(primIOReadArr) {		/* :: IOArray a b -> Int -> IO b   */    aEvalModel(2+IOArity);    eval(primArg(1+IOArity));    aGetElt(2+IOArity);    IOReturn(top());} primFun(primIOWriteArr) {		/* :: IOArray a b -> Int -> b	   */    aEvalModel(3+IOArity);		/*    -> IO ()			   */    eval(primArg(2+IOArity));    aPutElt(3+IOArity,IOArg(1));    IOReturn(nameUnit);} primFun(primIOFreeze) {			/* :: IOArray a b		   */    declArr;				/*    -> IO (Array a b)		   */    aEvalModel(1+IOArity);    aNewCopy(1+IOArity);    aRetForIO();} primFun(primIOArrEq) {		        /* :: IOArray a b                 */    aEvalModel(1);                      /*    -> IOArray a b -> Bool      */    aEvalModel(2);    BoolResult(primArg(1)==primArg(2));} #endif /* IO_MONAD */ /* Retire macros used in the implementation of arrays -------------------- */ #undef aNewSet#undef aNewNil#undef aNewCopy#undef aNewLike#undef aEvalModel#undef aAssocs#undef aSetElt#undef aAddElt#undef aNullElts#undef aCopyNull#undef aMapElts#undef aGetElt#undef aPutElt#undef aElems#undef aBounds#undef aGetBounds#undef updarrRoot#undef aRetForIO /*-------------------------------------------------------------------------*/