/*
* Copyright 1993, University Corporation for Atmospheric Research
* See netcdf/COPYRIGHT file for copying and redistribution conditions.
*
* This file supports netCDF variable I/O for generalized hyperslabs.
* A generalized hyperslab is one in which the locations of the
* memory-resident data values may be arbitrary, though they are
* constrained to have a regular structure. In addition, the values
* of the netCDF variable may be accessed using non-unity strides.
*
* $Id: putgetg.c,v 1.8 1997/11/13 20:19:46 acheng Exp $
*/
#include "local_nc.h"
/*
* Perform I/O on a generalized hyperslab. The efficiency of this
* implementation is dependent upon caching in the lower layers.
*/
#ifndef HDF
static
#endif
int
NCgenio(handle, varid, start, count, stride, imap, values)
NC *handle;
int varid;
const long *start; /* NULL => first corner */
const long *count; /* NULL => everything following start[] */
const long *stride; /* NULL => unity strides */
const long *imap; /* NULL => same structure as netCDF variable */
void *values ;
{
int maxidim; /* maximum dimensional index */
NC_var *vp = NC_hlookupvar( handle, varid );
if (vp == NULL)
return(-1) ;
maxidim = vp->assoc->count - 1;
if (maxidim < 0) {
/*
* The variable is a scalar; consequently, there's only one thing
* to get and only one place to put it. (Why was I called?)
*/
return NCvario(handle, varid, start, count, values);
} else {
/*
* The variable is an array.
*/
int idim;
char *valp = values;
long mycount[MAX_VAR_DIMS];
long mystart[MAX_VAR_DIMS];
long mystride[MAX_VAR_DIMS];
long myimap[MAX_VAR_DIMS];
long iocount[MAX_VAR_DIMS]; /* count vector for NCvario() */
long stop[MAX_VAR_DIMS]; /* stop indexes */
long length[MAX_VAR_DIMS]; /* edge lengths in bytes */
/*
* Verify stride argument.
*/
for (idim = 0; idim <= maxidim; ++idim) {
if (stride != NULL && stride[idim] < 1) {
NCadvise(NC_EINVAL, "Non-positive stride");
return(-1) ;
}
}
/*
* Initialize I/O parameters.
*/
for (idim = maxidim; idim >= 0; --idim) {
mystart[idim] = start != NULL
? start[idim]
: 0;
mycount[idim] = count != NULL
? count[idim]
: idim == 0 && IS_RECVAR(vp)
? handle->numrecs - mystart[idim]
: vp->shape[idim] - mystart[idim];
mystride[idim] = stride != NULL
? stride[idim]
: 1;
myimap[idim] = imap != NULL
? imap[idim]
: idim == maxidim
? vp->szof
: myimap[idim+1] * mycount[idim+1];
iocount[idim] = 1;
length[idim] = myimap[idim] * mycount[idim];
stop[idim] = mystart[idim] + mycount[idim]*mystride[idim];
}
/*
* As an optimization, adjust I/O parameters when the fastest
* dimension has unity stride both externally and internally.
* In this case, the user could have called a simpler routine
* (i.e. ncvarget() or ncvarput()).
*/
if (mystride[maxidim] == 1 && myimap[maxidim] == vp->szof) {
iocount[maxidim] = mycount[maxidim];
mystride[maxidim] = mycount[maxidim];
myimap[maxidim] = length[maxidim];
}
/*
* Perform I/O. Exit when done.
*/
for (;;) {
int iostat = NCvario(handle, varid, mystart, iocount,
(Void*)valp);
if (iostat != 0)
return iostat;
/*
* The following code permutes through the variable's external
* start-index space and it's internal address space. At the
* UPC, this algorithm is commonly called `odometer code'.
*/
idim = maxidim;
carry:
valp += myimap[idim];
mystart[idim] += mystride[idim];
if (mystart[idim] >= stop[idim]) {
mystart[idim] = start[idim];
valp -= length[idim];
if (--idim < 0)
return 0;
goto carry;
}
} /* I/O loop */
} /* variable is array */
}
/*
* Generalized hyperslab output.
*/
int
ncvarputg(cdfid, varid, start, count, stride, imap, values)
int cdfid ;
int varid ;
const long *start ;
const long *count ;
const long *stride ;
const long *imap ;
ncvoid *values ;
{
NC *handle ;
cdf_routine_name = "ncvarputg" ;
handle = NC_check_id(cdfid) ;
if(handle == NULL)
return(-1) ;
if(!(handle->flags & NC_RDWR))
{
NCadvise(NC_EPERM, "%s: NC_NOWRITE", handle->path) ;
return(-1) ;
}
handle->xdrs->x_op = XDR_ENCODE ;
return NCgenio(handle, varid, start, count, stride, imap, values);
}
/*
* Generalized hyperslab input.
*/
int
ncvargetg(cdfid, varid, start, count, stride, imap, values)
int cdfid ;
int varid ;
const long *start ;
const long *count ;
const long *stride ;
const long *imap ;
ncvoid *values ;
{
NC *handle ;
cdf_routine_name = "ncvargetg" ;
handle = NC_check_id(cdfid) ;
if (handle == NULL)
return(-1) ;
handle->xdrs->x_op = XDR_DECODE ;
return NCgenio(handle, varid, start, count,
stride, imap, (Void*)values);
}
/*
* Stride-oriented hyperslab output.
*/
int
ncvarputs(cdfid, varid, start, count, stride, values)
int cdfid ;
int varid ;
const long *start ;
const long *count ;
const long *stride ;
ncvoid *values ;
{
NC *handle ;
cdf_routine_name = "ncvarputs" ;
handle = NC_check_id(cdfid) ;
if(handle == NULL)
return(-1) ;
if(!(handle->flags & NC_RDWR))
{
NCadvise(NC_EPERM, "%s: NC_NOWRITE", handle->path) ;
return(-1) ;
}
handle->xdrs->x_op = XDR_ENCODE ;
return NCgenio(handle, varid, start, count, stride, NULL, values);
}
/*
* Stride-oriented hyperslab input.
*/
int
ncvargets(cdfid, varid, start, count, stride, values)
int cdfid ;
int varid ;
const long *start ;
const long *count ;
const long *stride ;
ncvoid *values ;
{
NC *handle ;
cdf_routine_name = "ncvargets" ;
handle = NC_check_id(cdfid) ;
if (handle == NULL)
return(-1) ;
handle->xdrs->x_op = XDR_DECODE ;
return NCgenio(handle, varid, start, count,
stride, (long*)0, (Void*)values);
}
syntax highlighted by Code2HTML, v. 0.9.1