"Fossies" - the Fresh Open Source Software archive

Member "dx-4.4.4/src/exec/libdx/array.c" of archive dx-4.4.4.tar.gz:


/***********************************************************************/
/* Open Visualization Data Explorer                                    */
/* (C) Copyright IBM Corp. 1989,1999                                   */
/* ALL RIGHTS RESERVED                                                 */
/* This code licensed under the                                        */
/*    "IBM PUBLIC LICENSE - Open Visualization Data Explorer"          */
/***********************************************************************/

#include <dxconfig.h>

#include <stdarg.h>
#include <string.h>
#include "arrayClass.h"

/*
 * size multipliers for type, category
 */

/* XXX */
int
DXTypeSize(Type t)
{
    switch (t) {
        case TYPE_BYTE:   return sizeof(byte);
        case TYPE_UBYTE:  return sizeof(ubyte);
        case TYPE_SHORT:  return sizeof(short);
        case TYPE_USHORT: return sizeof(ushort);
        case TYPE_INT:    return sizeof(int);
        case TYPE_UINT:   return sizeof(uint);
        case TYPE_HYPER:  return 8;
        case TYPE_FLOAT:  return sizeof(float);
        case TYPE_DOUBLE: return sizeof(double);
        case TYPE_STRING: return sizeof(char);
        default:
	    return DXSetError(ERROR_BAD_PARAMETER, "unknown Type %d", t);
    }
}

int
DXCategorySize(Category category)
{
    switch(category) {
        case CATEGORY_REAL:       return 1;
        case CATEGORY_COMPLEX:    return 2;
        case CATEGORY_QUATERNION: return 4;
        default:
	    return DXSetError(ERROR_BAD_PARAMETER,
			    "unknown Category %d", category);
    }
}


/*
 * new array, shape specified as a vector
 */

Array
_dxf_NewArrayV(Type type, Category category, int rank, int *shape,
	   struct array_class *class)
{
    int i;
    Array a = (Array) _dxf_NewObject((struct object_class *)class);
    if (!a)
	return NULL;

    /* specified info */
    a->type = type;
    a->category = category;
    a->rank = rank;
    if (shape && rank!=0) {
	a->shape = rank>NLSHAPE?
	    (int*)DXAllocate(rank*sizeof(*shape)) : a->lshape;
	if (!a->shape)
	    return NULL;
	for (i=0; i<rank; i++)
	    a->shape[i] = shape[i];
    } else if (rank != 0) {
	DXSetError(ERROR_BAD_PARAMETER,
		 "rank=%d but shape was not specified in DXNewArray", rank);
	return NULL;
    } else
	a->shape = NULL;

    /* size is derived */
    a->size = DXTypeSize(type) * DXCategorySize(category);
    if (!a->size)
	return NULL;
    for (i=0; i<rank; i++)
	a->size *= shape[i];
    if (!a->size)
	DXErrorReturn(ERROR_BAD_PARAMETER, "extent specified as 0 in DXNewArray");
    a->items = 0;
    a->data = NULL;
    DXcreate_lock(&a->inprogress, "in progress");

    return a;
}    


Array
DXNewArrayV(Type type, Category category, int rank, int *shape)
{
    return _dxf_NewArrayV(type, category, rank, shape, &_dxdarray_class);
}


Array
DXNewArray(Type type, Category category, int rank, ...)
{
    int shape[100];
    int i;
    va_list arg;

    ASSERT(rank<100);

    /* collect args */
    va_start(arg,rank);
    for (i=0; i<rank; i++)
	shape[i] = va_arg(arg, int);
    va_end(arg);

    /* call V version */
    return DXNewArrayV(type, category, rank, shape);
}


Array
DXGetArrayInfo(Array a, int *items, Type *type, Category *category,
	     int *rank, int *shape)
{
    int i;

    CHECK(a, CLASS_ARRAY);

    if (items)
	*items = a->items;
    if (type)
	*type = a->type;
    if (category)
	*category = a->category;
    if (rank)
	*rank = a->rank;
    if (shape)
	for (i=0; i<a->rank; i++)
	    shape[i] = a->shape[i];

    return a;
}


Object
_dxfArray_GetType(Array a, Type *t, Category *c, int *rank, int *shape)
{
    int i;

    if (t)
	*t = a->type;
    if (c)
	*c = a->category;
    if (rank)
	*rank = a->rank;
    if (shape)
	for (i=0; i<a->rank; i++)
	    shape[i] = a->shape[i];

    return (Object) a;
}


int DXGetItemSize(Array a)
{
    CHECK(a, CLASS_ARRAY);
    return a->size;
}


Array
DXTypeCheckV(Array a, Type type, Category category, int rank, int *shape)
{
    Type t;
    Category c;
    int i, r, s[100];

    ASSERT(rank<100);

    if (!DXGetArrayInfo(a, NULL, &t, &c, &r, NULL))
	return NULL;
    if (t!=type || c!=category || r!=rank)
	return NULL;

    if (!DXGetArrayInfo(a, NULL, NULL, NULL, NULL, s))
	return NULL;
    if (shape)
	for (i=0; i<rank; i++)
	    if (s[i]!=shape[i])
		return NULL;

    return a;
}


Array
DXTypeCheck(Array a, Type type, Category category, int rank, ...)
{
    int shape[100];
    int i;
    va_list arg;

    ASSERT(rank<100);

    /* collect args */
    va_start(arg,rank);
    for (i=0; i<rank; i++)
	shape[i] = va_arg(arg, int);
    va_end(arg);

    /* call V version */
    return DXTypeCheckV(a, type, category, rank, shape);
}


Pointer
_dxfArray_GetArrayData(Array a)
{
    CHECK(a, CLASS_ARRAY);

    /* always return something */
    if (!a->data)
	DXAllocateArray(a, 0);

    return a->data;
}



Pointer
DXGetArrayDataLocal(Array a)
{
	Pointer data;

	CHECK(a, CLASS_ARRAY);
	data = DXGetArrayData(a);
#if DXD_HAS_LOCAL_MEMORY
	{
		int n;
		Pointer local;
		if (!data)
			return NULL;
		/* XXX - copy, record local reference */
		n = a->size * a->items;
		local = DXAllocateLocal(n);
		if (!local) {
			DXResetError();
			DXWarning("no room for array of %d bytes in local memory", n);
			return data;
		}
		memcpy(local, data, n);
		return local;
	}
#else
	return data;
#endif
}



Array
DXFreeArrayDataLocal(Array a, Pointer data)
{
    CHECK(a, CLASS_ARRAY);
#if DXD_HAS_LOCAL_MEMORY
    if (data!=a->data)
	DXFree(data);
#endif
    return a;
}


Error
_dxfArray_Delete(Array a)
{
    if (a->shape != a->lshape)
	DXFree((Pointer)(a->shape));
    if (a->data != (Pointer)a->ldata)
	DXFree((Pointer)(a->data));
    return OK;
}


Object
_dxfArray_Copy(Array old, enum _dxd_copy copy)
{
    if (copy==COPY_DATA)
	DXErrorReturn(ERROR_BAD_PARAMETER, "copying data is not implemented");
    return (Object)old;
}


Array
DXAddArrayData(Array a, int start, int n, Pointer data)
{
    CHECKARRAY(a, CLASS_ARRAY);   /* only valid for irregular arrays */

    /* expand if necessary */
    /* second test guarantees that we allocate a buffer */
    if (start+n > a->allocated || a->allocated==0) {
	/* allocate 25% extra iff this is a realloc */	
        int alloc = (a->allocated? (start+n)*5/4 : start+n);
	if (!DXAllocateArray(a, alloc))
	    return NULL;
    }

    /* copy the data */
    if (data)
	memcpy((char *)(a->data)+start*a->size, data, n*a->size);

    /* record the new number of items */
    if (start+n > a->items)
	a->items = start+n;

    return a;
}


Array
DXAllocateArray(Array a, int n)
{
    CHECKARRAY(a, CLASS_ARRAY);    /* only valid for irregular arrays */

    /* second test guarantees something will be allocated even if 0 length */
    if (n > a->allocated || a->allocated==0) {
	int bytes = n * a->size;
	Pointer d;
	if (bytes > sizeof(a->ldata)) {
	    if (a->data == (Pointer)a->ldata) {
		d = DXAllocate(bytes);
		if (!d)
		    return NULL;
		memcpy(d, a->ldata, sizeof(a->ldata));
	    } else {
		d = DXReAllocate(a->data, bytes);
		if (!d)
		    return NULL;
	    }
	    a->data = d;
	} else
	    a->data = (Pointer)a->ldata;
	a->allocated = n;
    }
    return a;
}


Array
DXTrim(Array a)
{
#if 0  /* EndField() calls this on all arrays regardless of type */
    CHECKARRAY(a, CLASS_ARRAY);   /* only valid for irregular arrays */
#else
    CHECK(a, CLASS_ARRAY);
#endif

    if (a->allocated > a->items) {
	if (a->data != (Pointer)a->ldata) {
	    Pointer d = DXReAllocate(a->data, a->items*a->size);
	    if (!d)   /* realloc shouldn't fail, but just in case ... */
		DXErrorReturn(ERROR_UNEXPECTED, "re-alloc failed!");
	    a->data = d;
	}
	a->allocated = a->items;
    }				   
    return a;
}

/* this might be a useful function to add sometime */
Array
DXTrimItems(Array a, int nitems)
{
    CHECKARRAY(a, CLASS_ARRAY);   /* only valid for irregular arrays */

    /* reset the item count only if smaller, 
     * and release any extra space in either case.
     */
    if (a->items > nitems)
	a->items = nitems;

    return DXTrim(a);
}

Pointer
DXGetArrayData(Array a)
{
    return _dxfGetArrayData(a);
}

ArrayHandle
DXCreateArrayHandle(Array array)
{
    ArrayHandle handle = NULL;
    Array *terms = NULL;

    handle = (ArrayHandle)DXAllocateZero(sizeof(struct arrayHandle));
    if (! handle)
	goto error;
    
    handle->class    = DXGetArrayClass(array);
    handle->itemSize = DXGetItemSize(array);

    DXGetArrayInfo(array, &handle->nElements,
		&handle->type, &handle->cat, NULL, NULL);

    handle->nValues = handle->itemSize / DXTypeSize(handle->type);

    if (array->data)
    {
	handle->data = array->data;
    }
    else if (DXQueryConstantArray(array, NULL, NULL))
    {
	handle->cdata = DXAllocate(handle->itemSize);
	if (! handle->cdata)
	    goto error;

	DXQueryConstantArray(array, NULL, handle->cdata);
    }
    else
	switch(handle->class)
	{
	    case CLASS_REGULARARRAY:
		handle->origin = DXAllocate(handle->itemSize);
		handle->delta  = DXAllocate(handle->itemSize);
		if (! handle->origin || ! handle->delta)
		    goto error;
		DXGetRegularArrayInfo((RegularArray)array, NULL,
					handle->origin, handle->delta);
	    break;
	    
	    case CLASS_PATHARRAY:
	    break;

	    case CLASS_PRODUCTARRAY:
	    {
		int i;

		DXGetProductArrayInfo((ProductArray)array,
						&handle->nTerms, NULL);

		terms = (Array *)DXAllocate(handle->nTerms * sizeof(Array));

		handle->scratch1 = (int *)DXAllocate(handle->itemSize);
		handle->scratch2 = (int *)DXAllocate(handle->itemSize);
		
		handle->strides = (int *)
			DXAllocateZero(handle->nTerms * sizeof(int));
		handle->counts = (int *)
			DXAllocateZero(handle->nTerms * sizeof(int));
		handle->scratch = (Pointer *)
			DXAllocateZero(handle->nTerms * sizeof(Pointer));
		handle->handles = (ArrayHandle *)
			DXAllocateZero(handle->nTerms * sizeof(ArrayHandle));
		handle->indices = (int *)
			DXAllocateZero(handle->nTerms * sizeof(int));
		
		if (! handle->strides || ! handle->counts  ||
		    ! terms           || ! handle->indices ||
		    ! handle->scratch1    || ! handle->scratch2    ||
		    ! handle->scratch || ! handle->handles) goto error;

		DXGetProductArrayInfo((ProductArray)array, NULL, terms);

		for (i = 0; i < handle->nTerms; i++)
		{
		    handle->handles[i] = DXCreateArrayHandle(terms[i]);
		    if (NULL == handle->handles[i])
			goto error;
		    
		    handle->scratch[i]=DXAllocate(DXGetItemSize(terms[i]));
		    if (NULL == handle->scratch)
			goto error;
		    
		    DXGetArrayInfo(terms[i], &handle->counts[i],
						NULL, NULL, NULL, NULL);
		}

		DXFree((Pointer)terms);

		handle->strides[handle->nTerms-1] = 1;
		for (i = handle->nTerms-2; i >= 0; i--)
		    handle->strides[i] = 
			    handle->strides[i+1]*handle->counts[i+1];
		
	    }
	    break;

	    case CLASS_MESHARRAY:
	    {
		int i;

		DXGetMeshArrayInfo((MeshArray)array, &handle->nTerms, NULL);

		terms = (Array *)DXAllocate(handle->nTerms * sizeof(Array));

		handle->scratch1 = (int *)DXAllocate(handle->itemSize);
		handle->scratch2 = (int *)DXAllocate(handle->itemSize);
		
		handle->strides = (int *)
			DXAllocateZero(handle->nTerms * sizeof(int));
		handle->counts = (int *)
			DXAllocateZero(handle->nTerms * sizeof(int));
		handle->scratch = (Pointer *)
			DXAllocateZero(handle->nTerms * sizeof(Pointer));
		handle->handles = (ArrayHandle *)
			DXAllocateZero(handle->nTerms * sizeof(ArrayHandle));
		handle->indices = (int *)
			DXAllocateZero(handle->nTerms * sizeof(int));
		
		if (! handle->strides || ! handle->counts || ! terms ||
		    ! handle->scratch1    || ! handle->scratch2   ||
		    ! handle->indices ||
		    ! handle->scratch || ! handle->handles) goto error;

		DXGetMeshArrayInfo((MeshArray)array, NULL, terms);
		
		for (i = 0; i < handle->nTerms; i++)
		{
		    handle->handles[i] = DXCreateArrayHandle(terms[i]);
		    if (NULL == handle->handles[i])
			goto error;
		    
		    handle->scratch[i]=DXAllocate(DXGetItemSize(terms[i]));
		    if (NULL == handle->scratch)
			goto error;
		    
		    DXGetArrayInfo(terms[i], &handle->counts[i],
						NULL, NULL, NULL, NULL);
		    handle->counts[i] += 1;
		}

		DXFree((Pointer)terms);

		handle->strides[handle->nTerms-1] = 1;
		for (i = handle->nTerms-2; i >= 0; i--)
		    handle->strides[i] = 
			    handle->strides[i+1]*(handle->counts[i+1]-1);
		
	    }
	    break;

	    default:
		handle->data = DXGetArrayData(array);
		break;
	}
    
    return handle;

error:
    DXFreeArrayHandle(handle);
    DXFree((Pointer)terms);
    return NULL;
}

Error
DXFreeArrayHandle(ArrayHandle handle)
{
    int i;

    if (handle)
    {
	for (i = 0; i < handle->nTerms; i++)
	{
	    DXFreeArrayHandle(handle->handles[i]);
	    DXFree(handle->scratch[i]);
	}

	DXFree((Pointer)handle->strides);
	DXFree((Pointer)handle->counts);
	DXFree((Pointer)handle->handles);
	DXFree((Pointer)handle->indices);
	DXFree((Pointer)handle->scratch);
	DXFree((Pointer)handle->scratch1);
	DXFree((Pointer)handle->scratch2);
	DXFree((Pointer)handle->cdata);
	DXFree((Pointer)handle->origin);
	DXFree((Pointer)handle->delta);
	DXFree((Pointer)handle);
    }

    return OK;
}

#define REGULAR_GETELEMENT(type)					\
{									\
    type *dst = (type *)scratch;					\
    type *org = (type *)handle->origin;					\
    type *del = (type *)handle->delta;					\
    int i;								\
    for (i = 0; i < handle->nValues; i++)				\
	*dst++ = *org++ + offset*(*del++);				\
}	

#define MESHARRAY_ADDTERM(type)						\
{									\
    type *dst = (type *)scratch;					\
    type *right;							\
    int i, j;								\
									\
    for (i = 1; i < handle->nTerms; i++)				\
    {									\
	right = (type *)DXGetArrayEntry(handle->handles[i],		\
		    handle->indices[i], handle->scratch[i]);		\
	for (j = 0; j < handle->nValues; j++)				\
	    dst[j] += right[j];						\
    }									\
}

static void
_dxfTermIndices(ArrayHandle handle, int offset, int *indices)
{
    int i;
    for (i = 0; i < handle->nTerms-1; i++)
    {
	indices[i] = offset / handle->strides[i];
	offset = offset % handle->strides[i];
    }

    indices[handle->nTerms-1] = offset;
}

Pointer
DXCalculateArrayEntry(ArrayHandle handle, int offset, Pointer scratch)
{
    if (handle->data)
        return (Pointer)(((char *)handle->data) + offset*handle->itemSize);
    else if (handle->cdata)
	return handle->cdata;
    else
    {
	switch (handle->class)
	{
	    case CLASS_REGULARARRAY:
		switch(handle->type)
		{
		    case TYPE_DOUBLE: REGULAR_GETELEMENT(double);  break;
		    case TYPE_FLOAT:  REGULAR_GETELEMENT(float);   break;
		    case TYPE_INT:    REGULAR_GETELEMENT(int);     break;
		    case TYPE_UINT:   REGULAR_GETELEMENT(uint);    break;
		    case TYPE_SHORT:  REGULAR_GETELEMENT(short);   break;
		    case TYPE_USHORT: REGULAR_GETELEMENT(ushort);  break;
		    case TYPE_BYTE:   REGULAR_GETELEMENT(byte);    break;
		    case TYPE_UBYTE:  REGULAR_GETELEMENT(ubyte);   break;
		    case TYPE_HYPER: case TYPE_STRING: break;
		}
	    break;
	    
	    case CLASS_PATHARRAY:
		((int *)scratch)[0] = offset;
		((int *)scratch)[1] = offset+1;
	    break;

	    case CLASS_MESHARRAY:
	    {
		_dxfTermIndices(handle, offset, handle->indices);

		if (handle->nTerms == 1)
		{
		    memcpy(scratch, DXGetArrayEntry(handle->handles[0],
			handle->indices[0], handle->scratch[0]),
			handle->handles[0]->itemSize);
		}
		else
		{
		    int *left, *right, *dst, *ptr, i, j, k, nItems;

		    memcpy(handle->scratch1, DXGetArrayEntry(handle->handles[0],
			handle->indices[0], handle->scratch[0]),
			handle->handles[0]->itemSize);

		    nItems = handle->handles[0]->nValues;
		    left = handle->scratch1; dst = handle->scratch2;
		    for (i = 1; i < handle->nTerms; i++)
		    {
			if (i == handle->nTerms-1)
			    dst = (int *)scratch;

			right = (int *)DXGetArrayEntry(handle->handles[i],
					handle->indices[i], handle->scratch[i]);

			ptr = dst;
			for (j = 0; j < nItems; j++)
			{
			    int tmp = left[j] * handle->counts[i];

			    for (k = 0; k < handle->handles[i]->nValues; k++)
				*ptr++ = tmp + right[k];
			}

			nItems *= handle->handles[i]->nValues;

			ptr = dst;
			dst = left;
			left = ptr;
		    }
		}
	    }
	    break;
		    
	    case CLASS_PRODUCTARRAY:
	    {
		_dxfTermIndices(handle, offset, handle->indices);

		if (handle->nTerms == 1)
		{
		    memcpy(scratch, DXGetArrayEntry(handle->handles[0],
			handle->indices[0], handle->scratch[0]),
			handle->handles[0]->itemSize);
		}
		else
		{
		    memcpy(scratch, DXGetArrayEntry(handle->handles[0],
			handle->indices[0], handle->scratch[0]),
			handle->handles[0]->itemSize);
		    
		    switch(handle->type)
		    {
			case TYPE_DOUBLE: MESHARRAY_ADDTERM(double);  break;
			case TYPE_FLOAT:  MESHARRAY_ADDTERM(float);   break;
			case TYPE_INT:    MESHARRAY_ADDTERM(int);     break;
			case TYPE_UINT:   MESHARRAY_ADDTERM(uint);    break;
			case TYPE_SHORT:  MESHARRAY_ADDTERM(short);   break;
			case TYPE_USHORT: MESHARRAY_ADDTERM(ushort);  break;
			case TYPE_BYTE:   MESHARRAY_ADDTERM(byte);    break;
			case TYPE_UBYTE:  MESHARRAY_ADDTERM(ubyte);   break;
		    case TYPE_HYPER: case TYPE_STRING: break;
		    }
		}
	    }
	    break;
	    default: /* All other TYPEs and CLASSes  */
	    break;
	}

    }
    return scratch;

}


/* make string arrays */
Array
DXMakeStringList(int n, char *s, ...)
{
    int i;
    char **c;
    va_list arg;
    Array a;

    if (n == 0)
	return NULL;

    if (n < 0) {
	DXSetError(ERROR_BAD_PARAMETER, "#10020", "stringlist count");
	return NULL;
    }

    c = (char **)DXAllocate(n * sizeof(char *));
    if (!c)
	return NULL;

    c[0] = s;

    /* collect args */
    va_start(arg,s);
    for (i=1; i<n; i++)
	c[i] = va_arg(arg, char *);
    va_end(arg);

    /* call V version */
    a = DXMakeStringListV(n, c);

    DXFree(c);
    return a;
}

/* count plus string list */
Array
DXMakeStringListV(int n, char **s)
{
    Array a;
    int i;
    int count, l, maxlen = 0;
    char *p;

    if (n == 0 || !s)
	return NULL;

    if (n < 0) {
	DXSetError(ERROR_BAD_PARAMETER, "#10020", "stringlist count");
	return NULL;
    }

    for (count=0; count < n; count++) {
	if (!s[count])
	    continue;

	if ((l=strlen(s[count])) > maxlen)
	    maxlen = l;
    }
    
    a = DXNewArray(TYPE_STRING, CATEGORY_REAL, 1, maxlen+1);
    if (!a)
	return NULL;

    if (!DXAddArrayData(a, 0, n, NULL))
	goto error;

    p = (char *)DXGetArrayData(a);
    if (!p)
	goto error;

    for (i=0; i<n; i++, p += maxlen+1)
	s[i] ? strncpy(p, s[i], maxlen+1) : memset(p, '\0', maxlen+1);

    return a;

  error:
    DXDelete((Object)a);
    return NULL;
}

static Array 
packit(int n, Type t, Category c, int rank, int *shape, Pointer p)
{
    Array a = NULL;

    a = DXNewArrayV(t, c, rank, shape);
    if (!a)
	return NULL;

    if (!DXAddArrayData(a, 0, n, p)) {
	DXDelete((Object)a);
	return NULL;
    }

    return a;
}

Array DXMakeInteger(int n)
{
    return packit(1, TYPE_INT, CATEGORY_REAL, 0, NULL, (Pointer)&n);
}

Array DXMakeFloat(float f)
{
    return packit(1, TYPE_FLOAT, CATEGORY_REAL, 0, NULL, (Pointer)&f);
}