/* $Header$ */
/*
* Copyright © 1988-2004 Keith Packard and Bart Massey.
* All Rights Reserved. See the file COPYING in this directory
* for licensing information.
*/
#include "nickle.h"
#include "gram.h"
int
ArrayInit (void)
{
return 1;
}
static int
ArrayNextI (Array *a, int i)
{
int step = 1;
int sub_size = 1;
int d;
int dim, lim;
int j = i + 1;
for (d = 0; d < a->ndim - 1; d++)
{
dim = ArrayDims(a)[d];
lim = ArrayLimits(a)[d];
if (dim != lim && j % dim == lim)
step += (dim - lim) * sub_size;
sub_size *= ArrayDims(a)[d];
j /= dim;
}
return i + step;
}
static int
ArrayLimit (Value av)
{
Array *a = &av->array;
int *limits = ArrayLimits(a);
int *dims = ArrayDims(a);
int d;
int limit;
limit = limits[a->ndim-1];
for (d = 0; d < a->ndim - 1; d++)
limit *= dims[d];
return limit;
}
static Value
ArrayEqual (Value av, Value bv, int expandOk)
{
Array *a = &av->array, *b = &bv->array;
int ai, bi;
int alimit = ArrayLimit (av), blimit = ArrayLimit (bv);
int d;
if (a->ndim != b->ndim)
return FalseVal;
for (d = 0; d < a->ndim; d++)
if (ArrayLimits(a)[d] != ArrayLimits(b)[d])
return FalseVal;
ai = 0; bi = 0;
while (ai < alimit && bi < blimit)
{
if (False (Equal ( ArrayValue (a, ai),
ArrayValue (b, bi))))
return FalseVal;
ai = ArrayNextI (a, ai);
bi = ArrayNextI (b, bi);
}
return TrueVal;
}
static Bool
ArrayPrint (Value f, Value av, char format, int base, int width, int prec, int fill)
{
ENTER ();
Array *a = &av->array;
int *limits = ArrayLimits(a);
int *dims = ArrayDims(a);
int i, j, k;
int ndone;
int limit = ArrayLimit (av);
Bool ret = True;
Bool pretty = format == 'v' || format == 'g';
if (pretty)
{
FilePuts (f, "(");
if (!TypePoly (ArrayType(a)))
{
FilePutBaseType (f, ArrayType (a), False);
FilePuts (f, " ");
}
FilePuts (f, "[");
for (i = a->ndim - 1; i >= 0; i--)
{
if (a->resizable)
FilePuts (f, "...");
else
FilePutInt (f, limits[i]);
if (i)
FilePuts (f, ", ");
}
FilePuts (f, "]");
if (!TypePoly (ArrayType(a)))
{
FilePutSubscriptType (f, ArrayType (a), False);
}
FilePuts (f, ") ");
for (i = 0; i < a->ndim; i++)
FileOutput (f, '{');
}
i = 0;
while (i < limit)
{
if (!Print (f, ArrayValueGet (a, i), format, base, width, prec, fill))
{
ret = False;
break;
}
i = ArrayNextI (a, i);
if (i < limit)
{
ndone = 0;
if (pretty)
{
j = i;
k = 0;
while (k < a->ndim - 1 && j % dims[k] == 0)
{
ndone++;
j = j / dims[k];
k++;
}
for (k = 0; k < ndone; k++)
FileOutput (f, '}');
FileOutput (f, ',');
}
FileOutput (f, ' ');
if (pretty)
for (k = 0; k < ndone; k++)
FileOutput (f, '{');
}
}
if (pretty)
for (i = 0; i < a->ndim; i++)
FileOutput (f, '}');
EXIT ();
return True;
}
#define hrot(i) (((i) << 1) | ((i) >> (sizeof (HashValue) * 8 - 1)))
static HashValue
ArrayHash (Value av)
{
Array *a = &av->array;
int i;
HashValue h = 0;
int limit = ArrayLimit (av);
for (i = 0; i < limit; i = ArrayNextI (a, i))
h = hrot(h) ^ ValueInt (ValueHash (ArrayValueGet (a, i)));
return h;
}
static void
ArrayMark (void *object)
{
Array *array = object;
if (array->resizable)
MemReference (array->u.resize);
else
MemReference (array->u.fix);
}
ValueRep ArrayRep = {
{ ArrayMark, 0, "ArrayRep" },
rep_array,
{
0,
0,
0,
0,
0,
0,
0,
ArrayEqual,
0,
0,
},
{
0,
},
0,
0,
ArrayPrint,
0,
ArrayHash,
};
static void
BoxVectorMark (void *object)
{
BoxVectorPtr bv = object;
int i;
BoxPtr *boxes = BoxVectorBoxes (bv);
MemReference (bv->type);
for (i = 0; i < bv->nvalues; i++)
MemReference (boxes[i]);
}
DataType BoxVectorType = { BoxVectorMark, 0, "BoxVectorType" };
static BoxVectorPtr
NewBoxVector (int nvalues, TypePtr type)
{
ENTER ();
BoxVectorPtr bv = ALLOCATE (&BoxVectorType,
sizeof (BoxVector) +
nvalues * sizeof (BoxPtr));
int i;
BoxPtr *boxes = BoxVectorBoxes (bv);
bv->nvalues = nvalues;
bv->type = type;
for (i = 0; i < nvalues; i++)
boxes[i] = 0;
RETURN (bv);
}
static void
FillBoxVector (BoxVectorPtr bv, BoxPtr *boxes, int n)
{
ENTER();
while (n--)
*boxes++ = NewBox (False, False, 1, bv->type);
EXIT ();
}
Value
NewArray (Bool constant, Bool resizable, TypePtr type, int ndim, int *dims)
{
ENTER ();
Value ret;
int ents;
int dim;
if (ndim)
{
ents = 1;
for (dim = 0; dim < ndim; dim++)
ents *= dims[dim];
}
else
ents = 0;
ret = ALLOCATE (&ArrayRep.data, sizeof (Array) + (ndim * 2) * sizeof (int));
ret->array.ndim = ndim;
for (dim = 0; dim < ndim; dim++)
ArrayLimits(&ret->array)[dim] = ArrayDims(&ret->array)[dim] = dims[dim];
ret->array.resizable = resizable;
if (resizable)
{
ret->array.u.resize = 0;
ret->array.u.resize = NewBoxVector (ents, type);
FillBoxVector (ret->array.u.resize,
BoxVectorBoxes (ret->array.u.resize),
ents);
}
else
{
ret->array.u.fix = 0;
ret->array.u.fix = NewBox (constant, True, ents, type);
}
RETURN (ret);
}
void
ArrayResize (Value av, int dim, int size)
{
ENTER ();
Array *a = &av->array;
int *dims = ArrayDims(a);
int *limits = ArrayLimits(a);
int odim = dims[dim];
int ents;
int d;
int stride; /* size of each chunk */
int nchunk; /* number of chunks */
int c;
int unit;
int good;
BoxPtr *b;
assert (av->array.resizable);
if (size == limits[dim])
return;
ents = a->u.resize->nvalues;
stride = 1;
for (d = 0; d <= dim; d++)
stride *= dims[d];
if (stride)
nchunk = ents / stride;
else
nchunk = 1;
/*
* Resize if necessary.
*/
if (dims[dim] < size || dims[dim] > size * 2)
{
int ostride = stride;
int nstride = stride;
BoxVectorPtr nboxes;
BoxPtr *o, *n;
if (odim < size)
{
/* was empty */
if (odim == 0)
{
odim = 1;
ents = 1;
nstride = 1;
for (d = 0; d < a->ndim; d++)
dims[d] = 1;
}
/* bigger */
while (odim < size)
{
odim <<= 1;
ents <<= 1;
nstride <<= 1;
}
good = ostride;
}
else if (size > 0)
{
/* smaller */
while (odim > size * 2)
{
odim >>= 1;
ents >>= 1;
nstride >>= 1;
}
good = nstride;
}
else
{
/* empty */
ents = 0;
nstride = 0;
odim = 0;
size = 0;
nchunk = 0;
for (d = 0; d < a->ndim; d++)
{
dims[d] = 0;
limits[d] = 0;
}
good = 0;
}
nboxes = NewBoxVector (ents, a->u.resize->type);
o = BoxVectorBoxes (a->u.resize);
n = BoxVectorBoxes (nboxes);
for (c = 0; c < nchunk; c++)
{
memcpy (n, o, good * sizeof (BoxPtr));
if (nstride > good)
FillBoxVector (nboxes, n + good, nstride - good);
o += ostride;
n += nstride;
}
a->u.resize = nboxes;
dims[dim] = odim;
limits[dim] = size;
stride = nstride;
}
/*
* When shrinking the array, replace the
* now discarded entries with new boxes.
* This leaves growing trivial; all unused
* elements of the array have clean boxes
*/
if (limits[dim] > size)
{
b = BoxVectorBoxes (a->u.resize);
unit = stride / dims[dim];
good = size * unit;
for (c = 0; c < nchunk; c++)
{
FillBoxVector (a->u.resize,
b + good,
stride - good);
b += stride;
}
}
limits[dim] = size;
EXIT ();
}
void
ArraySetDimensions (Value av, int *dims)
{
Array *a = &av->array;
int i;
for (i = 0; i < a->ndim; i++)
ArrayResize (av, i, dims[i]);
}
Type *
BuildArrayType (Type *subtype, int ndim, ...)
{
ENTER ();
Expr *dims = 0;
int i;
int dim;
va_list ap;
Type *type;
Value dimArray;
dimArray = NewArray (True, False, typePrim[rep_integer], 1, &ndim);
va_start (ap, ndim);
for (i = 0; i < ndim; i++)
{
dim = va_arg (ap, int);
ArrayValueSet(&dimArray->array, i, NewInt (dim));
dims = NewExprTree (COMMA, NewExprConst (TEN_FLOAT, NewInt (dim)),
dims);
}
va_end (ap);
type = NewTypeArray (subtype, dims, False);
/*
* Create an array to hold the dimension information and
* fill it in
*/
type->array.storage = DimStorageGlobal;
type->array.u.global = NewBox (True, False, 1, typeArrayInt);
BoxValueSet (type->array.u.global, 0, dimArray);
RETURN (type);
}
syntax highlighted by Code2HTML, v. 0.9.1