/* Recursive helper */ static void gen_chararrayr(Dimset* dimset, int dimindex, Bytebuffer* databuf, Datalist* data, int fillchar, int unitsize, int expectedsize) { int i; size_t dimsize = declsizefor(dimset,dimindex); int rank = dimset->ndims; int firstunlim = findunlimited(dimset,0); int lastunlimited = findlastunlimited(dimset); int nextunlimited = findunlimited(dimset,dimindex+1); int islastgroup = (lastunlimited == rank || dimindex >= lastunlimited || dimindex == rank-1); Odometer* subodom = NULL; ASSERT(rank > 0); ASSERT((islastgroup)); /* we should be at a list of simple constants */ for(i=0;i<data->length;i++) { NCConstant* c = datalistith(data,i); ASSERT(!islistconst(c)); if(isstringable(c->nctype)) { int j; size_t constsize; constsize = gen_charconstant(c,databuf,fillchar); if(constsize % unitsize > 0) { size_t padsize = unitsize - (constsize % unitsize); for(j=0;j<padsize;j++) bbAppend(databuf,fillchar); } } else { semwarn(constline(c), "Encountered non-string and non-char constant in datalist; ignored"); } }/* for */ /* If |databuf| > expectedsize, complain: exception is zero length */ if(bbLength(databuf) == 0 && expectedsize == 1) { /* this is okay */ } else if(bbLength(databuf) > expectedsize) { semwarn(data->data[0].lineno,"character data list too long; expected %d character constant, found %d: ",expectedsize,bbLength(databuf)); } else { size_t bufsize = bbLength(databuf); /* Pad to size dimproduct size */ if(bufsize % expectedsize > 0) { size_t padsize = expectedsize - (bufsize % expectedsize); for(i=0;i<padsize;i++) bbAppend(databuf,fillchar); } } }
static void processunlimiteddims(void) { int i; /* Set all unlimited dims to size 0; */ for(i=0;i<listlength(dimdefs);i++) { Symbol* dim = (Symbol*)listget(dimdefs,i); if(dim->dim.isunlimited) dim->dim.declsize = 0; } /* Walk all variables */ for(i=0;i<listlength(vardefs);i++) { Symbol* var = (Symbol*)listget(vardefs,i); int first,ischar; Dimset* dimset = &var->typ.dimset; if(dimset->ndims == 0) continue; /* ignore scalars */ if(var->data == NULL) continue; /* no data list to walk */ ischar = (var->typ.basetype->typ.typecode == NC_CHAR); first = findunlimited(dimset,0); if(first == dimset->ndims) continue; /* no unlimited dims */ if(first == 0) { computeunlimitedsizes(dimset,first,var->data,ischar); } else { int j; for(j=0;j<var->data->length;j++) { NCConstant* con = var->data->data[j]; if(con->nctype != NC_COMPOUND) semerror(con->lineno,"UNLIMITED dimension (other than first) must be enclosed in {}"); else computeunlimitedsizes(dimset,first,con->value.compoundv,ischar); } } } #ifdef GENDEBUG1 /* print unlimited dim size */ if(listlength(dimdefs) == 0) fprintf(stderr,"unlimited: no unlimited dimensions\n"); else for(i=0;i<listlength(dimdefs);i++) { Symbol* dim = (Symbol*)listget(dimdefs,i); if(dim->dim.isunlimited) fprintf(stderr,"unlimited: %s = %lu\n", dim->name, (unsigned long)dim->dim.declsize); } #endif }
void gen_chararray(Dimset* dimset, int dimindex, Datalist* data, Bytebuffer* charbuf, Datalist* fillsrc) { int fillchar = getfillchar(fillsrc); int rank = rankfor(dimset); int firstunlim = findunlimited(dimset,0); int nunlim = countunlimited(dimset); int nc3unlim = (nunlim <= 1 && (firstunlim == 0 || firstunlim == rank)); /* netcdf-3 case of at most 1 unlim in 0th dimension */ /* Case: netcdf3 case */ if(nc3unlim) { gen_leafchararray(dimset,0,data,charbuf,fillchar); return; } /* else generate should have done all the hard work */ gen_leafchararray(dimset,dimindex,data,charbuf,fillchar); }
static void generate_array(Symbol* vsym, Bytebuffer* code, Datalist* filler, Generator* generator, Writer writer ) { Dimset* dimset = &vsym->typ.dimset; int rank = dimset->ndims; Symbol* basetype = vsym->typ.basetype; nc_type typecode = basetype->typ.typecode; Odometer* odom; nciter_t iter; ASSERT(rank > 0); /* Start by doing easy cases */ #ifdef CHARBUG if(typecode == NC_CHAR) { /* case: character typed variable, rank > 0 */ Bytebuffer* charbuf = bbNew(); gen_chararray(dimset,vsym->data,charbuf,filler); generator->charconstant(generator,code,charbuf); bbFree(charbuf); odom = newodometer(dimset,NULL,NULL); writer(generator,vsym,code,odom->rank,odom->start,odom->count); } else #else /*!CHARBUG*/ /* Case: char var && dim 1..n are not unlimited */ if(findunlimited(dimset,1) == rank && typecode == NC_CHAR) { Bytebuffer* charbuf = bbNew(); gen_leafchararray(dimset,0,vsym->data,charbuf,filler); generator->charconstant(generator,code,charbuf); bbFree(charbuf); odom = newodometer(dimset,NULL,NULL); writer(generator,vsym,code,odom->rank,odom->start,odom->count); } else #endif /* Case 2: dim 1..n are not unlimited */ if(findunlimited(dimset,1) == rank) { size_t offset = 0; /* where are we in the data list */ size_t nelems = 0; /* # of data list items to read */ /* Create an iterator and odometer and just walk the datalist */ nc_get_iter(vsym,nciterbuffersize,&iter); odom = newodometer(dimset,NULL,NULL); for(;;offset+=nelems) { int i,uid; nelems=nc_next_iter(&iter,odom->start,odom->count); if(nelems == 0) break; bbClear(code); generator->listbegin(generator,LISTDATA,vsym->data->length,code,&uid); for(i=0;i<nelems;i++) { #ifdef ITERBUG Constant* con = datalistith(vsym->data,i); #else NCConstant* con = datalistith(vsym->data,i+offset); #endif generator->list(generator,LISTDATA,uid,i,code); #ifdef USE_NOFILL if(nofill_flag && con == NULL) break; else #endif generate_basetype(basetype,con,code,filler,generator); } generator->listend(generator,LISTDATA,uid,i,code); #ifdef USE_NOFILL writer(generator,vsym,code,rank,odom->start,odom->index); #else writer(generator,vsym,code,rank,odom->start,odom->count); #endif } } else { /* Hard case: multiple unlimited dimensions */ /* Setup iterator and odometer */ #ifdef CHARBUG nc_get_iter(vsym,nciterbuffersize,&iter); #else nc_get_iter(vsym,NC_MAX_UINT,&iter); /* effectively infinite */ #endif odom = newodometer(dimset,NULL,NULL); for(;;) {/* iterate in nelem chunks */ /* get nelems count and modify odometer */ size_t nelems=nc_next_iter(&iter,odom->start,odom->count); if(nelems == 0) break; generate_arrayr(vsym,code,vsym->data, odom, /*dim index=*/0, filler,generator ); #ifdef USE_NOFILL writer(generator,vsym,code,odom->rank,odom->start,odom->index); #else writer(generator,vsym,code,odom->rank,odom->start,odom->count); #endif } } odometerfree(odom); }
static void generate_arrayr(Symbol* vsym, Bytebuffer* code, Datalist* list, Odometer* odom, int dimindex, Datalist* filler, Generator* generator ) { Symbol* basetype = vsym->typ.basetype; Dimset* dimset = &vsym->typ.dimset; int rank = dimset->ndims; int lastunlimited; int typecode = basetype->typ.typecode; lastunlimited = findlastunlimited(dimset); if(lastunlimited == rank) lastunlimited = 0; ASSERT(rank > 0); ASSERT(dimindex >= 0 && dimindex < rank); #ifdef CHARBUG ASSERT(typecode != NC_CHAR); #else /*!CHARBUG*/ if(dimindex == lastunlimited && typecode == NC_CHAR) { Bytebuffer* charbuf = bbNew(); gen_leafchararray(dimset,dimindex,list,charbuf,filler); generator->charconstant(generator,code,charbuf); bbFree(charbuf); } else #endif /*!CHARBUG*/ if(dimindex == lastunlimited) { int uid,i; Odometer* slabodom; /* build a special odometer to walk the last few dimensions (similar to case 2 above) */ slabodom = newsubodometer(odom,dimset,dimindex,rank); /* compute the starting offset in our datalist (Assumes that slabodom->index[i] == slabodom->start[i]) */ generator->listbegin(generator,LISTDATA,list->length,code,&uid); for(i=0;odometermore(slabodom);i++) { size_t offset = odometeroffset(slabodom); NCConstant* con = datalistith(list,offset); #ifdef USE_NOFILL if(nofill_flag && con == NULL) break; #endif generator->list(generator,LISTDATA,uid,i,code); generate_basetype(basetype,con,code,filler,generator); odometerincr(slabodom); } generator->listend(generator,LISTDATA,uid,i,code); odometerfree(slabodom); } else { /* If we are strictly to the left of the next unlimited then our datalist is a list of compounds representing the next unlimited; so walk the subarray from this index upto next unlimited. */ int i; Odometer* slabodom; int nextunlimited = findunlimited(dimset,dimindex+1); ASSERT((dimindex < nextunlimited && (dimset->dimsyms[nextunlimited]->dim.isunlimited))); /* build a sub odometer */ slabodom = newsubodometer(odom,dimset,dimindex,nextunlimited); /* compute the starting offset in our datalist (Assumes that slabodom->index[i] == slabodom->start[i]) */ for(i=0;odometermore(slabodom);i++) { size_t offset = odometeroffset(slabodom); NCConstant* con = datalistith(list,offset); #ifdef USE_NOFILL if(nofill_flag && con == NULL) break; #endif if(con == NULL || con->nctype == NC_FILL) { if(filler == NULL) filler = getfiller(vsym); generate_arrayr(vsym,code,filler,odom,nextunlimited,NULL,generator); } else if(!islistconst(con)) semwarn(constline(con),"Expected {...} representing unlimited list"); else { Datalist* sublist = con->value.compoundv; generate_arrayr(vsym,code,sublist,odom,nextunlimited,filler,generator); } odometerincr(slabodom); } odometerfree(slabodom); } return; }
static void computeunlimitedsizes(Dimset* dimset, int dimindex, Datalist* data, int ischar) { int i; size_t xproduct, unlimsize; int nextunlim,lastunlim; Symbol* thisunlim = dimset->dimsyms[dimindex]; size_t length; ASSERT(thisunlim->dim.isunlimited); nextunlim = findunlimited(dimset,dimindex+1); lastunlim = (nextunlim == dimset->ndims); xproduct = crossproduct(dimset,dimindex+1,nextunlim); if(!lastunlim) { /* Compute candidate size of this unlimited */ length = data->length; unlimsize = length / xproduct; if(length % xproduct != 0) unlimsize++; /* => fill requires at some point */ #ifdef GENDEBUG2 fprintf(stderr,"unlimsize: dim=%s declsize=%lu xproduct=%lu newsize=%lu\n", thisunlim->name, (unsigned long)thisunlim->dim.declsize, (unsigned long)xproduct, (unsigned long)unlimsize); #endif if(thisunlim->dim.declsize < unlimsize) /* want max length of the unlimited*/ thisunlim->dim.declsize = unlimsize; /*!lastunlim => data is list of sublists, recurse on each sublist*/ for(i=0;i<data->length;i++) { NCConstant* con = data->data[i]; if(con->nctype != NC_COMPOUND) { semerror(con->lineno,"UNLIMITED dimension (other than first) must be enclosed in {}"); } computeunlimitedsizes(dimset,nextunlim,con->value.compoundv,ischar); } } else { /* lastunlim */ if(ischar) { /* Char case requires special computations; compute total number of characters */ length = 0; for(i=0;i<data->length;i++) { NCConstant* con = data->data[i]; switch (con->nctype) { case NC_CHAR: case NC_BYTE: case NC_UBYTE: length++; break; case NC_STRING: length += con->value.stringv.len; break; case NC_COMPOUND: semwarn(datalistline(data),"Expected character constant, found {...}"); break; default: semwarn(datalistline(data),"Illegal character constant: %d",con->nctype); } } } else { /* Data list should be a list of simple non-char constants */ length = data->length; } unlimsize = length / xproduct; if(length % xproduct != 0) unlimsize++; /* => fill requires at some point */ #ifdef GENDEBUG2 fprintf(stderr,"unlimsize: dim=%s declsize=%lu xproduct=%lu newsize=%lu\n", thisunlim->name, (unsigned long)thisunlim->dim.declsize, (unsigned long)xproduct, (unsigned long)unlimsize); #endif if(thisunlim->dim.declsize < unlimsize) /* want max length of the unlimited*/ thisunlim->dim.declsize = unlimsize; } }
/** The basic idea is to split the set of dimensions into groups and iterate over each group. A group is defined as the range of indices starting at an unlimited dimension upto (but not including) the next unlimited. The first group starts at index 0, even if dimension 0 is not unlimited. The last group is everything from the last unlimited dimension thru the last dimension (index rank-1). */ static void generate_arrayr(Symbol* vsym, Bytebuffer* code, Datalist* list, Odometer* odom, int dimindex, Datalist* filler, Generator* generator ) { int uid,i; Symbol* basetype = vsym->typ.basetype; Dimset* dimset = &vsym->typ.dimset; int rank = dimset->ndims; int lastunlimited = findlastunlimited(dimset); int nextunlimited = findunlimited(dimset,dimindex+1); int typecode = basetype->typ.typecode; int islastgroup = (lastunlimited == rank || dimindex >= lastunlimited || dimindex == rank-1); Odometer* subodom = NULL; ASSERT(rank > 0); ASSERT((dimindex >= 0 && dimindex < rank)); if(islastgroup) { /* Handle NC_CHAR case separately */ if(typecode == NC_CHAR) { Bytebuffer* charbuf = bbNew(); gen_chararray(dimset,dimindex,list,charbuf,filler); generator->charconstant(generator,code,charbuf); bbFree(charbuf); } else { /* build a special odometer to walk the last few dimensions */ subodom = newsubodometer(odom,dimset,dimindex,rank); generator->listbegin(generator,LISTDATA,list->length,code,&uid); for(i=0;odometermore(subodom);i++) { size_t offset = odometeroffset(subodom); NCConstant* con = datalistith(list,offset); generator->list(generator,LISTDATA,uid,i,code); generate_basetype(basetype,con,code,filler,generator); odometerincr(subodom); } generator->listend(generator,LISTDATA,uid,i,code); odometerfree(subodom); subodom = NULL; } } else {/* !islastgroup */ /* Our datalist must be a list of compounds representing the next unlimited; so walk the subarray from this index upto next unlimited. */ ASSERT((dimindex < nextunlimited)); ASSERT((isunlimited(dimset,nextunlimited))); /* build a sub odometer */ subodom = newsubodometer(odom,dimset,dimindex,nextunlimited); for(i=0;odometermore(subodom);i++) { size_t offset = odometeroffset(subodom); NCConstant* con = datalistith(list,offset); if(con == NULL || con->nctype == NC_FILL) { if(filler == NULL) filler = getfiller(vsym); generate_arrayr(vsym,code,filler,odom,nextunlimited,NULL,generator); } else if(islistconst(con)) { Datalist* sublist = compoundfor(con); generate_arrayr(vsym,code,sublist,odom,nextunlimited,filler,generator); } else { semerror(constline(con),"Expected {...} representing unlimited list"); return; } odometerincr(subodom); } odometerfree(subodom); subodom = NULL; } if(subodom != NULL) odometerfree(subodom); return; }
static void generate_array(Symbol* vsym, Bytebuffer* code, Datalist* filler, Generator* generator, Writer writer ) { Dimset* dimset = &vsym->typ.dimset; int rank = dimset->ndims; Symbol* basetype = vsym->typ.basetype; nc_type typecode = basetype->typ.typecode; Odometer* odom = NULL; nciter_t iter; int firstunlim = findunlimited(dimset,1); int nunlim = countunlimited(dimset); int isnc3unlim = (nunlim <= 1 && (firstunlim == 0 || firstunlim == rank)); /* netcdf-3 case of at most 1 unlim in 0th dimension */ ASSERT(rank > 0); if(isnc3unlim) { /* Handle NC_CHAR case separately */ if(typecode == NC_CHAR) { Bytebuffer* charbuf = bbNew(); gen_chararray(dimset,0,vsym->data,charbuf,filler); generator->charconstant(generator,code,charbuf); /* Create an odometer to get the dimension info */ odom = newodometer(dimset,NULL,NULL); writer(generator,vsym,code,odom->rank,odom->start,odom->count); // writer(generator,vsym,code,odom->rank,0,bbLength(charbuf)); bbFree(charbuf); } else { /* typecode != NC_CHAR */ /* Case: dim 1..rank-1 are not unlimited, dim 0 might be */ size_t offset = 0; /* where are we in the data list */ size_t nelems = 0; /* # of data list items to generate */ /* Create an iterator and odometer and just walk the datalist */ nc_get_iter(vsym,nciterbuffersize,&iter); odom = newodometer(dimset,NULL,NULL); for(;;offset+=nelems) { int i,uid; nelems=nc_next_iter(&iter,odometerstartvector(odom),odometercountvector(odom)); if(nelems == 0) break; bbClear(code); generator->listbegin(generator,LISTDATA,vsym->data->length,code,&uid); for(i=0;i<nelems;i++) { NCConstant* con = datalistith(vsym->data,i+offset); generator->list(generator,LISTDATA,uid,i,code); generate_basetype(basetype,con,code,filler,generator); } generator->listend(generator,LISTDATA,uid,i,code); writer(generator,vsym,code,rank,odom->start,odom->count); } } } else { /* Hard case: multiple unlimited dimensions or unlim in dim > 0*/ /* Setup iterator and odometer */ nc_get_iter(vsym,NC_MAX_UINT,&iter); /* effectively infinite */ odom = newodometer(dimset,NULL,NULL); for(;;) {/* iterate in nelem chunks */ /* get nelems count and modify odometer */ size_t nelems=nc_next_iter(&iter,odom->start,odom->count); if(nelems == 0) break; generate_arrayr(vsym,code,vsym->data, odom, /*dim index=*/0, filler,generator ); writer(generator,vsym,code,odom->rank,odom->start,odom->count); } } if(odom != NULL) odometerfree(odom); }