| /* | |
| * AIF routines that operate specifically on arrays. | |
| * | |
| * Copyright (c) 1996-2002 by Guardsoft Pty Ltd. | |
| * | |
| * All rights reserved. This program and the accompanying materials | |
| * are made available under the terms of the Eclipse Public License v1.0 | |
| * which accompanies this distribution, and is available at | |
| * http://www.eclipse.org/legal/epl-v10.html | |
| * | |
| */ | |
| #ifdef HAVE_CONFIG_H | |
| #include <config.h> | |
| #endif /* HAVE_CONFIG_H */ | |
| #include <stdio.h> | |
| #include <memory.h> | |
| #include <string.h> | |
| #include "aif.h" | |
| #include "aiferr.h" | |
| #include "aifint.h" | |
| /* | |
| * Find the rank of the array. | |
| */ | |
| int | |
| AIFArrayRank(AIF *a) | |
| { | |
| if ( a == (AIF *)NULL ) | |
| { | |
| SetAIFError(AIFERR_BADARG, NULL); | |
| return -1; | |
| } | |
| if ( AIFType(a) != AIF_ARRAY ) | |
| { | |
| SetAIFError(AIFERR_TYPE, NULL); | |
| return -1; | |
| } | |
| return FDSArrayRank(AIF_FORMAT(a)); | |
| } | |
| /* | |
| * Find the total number of elements in an array. This | |
| * will count all the elements in a nested array. | |
| */ | |
| int | |
| AIFArraySize(AIF *a) | |
| { | |
| if ( a == (AIF *)NULL ) | |
| { | |
| SetAIFError(AIFERR_BADARG, NULL); | |
| return -1; | |
| } | |
| if ( AIFType(a) != AIF_ARRAY ) | |
| { | |
| SetAIFError(AIFERR_TYPE, NULL); | |
| return -1; | |
| } | |
| return FDSArraySize(AIF_FORMAT(a)); | |
| } | |
| /* | |
| * Parse array type descriptor and extract the minimum index and | |
| * number of elements for each dimension. | |
| */ | |
| int | |
| AIFArrayBounds(AIF *a, int rank, int **min, int **size) | |
| { | |
| if ( a == (AIF *)NULL || min == (int **)NULL || size == (int **)NULL ) | |
| { | |
| SetAIFError(AIFERR_BADARG, NULL); | |
| return -1; | |
| } | |
| if ( AIFType(a) != AIF_ARRAY ) | |
| { | |
| SetAIFError(AIFERR_TYPE, NULL); | |
| return -1; | |
| } | |
| FDSArrayBounds(AIF_FORMAT(a), rank, min, size); | |
| return 0; | |
| } | |
| /* | |
| * Extract info about an array. Returns the index type of the | |
| * first dimension (assumes all dimensions are the same type), | |
| * the element type of the array, and the number of dimensions | |
| * of the array. | |
| */ | |
| int | |
| AIFArrayInfo(AIF *a, int *rank, char **type, int *idx) | |
| { | |
| char * itype; | |
| if ( a == (AIF *)NULL || rank == (int *)NULL || type == (char **)NULL ) | |
| { | |
| SetAIFError(AIFERR_BADARG, NULL); | |
| return -1; | |
| } | |
| if ( AIFType(a) != AIF_ARRAY ) | |
| { | |
| SetAIFError(AIFERR_TYPE, NULL); | |
| return -1; | |
| } | |
| FDSArrayInfo(AIF_FORMAT(a), rank, (char **)type, &itype); | |
| if ( idx != (int *)NULL ) | |
| *idx = FDSType(itype); | |
| return 0; | |
| } | |
| /* A post-processing routine that is called by AIFArraySlice(). | |
| * This routine checks the fds and the data of an AIF object, and it creates | |
| * a new data for the object 'rdata' which is consistent. The function checks | |
| * all of the AIF_PTR_REFERENCEs and it changes the first occurence of a | |
| * particular AIF_PTR_REFERENCE to an appropriate AIF_PTR_NAME based on the | |
| * 'res' array. It modifies the 'fds' and the 'data'. 'rdata' will also | |
| * be advanced to the end. | |
| * | |
| * The routine gets 4 parameters: | |
| * fds - the fds of an AIF object | |
| * data - the original data of an AIF object | |
| * rdata - the new data for the object | |
| * res - a 'char *' array that stores the references | |
| */ | |
| int | |
| _aif_array_slice_post(char **fds, char **data, char **rdata, char **res) | |
| { | |
| int datalen; | |
| int index; | |
| char * fmt; | |
| char ** d; | |
| _fds_resolve(fds); | |
| switch ( FDSType(*fds) ) | |
| { | |
| case AIF_REFERENCE: | |
| fmt = _fds_lookup(fds); | |
| _aif_array_slice_post(&fmt, data, rdata, res); | |
| return 0; | |
| case AIF_ARRAY: | |
| { | |
| AIFIndex * ix; | |
| int i; | |
| char * fbase; | |
| ix = FDSArrayIndexInit(*fds); | |
| _fds_advance(fds); | |
| for ( i = 0; i < ix->i_nel; i++ ) | |
| { | |
| fbase = ix->i_btype; | |
| _aif_array_slice_post(&fbase, data, rdata, res); | |
| } | |
| return 0; | |
| } | |
| case AIF_AGGREGATE: | |
| (*fds)++; | |
| _fds_skip_typename(fds); | |
| while ( **fds != FDS_AGGREGATE_ACCESS_SEP ) | |
| { | |
| *fds = strchr(*fds, FDS_AGGREGATE_FIELD_NAME_END) + 1; | |
| _aif_array_slice_post(fds, data, rdata, res); | |
| if ( **fds == FDS_AGGREGATE_FIELD_SEP ) | |
| (*fds)++; | |
| } | |
| *fds = strchr(*fds, FDS_AGGREGATE_END) + 1; | |
| return 0; | |
| case AIF_POINTER: | |
| (*fds)++; | |
| switch ( (int)**data ) | |
| { | |
| case AIF_PTR_NIL: | |
| **rdata = **data; | |
| (*data)++; | |
| (*rdata)++; | |
| _fds_advance(fds); | |
| return 0; | |
| case AIF_PTR_NORMAL: | |
| **rdata = **data; | |
| (*data)++; | |
| (*rdata)++; | |
| _aif_array_slice_post(fds, data, rdata, res); | |
| return 0; | |
| case AIF_PTR_NAME: | |
| memcpy(*rdata, *data, 5); /* 1 + 4 (ptr name) */ | |
| (*data) += 5; | |
| (*rdata) += 5; | |
| _aif_array_slice_post(fds, data, rdata, res); | |
| return 0; | |
| case AIF_PTR_REFERENCE: | |
| d = data; | |
| _ptrname_to_int(d, &index); | |
| if ( res[index] != NULL ) | |
| { | |
| *(*rdata)++ = AIF_PTR_NAME; | |
| _int_to_ptrname(index, *rdata); | |
| *rdata += 4; | |
| datalen = FDSDataSize(*fds, res[index]); | |
| memcpy(*rdata, res[index], datalen); | |
| (*rdata) += datalen; | |
| (*data) += 5; | |
| _fds_advance(fds); | |
| res[index]=NULL; | |
| } | |
| else | |
| { | |
| memcpy(*rdata, *data, 5); | |
| (*data) += 5; | |
| (*rdata) += 5; | |
| } | |
| return 0; | |
| } | |
| default: | |
| datalen = FDSDataSize(*fds, *data); | |
| _fds_advance(fds); | |
| memcpy(*rdata, *data, datalen); | |
| (*data) += datalen; | |
| (*rdata) += datalen; | |
| return 0; | |
| } | |
| } | |
| /* | |
| * A pre-processing routine that is called by AIFArraySlice(). | |
| * This routine checks the fds and the data, and it saves all of the | |
| * references that are pointed by AIF_PTR_NAMEs into 'res'. | |
| * | |
| * The function gets 3 parameters, the fds and the data of an AIF object | |
| * that is going to be scanned, and a 'char *' array (res) to store | |
| * the results. All of the elements of the 'res' array must be initialized | |
| * to NULL. It modifies 'fds' and 'data'. | |
| */ | |
| int | |
| _aif_array_slice_pre(char **fds, char **data, char **res) | |
| { | |
| int datalen; | |
| char * fmt; | |
| _fds_resolve(fds); | |
| switch ( FDSType(*fds) ) | |
| { | |
| case AIF_REFERENCE: | |
| fmt = _fds_lookup(fds); | |
| _aif_array_slice_pre(&fmt, data, res); | |
| return 0; | |
| case AIF_ARRAY: | |
| { | |
| AIFIndex * ix; | |
| int i; | |
| char * fbase; | |
| ix = FDSArrayIndexInit(*fds); | |
| _fds_advance(fds); | |
| for ( i = 0; i < ix->i_nel; i++ ) | |
| { | |
| fbase = ix->i_btype; | |
| _aif_array_slice_pre(&fbase, data, res); | |
| } | |
| return 0; | |
| } | |
| case AIF_AGGREGATE: | |
| (*fds)++; | |
| _fds_skip_typename(fds); | |
| while ( **fds != FDS_AGGREGATE_ACCESS_SEP ) | |
| { | |
| *fds = strchr(*fds, FDS_AGGREGATE_FIELD_NAME_END) + 1; | |
| _aif_array_slice_pre(fds, data, res); | |
| if ( **fds == FDS_AGGREGATE_FIELD_SEP ) | |
| (*fds)++; | |
| } | |
| *fds = strchr(*fds, FDS_AGGREGATE_END) + 1; | |
| return 0; | |
| case AIF_POINTER: | |
| { | |
| int index; | |
| (*fds)++; | |
| switch ( (int)**data ) | |
| { | |
| case AIF_PTR_NIL: | |
| (*data)++; | |
| _fds_advance(fds); | |
| return 0; | |
| case AIF_PTR_NORMAL: | |
| (*data)++; | |
| _aif_array_slice_pre(fds, data, res); | |
| return 0; | |
| case AIF_PTR_NAME: | |
| (*data)++; | |
| _ptrname_to_int(data, &index); | |
| res[index] = *data; | |
| _aif_array_slice_pre(fds, data, res); | |
| return 0; | |
| case AIF_PTR_REFERENCE: | |
| (*data) += 5; | |
| _fds_advance(fds); | |
| return 0; | |
| } | |
| } | |
| default: | |
| datalen = FDSDataSize(*fds, *data); | |
| _fds_advance(fds); | |
| (*data) += datalen; | |
| return 0; | |
| } | |
| } | |
| /* | |
| * Evaluate array slice. | |
| * XXX: TOFIX | |
| */ | |
| AIF * | |
| AIFArraySlice(AIF *a, int rank, int *mn, int *sz) | |
| { | |
| int i; | |
| int nrank = 0; | |
| int * rankp; | |
| int rl; | |
| char * rf; | |
| char * fds; | |
| char * r; | |
| AIF * ra; | |
| AIFIndex * ix1; | |
| AIFIndex * ix2 = (AIFIndex *)NULL; | |
| char * res_array[MAX_VALUES_SEEN+1] = {NULL}; | |
| if ( a == (AIF *)NULL || mn == (int *)NULL || sz == (int *)NULL ) | |
| { | |
| SetAIFError(AIFERR_BADARG, NULL); | |
| return (AIF *)NULL; | |
| } | |
| if ( AIFType(a) != AIF_ARRAY ) | |
| { | |
| SetAIFError(AIFERR_TYPE, NULL); | |
| return (AIF *)NULL; | |
| } | |
| ix1 = FDSArrayIndexInit(AIF_FORMAT(a)); | |
| if ( rank != ix1->i_rank ) | |
| { | |
| SetAIFError(AIFERR_INDEX, NULL); | |
| AIFArrayIndexFree(ix1); | |
| return (AIF *)NULL; | |
| } | |
| /* | |
| ** Create rankp array used by AIFIndexInRange(). | |
| */ | |
| rankp = (int *)_aif_alloc(rank * sizeof(int *)); | |
| /* | |
| ** Construct a new fds. | |
| */ | |
| rl = strlen(AIF_FORMAT(a)) + 1; | |
| rf = fds = (char *)_aif_alloc(rl); | |
| /* | |
| ** Calculate nrank, the number of dimensions of the (new) array. | |
| ** This corresponds to the number of elements where sz > 0 | |
| ** (i.e. where an empty slice has not been specified.) | |
| ** When sz == -1 we slice the whole dimension. | |
| */ | |
| for ( i = 0 ; i < rank ; i++ ) | |
| { | |
| if ( sz[i] < 0 ) | |
| { | |
| mn[i] = ix1->i_min[i]; | |
| sz[i] = ix1->i_size[i]; | |
| } | |
| else if | |
| ( | |
| mn[i] < ix1->i_min[i] | |
| || | |
| mn[i] >= ix1->i_min[i] + ix1->i_size[i] | |
| || | |
| sz[i] > ix1->i_size[i] | |
| ) | |
| { | |
| SetAIFError(AIFERR_INDEX, NULL); | |
| AIFArrayIndexFree(ix1); | |
| _aif_free(fds); | |
| _aif_free(rankp); | |
| return (AIF *)NULL; | |
| } | |
| else if ( sz[i] == 0 ) { | |
| continue; | |
| } | |
| rankp[nrank++] = i; | |
| *rf++ = FDS_ARRAY_START; | |
| rl--; | |
| r = FDSRangeInit(mn[i], sz[i]); | |
| strncpy(rf, r, rl); | |
| rf += strlen(r); | |
| rl -= strlen(r); | |
| *rf++ = FDS_ARRAY_END; | |
| rl--; | |
| _aif_free(r); | |
| } | |
| strcpy(rf, ix1->i_btype); | |
| /* | |
| ** Create a new structure to hold the sliced array. | |
| */ | |
| /* In the old implementation, we use : ra = MakeAIF(fds, NULL); | |
| * However, with complex data structures, we cannot use MakeAIF() | |
| * since the actual size of the ra (i.e. AIF_LEN(ra)) cannot be known | |
| * only from the variable 'fds'. | |
| */ | |
| ra = NewAIF(0, BUFSIZ); | |
| AIF_FORMAT(ra) = fds; | |
| if ( nrank > 0 ) | |
| ix2 = FDSArrayIndexInit(AIF_FORMAT(ra)); | |
| /* | |
| ** Now build the data. | |
| */ | |
| for ( i = 0 ; i < ix1->i_nel ; i++ ) | |
| { | |
| char * data; | |
| char * ndata; | |
| int counter, limit; | |
| int size = 0; | |
| int subsize = 0; | |
| int len; | |
| if ( !AIFIndexInRange(rank, ix1->i_index, mn, sz) ) | |
| { | |
| AIFArrayIndexInc(ix1); | |
| continue; | |
| } | |
| limit = AIFIndexOffset(ix1->i_rank, ix1->i_index, | |
| ix1->i_min, ix1->i_size, NULL); | |
| for ( counter = 0; counter < limit; counter++ ) | |
| { | |
| subsize = FDSDataSize(ix1->i_btype,AIF_DATA(a)+size); | |
| size += subsize; | |
| } | |
| data = AIF_DATA(a) + size; | |
| len = FDSDataSize(ix1->i_btype, data); | |
| /* old code: data = AIF_DATA(a) + AIFIndexOffset(ix1->i_rank, ix1->i_index, ix1->i_min, ix1->i_max, NULL) * ix1->i_bsize; */ | |
| if ( nrank == 0 ) | |
| { | |
| memcpy(AIF_DATA(ra), data, len); | |
| break; | |
| } | |
| size = 0; subsize = 0; | |
| limit = AIFIndexOffset(ix2->i_rank, ix2->i_index, | |
| ix2->i_min, ix2->i_size, NULL); | |
| for ( counter = 0; counter < limit; counter++ ) | |
| { | |
| subsize = FDSDataSize(ix2->i_btype,AIF_DATA(ra)+size); | |
| size += subsize; | |
| } | |
| ndata = AIF_DATA(ra) + size; | |
| /* old code: ndata = AIF_DATA(ra) + AIFIndexOffset(ix2->i_rank, ix2->i_index, ix2->i_min, ix2->i_max, NULL) * ix2->i_bsize; */ | |
| /* old code: memcpy(ndata, data, ix1->i_bsize); */ | |
| memcpy(ndata, data, len); | |
| AIFArrayIndexInc(ix1); | |
| AIFArrayIndexInc(ix2); | |
| } | |
| /* Do pre-processing and post-processing steps */ | |
| { | |
| char * f = AIF_FORMAT(a); | |
| char * d = AIF_DATA(a); | |
| char * n; | |
| char * tmp; | |
| _aif_array_slice_pre(&f, &d, res_array); | |
| f = AIF_FORMAT(ra); | |
| d = _aif_alloc(BUFSIZ); | |
| tmp = d; | |
| memcpy(d, AIF_DATA(ra), BUFSIZ); | |
| n = AIF_DATA(ra); | |
| _aif_array_slice_post(&f, &d, &n, res_array); | |
| /* we need to use 'tmp' because after the call of | |
| * _aif_array_slice_post(), d points to the end, thus | |
| * the memory cannot be freed by using _aif_free(d) | |
| */ | |
| _aif_free(tmp); | |
| } | |
| AIFArrayIndexFree(ix1); | |
| if ( nrank > 0 ) | |
| AIFArrayIndexFree(ix2); | |
| _aif_free(rankp); | |
| return ra; | |
| } | |
| /* | |
| * XXX: TOFIX | |
| */ | |
| /* | |
| * The old AIFArrayPerm() relied on the assumption that all elements of the | |
| * AIF array have the same size (i.e. it wrote the data for the | |
| * resultant array in a "random access" way). | |
| * To solve this problem, we create dynamic arrays to hold the data and the | |
| * length, after that we iterate the arrays to copy the data to the resultant | |
| * AIF array. | |
| */ | |
| AIF * | |
| AIFArrayPerm(AIF *a, int *index) | |
| { | |
| int i; | |
| int rl; | |
| char * rf; | |
| AIF * ra; | |
| AIFIndex * ix; | |
| int len; | |
| char ** data_array; | |
| int * len_array; | |
| if ( a == (AIF *)NULL || index == (int *)NULL ) | |
| { | |
| SetAIFError(AIFERR_BADARG, NULL); | |
| return (AIF *)NULL; | |
| } | |
| if ( AIFType(a) != AIF_ARRAY ) | |
| { | |
| SetAIFError(AIFERR_TYPE, NULL); | |
| return (AIF *)NULL; | |
| } | |
| /* | |
| ** Initialise the index arrays. | |
| */ | |
| ix = FDSArrayIndexInit(AIF_FORMAT(a)); | |
| /* | |
| ** Create a new structure to hold the permuted array. | |
| */ | |
| ra = NewAIF(strlen(AIF_FORMAT(a))+1, BUFSIZ); | |
| /* | |
| ** Construct a new fds. | |
| */ | |
| memcpy(AIF_FORMAT(ra), AIF_FORMAT(a), strlen(AIF_FORMAT(a))+1); | |
| rf = AIF_FORMAT(ra); | |
| rl = strlen(rf) + 1; | |
| for ( i = 0 ; i < ix->i_rank ; i++ ) | |
| { | |
| char * r = FDSRangeInit(ix->i_min[index[i]], ix->i_size[index[i]]); | |
| *rf++ = FDS_ARRAY_START; | |
| rl--; | |
| strncpy(rf, r, rl); | |
| rf += strlen(r); | |
| rl -= strlen(r); | |
| *rf++ = FDS_ARRAY_END; | |
| rl--; | |
| _aif_free(r); | |
| } | |
| strcat(AIF_FORMAT(ra), ix->i_btype); | |
| len_array = _aif_alloc( ix->i_nel * sizeof(int) ); | |
| data_array = _aif_alloc( ix->i_nel * sizeof(char *) ); | |
| /* | |
| ** Now build the data. | |
| */ | |
| for ( i = 0 ; i < ix->i_nel ; i++ ) | |
| { | |
| char * d; | |
| int counter, limit; | |
| int size = 0; | |
| int subsize = 0; | |
| limit = AIFIndexOffset(ix->i_rank, ix->i_index, | |
| ix->i_min, ix->i_size, NULL); | |
| for ( counter = 0; counter < limit; counter++ ) | |
| { | |
| subsize = FDSDataSize(ix->i_btype, AIF_DATA(a)+size); | |
| size += subsize; | |
| } | |
| d = AIF_DATA(a) + size; | |
| len = FDSDataSize(ix->i_btype, d); | |
| size = 0; subsize = 0; | |
| limit = AIFIndexOffset(ix->i_rank, ix->i_index, | |
| ix->i_min, ix->i_size, NULL); | |
| data_array[limit] = d; | |
| len_array[limit] = len; | |
| AIFArrayIndexInc(ix); | |
| } | |
| len = 0; | |
| /* Copy the data to the resultant AIF array */ | |
| for ( i = 0 ; i < ix->i_nel ; i++ ) | |
| { | |
| char * rd; | |
| rd = AIF_DATA(ra) + len; | |
| memcpy(rd, data_array[i], len_array[i]); | |
| len += len_array[i]; | |
| } | |
| AIFArrayIndexFree(ix); | |
| _aif_free(data_array); | |
| _aif_free(len_array); | |
| return ra; | |
| } | |
| char * | |
| AIFArrayIndexType(AIF *a) | |
| { | |
| if ( a == (AIF *)NULL ) | |
| { | |
| SetAIFError(AIFERR_BADARG, NULL); | |
| return NULL; | |
| } | |
| if ( AIFType(a) != AIF_ARRAY ) | |
| { | |
| SetAIFError(AIFERR_TYPE, NULL); | |
| return NULL; | |
| } | |
| return FDSArrayIndexType(AIF_FORMAT(a)); | |
| } | |
| int | |
| AIFArrayMinIndex(AIF *a, int n) | |
| { | |
| if ( a == (AIF *)NULL ) | |
| { | |
| SetAIFError(AIFERR_BADARG, NULL); | |
| return -1; | |
| } | |
| if ( AIFType(a) != AIF_ARRAY ) | |
| { | |
| SetAIFError(AIFERR_TYPE, NULL); | |
| return -1; | |
| } | |
| return FDSArrayMinIndex(AIF_FORMAT(a), n); | |
| } | |
| int | |
| AIFArrayRankSize(AIF *a, int n) | |
| { | |
| if ( a == (AIF *)NULL ) | |
| { | |
| SetAIFError(AIFERR_BADARG, NULL); | |
| return -1; | |
| } | |
| if ( AIFType(a) != AIF_ARRAY ) | |
| { | |
| SetAIFError(AIFERR_TYPE, NULL); | |
| return -1; | |
| } | |
| return FDSArrayRankSize(AIF_FORMAT(a), n); | |
| } | |
| /* | |
| * The index array is used to compute the location of data in | |
| * a multi-dimensional array, and basically corresponds to a loop | |
| * counter in normal circumstances. | |
| */ | |
| #define PERMUTE(p, d) ((p) != NULL ? (p)[d] : d) | |
| /* | |
| * Initialise an index array to the minimum index value for each | |
| * dimension, given the number of dimensions (rank), and the minimum | |
| * and maximum values of each dimension (min, max). Returns the number | |
| * of elements in the array. | |
| */ | |
| AIFIndex * | |
| AIFArrayIndexInit(AIF *a) | |
| { | |
| if ( a == (AIF *)NULL ) | |
| { | |
| SetAIFError(AIFERR_BADARG, NULL); | |
| return (AIFIndex *)NULL; | |
| } | |
| if ( AIFType(a) != AIF_ARRAY ) | |
| { | |
| SetAIFError(AIFERR_TYPE, NULL); | |
| return (AIFIndex *)NULL; | |
| } | |
| return FDSArrayIndexInit(AIF_FORMAT(a)); | |
| } | |
| /* | |
| * Check that the index value of each index in rankp is within the range | |
| * min .. min+size-1. Returns 1 if they are, otherwise 0. | |
| * | |
| * Note: rankp, index, min and size are guaranteed to have at least | |
| * rank elements. | |
| */ | |
| int | |
| AIFIndexInRange(int rank, int *index, int *min, int *size) | |
| { | |
| int d; | |
| for ( d = rank - 1 ; d >= 0 ; d-- ) | |
| { | |
| if ( min[d] < 0 ) | |
| continue; | |
| if ( index[d] < min[d] || index[d] >= min[d] + size[d] ) | |
| return 0; | |
| } | |
| return 1; | |
| } | |
| /* | |
| * Step through indexes in the order specified by the perm array. | |
| * Indexes cycle from min to max. Returns 1 on carry out. | |
| */ | |
| int | |
| AIFArrayIndexInc(AIFIndex *ix) | |
| { | |
| int d; | |
| for ( d = ix->i_rank - 1 ; d >= 0 ; d-- ) | |
| { | |
| if ( ++(ix->i_index[d]) >= ix->i_min[d] + ix->i_size[d] ) | |
| { | |
| ix->i_index[d] = ix->i_min[d]; | |
| continue; | |
| } | |
| return 0; | |
| } | |
| ix->i_finished = 1; | |
| return 1; | |
| } | |
| void | |
| AIFArrayIndexFree(AIFIndex *ix) | |
| { | |
| _aif_free(ix->i_btype); | |
| _aif_free(ix->i_index); | |
| _aif_free(ix->i_min); | |
| _aif_free(ix->i_size); | |
| _aif_free(ix); | |
| } | |
| /* | |
| * Index array element and return as doublest | |
| * XXX: TOFIX | |
| */ | |
| int | |
| AIFArrayElementToDoublest(AIF *a, AIFIndex *ix, AIFDOUBLEST *val) | |
| { | |
| if ( a == (AIF *)NULL ) | |
| { | |
| SetAIFError(AIFERR_BADARG, NULL); | |
| return -1; | |
| } | |
| if ( AIFType(a) != AIF_ARRAY ) | |
| { | |
| SetAIFError(AIFERR_TYPE, NULL); | |
| return -1; | |
| } | |
| if ( AIFBaseType(a) != AIF_FLOATING ) | |
| { | |
| SetAIFError(AIFERR_TYPE, NULL); | |
| return -1; | |
| } | |
| return _aif_to_doublest(AIF_DATA(a) + AIFIndexOffset(ix->i_rank, ix->i_index, ix->i_min, ix->i_size, NULL) * ix->i_bsize, ix->i_bsize, val); | |
| } | |
| int | |
| AIFArrayElementToDouble(AIF *a, AIFIndex *ix, double *val) | |
| { | |
| int res; | |
| AIFDOUBLEST dd; | |
| res = AIFArrayElementToDoublest(a, ix, &dd); | |
| if ( res >= 0 ) | |
| *val = (double)dd; /* maybe lose some precision */ | |
| return res; | |
| } | |
| /* | |
| * Index array element and return as longest | |
| * XXX: TOFIX | |
| */ | |
| int | |
| AIFArrayElementToLongest(AIF *a, AIFIndex *ix, AIFLONGEST *val) | |
| { | |
| if ( a == (AIF *)NULL ) | |
| { | |
| SetAIFError(AIFERR_BADARG, NULL); | |
| return -1; | |
| } | |
| if ( AIFType(a) != AIF_ARRAY ) | |
| { | |
| SetAIFError(AIFERR_TYPE, NULL); | |
| return -1; | |
| } | |
| if ( AIFBaseType(a) != AIF_INTEGER ) | |
| { | |
| SetAIFError(AIFERR_TYPE, NULL); | |
| return -1; | |
| } | |
| return _aif_to_longest(AIF_DATA(a) + AIFIndexOffset(ix->i_rank, ix->i_index, ix->i_min, ix->i_size, NULL) * ix->i_bsize, ix->i_bsize, val); | |
| } | |
| int | |
| AIFArrayElementToInt(AIF *a, AIFIndex *ix, int *val) | |
| { | |
| int res; | |
| AIFLONGEST l; | |
| res = AIFArrayElementToLongest(a, ix, &l); | |
| if ( res >= 0 ) | |
| *val = (int)l; | |
| return res; | |
| } | |
| AIF * | |
| _aif_array_ref(AIF *a, int rank, int *index, int *min, int *size, char *btype, int bsize) | |
| { | |
| int counter; | |
| int offset; | |
| char * fds; | |
| char * data; | |
| char * data_start; | |
| char * data_end; | |
| offset = AIFIndexOffset(rank, index, min, size, (int *)NULL); | |
| data_start = data_end = AIF_DATA(a); | |
| for ( counter = 0 ; counter <= offset ; counter++ ) | |
| { | |
| fds = btype; | |
| data_start = data_end; | |
| _fds_skip_data(&fds, &data_end); | |
| } | |
| data = _aif_alloc(data_end - data_start); | |
| memcpy(data, data_start, data_end - data_start); | |
| return _make_aif(strdup(btype), data, data_end - data_start); | |
| } | |
| /* | |
| * Compute size of array. | |
| */ | |
| int | |
| _aif_array_size(char *fds, char *data) | |
| { | |
| int i; | |
| int n = 0; | |
| char * dstart; | |
| char * fmt; | |
| char * btype; | |
| AIFIndex * ix; | |
| ix = FDSArrayIndexInit(fds); | |
| btype = FDSBaseType(fds); | |
| for ( i = 0 ; i <= ix->i_nel ; i++ ) | |
| { | |
| fmt = btype; | |
| dstart = data; | |
| _fds_skip_data(&fmt, &data); | |
| n += data - dstart; | |
| } | |
| AIFArrayIndexFree(ix); | |
| return n; | |
| } | |
| /* | |
| * Return array element at index. | |
| */ | |
| AIF * | |
| AIFArrayElement(AIF *a, AIFIndex *ix) | |
| { | |
| if ( a == (AIF *)NULL ) | |
| { | |
| SetAIFError(AIFERR_BADARG, NULL); | |
| return (AIF *)NULL; | |
| } | |
| if ( AIFType(a) != AIF_ARRAY ) | |
| { | |
| SetAIFError(AIFERR_TYPE, NULL); | |
| return (AIF *)NULL; | |
| } | |
| if ( ix->i_finished ) | |
| return (AIF *)NULL; | |
| return _aif_array_ref(a, ix->i_rank, ix->i_index, ix->i_min, ix->i_size, ix->i_btype, ix->i_bsize); | |
| } | |
| /* | |
| * Return array element at location. | |
| */ | |
| AIF * | |
| AIFArrayRef(AIF *a, int rank, int *loc) | |
| { | |
| int i; | |
| AIF * ae; | |
| AIFIndex * ix; | |
| if ( a == (AIF *)NULL ) | |
| { | |
| SetAIFError(AIFERR_BADARG, NULL); | |
| return (AIF *)NULL; | |
| } | |
| if ( AIFType(a) != AIF_ARRAY ) | |
| { | |
| SetAIFError(AIFERR_TYPE, NULL); | |
| return (AIF *)NULL; | |
| } | |
| ix = AIFArrayIndexInit(a); | |
| if ( rank != ix->i_rank ) | |
| { | |
| AIFArrayIndexFree(ix); | |
| SetAIFError(AIFERR_INDEX, NULL); | |
| return (AIF *)NULL; | |
| } | |
| for ( i = 0 ; i < rank ; i++ ) | |
| { | |
| if ( loc[i] < ix->i_min[i] || loc[i] >= ix->i_min[i] + ix->i_size[i] ) | |
| { | |
| AIFArrayIndexFree(ix); | |
| SetAIFError(AIFERR_INDEX, NULL); | |
| return (AIF *)NULL; | |
| } | |
| } | |
| ae = _aif_array_ref(a, ix->i_rank, loc, ix->i_min, ix->i_size, ix->i_btype, ix->i_bsize); | |
| AIFArrayIndexFree(ix); | |
| return ae; | |
| } | |
| /* | |
| * Copy data into an array. | |
| * XXX: TOFIX | |
| */ | |
| int | |
| AIFSetArrayData(AIF *dst, AIFIndex *ix, AIF *src) | |
| { | |
| char * dd; | |
| if | |
| ( | |
| dst == (AIF *)NULL | |
| || | |
| src == (AIF *)NULL | |
| || | |
| ix == (AIFIndex *)NULL | |
| ) | |
| { | |
| SetAIFError(AIFERR_BADARG, NULL); | |
| return -1; | |
| } | |
| if | |
| ( | |
| AIFType(dst) != AIF_ARRAY | |
| || | |
| AIFBaseType(dst) != AIFType(src) | |
| ) | |
| { | |
| SetAIFError(AIFERR_TYPE, NULL); | |
| return -1; | |
| } | |
| dd = AIF_DATA(dst) + AIFIndexOffset(ix->i_rank, ix->i_index, ix->i_min, ix->i_size, NULL) * ix->i_bsize; | |
| memcpy(dd, AIF_DATA(src), ix->i_bsize); | |
| return 0; | |
| } | |
| /* | |
| * Calculate the data offset in the array given the current value | |
| * of the indexes, and the minimum indexes and size of each dimension. | |
| */ | |
| int | |
| AIFIndexOffset(int rank, int *index, int *min, int *size, int *perm) | |
| { | |
| int d; | |
| int p; | |
| int off = 0; | |
| int sz = 1; | |
| for ( d = rank - 1 ; d >= 0 ; d-- ) | |
| { | |
| p = PERMUTE(perm, d); | |
| off += (index[p] - min[p]) * sz; | |
| sz *= size[p]; | |
| } | |
| return off; | |
| } | |