mirror of
https://github.com/HDFGroup/hdf5.git
synced 2024-11-27 02:10:55 +08:00
6b45f5172c
Code cleanup Description: Trim trailing whitespace, which is making 'diff'ing the two branches difficult. Solution: Ran this script in each directory: foreach f (*.[ch] *.cpp) sed 's/[[:blank:]]*$//' $f > sed.out && mv sed.out $f end Platforms tested: FreeBSD 4.11 (sleipnir) Too minor to require h5committest
1344 lines
45 KiB
C
1344 lines
45 KiB
C
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||
* Copyright by the Board of Trustees of the University of Illinois. *
|
||
* All rights reserved. *
|
||
* *
|
||
* This file is part of HDF5. The full HDF5 copyright notice, including *
|
||
* terms governing use, modification, and redistribution, is contained in *
|
||
* the files COPYING and Copyright.html. COPYING can be found at the root *
|
||
* of the source code distribution tree; Copyright.html can be found at the *
|
||
* root level of an installed copy of the electronic HDF5 document set and *
|
||
* is linked from the top-level documents page. It can also be found at *
|
||
* http://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html. If you do not have *
|
||
* access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu. *
|
||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||
|
||
/*
|
||
* Programmer: Robb Matzke <matzke@llnl.gov>
|
||
* Friday, October 10, 1997
|
||
*/
|
||
|
||
|
||
#include "H5private.h"
|
||
#include "H5Eprivate.h"
|
||
#include "H5Oprivate.h"
|
||
#include "H5Vprivate.h"
|
||
|
||
/* Local macros */
|
||
#define H5V_HYPER_NDIMS H5O_LAYOUT_NDIMS
|
||
|
||
/* Local prototypes */
|
||
static void
|
||
H5V_stride_optimize1(unsigned *np/*in,out*/, hsize_t *elmt_size/*in,out*/,
|
||
const hsize_t *size, hsize_t *stride1);
|
||
static void
|
||
H5V_stride_optimize2(unsigned *np/*in,out*/, hsize_t *elmt_size/*in,out*/,
|
||
const hsize_t *size, hsize_t *stride1, hsize_t *stride2);
|
||
#ifdef LATER
|
||
static void
|
||
H5V_stride_copy2(hsize_t nelmts, hsize_t elmt_size,
|
||
unsigned dst_n, const hsize_t *dst_size, const ssize_t *dst_stride, void *_dst,
|
||
unsigned src_n, const hsize_t *src_size, const ssize_t *src_stride, const void *_src);
|
||
#endif /* LATER */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5V_stride_optimize1
|
||
*
|
||
* Purpose: Given a stride vector which references elements of the
|
||
* specified size, optimize the dimensionality, the stride
|
||
* vector, and the element size to minimize the dimensionality
|
||
* and the number of memory accesses.
|
||
*
|
||
* All arguments are passed by reference and their values may be
|
||
* modified by this function.
|
||
*
|
||
* Return: None
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* Saturday, October 11, 1997
|
||
*
|
||
* Modifications:
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
static void
|
||
H5V_stride_optimize1(unsigned *np/*in,out*/, hsize_t *elmt_size/*in,out*/,
|
||
const hsize_t *size, hsize_t *stride1)
|
||
{
|
||
FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5V_stride_optimize1);
|
||
|
||
/*
|
||
* This has to be true because if we optimize the dimensionality down to
|
||
* zero we still must make one reference.
|
||
*/
|
||
assert(1 == H5V_vector_reduce_product(0, NULL));
|
||
|
||
/*
|
||
* Combine adjacent memory accesses
|
||
*/
|
||
while (*np && stride1[*np-1]>0 &&
|
||
(hsize_t)(stride1[*np-1])==*elmt_size) {
|
||
*elmt_size *= size[*np-1];
|
||
if (--*np)
|
||
stride1[*np-1] += size[*np] * stride1[*np];
|
||
}
|
||
|
||
FUNC_LEAVE_NOAPI_VOID
|
||
}
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5V_stride_optimize2
|
||
*
|
||
* Purpose: Given two stride vectors which reference elements of the
|
||
* specified size, optimize the dimensionality, the stride
|
||
* vectors, and the element size to minimize the dimensionality
|
||
* and the number of memory accesses.
|
||
*
|
||
* All arguments are passed by reference and their values may be
|
||
* modified by this function.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* Saturday, October 11, 1997
|
||
*
|
||
* Modifications:
|
||
* Unrolled loops for common cases
|
||
* Quincey Koziol
|
||
* ?, ? ?, 2001?
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
static void
|
||
H5V_stride_optimize2(unsigned *np/*in,out*/, hsize_t *elmt_size/*in,out*/,
|
||
const hsize_t *size, hsize_t *stride1, hsize_t *stride2)
|
||
{
|
||
FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5V_stride_optimize2)
|
||
|
||
/*
|
||
* This has to be true because if we optimize the dimensionality down to
|
||
* zero we still must make one reference.
|
||
*/
|
||
assert(1 == H5V_vector_reduce_product(0, NULL));
|
||
assert (*elmt_size>0);
|
||
|
||
/*
|
||
* Combine adjacent memory accesses
|
||
*/
|
||
|
||
/* Unroll loop for common cases */
|
||
switch(*np) {
|
||
case 1: /* For 0-D datasets (dunno if this ever gets used...) */
|
||
if(stride1[0] == *elmt_size && stride2[0] == *elmt_size) {
|
||
*elmt_size *= size[0];
|
||
--*np; /* *np decrements to a value of 0 now */
|
||
} /* end if */
|
||
break;
|
||
|
||
case 2: /* For 1-D datasets */
|
||
if(stride1[1] == *elmt_size && stride2[1] == *elmt_size) {
|
||
*elmt_size *= size[1];
|
||
--*np; /* *np decrements to a value of 1 now */
|
||
stride1[0] += size[1] * stride1[1];
|
||
stride2[0] += size[1] * stride2[1];
|
||
|
||
if(stride1[0] == *elmt_size && stride2[0] == *elmt_size) {
|
||
*elmt_size *= size[0];
|
||
--*np; /* *np decrements to a value of 0 now */
|
||
} /* end if */
|
||
} /* end if */
|
||
break;
|
||
|
||
case 3: /* For 2-D datasets */
|
||
if(stride1[2] == *elmt_size && stride2[2] == *elmt_size) {
|
||
*elmt_size *= size[2];
|
||
--*np; /* *np decrements to a value of 2 now */
|
||
stride1[1] += size[2] * stride1[2];
|
||
stride2[1] += size[2] * stride2[2];
|
||
|
||
if(stride1[1] == *elmt_size && stride2[1] == *elmt_size) {
|
||
*elmt_size *= size[1];
|
||
--*np; /* *np decrements to a value of 1 now */
|
||
stride1[0] += size[1] * stride1[1];
|
||
stride2[0] += size[1] * stride2[1];
|
||
|
||
if(stride1[0] == *elmt_size && stride2[0] == *elmt_size) {
|
||
*elmt_size *= size[0];
|
||
--*np; /* *np decrements to a value of 0 now */
|
||
} /* end if */
|
||
} /* end if */
|
||
} /* end if */
|
||
break;
|
||
|
||
case 4: /* For 3-D datasets */
|
||
if(stride1[3] == *elmt_size && stride2[3] == *elmt_size) {
|
||
*elmt_size *= size[3];
|
||
--*np; /* *np decrements to a value of 3 now */
|
||
stride1[2] += size[3] * stride1[3];
|
||
stride2[2] += size[3] * stride2[3];
|
||
|
||
if(stride1[2] == *elmt_size && stride2[2] == *elmt_size) {
|
||
*elmt_size *= size[2];
|
||
--*np; /* *np decrements to a value of 2 now */
|
||
stride1[1] += size[2] * stride1[2];
|
||
stride2[1] += size[2] * stride2[2];
|
||
|
||
if(stride1[1] == *elmt_size && stride2[1] == *elmt_size) {
|
||
*elmt_size *= size[1];
|
||
--*np; /* *np decrements to a value of 1 now */
|
||
stride1[0] += size[1] * stride1[1];
|
||
stride2[0] += size[1] * stride2[1];
|
||
|
||
if(stride1[0] == *elmt_size && stride2[0] == *elmt_size) {
|
||
*elmt_size *= size[0];
|
||
--*np; /* *np decrements to a value of 0 now */
|
||
} /* end if */
|
||
} /* end if */
|
||
} /* end if */
|
||
} /* end if */
|
||
break;
|
||
|
||
default:
|
||
while (*np &&
|
||
stride1[*np-1] == *elmt_size &&
|
||
stride2[*np-1] == *elmt_size) {
|
||
*elmt_size *= size[*np-1];
|
||
if (--*np) {
|
||
stride1[*np-1] += size[*np] * stride1[*np];
|
||
stride2[*np-1] += size[*np] * stride2[*np];
|
||
}
|
||
}
|
||
break;
|
||
} /* end switch */
|
||
|
||
FUNC_LEAVE_NOAPI_VOID
|
||
}
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5V_hyper_stride
|
||
*
|
||
* Purpose: Given a description of a hyperslab, this function returns
|
||
* (through STRIDE[]) the byte strides appropriate for accessing
|
||
* all bytes of the hyperslab and the byte offset where the
|
||
* striding will begin. The SIZE can be passed to the various
|
||
* stride functions.
|
||
*
|
||
* The dimensionality of the whole array, the hyperslab, and the
|
||
* returned stride array is N. The whole array dimensions are
|
||
* TOTAL_SIZE and the hyperslab is at offset OFFSET and has
|
||
* dimensions SIZE.
|
||
*
|
||
* The stride and starting point returned will cause the
|
||
* hyperslab elements to be referenced in C order.
|
||
*
|
||
* Return: Success: Byte offset from beginning of array to start
|
||
* of striding.
|
||
*
|
||
* Failure: abort() -- should never fail
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* Saturday, October 11, 1997
|
||
*
|
||
* Modifications:
|
||
* Unrolled loops for common cases
|
||
* Quincey Koziol
|
||
* ?, ? ?, 2001?
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
hsize_t
|
||
H5V_hyper_stride(unsigned n, const hsize_t *size,
|
||
const hsize_t *total_size, const hsize_t *offset,
|
||
hsize_t *stride/*out*/)
|
||
{
|
||
hsize_t skip; /*starting point byte offset */
|
||
hsize_t acc; /*accumulator */
|
||
int i; /*counter */
|
||
hsize_t ret_value; /* Return value */
|
||
|
||
FUNC_ENTER_NOAPI_NOFUNC(H5V_hyper_stride)
|
||
|
||
assert(n <= H5V_HYPER_NDIMS);
|
||
assert(size);
|
||
assert(total_size);
|
||
assert(stride);
|
||
|
||
/* init */
|
||
assert(n>0);
|
||
stride[n-1] = 1;
|
||
skip = offset ? offset[n-1] : 0;
|
||
|
||
switch(n) {
|
||
case 2: /* 1-D dataset */
|
||
assert (total_size[1]>=size[1]);
|
||
stride[0] = total_size[1]-size[1]; /*overflow checked*/
|
||
acc = total_size[1];
|
||
skip += acc * (offset ? offset[0] : 0);
|
||
break;
|
||
|
||
case 3: /* 2-D dataset */
|
||
assert (total_size[2]>=size[2]);
|
||
stride[1] = total_size[2]-size[2]; /*overflow checked*/
|
||
acc = total_size[2];
|
||
skip += acc * (offset ? (hsize_t)offset[1] : 0);
|
||
|
||
assert (total_size[1]>=size[1]);
|
||
stride[0] = acc * (total_size[1] - size[1]); /*overflow checked*/
|
||
acc *= total_size[1];
|
||
skip += acc * (offset ? (hsize_t)offset[0] : 0);
|
||
break;
|
||
|
||
case 4: /* 3-D dataset */
|
||
assert (total_size[3]>=size[3]);
|
||
stride[2] = total_size[3]-size[3]; /*overflow checked*/
|
||
acc = total_size[3];
|
||
skip += acc * (offset ? (hsize_t)offset[2] : 0);
|
||
|
||
assert (total_size[2]>=size[2]);
|
||
stride[1] = acc * (total_size[2] - size[2]); /*overflow checked*/
|
||
acc *= total_size[2];
|
||
skip += acc * (offset ? (hsize_t)offset[1] : 0);
|
||
|
||
assert (total_size[1]>=size[1]);
|
||
stride[0] = acc * (total_size[1] - size[1]); /*overflow checked*/
|
||
acc *= total_size[1];
|
||
skip += acc * (offset ? (hsize_t)offset[0] : 0);
|
||
break;
|
||
|
||
default:
|
||
/* others */
|
||
for (i=(int)(n-2), acc=1; i>=0; --i) {
|
||
assert (total_size[i+1]>=size[i+1]);
|
||
stride[i] = acc * (total_size[i+1] - size[i+1]); /*overflow checked*/
|
||
acc *= total_size[i+1];
|
||
skip += acc * (offset ? (hsize_t)offset[i] : 0);
|
||
}
|
||
break;
|
||
} /* end switch */
|
||
|
||
/* Set return value */
|
||
ret_value=skip;
|
||
|
||
FUNC_LEAVE_NOAPI(ret_value)
|
||
}
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5V_hyper_eq
|
||
*
|
||
* Purpose: Determines whether two hyperslabs are equal. This function
|
||
* assumes that both hyperslabs are relative to the same array,
|
||
* for if not, they could not possibly be equal.
|
||
*
|
||
* Return: Success: TRUE if the hyperslabs are equal (that is,
|
||
* both refer to exactly the same elements of an
|
||
* array)
|
||
*
|
||
* FALSE otherwise.
|
||
*
|
||
* Failure: TRUE the rank is zero or if both hyperslabs
|
||
* are of zero size.
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* Friday, October 17, 1997
|
||
*
|
||
* Modifications:
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
htri_t
|
||
H5V_hyper_eq(unsigned n,
|
||
const hsize_t *offset1, const hsize_t *size1,
|
||
const hsize_t *offset2, const hsize_t *size2)
|
||
{
|
||
hsize_t nelmts1 = 1, nelmts2 = 1;
|
||
unsigned i;
|
||
htri_t ret_value=TRUE; /* Return value */
|
||
|
||
/* Use FUNC_ENTER_NOAPI_NOINIT_NOFUNC here to avoid performance issues */
|
||
FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5V_hyper_eq)
|
||
|
||
if (n == 0) HGOTO_DONE(TRUE)
|
||
|
||
for (i=0; i<n; i++) {
|
||
if ((offset1 ? offset1[i] : 0) != (offset2 ? offset2[i] : 0))
|
||
HGOTO_DONE(FALSE)
|
||
if ((size1 ? size1[i] : 0) != (size2 ? size2[i] : 0))
|
||
HGOTO_DONE(FALSE)
|
||
if (0 == (nelmts1 *= (size1 ? size1[i] : 0)))
|
||
HGOTO_DONE(FALSE)
|
||
if (0 == (nelmts2 *= (size2 ? size2[i] : 0)))
|
||
HGOTO_DONE(FALSE)
|
||
}
|
||
|
||
done:
|
||
FUNC_LEAVE_NOAPI(ret_value)
|
||
}
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5V_hyper_disjointp
|
||
*
|
||
* Purpose: Determines if two hyperslabs are disjoint.
|
||
*
|
||
* Return: Success: FALSE if they are not disjoint.
|
||
* TRUE if they are disjoint.
|
||
*
|
||
* Failure: A hyperslab of zero size is disjoint from all
|
||
* other hyperslabs.
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* Thursday, October 16, 1997
|
||
*
|
||
* Modifications:
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
htri_t
|
||
H5V_hyper_disjointp(unsigned n,
|
||
const hsize_t *offset1, const size_t *size1,
|
||
const hsize_t *offset2, const size_t *size2)
|
||
{
|
||
unsigned u;
|
||
htri_t ret_value=FALSE; /* Return value */
|
||
|
||
/* Use FUNC_ENTER_NOAPI_NOINIT_NOFUNC here to avoid performance issues */
|
||
FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5V_hyper_disjointp)
|
||
|
||
if (!n || !size1 || !size2) HGOTO_DONE(TRUE)
|
||
|
||
for (u=0; u<n; u++) {
|
||
assert (size1[u]<HSIZET_MAX);
|
||
assert (size2[u]<HSIZET_MAX);
|
||
|
||
if (0==size1[u] || 0==size2[u])
|
||
HGOTO_DONE(TRUE)
|
||
if (((offset1?offset1[u]:0) < (offset2?offset2[u]:0) &&
|
||
((offset1?offset1[u]:0) + size1[u] <= (offset2?offset2[u]:0))) ||
|
||
((offset2?offset2[u]:0) < (offset1?offset1[u]:0) &&
|
||
((offset2?offset2[u]:0) + size2[u] <= (offset1?offset1[u]:0))))
|
||
HGOTO_DONE(TRUE)
|
||
}
|
||
|
||
done:
|
||
FUNC_LEAVE_NOAPI(ret_value)
|
||
}
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5V_hyper_fill
|
||
*
|
||
* Purpose: Similar to memset() except it operates on hyperslabs...
|
||
*
|
||
* Fills a hyperslab of array BUF with some value VAL. BUF
|
||
* is treated like a C-order array with N dimensions where the
|
||
* size of each dimension is TOTAL_SIZE[]. The hyperslab which
|
||
* will be filled with VAL begins at byte offset OFFSET[] from
|
||
* the minimum corner of BUF and continues for SIZE[] bytes in
|
||
* each dimension.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* Friday, October 10, 1997
|
||
*
|
||
* Modifications:
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5V_hyper_fill(unsigned n, const hsize_t *_size,
|
||
const hsize_t *total_size, const hsize_t *offset, void *_dst,
|
||
unsigned fill_value)
|
||
{
|
||
uint8_t *dst = (uint8_t*)_dst; /*cast for ptr arithmetic */
|
||
hsize_t size[H5V_HYPER_NDIMS]; /*a modifiable copy of _size */
|
||
hsize_t dst_stride[H5V_HYPER_NDIMS]; /*destination stride info */
|
||
hsize_t dst_start; /*byte offset to start of stride*/
|
||
hsize_t elmt_size = 1; /*bytes per element */
|
||
herr_t ret_value; /*function return status */
|
||
#ifndef NDEBUG
|
||
unsigned u;
|
||
#endif
|
||
|
||
FUNC_ENTER_NOAPI_NOFUNC(H5V_hyper_fill)
|
||
|
||
/* check args */
|
||
assert(n > 0 && n <= H5V_HYPER_NDIMS);
|
||
assert(_size);
|
||
assert(total_size);
|
||
assert(dst);
|
||
#ifndef NDEBUG
|
||
for (u = 0; u < n; u++) {
|
||
assert(_size[u] > 0);
|
||
assert(total_size[u] > 0);
|
||
}
|
||
#endif
|
||
|
||
/* Copy the size vector so we can modify it */
|
||
H5V_vector_cpy(n, size, _size);
|
||
|
||
/* Compute an optimal destination stride vector */
|
||
dst_start = H5V_hyper_stride(n, size, total_size, offset, dst_stride);
|
||
H5V_stride_optimize1(&n, &elmt_size, size, dst_stride);
|
||
|
||
/* Copy */
|
||
ret_value = H5V_stride_fill(n, elmt_size, size, dst_stride, dst+dst_start,
|
||
fill_value);
|
||
|
||
FUNC_LEAVE_NOAPI(ret_value)
|
||
}
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5V_hyper_copy
|
||
*
|
||
* Purpose: Copies a hyperslab from the source to the destination.
|
||
*
|
||
* A hyperslab is a logically contiguous region of
|
||
* multi-dimensional size SIZE of an array whose dimensionality
|
||
* is N and whose total size is DST_TOTAL_SIZE or SRC_TOTAL_SIZE.
|
||
* The minimum corner of the hyperslab begins at a
|
||
* multi-dimensional offset from the minimum corner of the DST
|
||
* (destination) or SRC (source) array. The sizes and offsets
|
||
* are assumed to be in C order, that is, the first size/offset
|
||
* varies the slowest while the last varies the fastest in the
|
||
* mapping from N-dimensional space to linear space. This
|
||
* function assumes that the array elements are single bytes (if
|
||
* your array has multi-byte elements then add an additional
|
||
* dimension whose size is that of your element).
|
||
*
|
||
* The SRC and DST array may be the same array, but the results
|
||
* are undefined if the source hyperslab overlaps the
|
||
* destination hyperslab.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* Friday, October 10, 1997
|
||
*
|
||
* Modifications:
|
||
* Unrolled loops for common cases
|
||
* Quincey Koziol
|
||
* ?, ? ?, 2001?
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5V_hyper_copy(unsigned n, const hsize_t *_size,
|
||
|
||
/*destination*/
|
||
const hsize_t *dst_size, const hsize_t *dst_offset,
|
||
void *_dst,
|
||
|
||
/*source*/
|
||
const hsize_t *src_size, const hsize_t *src_offset,
|
||
const void *_src)
|
||
{
|
||
const uint8_t *src = (const uint8_t*)_src; /*cast for ptr arithmtc */
|
||
uint8_t *dst = (uint8_t*) _dst; /*cast for ptr arithmtc */
|
||
hsize_t size[H5V_HYPER_NDIMS]; /*a modifiable _size */
|
||
hsize_t src_stride[H5V_HYPER_NDIMS]; /*source stride info */
|
||
hsize_t dst_stride[H5V_HYPER_NDIMS]; /*dest stride info */
|
||
hsize_t dst_start, src_start; /*offset to start at */
|
||
hsize_t elmt_size = 1; /*element size in bytes */
|
||
herr_t ret_value; /*return status */
|
||
#ifndef NDEBUG
|
||
unsigned u;
|
||
#endif
|
||
|
||
FUNC_ENTER_NOAPI_NOFUNC(H5V_hyper_copy)
|
||
|
||
/* check args */
|
||
assert(n > 0 && n <= H5V_HYPER_NDIMS);
|
||
assert(_size);
|
||
assert(dst_size);
|
||
assert(src_size);
|
||
assert(dst);
|
||
assert(src);
|
||
#ifndef NDEBUG
|
||
for (u = 0; u < n; u++) {
|
||
assert(_size[u] > 0);
|
||
assert(dst_size[u] > 0);
|
||
assert(src_size[u] > 0);
|
||
}
|
||
#endif
|
||
|
||
/* Copy the size vector so we can modify it */
|
||
H5V_vector_cpy(n, size, _size);
|
||
|
||
/* Compute stride vectors for source and destination */
|
||
#ifdef NO_INLINED_CODE
|
||
dst_start = H5V_hyper_stride(n, size, dst_size, dst_offset, dst_stride);
|
||
src_start = H5V_hyper_stride(n, size, src_size, src_offset, src_stride);
|
||
#else /* NO_INLINED_CODE */
|
||
/* in-line version of two calls to H5V_hyper_stride() */
|
||
{
|
||
hsize_t dst_acc; /*accumulator */
|
||
hsize_t src_acc; /*accumulator */
|
||
int ii; /*counter */
|
||
|
||
/* init */
|
||
assert(n>0);
|
||
dst_stride[n-1] = 1;
|
||
src_stride[n-1] = 1;
|
||
dst_start = dst_offset ? dst_offset[n-1] : 0;
|
||
src_start = src_offset ? src_offset[n-1] : 0;
|
||
|
||
/* Unroll loop for common cases */
|
||
switch(n) {
|
||
case 2:
|
||
assert (dst_size[1]>=size[1]);
|
||
assert (src_size[1]>=size[1]);
|
||
dst_stride[0] = dst_size[1] - size[1]; /*overflow checked*/
|
||
src_stride[0] = src_size[1] - size[1]; /*overflow checked*/
|
||
dst_acc = dst_size[1];
|
||
src_acc = src_size[1];
|
||
dst_start += dst_acc * (dst_offset ? dst_offset[0] : 0);
|
||
src_start += src_acc * (src_offset ? src_offset[0] : 0);
|
||
break;
|
||
|
||
case 3:
|
||
assert (dst_size[2]>=size[2]);
|
||
assert (src_size[2]>=size[2]);
|
||
dst_stride[1] = dst_size[2] - size[2]; /*overflow checked*/
|
||
src_stride[1] = src_size[2] - size[2]; /*overflow checked*/
|
||
dst_acc = dst_size[2];
|
||
src_acc = src_size[2];
|
||
dst_start += dst_acc * (dst_offset ? dst_offset[1] : 0);
|
||
src_start += src_acc * (src_offset ? src_offset[1] : 0);
|
||
|
||
assert (dst_size[1]>=size[1]);
|
||
assert (src_size[1]>=size[1]);
|
||
dst_stride[0] = dst_acc * (dst_size[1] - size[1]); /*overflow checked*/
|
||
src_stride[0] = src_acc * (src_size[1] - size[1]); /*overflow checked*/
|
||
dst_acc *= dst_size[1];
|
||
src_acc *= src_size[1];
|
||
dst_start += dst_acc * (dst_offset ? dst_offset[0] : 0);
|
||
src_start += src_acc * (src_offset ? src_offset[0] : 0);
|
||
break;
|
||
|
||
case 4:
|
||
assert (dst_size[3]>=size[3]);
|
||
assert (src_size[3]>=size[3]);
|
||
dst_stride[2] = dst_size[3] - size[3]; /*overflow checked*/
|
||
src_stride[2] = src_size[3] - size[3]; /*overflow checked*/
|
||
dst_acc = dst_size[3];
|
||
src_acc = src_size[3];
|
||
dst_start += dst_acc * (dst_offset ? dst_offset[2] : 0);
|
||
src_start += src_acc * (src_offset ? src_offset[2] : 0);
|
||
|
||
assert (dst_size[2]>=size[2]);
|
||
assert (src_size[2]>=size[2]);
|
||
dst_stride[1] = dst_acc * (dst_size[2] - size[2]); /*overflow checked*/
|
||
src_stride[1] = src_acc * (src_size[2] - size[2]); /*overflow checked*/
|
||
dst_acc *= dst_size[2];
|
||
src_acc *= src_size[2];
|
||
dst_start += dst_acc * (dst_offset ? dst_offset[1] : 0);
|
||
src_start += src_acc * (src_offset ? src_offset[1] : 0);
|
||
|
||
assert (dst_size[1]>=size[1]);
|
||
assert (src_size[1]>=size[1]);
|
||
dst_stride[0] = dst_acc * (dst_size[1] - size[1]); /*overflow checked*/
|
||
src_stride[0] = src_acc * (src_size[1] - size[1]); /*overflow checked*/
|
||
dst_acc *= dst_size[1];
|
||
src_acc *= src_size[1];
|
||
dst_start += dst_acc * (dst_offset ? dst_offset[0] : 0);
|
||
src_start += src_acc * (src_offset ? src_offset[0] : 0);
|
||
break;
|
||
|
||
default:
|
||
/* others */
|
||
for (ii=(int)(n-2), dst_acc=1, src_acc=1; ii>=0; --ii) {
|
||
assert (dst_size[ii+1]>=size[ii+1]);
|
||
assert (src_size[ii+1]>=size[ii+1]);
|
||
dst_stride[ii] = dst_acc * (dst_size[ii+1] - size[ii+1]); /*overflow checked*/
|
||
src_stride[ii] = src_acc * (src_size[ii+1] - size[ii+1]); /*overflow checked*/
|
||
dst_acc *= dst_size[ii+1];
|
||
src_acc *= src_size[ii+1];
|
||
dst_start += dst_acc * (dst_offset ? dst_offset[ii] : 0);
|
||
src_start += src_acc * (src_offset ? src_offset[ii] : 0);
|
||
}
|
||
break;
|
||
} /* end switch */
|
||
}
|
||
#endif /* NO_INLINED_CODE */
|
||
|
||
/* Optimize the strides as a pair */
|
||
H5V_stride_optimize2(&n, &elmt_size, size, dst_stride, src_stride);
|
||
|
||
/* Perform the copy in terms of stride */
|
||
ret_value = H5V_stride_copy(n, elmt_size, size,
|
||
dst_stride, dst+dst_start, src_stride, src+src_start);
|
||
|
||
FUNC_LEAVE_NOAPI(ret_value)
|
||
}
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5V_stride_fill
|
||
*
|
||
* Purpose: Fills all bytes of a hyperslab with the same value using
|
||
* memset().
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* Saturday, October 11, 1997
|
||
*
|
||
* Modifications:
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5V_stride_fill(unsigned n, hsize_t elmt_size, const hsize_t *size,
|
||
const hsize_t *stride, void *_dst, unsigned fill_value)
|
||
{
|
||
uint8_t *dst = (uint8_t*)_dst; /*cast for ptr arithmetic */
|
||
hsize_t idx[H5V_HYPER_NDIMS]; /*1-origin indices */
|
||
hsize_t nelmts; /*number of elements to fill */
|
||
hsize_t i; /*counter */
|
||
int j; /*counter */
|
||
hbool_t carry; /*subtraction carray value */
|
||
|
||
FUNC_ENTER_NOAPI_NOFUNC(H5V_stride_fill)
|
||
assert (elmt_size < SIZET_MAX);
|
||
|
||
H5V_vector_cpy(n, idx, size);
|
||
nelmts = H5V_vector_reduce_product(n, size);
|
||
for (i=0; i<nelmts; i++) {
|
||
/* Copy an element */
|
||
H5_CHECK_OVERFLOW(elmt_size,hsize_t,size_t);
|
||
HDmemset(dst, (int)fill_value, (size_t)elmt_size); /*lint !e671 The elmt_size will be OK */
|
||
|
||
/* Decrement indices and advance pointer */
|
||
for (j=(int)(n-1), carry=TRUE; j>=0 && carry; --j) {
|
||
dst += stride[j];
|
||
|
||
if (--idx[j])
|
||
carry = FALSE;
|
||
else {
|
||
assert(size);
|
||
idx[j] = size[j];
|
||
} /* end else */
|
||
}
|
||
}
|
||
|
||
FUNC_LEAVE_NOAPI(SUCCEED)
|
||
}
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5V_stride_copy
|
||
*
|
||
* Purpose: Uses DST_STRIDE and SRC_STRIDE to advance through the arrays
|
||
* DST and SRC while copying bytes from SRC to DST. This
|
||
* function minimizes the number of calls to memcpy() by
|
||
* combining various strides, but it will never touch memory
|
||
* outside the hyperslab defined by the strides.
|
||
*
|
||
* Note: If the src_stride is all zero and elmt_size is one, then it's
|
||
* probably more efficient to use H5V_stride_fill() instead.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* Saturday, October 11, 1997
|
||
*
|
||
* Modifications:
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5V_stride_copy(unsigned n, hsize_t elmt_size, const hsize_t *size,
|
||
const hsize_t *dst_stride, void *_dst,
|
||
const hsize_t *src_stride, const void *_src)
|
||
{
|
||
uint8_t *dst = (uint8_t*)_dst; /*cast for ptr arithmetic*/
|
||
const uint8_t *src = (const uint8_t*) _src; /*cast for ptr arithmetic*/
|
||
hsize_t idx[H5V_HYPER_NDIMS]; /*1-origin indices */
|
||
hsize_t nelmts; /*num elements to copy */
|
||
hsize_t i; /*counter */
|
||
int j; /*counters */
|
||
hbool_t carry; /*carray for subtraction*/
|
||
|
||
FUNC_ENTER_NOAPI_NOFUNC(H5V_stride_copy)
|
||
assert (elmt_size<SIZET_MAX);
|
||
|
||
if (n) {
|
||
H5V_vector_cpy(n, idx, size);
|
||
nelmts = H5V_vector_reduce_product(n, size);
|
||
for (i=0; i<nelmts; i++) {
|
||
|
||
/* Copy an element */
|
||
H5_CHECK_OVERFLOW(elmt_size,hsize_t,size_t);
|
||
HDmemcpy(dst, src, (size_t)elmt_size); /*lint !e671 The elmt_size will be OK */
|
||
|
||
/* Decrement indices and advance pointers */
|
||
for (j=(int)(n-1), carry=TRUE; j>=0 && carry; --j) {
|
||
src += src_stride[j];
|
||
dst += dst_stride[j];
|
||
|
||
if (--idx[j])
|
||
carry = FALSE;
|
||
else {
|
||
assert(size);
|
||
idx[j] = size[j];
|
||
}
|
||
}
|
||
}
|
||
} else {
|
||
H5_CHECK_OVERFLOW(elmt_size,hsize_t,size_t);
|
||
HDmemcpy (dst, src, (size_t)elmt_size); /*lint !e671 The elmt_size will be OK */
|
||
}
|
||
|
||
FUNC_LEAVE_NOAPI(SUCCEED)
|
||
}
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5V_stride_copy_s
|
||
*
|
||
* Purpose: Uses DST_STRIDE and SRC_STRIDE to advance through the arrays
|
||
* DST and SRC while copying bytes from SRC to DST. This
|
||
* function minimizes the number of calls to memcpy() by
|
||
* combining various strides, but it will never touch memory
|
||
* outside the hyperslab defined by the strides.
|
||
*
|
||
* Note: If the src_stride is all zero and elmt_size is one, then it's
|
||
* probably more efficient to use H5V_stride_fill() instead.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* Saturday, October 11, 1997
|
||
*
|
||
* Modifications:
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5V_stride_copy_s(unsigned n, hsize_t elmt_size, const hsize_t *size,
|
||
const hssize_t *dst_stride, void *_dst,
|
||
const hssize_t *src_stride, const void *_src)
|
||
{
|
||
uint8_t *dst = (uint8_t*)_dst; /*cast for ptr arithmetic*/
|
||
const uint8_t *src = (const uint8_t*) _src; /*cast for ptr arithmetic*/
|
||
hsize_t idx[H5V_HYPER_NDIMS]; /*1-origin indices */
|
||
hsize_t nelmts; /*num elements to copy */
|
||
hsize_t i; /*counter */
|
||
int j; /*counters */
|
||
hbool_t carry; /*carray for subtraction*/
|
||
|
||
FUNC_ENTER_NOAPI_NOFUNC(H5V_stride_copy_s)
|
||
assert (elmt_size<SIZET_MAX);
|
||
|
||
if (n) {
|
||
H5V_vector_cpy(n, idx, size);
|
||
nelmts = H5V_vector_reduce_product(n, size);
|
||
for (i=0; i<nelmts; i++) {
|
||
|
||
/* Copy an element */
|
||
H5_CHECK_OVERFLOW(elmt_size,hsize_t,size_t);
|
||
HDmemcpy(dst, src, (size_t)elmt_size); /*lint !e671 The elmt_size will be OK */
|
||
|
||
/* Decrement indices and advance pointers */
|
||
for (j=(int)(n-1), carry=TRUE; j>=0 && carry; --j) {
|
||
src += src_stride[j];
|
||
dst += dst_stride[j];
|
||
|
||
if (--idx[j])
|
||
carry = FALSE;
|
||
else {
|
||
assert(size);
|
||
idx[j] = size[j];
|
||
}
|
||
}
|
||
}
|
||
} else {
|
||
H5_CHECK_OVERFLOW(elmt_size,hsize_t,size_t);
|
||
HDmemcpy (dst, src, (size_t)elmt_size); /*lint !e671 The elmt_size will be OK */
|
||
}
|
||
|
||
FUNC_LEAVE_NOAPI(SUCCEED)
|
||
}
|
||
|
||
#ifdef LATER
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5V_stride_copy2
|
||
*
|
||
* Purpose: Similar to H5V_stride_copy() except the source and
|
||
* destination each have their own dimensionality and size and
|
||
* we copy exactly NELMTS elements each of size ELMT_SIZE. The
|
||
* size counters wrap if NELMTS is more than a size counter.
|
||
*
|
||
* Return: None
|
||
*
|
||
* Programmer: Robb Matzke
|
||
* Saturday, October 11, 1997
|
||
*
|
||
* Modifications:
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
static void
|
||
H5V_stride_copy2(hsize_t nelmts, hsize_t elmt_size,
|
||
|
||
/* destination */
|
||
unsigned dst_n, const hsize_t *dst_size,
|
||
const hsize_t *dst_stride,
|
||
void *_dst,
|
||
|
||
/* source */
|
||
unsigned src_n, const hsize_t *src_size,
|
||
const hsize_t *src_stride,
|
||
const void *_src)
|
||
{
|
||
uint8_t *dst = (uint8_t *) _dst;
|
||
const uint8_t *src = (const uint8_t *) _src;
|
||
hsize_t dst_idx[H5V_HYPER_NDIMS];
|
||
hsize_t src_idx[H5V_HYPER_NDIMS];
|
||
hsize_t i; /* Local index variable */
|
||
int j; /* Local index variable */
|
||
hbool_t carry;
|
||
|
||
FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5V_stride_copy2)
|
||
|
||
assert (elmt_size < SIZET_MAX);
|
||
assert(dst_n>0);
|
||
assert(src_n>0);
|
||
|
||
H5V_vector_cpy(dst_n, dst_idx, dst_size);
|
||
H5V_vector_cpy(src_n, src_idx, src_size);
|
||
|
||
for (i=0; i<nelmts; i++) {
|
||
|
||
/* Copy an element */
|
||
H5_CHECK_OVERFLOW(elmt_size,hsize_t,size_t);
|
||
HDmemcpy(dst, src, (size_t)elmt_size); /*lint !e671 The elmt_size will be OK */
|
||
|
||
/* Decrement indices and advance pointers */
|
||
for (j=(int)(dst_n-1), carry=TRUE; j>=0 && carry; --j) {
|
||
dst += dst_stride[j];
|
||
if (--dst_idx[j])
|
||
carry = FALSE;
|
||
else {
|
||
assert(dst_size);
|
||
dst_idx[j] = dst_size[j];
|
||
} /* end else */
|
||
}
|
||
for (j=(int)(src_n-1), carry=TRUE; j>=0 && carry; --j) {
|
||
src += src_stride[j];
|
||
if (--src_idx[j])
|
||
carry = FALSE;
|
||
else {
|
||
assert(src_size);
|
||
src_idx[j] = src_size[j];
|
||
} /* end else */
|
||
}
|
||
}
|
||
|
||
FUNC_LEAVE_NOAPI_VOID
|
||
}
|
||
#endif /* LATER */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5V_array_fill
|
||
*
|
||
* Purpose: Fills all bytes of an array with the same value using
|
||
* memset(). Increases amount copied by power of two until the
|
||
* halfway point is crossed, then copies the rest in one swoop.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Quincey Koziol
|
||
* Thursday, June 18, 1998
|
||
*
|
||
* Modifications:
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5V_array_fill(void *_dst, const void *src, size_t size, size_t count)
|
||
{
|
||
size_t copy_size; /* size of the buffer to copy */
|
||
size_t copy_items; /* number of items currently copying*/
|
||
size_t items_left; /* number of items left to copy */
|
||
uint8_t *dst=(uint8_t*)_dst;/* alias for pointer arithmetic */
|
||
|
||
FUNC_ENTER_NOAPI_NOFUNC(H5V_array_fill)
|
||
|
||
assert (dst);
|
||
assert (src);
|
||
assert (size < SIZET_MAX && size > 0);
|
||
assert (count < SIZET_MAX && count > 0);
|
||
|
||
HDmemcpy(dst, src, size); /* copy first item */
|
||
|
||
/* Initialize counters, etc. while compensating for first element copied */
|
||
copy_size = size;
|
||
copy_items = 1;
|
||
items_left = count - 1;
|
||
dst += size;
|
||
|
||
/* copy until we've copied at least half of the items */
|
||
while (items_left >= copy_items)
|
||
{
|
||
HDmemcpy(dst, _dst, copy_size); /* copy the current chunk */
|
||
dst += copy_size; /* move the offset for the next chunk */
|
||
items_left -= copy_items; /* decrement the number of items left */
|
||
|
||
copy_size *= 2; /* increase the size of the chunk to copy */
|
||
copy_items *= 2; /* increase the count of items we are copying */
|
||
} /* end while */
|
||
if (items_left > 0) /* if there are any items left to copy */
|
||
HDmemcpy(dst, _dst, items_left * size);
|
||
|
||
FUNC_LEAVE_NOAPI(SUCCEED)
|
||
} /* H5V_array_fill() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5V_array_down
|
||
*
|
||
* Purpose: Given a set of dimension sizes, calculate the size of each
|
||
* "down" slice. This is the size of the dimensions for all the
|
||
* dimensions below the current one, which is used for indexing
|
||
* offsets in this dimension.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Quincey Koziol
|
||
* Monday, April 28, 2003
|
||
*
|
||
* Modifications:
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5V_array_down(unsigned n, const hsize_t *total_size, hsize_t *down)
|
||
{
|
||
hsize_t acc; /*accumulator */
|
||
int i; /*counter */
|
||
|
||
FUNC_ENTER_NOAPI_NOFUNC(H5V_array_down)
|
||
|
||
assert(n <= H5V_HYPER_NDIMS);
|
||
assert(total_size);
|
||
assert(down);
|
||
|
||
/* Build the sizes of each dimension in the array */
|
||
/* (From fastest to slowest) */
|
||
for(i=(int)(n-1),acc=1; i>=0; i--) {
|
||
down[i]=acc;
|
||
acc *= total_size[i];
|
||
} /* end for */
|
||
|
||
FUNC_LEAVE_NOAPI(SUCCEED)
|
||
} /* end H5V_array_down() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5V_array_offset_pre
|
||
*
|
||
* Purpose: Given a coordinate description of a location in an array, this
|
||
* function returns the byte offset of the coordinate.
|
||
*
|
||
* The dimensionality of the whole array, and the offset is N.
|
||
* The whole array dimensions are TOTAL_SIZE and the coordinate
|
||
* is at offset OFFSET.
|
||
*
|
||
* Return: Success: Byte offset from beginning of array to element offset
|
||
* Failure: abort() -- should never fail
|
||
*
|
||
* Programmer: Quincey Koziol
|
||
* Tuesday, June 22, 1999
|
||
*
|
||
* Modifications:
|
||
* Use precomputed accumulator array
|
||
* Quincey Koziol
|
||
* Saturday, April 26, 2003
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
hsize_t
|
||
H5V_array_offset_pre(unsigned n, const hsize_t *acc, const hsize_t *offset)
|
||
{
|
||
int i; /*counter */
|
||
hsize_t ret_value; /* Return value */
|
||
|
||
FUNC_ENTER_NOAPI_NOFUNC(H5V_array_offset_pre)
|
||
|
||
assert(n <= H5V_HYPER_NDIMS);
|
||
assert(acc);
|
||
assert(offset);
|
||
|
||
/* Compute offset in array */
|
||
for (i=(int)(n-1), ret_value=0; i>=0; --i)
|
||
ret_value += acc[i] * offset[i];
|
||
|
||
FUNC_LEAVE_NOAPI(ret_value)
|
||
} /* end H5V_array_offset_pre() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5V_array_offset
|
||
*
|
||
* Purpose: Given a coordinate description of a location in an array, this
|
||
* function returns the byte offset of the coordinate.
|
||
*
|
||
* The dimensionality of the whole array, and the offset is N.
|
||
* The whole array dimensions are TOTAL_SIZE and the coordinate
|
||
* is at offset OFFSET.
|
||
*
|
||
* Return: Success: Byte offset from beginning of array to element offset
|
||
* Failure: abort() -- should never fail
|
||
*
|
||
* Programmer: Quincey Koziol
|
||
* Tuesday, June 22, 1999
|
||
*
|
||
* Modifications:
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
hsize_t
|
||
H5V_array_offset(unsigned n, const hsize_t *total_size, const hsize_t *offset)
|
||
{
|
||
hsize_t acc_arr[H5V_HYPER_NDIMS]; /* Accumulated size of down dimensions */
|
||
hsize_t ret_value; /* Return value */
|
||
|
||
FUNC_ENTER_NOAPI(H5V_array_offset, (HDabort(), 0)) /*lint !e527 Don't worry about unreachable statement */
|
||
|
||
assert(n <= H5V_HYPER_NDIMS);
|
||
assert(total_size);
|
||
assert(offset);
|
||
|
||
/* Build the sizes of each dimension in the array */
|
||
if(H5V_array_down(n,total_size,acc_arr)<0)
|
||
HGOTO_ERROR(H5E_INTERNAL, H5E_BADVALUE, UFAIL, "can't compute down sizes")
|
||
|
||
/* Set return value */
|
||
ret_value=H5V_array_offset_pre(n,acc_arr,offset);
|
||
|
||
done:
|
||
FUNC_LEAVE_NOAPI(ret_value)
|
||
} /* end H5V_array_offset() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5V_array_calc
|
||
*
|
||
* Purpose: Given a linear offset in an array and the dimensions of that
|
||
* array, this function computes the coordinates of that offset
|
||
* in the array.
|
||
*
|
||
* The dimensionality of the whole array, and the coordinates is N.
|
||
* The array dimensions are TOTAL_SIZE and the coordinates
|
||
* are returned in COORD. The linear offset is in OFFSET.
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Quincey Koziol
|
||
* Wednesday, April 16, 2003
|
||
*
|
||
* Modifications:
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5V_array_calc(hsize_t offset, unsigned n, const hsize_t *total_size, hsize_t *coords)
|
||
{
|
||
hsize_t idx[H5V_HYPER_NDIMS]; /* Size of each dimension in bytes */
|
||
hsize_t acc; /* Size accumulator */
|
||
unsigned u; /* Local index variable */
|
||
int i; /* Local index variable */
|
||
|
||
FUNC_ENTER_NOAPI_NOFUNC(H5V_array_calc)
|
||
|
||
/* Sanity check */
|
||
assert(n <= H5V_HYPER_NDIMS);
|
||
assert(total_size);
|
||
assert(coords);
|
||
|
||
/* Build the sizes of each dimension in the array */
|
||
/* (From fastest to slowest) */
|
||
for(i=(int)(n-1),acc=1; i>=0; i--) {
|
||
idx[i]=acc;
|
||
acc *= total_size[i];
|
||
} /* end for */
|
||
|
||
/* Compute the coordinates from the offset */
|
||
for(u=0; u<n; u++) {
|
||
coords[u]=offset/idx[u];
|
||
offset %= idx[u];
|
||
} /* end for */
|
||
|
||
FUNC_LEAVE_NOAPI(SUCCEED)
|
||
} /* end H5V_array_calc() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5V_chunk_index
|
||
*
|
||
* Purpose: Given a coordinate offset (COORD), the size of each chunk
|
||
* (CHUNK), the number of chunks in each dimension (NCHUNKS)
|
||
* and the number of dimensions of all of these (NDIMS), calculate
|
||
* a "chunk index" for the chunk that the coordinate offset is
|
||
* located in.
|
||
*
|
||
* The chunk index starts at 0 and increases according to the
|
||
* fastest changing dimension, then the next fastest, etc.
|
||
*
|
||
* For example, with a 3x5 chunk size and 6 chunks in the fastest
|
||
* changing dimension and 3 chunks in the slowest changing
|
||
* dimension, the chunk indices are as follows:
|
||
*
|
||
* +-----+-----+-----+-----+-----+-----+
|
||
* | | | | | | |
|
||
* | 0 | 1 | 2 | 3 | 4 | 5 |
|
||
* | | | | | | |
|
||
* +-----+-----+-----+-----+-----+-----+
|
||
* | | | | | | |
|
||
* | 6 | 7 | 8 | 9 | 10 | 11 |
|
||
* | | | | | | |
|
||
* +-----+-----+-----+-----+-----+-----+
|
||
* | | | | | | |
|
||
* | 12 | 13 | 14 | 15 | 16 | 17 |
|
||
* | | | | | | |
|
||
* +-----+-----+-----+-----+-----+-----+
|
||
*
|
||
* The chunk index is placed in the CHUNK_IDX location for return
|
||
* from this function
|
||
*
|
||
* Return: Non-negative on success/Negative on failure
|
||
*
|
||
* Programmer: Quincey Koziol
|
||
* Monday, April 21, 2003
|
||
*
|
||
* Modifications:
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
herr_t
|
||
H5V_chunk_index(unsigned ndims, const hsize_t *coord, const size_t *chunk,
|
||
const hsize_t *down_nchunks, hsize_t *chunk_idx)
|
||
{
|
||
hsize_t scaled_coord[H5V_HYPER_NDIMS]; /* Scaled, coordinates, in terms of chunks */
|
||
unsigned u; /* Local index variable */
|
||
|
||
FUNC_ENTER_NOAPI_NOFUNC(H5V_chunk_index)
|
||
|
||
/* Sanity check */
|
||
assert(ndims <= H5V_HYPER_NDIMS);
|
||
assert(coord);
|
||
assert(chunk);
|
||
assert(chunk_idx);
|
||
|
||
/* Compute the scaled coordinates for actual coordinates */
|
||
for(u=0; u<ndims; u++)
|
||
scaled_coord[u]=coord[u]/chunk[u];
|
||
|
||
/* Compute the chunk index */
|
||
*chunk_idx=H5V_array_offset_pre(ndims,down_nchunks,scaled_coord); /*lint !e772 scaled_coord will always be initialized */
|
||
|
||
FUNC_LEAVE_NOAPI(SUCCEED)
|
||
} /* end H5V_chunk_index() */
|
||
|
||
|
||
/*-------------------------------------------------------------------------
|
||
* Function: H5V_memcpyvv
|
||
*
|
||
* Purpose: Given source and destination buffers in memory (SRC & DST)
|
||
* copy sequences of from the source buffer into the destination
|
||
* buffer. Each set of sequnces has an array of lengths, an
|
||
* array of offsets, the maximum number of sequences and the
|
||
* current sequence to start at in the sequence.
|
||
*
|
||
* There may be different numbers of bytes in the source and
|
||
* destination sequences, data copying stops when either the
|
||
* source or destination buffer runs out of sequence information.
|
||
*
|
||
* Return: Non-negative # of bytes copied on success/Negative on failure
|
||
*
|
||
* Programmer: Quincey Koziol
|
||
* Friday, May 2, 2003
|
||
*
|
||
* Modifications:
|
||
*
|
||
*-------------------------------------------------------------------------
|
||
*/
|
||
ssize_t
|
||
H5V_memcpyvv(void *_dst,
|
||
size_t dst_max_nseq, size_t *dst_curr_seq, size_t dst_len_arr[], hsize_t dst_off_arr[],
|
||
const void *_src,
|
||
size_t src_max_nseq, size_t *src_curr_seq, size_t src_len_arr[], hsize_t src_off_arr[])
|
||
{
|
||
unsigned char *dst; /* Destination buffer pointer */
|
||
const unsigned char *src; /* Source buffer pointer */
|
||
size_t total_size=0; /* Total size of sequence in bytes */
|
||
size_t size; /* Size of sequence in bytes */
|
||
size_t u,v; /* Local index variables */
|
||
ssize_t ret_value; /* Return value */
|
||
|
||
FUNC_ENTER_NOAPI_NOFUNC(H5V_memcpyvv)
|
||
|
||
/* Sanity check */
|
||
assert(_dst);
|
||
assert(dst_curr_seq);
|
||
assert(*dst_curr_seq<dst_max_nseq);
|
||
assert(dst_len_arr);
|
||
assert(dst_off_arr);
|
||
assert(_src);
|
||
assert(src_curr_seq);
|
||
assert(*src_curr_seq<src_max_nseq);
|
||
assert(src_len_arr);
|
||
assert(src_off_arr);
|
||
|
||
/* Work through all the sequences */
|
||
for(u=*dst_curr_seq, v=*src_curr_seq; u<dst_max_nseq && v<src_max_nseq; ) {
|
||
/* Choose smallest buffer to write */
|
||
if(src_len_arr[v]<dst_len_arr[u])
|
||
size=src_len_arr[v];
|
||
else
|
||
size=dst_len_arr[u];
|
||
|
||
/* Compute offset on disk */
|
||
dst=(unsigned char *)_dst+dst_off_arr[u];
|
||
|
||
/* Compute offset in memory */
|
||
src=(const unsigned char *)_src+src_off_arr[v];
|
||
|
||
/* Copy data */
|
||
HDmemcpy(dst,src,size);
|
||
|
||
/* Update source information */
|
||
src_len_arr[v]-=size;
|
||
src_off_arr[v]+=size;
|
||
if(src_len_arr[v]==0)
|
||
v++;
|
||
|
||
/* Update destination information */
|
||
dst_len_arr[u]-=size;
|
||
dst_off_arr[u]+=size;
|
||
if(dst_len_arr[u]==0)
|
||
u++;
|
||
|
||
/* Increment number of bytes copied */
|
||
total_size+=size;
|
||
} /* end for */
|
||
|
||
/* Update current sequence vectors */
|
||
*dst_curr_seq=u;
|
||
*src_curr_seq=v;
|
||
|
||
/* Set return value */
|
||
H5_ASSIGN_OVERFLOW(ret_value,total_size,size_t,ssize_t);
|
||
|
||
FUNC_LEAVE_NOAPI(ret_value)
|
||
} /* end H5V_memcpyvv() */
|
||
|