/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright by The HDF Group. * * 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 COPYING file, which can be found at the root of the source code * * distribution tree, or in https://www.hdfgroup.org/licenses. * * If you do not have access to either file, you may request a copy from * * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /****************/ /* Module Setup */ /****************/ #define H5D_PACKAGE /*suppress error about including H5Dpkg */ /***********/ /* Headers */ /***********/ #include "H5private.h" /* Generic Functions */ #include "H5Dpkg.h" /* Dataset functions */ #include "H5Eprivate.h" /* Error handling */ #include "H5FLprivate.h" /* Free Lists */ #include "H5Iprivate.h" /* IDs */ /****************/ /* Local Macros */ /****************/ /******************/ /* Local Typedefs */ /******************/ /********************/ /* Local Prototypes */ /********************/ static herr_t H5D__scatter_file(const H5D_io_info_t *io_info, const H5S_t *file_space, H5S_sel_iter_t *file_iter, size_t nelmts, const void *buf); static size_t H5D__gather_file(const H5D_io_info_t *io_info, const H5S_t *file_space, H5S_sel_iter_t *file_iter, size_t nelmts, void *buf); static size_t H5D__gather_mem(const void *_buf, const H5S_t *space, H5S_sel_iter_t *iter, size_t nelmts, const H5D_dxpl_cache_t *dxpl_cache, void *_tgath_buf /*out*/); static herr_t H5D__compound_opt_read(size_t nelmts, const H5S_t *mem_space, H5S_sel_iter_t *iter, const H5D_dxpl_cache_t *dxpl_cache, const H5D_type_info_t *type_info, void *user_buf /*out*/); static herr_t H5D__compound_opt_write(size_t nelmts, const H5D_type_info_t *type_info); /*********************/ /* Package Variables */ /*********************/ /*******************/ /* Local Variables */ /*******************/ /* Declare a free list to manage sequences of size_t */ H5FL_SEQ_EXTERN(size_t); /* Declare a free list to manage sequences of hsize_t */ H5FL_SEQ_EXTERN(hsize_t); /*------------------------------------------------------------------------- * Function: H5D__scatter_file * * Purpose: Scatters dataset elements from the type conversion buffer BUF * to the file F where the data points are arranged according to * the file dataspace FILE_SPACE and stored according to * LAYOUT and EFL. Each element is ELMT_SIZE bytes. * The caller is requesting that NELMTS elements are copied. * * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol * Thursday, June 20, 2002 * *------------------------------------------------------------------------- */ static herr_t H5D__scatter_file(const H5D_io_info_t *_io_info, const H5S_t *space, H5S_sel_iter_t *iter, size_t nelmts, const void *_buf) { H5D_io_info_t tmp_io_info; /* Temporary I/O info object */ hsize_t _off[H5D_IO_VECTOR_SIZE]; /* Array to store sequence offsets */ hsize_t *off = NULL; /* Pointer to sequence offsets */ hsize_t mem_off; /* Offset in memory */ size_t mem_curr_seq; /* "Current sequence" in memory */ size_t dset_curr_seq; /* "Current sequence" in dataset */ size_t _len[H5D_IO_VECTOR_SIZE]; /* Array to store sequence lengths */ size_t *len = NULL; /* Array to store sequence lengths */ size_t orig_mem_len, mem_len; /* Length of sequence in memory */ size_t nseq; /* Number of sequences generated */ size_t nelem; /* Number of elements used in sequences */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_STATIC /* Check args */ HDassert(_io_info); HDassert(space); HDassert(iter); HDassert(nelmts > 0); HDassert(_buf); /* Set up temporary I/O info object */ HDmemcpy(&tmp_io_info, _io_info, sizeof(*_io_info)); tmp_io_info.op_type = H5D_IO_OP_WRITE; tmp_io_info.u.wbuf = _buf; /* Allocate the vector I/O arrays */ if (tmp_io_info.dxpl_cache->vec_size > H5D_IO_VECTOR_SIZE) { if (NULL == (len = H5FL_SEQ_MALLOC(size_t, tmp_io_info.dxpl_cache->vec_size))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate I/O length vector array") if (NULL == (off = H5FL_SEQ_MALLOC(hsize_t, tmp_io_info.dxpl_cache->vec_size))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate I/O offset vector array") } /* end if */ else { len = _len; off = _off; } /* end else */ /* Loop until all elements are written */ while (nelmts > 0) { /* Get list of sequences for selection to write */ if (H5S_SELECT_GET_SEQ_LIST(space, H5S_GET_SEQ_LIST_SORTED, iter, tmp_io_info.dxpl_cache->vec_size, nelmts, &nseq, &nelem, off, len) < 0) HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed") /* Reset the current sequence information */ mem_curr_seq = dset_curr_seq = 0; orig_mem_len = mem_len = nelem * iter->elmt_size; mem_off = 0; /* Write sequence list out */ if ((*tmp_io_info.layout_ops.writevv)(&tmp_io_info, nseq, &dset_curr_seq, len, off, (size_t)1, &mem_curr_seq, &mem_len, &mem_off) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_WRITEERROR, FAIL, "write error") /* Update buffer */ tmp_io_info.u.wbuf = (const uint8_t *)tmp_io_info.u.wbuf + orig_mem_len; /* Decrement number of elements left to process */ nelmts -= nelem; } /* end while */ done: /* Release resources, if allocated */ if (len && len != _len) len = H5FL_SEQ_FREE(size_t, len); if (off && off != _off) off = H5FL_SEQ_FREE(hsize_t, off); FUNC_LEAVE_NOAPI(ret_value) } /* H5D__scatter_file() */ /*------------------------------------------------------------------------- * Function: H5D__gather_file * * Purpose: Gathers data points from file F and accumulates them in the * type conversion buffer BUF. The LAYOUT argument describes * how the data is stored on disk and EFL describes how the data * is organized in external files. ELMT_SIZE is the size in * bytes of a datum which this function treats as opaque. * FILE_SPACE describes the dataspace of the dataset on disk * and the elements that have been selected for reading (via * hyperslab, etc). This function will copy at most NELMTS * elements. * * Return: Success: Number of elements copied. * Failure: 0 * * Programmer: Quincey Koziol * Monday, June 24, 2002 * *------------------------------------------------------------------------- */ static size_t H5D__gather_file(const H5D_io_info_t *_io_info, const H5S_t *space, H5S_sel_iter_t *iter, size_t nelmts, void *_buf /*out*/) { H5D_io_info_t tmp_io_info; /* Temporary I/O info object */ hsize_t _off[H5D_IO_VECTOR_SIZE]; /* Array to store sequence offsets */ hsize_t *off = NULL; /* Pointer to sequence offsets */ hsize_t mem_off; /* Offset in memory */ size_t mem_curr_seq; /* "Current sequence" in memory */ size_t dset_curr_seq; /* "Current sequence" in dataset */ size_t _len[H5D_IO_VECTOR_SIZE]; /* Array to store sequence lengths */ size_t *len = NULL; /* Pointer to sequence lengths */ size_t orig_mem_len, mem_len; /* Length of sequence in memory */ size_t nseq; /* Number of sequences generated */ size_t nelem; /* Number of elements used in sequences */ size_t ret_value = nelmts; /* Return value */ FUNC_ENTER_STATIC /* Check args */ HDassert(_io_info); HDassert(_io_info->dset); HDassert(_io_info->store); HDassert(space); HDassert(iter); HDassert(nelmts > 0); HDassert(_buf); /* Set up temporary I/O info object */ HDmemcpy(&tmp_io_info, _io_info, sizeof(*_io_info)); tmp_io_info.op_type = H5D_IO_OP_READ; tmp_io_info.u.rbuf = _buf; /* Allocate the vector I/O arrays */ if (tmp_io_info.dxpl_cache->vec_size > H5D_IO_VECTOR_SIZE) { if (NULL == (len = H5FL_SEQ_MALLOC(size_t, tmp_io_info.dxpl_cache->vec_size))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 0, "can't allocate I/O length vector array") if (NULL == (off = H5FL_SEQ_MALLOC(hsize_t, tmp_io_info.dxpl_cache->vec_size))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 0, "can't allocate I/O offset vector array") } /* end if */ else { len = _len; off = _off; } /* end else */ /* Loop until all elements are read */ while (nelmts > 0) { /* Get list of sequences for selection to read */ if (H5S_SELECT_GET_SEQ_LIST(space, H5S_GET_SEQ_LIST_SORTED, iter, tmp_io_info.dxpl_cache->vec_size, nelmts, &nseq, &nelem, off, len) < 0) HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, 0, "sequence length generation failed") /* Reset the current sequence information */ mem_curr_seq = dset_curr_seq = 0; orig_mem_len = mem_len = nelem * iter->elmt_size; mem_off = 0; /* Read sequence list in */ if ((*tmp_io_info.layout_ops.readvv)(&tmp_io_info, nseq, &dset_curr_seq, len, off, (size_t)1, &mem_curr_seq, &mem_len, &mem_off) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_READERROR, 0, "read error") /* Update buffer */ tmp_io_info.u.rbuf = (uint8_t *)tmp_io_info.u.rbuf + orig_mem_len; /* Decrement number of elements left to process */ nelmts -= nelem; } /* end while */ done: /* Release resources, if allocated */ if (len && len != _len) len = H5FL_SEQ_FREE(size_t, len); if (off && off != _off) off = H5FL_SEQ_FREE(hsize_t, off); FUNC_LEAVE_NOAPI(ret_value) } /* H5D__gather_file() */ /*------------------------------------------------------------------------- * Function: H5D__scatter_mem * * Purpose: Scatters NELMTS data points from the scatter buffer * TSCAT_BUF to the application buffer BUF. Each element is * ELMT_SIZE bytes and they are organized in application memory * according to SPACE. * * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol * Monday, July 8, 2002 * *------------------------------------------------------------------------- */ herr_t H5D__scatter_mem(const void *_tscat_buf, const H5S_t *space, H5S_sel_iter_t *iter, size_t nelmts, const H5D_dxpl_cache_t *dxpl_cache, void *_buf /*out*/) { uint8_t *buf = (uint8_t *)_buf; /* Get local copies for address arithmetic */ const uint8_t *tscat_buf = (const uint8_t *)_tscat_buf; hsize_t _off[H5D_IO_VECTOR_SIZE]; /* Array to store sequence offsets */ hsize_t *off = NULL; /* Pointer to sequence offsets */ size_t _len[H5D_IO_VECTOR_SIZE]; /* Array to store sequence lengths */ size_t *len = NULL; /* Pointer to sequence lengths */ size_t curr_len; /* Length of bytes left to process in sequence */ size_t nseq; /* Number of sequences generated */ size_t curr_seq; /* Current sequence being processed */ size_t nelem; /* Number of elements used in sequences */ herr_t ret_value = SUCCEED; /* Number of elements scattered */ FUNC_ENTER_PACKAGE /* Check args */ HDassert(tscat_buf); HDassert(space); HDassert(iter); HDassert(nelmts > 0); HDassert(buf); /* Allocate the vector I/O arrays */ if (dxpl_cache->vec_size > H5D_IO_VECTOR_SIZE) { if (NULL == (len = H5FL_SEQ_MALLOC(size_t, dxpl_cache->vec_size))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate I/O length vector array") if (NULL == (off = H5FL_SEQ_MALLOC(hsize_t, dxpl_cache->vec_size))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate I/O offset vector array") } /* end if */ else { len = _len; off = _off; } /* end else */ /* Loop until all elements are written */ while (nelmts > 0) { /* Get list of sequences for selection to write */ if (H5S_SELECT_GET_SEQ_LIST(space, 0, iter, dxpl_cache->vec_size, nelmts, &nseq, &nelem, off, len) < 0) HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, 0, "sequence length generation failed") /* Loop, while sequences left to process */ for (curr_seq = 0; curr_seq < nseq; curr_seq++) { /* Get the number of bytes in sequence */ curr_len = len[curr_seq]; HDmemcpy(buf + off[curr_seq], tscat_buf, curr_len); /* Advance offset in destination buffer */ tscat_buf += curr_len; } /* end for */ /* Decrement number of elements left to process */ nelmts -= nelem; } /* end while */ done: /* Release resources, if allocated */ if (len && len != _len) len = H5FL_SEQ_FREE(size_t, len); if (off && off != _off) off = H5FL_SEQ_FREE(hsize_t, off); FUNC_LEAVE_NOAPI(ret_value) } /* H5D__scatter_mem() */ /*------------------------------------------------------------------------- * Function: H5D__gather_mem * * Purpose: Gathers dataset elements from application memory BUF and * copies them into the gather buffer TGATH_BUF. * Each element is ELMT_SIZE bytes and arranged in application * memory according to SPACE. * The caller is requesting that exactly NELMTS be gathered. * * Return: Success: Number of elements copied. * Failure: 0 * * Programmer: Quincey Koziol * Monday, June 24, 2002 * *------------------------------------------------------------------------- */ static size_t H5D__gather_mem(const void *_buf, const H5S_t *space, H5S_sel_iter_t *iter, size_t nelmts, const H5D_dxpl_cache_t *dxpl_cache, void *_tgath_buf /*out*/) { const uint8_t *buf = (const uint8_t *)_buf; /* Get local copies for address arithmetic */ uint8_t *tgath_buf = (uint8_t *)_tgath_buf; hsize_t _off[H5D_IO_VECTOR_SIZE]; /* Array to store sequence offsets */ hsize_t *off = NULL; /* Pointer to sequence offsets */ size_t _len[H5D_IO_VECTOR_SIZE]; /* Array to store sequence lengths */ size_t *len = NULL; /* Pointer to sequence lengths */ size_t curr_len; /* Length of bytes left to process in sequence */ size_t nseq; /* Number of sequences generated */ size_t curr_seq; /* Current sequence being processed */ size_t nelem; /* Number of elements used in sequences */ size_t ret_value = nelmts; /* Number of elements gathered */ FUNC_ENTER_STATIC /* Check args */ HDassert(buf); HDassert(space); HDassert(iter); HDassert(nelmts > 0); HDassert(tgath_buf); /* Allocate the vector I/O arrays */ if (dxpl_cache->vec_size > H5D_IO_VECTOR_SIZE) { if (NULL == (len = H5FL_SEQ_MALLOC(size_t, dxpl_cache->vec_size))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 0, "can't allocate I/O length vector array") if (NULL == (off = H5FL_SEQ_MALLOC(hsize_t, dxpl_cache->vec_size))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 0, "can't allocate I/O offset vector array") } /* end if */ else { len = _len; off = _off; } /* end else */ /* Loop until all elements are written */ while (nelmts > 0) { /* Get list of sequences for selection to write */ if (H5S_SELECT_GET_SEQ_LIST(space, 0, iter, dxpl_cache->vec_size, nelmts, &nseq, &nelem, off, len) < 0) HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, 0, "sequence length generation failed") /* Loop, while sequences left to process */ for (curr_seq = 0; curr_seq < nseq; curr_seq++) { /* Get the number of bytes in sequence */ curr_len = len[curr_seq]; HDmemcpy(tgath_buf, buf + off[curr_seq], curr_len); /* Advance offset in gather buffer */ tgath_buf += curr_len; } /* end for */ /* Decrement number of elements left to process */ nelmts -= nelem; } /* end while */ done: /* Release resources, if allocated */ if (len && len != _len) len = H5FL_SEQ_FREE(size_t, len); if (off && off != _off) off = H5FL_SEQ_FREE(hsize_t, off); FUNC_LEAVE_NOAPI(ret_value) } /* H5D__gather_mem() */ /*------------------------------------------------------------------------- * Function: H5D__scatgath_read * * Purpose: Perform scatter/gather ead from a contiguous [piece of a] dataset. * * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol * Thursday, March 6, 2008 * *------------------------------------------------------------------------- */ herr_t H5D__scatgath_read(const H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space) { const H5D_dxpl_cache_t *dxpl_cache = io_info->dxpl_cache; /* Local pointer to dataset transfer info */ void *buf = io_info->u.rbuf; /* Local pointer to application buffer */ H5S_sel_iter_t mem_iter; /*memory selection iteration info*/ hbool_t mem_iter_init = FALSE; /*memory selection iteration info has been initialized */ H5S_sel_iter_t bkg_iter; /*background iteration info*/ hbool_t bkg_iter_init = FALSE; /*background iteration info has been initialized */ H5S_sel_iter_t file_iter; /*file selection iteration info*/ hbool_t file_iter_init = FALSE; /*file selection iteration info has been initialized */ hsize_t smine_start; /*strip mine start loc */ size_t smine_nelmts; /*elements per strip */ herr_t ret_value = SUCCEED; /*return value */ FUNC_ENTER_PACKAGE /* Sanity check */ HDassert(io_info); HDassert(type_info); HDassert(mem_space); HDassert(file_space); HDassert(buf); /* Check for NOOP read */ if (nelmts == 0) HGOTO_DONE(SUCCEED) /* Figure out the strip mine size. */ if (H5S_select_iter_init(&file_iter, file_space, type_info->src_type_size) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize file selection information") file_iter_init = TRUE; /*file selection iteration info has been initialized */ if (H5S_select_iter_init(&mem_iter, mem_space, type_info->dst_type_size) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize memory selection information") mem_iter_init = TRUE; /*file selection iteration info has been initialized */ if (H5S_select_iter_init(&bkg_iter, mem_space, type_info->dst_type_size) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize background selection information") bkg_iter_init = TRUE; /*file selection iteration info has been initialized */ /* Start strip mining... */ for (smine_start = 0; smine_start < nelmts; smine_start += smine_nelmts) { size_t n; /* Elements operated on */ /* Go figure out how many elements to read from the file */ HDassert(H5S_SELECT_ITER_NELMTS(&file_iter) == (nelmts - smine_start)); smine_nelmts = (size_t)MIN(type_info->request_nelmts, (nelmts - smine_start)); /* * Gather the data from disk into the datatype conversion * buffer. Also gather data from application to background buffer * if necessary. */ /* * Gather data */ n = H5D__gather_file(io_info, file_space, &file_iter, smine_nelmts, type_info->tconv_buf /*out*/); if (n != smine_nelmts) HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "file gather failed") /* If the source and destination are compound types and subset of each other * and no conversion is needed, copy the data directly into user's buffer and * bypass the rest of steps. */ if (type_info->cmpd_subset && H5T_SUBSET_FALSE != type_info->cmpd_subset->subset) { if (H5D__compound_opt_read(smine_nelmts, mem_space, &mem_iter, dxpl_cache, type_info, buf /*out*/) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "datatype conversion failed") } /* end if */ else { if (H5T_BKG_YES == type_info->need_bkg) { n = H5D__gather_mem(buf, mem_space, &bkg_iter, smine_nelmts, dxpl_cache, type_info->bkg_buf /*out*/); if (n != smine_nelmts) HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "mem gather failed") } /* end if */ /* * Perform datatype conversion. */ if (H5T_convert(type_info->tpath, type_info->src_type_id, type_info->dst_type_id, smine_nelmts, (size_t)0, (size_t)0, type_info->tconv_buf, type_info->bkg_buf, io_info->dxpl_id) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTCONVERT, FAIL, "datatype conversion failed") /* Do the data transform after the conversion (since we're using type mem_type) */ if (!type_info->is_xform_noop) if (H5Z_xform_eval(dxpl_cache->data_xform_prop, type_info->tconv_buf, smine_nelmts, type_info->mem_type) < 0) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Error performing data transform") /* * Scatter the data into memory. */ if (H5D__scatter_mem(type_info->tconv_buf, mem_space, &mem_iter, smine_nelmts, dxpl_cache, buf /*out*/) < 0) HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "scatter failed") } /* end else */ } /* end for */ done: /* Release selection iterators */ if (file_iter_init) { if (H5S_SELECT_ITER_RELEASE(&file_iter) < 0) HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator") } /* end if */ if (mem_iter_init) { if (H5S_SELECT_ITER_RELEASE(&mem_iter) < 0) HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator") } /* end if */ if (bkg_iter_init) { if (H5S_SELECT_ITER_RELEASE(&bkg_iter) < 0) HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator") } /* end if */ FUNC_LEAVE_NOAPI(ret_value) } /* end H5D__scatgath_read() */ /*------------------------------------------------------------------------- * Function: H5D__scatgath_write * * Purpose: Perform scatter/gather write to a contiguous [piece of a] dataset. * * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol * Thursday, March 6, 2008 * *------------------------------------------------------------------------- */ herr_t H5D__scatgath_write(const H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space) { const H5D_dxpl_cache_t *dxpl_cache = io_info->dxpl_cache; /* Local pointer to dataset transfer info */ const void *buf = io_info->u.wbuf; /* Local pointer to application buffer */ H5S_sel_iter_t mem_iter; /*memory selection iteration info*/ hbool_t mem_iter_init = FALSE; /*memory selection iteration info has been initialized */ H5S_sel_iter_t bkg_iter; /*background iteration info*/ hbool_t bkg_iter_init = FALSE; /*background iteration info has been initialized */ H5S_sel_iter_t file_iter; /*file selection iteration info*/ hbool_t file_iter_init = FALSE; /*file selection iteration info has been initialized */ hsize_t smine_start; /*strip mine start loc */ size_t smine_nelmts; /*elements per strip */ herr_t ret_value = SUCCEED; /*return value */ FUNC_ENTER_PACKAGE /* Sanity check */ HDassert(io_info); HDassert(type_info); HDassert(mem_space); HDassert(file_space); HDassert(buf); /* Check for NOOP write */ if (nelmts == 0) HGOTO_DONE(SUCCEED) /* Figure out the strip mine size. */ if (H5S_select_iter_init(&file_iter, file_space, type_info->dst_type_size) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize file selection information") file_iter_init = TRUE; /*file selection iteration info has been initialized */ if (H5S_select_iter_init(&mem_iter, mem_space, type_info->src_type_size) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize memory selection information") mem_iter_init = TRUE; /*file selection iteration info has been initialized */ if (H5S_select_iter_init(&bkg_iter, file_space, type_info->dst_type_size) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize background selection information") bkg_iter_init = TRUE; /*file selection iteration info has been initialized */ /* Start strip mining... */ for (smine_start = 0; smine_start < nelmts; smine_start += smine_nelmts) { size_t n; /* Elements operated on */ /* Go figure out how many elements to read from the file */ HDassert(H5S_SELECT_ITER_NELMTS(&file_iter) == (nelmts - smine_start)); smine_nelmts = (size_t)MIN(type_info->request_nelmts, (nelmts - smine_start)); /* * Gather data from application buffer into the datatype conversion * buffer. Also gather data from the file into the background buffer * if necessary. */ n = H5D__gather_mem(buf, mem_space, &mem_iter, smine_nelmts, dxpl_cache, type_info->tconv_buf /*out*/); if (n != smine_nelmts) HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "mem gather failed") /* If the source and destination are compound types and the destination is * is a subset of the source and no conversion is needed, copy the data * directly into user's buffer and bypass the rest of steps. If the source * is a subset of the destination, the optimization is done in conversion * function H5T_conv_struct_opt to protect the background data. */ if (type_info->cmpd_subset && H5T_SUBSET_DST == type_info->cmpd_subset->subset && type_info->dst_type_size == type_info->cmpd_subset->copy_size) { if (H5D__compound_opt_write(smine_nelmts, type_info) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "datatype conversion failed") } /* end if */ else { if (H5T_BKG_YES == type_info->need_bkg) { n = H5D__gather_file(io_info, file_space, &bkg_iter, smine_nelmts, type_info->bkg_buf /*out*/); if (n != smine_nelmts) HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "file gather failed") } /* end if */ /* Do the data transform before the type conversion (since * transforms must be done in the memory type). */ if (!type_info->is_xform_noop) if (H5Z_xform_eval(dxpl_cache->data_xform_prop, type_info->tconv_buf, smine_nelmts, type_info->mem_type) < 0) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Error performing data transform") /* * Perform datatype conversion. */ if (H5T_convert(type_info->tpath, type_info->src_type_id, type_info->dst_type_id, smine_nelmts, (size_t)0, (size_t)0, type_info->tconv_buf, type_info->bkg_buf, io_info->dxpl_id) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTCONVERT, FAIL, "datatype conversion failed") } /* end else */ /* * Scatter the data out to the file. */ if (H5D__scatter_file(io_info, file_space, &file_iter, smine_nelmts, type_info->tconv_buf) < 0) HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "scatter failed") } /* end for */ done: /* Release selection iterators */ if (file_iter_init) { if (H5S_SELECT_ITER_RELEASE(&file_iter) < 0) HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator") } /* end if */ if (mem_iter_init) { if (H5S_SELECT_ITER_RELEASE(&mem_iter) < 0) HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator") } /* end if */ if (bkg_iter_init) { if (H5S_SELECT_ITER_RELEASE(&bkg_iter) < 0) HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator") } /* end if */ FUNC_LEAVE_NOAPI(ret_value) } /* end H5D__scatgath_write() */ /*------------------------------------------------------------------------- * Function: H5D__compound_opt_read * * Purpose: A special optimization case when the source and * destination members are a subset of each other, and * the order is the same, and no conversion is needed. * For example: * struct source { struct destination { * TYPE1 A; --> TYPE1 A; * TYPE2 B; --> TYPE2 B; * TYPE3 C; --> TYPE3 C; * }; TYPE4 D; * TYPE5 E; * }; * or * struct destination { struct source { * TYPE1 A; <-- TYPE1 A; * TYPE2 B; <-- TYPE2 B; * TYPE3 C; <-- TYPE3 C; * }; TYPE4 D; * TYPE5 E; * }; * The optimization is simply moving data to the appropriate * places in the buffer. * * Return: Non-negative on success/Negative on failure * * Programmer: Raymond Lu * 11 June 2007 * *------------------------------------------------------------------------- */ static herr_t H5D__compound_opt_read(size_t nelmts, const H5S_t *space, H5S_sel_iter_t *iter, const H5D_dxpl_cache_t *dxpl_cache, const H5D_type_info_t *type_info, void *user_buf /*out*/) { uint8_t *ubuf = (uint8_t *)user_buf; /* Cast for pointer arithmetic */ uint8_t *xdbuf; /* Pointer into dataset buffer */ hsize_t _off[H5D_IO_VECTOR_SIZE]; /* Array to store sequence offsets */ hsize_t *off = NULL; /* Pointer to sequence offsets */ size_t _len[H5D_IO_VECTOR_SIZE]; /* Array to store sequence lengths */ size_t *len = NULL; /* Pointer to sequence lengths */ size_t src_stride, dst_stride, copy_size; herr_t ret_value = SUCCEED; /*return value */ FUNC_ENTER_STATIC /* Check args */ HDassert(nelmts > 0); HDassert(space); HDassert(iter); HDassert(dxpl_cache); HDassert(type_info); HDassert(type_info->cmpd_subset); HDassert(H5T_SUBSET_SRC == type_info->cmpd_subset->subset || H5T_SUBSET_DST == type_info->cmpd_subset->subset); HDassert(user_buf); /* Allocate the vector I/O arrays */ if (dxpl_cache->vec_size > H5D_IO_VECTOR_SIZE) { if (NULL == (len = H5FL_SEQ_MALLOC(size_t, dxpl_cache->vec_size))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate I/O length vector array") if (NULL == (off = H5FL_SEQ_MALLOC(hsize_t, dxpl_cache->vec_size))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate I/O offset vector array") } /* end if */ else { len = _len; off = _off; } /* end else */ /* Get source & destination strides */ src_stride = type_info->src_type_size; dst_stride = type_info->dst_type_size; /* Get the size, in bytes, to copy for each element */ copy_size = type_info->cmpd_subset->copy_size; /* Loop until all elements are written */ xdbuf = type_info->tconv_buf; while (nelmts > 0) { size_t nseq; /* Number of sequences generated */ size_t curr_seq; /* Current sequence being processed */ size_t elmtno; /* Element counter */ /* Get list of sequences for selection to write */ if (H5S_SELECT_GET_SEQ_LIST(space, 0, iter, dxpl_cache->vec_size, nelmts, &nseq, &elmtno, off, len) < 0) HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, 0, "sequence length generation failed") /* Loop, while sequences left to process */ for (curr_seq = 0; curr_seq < nseq; curr_seq++) { size_t curr_off; /* Offset of bytes left to process in sequence */ size_t curr_len; /* Length of bytes left to process in sequence */ size_t curr_nelmts; /* Number of elements to process in sequence */ uint8_t *xubuf; size_t i; /* Local index variable */ /* Get the number of bytes and offset in sequence */ curr_len = len[curr_seq]; H5_CHECK_OVERFLOW(off[curr_seq], hsize_t, size_t); curr_off = (size_t)off[curr_seq]; /* Decide the number of elements and position in the buffer. */ curr_nelmts = curr_len / dst_stride; xubuf = ubuf + curr_off; /* Copy the data into the right place. */ for (i = 0; i < curr_nelmts; i++) { HDmemmove(xubuf, xdbuf, copy_size); /* Update pointers */ xdbuf += src_stride; xubuf += dst_stride; } /* end for */ } /* end for */ /* Decrement number of elements left to process */ nelmts -= elmtno; } /* end while */ done: /* Release resources, if allocated */ if (len && len != _len) len = H5FL_SEQ_FREE(size_t, len); if (off && off != _off) off = H5FL_SEQ_FREE(hsize_t, off); FUNC_LEAVE_NOAPI(ret_value) } /* end H5D__compound_opt_read() */ /*------------------------------------------------------------------------- * Function: H5D__compound_opt_write * * Purpose: A special optimization case when the source and * destination members are a subset of each other, and * the order is the same, and no conversion is needed. * For example: * struct source { struct destination { * TYPE1 A; --> TYPE1 A; * TYPE2 B; --> TYPE2 B; * TYPE3 C; --> TYPE3 C; * }; TYPE4 D; * TYPE5 E; * }; * or * struct destination { struct source { * TYPE1 A; <-- TYPE1 A; * TYPE2 B; <-- TYPE2 B; * TYPE3 C; <-- TYPE3 C; * }; TYPE4 D; * TYPE5 E; * }; * The optimization is simply moving data to the appropriate * places in the buffer. * * * Return: Non-negative on success/Negative on failure * * Programmer: Raymond Lu * 11 June 2007 * *------------------------------------------------------------------------- */ static herr_t H5D__compound_opt_write(size_t nelmts, const H5D_type_info_t *type_info) { uint8_t *xsbuf, *xdbuf; /* Source & destination pointers into dataset buffer */ size_t src_stride, dst_stride; /* Strides through source & destination datatypes */ size_t i; /* Local index variable */ FUNC_ENTER_STATIC_NOERR /* Check args */ HDassert(nelmts > 0); HDassert(type_info); /* Initialize values for loop */ src_stride = type_info->src_type_size; dst_stride = type_info->dst_type_size; /* Loop until all elements are written */ xsbuf = (uint8_t *)type_info->tconv_buf; xdbuf = (uint8_t *)type_info->tconv_buf; for (i = 0; i < nelmts; i++) { HDmemmove(xdbuf, xsbuf, dst_stride); /* Update pointers */ xsbuf += src_stride; xdbuf += dst_stride; } /* end for */ FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5D__compound_opt_write() */ /*------------------------------------------------------------------------- * Function: H5Dscatter * * Purpose: Scatters data provided by the callback op to the * destination buffer dst_buf, where the dimensions of * dst_buf and the selection to be scattered to are specified * by the dataspace dst_space_id. The type of the data to be * scattered is specified by type_id. * * Return: Non-negative on success/Negative on failure * * Programmer: Neil Fortner * 14 Jan 2013 * *------------------------------------------------------------------------- */ herr_t H5Dscatter(H5D_scatter_func_t op, void *op_data, hid_t type_id, hid_t dst_space_id, void *dst_buf) { H5T_t *type; /* Datatype */ H5S_t *dst_space; /* Dataspace */ H5S_sel_iter_t iter; /* Selection iteration info*/ hbool_t iter_init = FALSE; /* Selection iteration info has been initialized */ const void *src_buf = NULL; /* Source (contiguous) data buffer */ size_t src_buf_nbytes = 0; /* Size of src_buf */ size_t type_size; /* Datatype element size */ hssize_t nelmts; /* Number of remaining elements in selection */ size_t nelmts_scatter = 0; /* Number of elements to scatter to dst_buf */ H5D_dxpl_cache_t _dxpl_cache; /* Data transfer property cache buffer */ H5D_dxpl_cache_t *dxpl_cache = &_dxpl_cache; /* Data transfer property cache */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_API(FAIL) H5TRACE5("e", "x*xii*x", op, op_data, type_id, dst_space_id, dst_buf); /* Check args */ if (op == NULL) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid callback function pointer") if (NULL == (type = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype") if (NULL == (dst_space = (H5S_t *)H5I_object_verify(dst_space_id, H5I_DATASPACE))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace") if (dst_buf == NULL) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no destination buffer provided") /* Fill the DXPL cache values for later use */ if (H5D__get_dxpl_cache(H5P_DATASET_XFER_DEFAULT, &dxpl_cache) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't fill dxpl cache") /* Get datatype element size */ if (0 == (type_size = H5T_GET_SIZE(type))) HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get datatype size") /* Get number of elements in dataspace */ if ((nelmts = (hssize_t)H5S_GET_SELECT_NPOINTS(dst_space)) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTCOUNT, FAIL, "unable to get number of elements in selection") /* Initialize selection iterator */ if (H5S_select_iter_init(&iter, dst_space, type_size) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize selection iterator information") iter_init = TRUE; /* Loop until all data has been scattered */ while (nelmts > 0) { /* Make callback to retrieve data */ if (op(&src_buf, &src_buf_nbytes, op_data) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CALLBACK, FAIL, "callback operator returned failure") /* Calculate number of elements */ nelmts_scatter = src_buf_nbytes / type_size; /* Check callback results */ if (!src_buf) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "callback did not return a buffer") if (src_buf_nbytes == 0) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "callback returned a buffer size of 0") if (src_buf_nbytes % type_size) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "buffer size is not a multiple of datatype size") if (nelmts_scatter > (size_t)nelmts) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "callback returned more elements than in selection") /* Scatter data */ if (H5D__scatter_mem(src_buf, dst_space, &iter, nelmts_scatter, dxpl_cache, dst_buf) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "scatter failed") nelmts -= (hssize_t)nelmts_scatter; } /* end while */ done: /* Release selection iterator */ if (iter_init) { if (H5S_SELECT_ITER_RELEASE(&iter) < 0) HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator") } /* end if */ FUNC_LEAVE_API(ret_value) } /* H5Dscatter() */ /*------------------------------------------------------------------------- * Function: H5Dgather * * Purpose: Gathers data provided from the source buffer src_buf to * contiguous buffer dst_buf, then calls the callback op. * The dimensions of src_buf and the selection to be gathered * are specified by the dataspace src_space_id. The type of * the data to be gathered is specified by type_id. * * Return: Non-negative on success/Negative on failure * * Programmer: Neil Fortner * 16 Jan 2013 * *------------------------------------------------------------------------- */ herr_t H5Dgather(hid_t src_space_id, const void *src_buf, hid_t type_id, size_t dst_buf_size, void *dst_buf, H5D_gather_func_t op, void *op_data) { H5T_t *type; /* Datatype */ H5S_t *src_space; /* Dataspace */ H5S_sel_iter_t iter; /* Selection iteration info*/ hbool_t iter_init = FALSE; /* Selection iteration info has been initialized */ size_t type_size; /* Datatype element size */ hssize_t nelmts; /* Number of remaining elements in selection */ size_t dst_buf_nelmts; /* Number of elements that can fit in dst_buf */ size_t nelmts_gathered; /* Number of elements gathered from src_buf */ H5D_dxpl_cache_t _dxpl_cache; /* Data transfer property cache buffer */ H5D_dxpl_cache_t *dxpl_cache = &_dxpl_cache; /* Data transfer property cache */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_API(FAIL) H5TRACE7("e", "i*xiz*xx*x", src_space_id, src_buf, type_id, dst_buf_size, dst_buf, op, op_data); /* Check args */ if (NULL == (src_space = (H5S_t *)H5I_object_verify(src_space_id, H5I_DATASPACE))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace") if (src_buf == NULL) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no source buffer provided") if (NULL == (type = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype") if (dst_buf_size == 0) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "destination buffer size is 0") if (dst_buf == NULL) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no destination buffer provided") /* Fill the DXPL cache values for later use */ if (H5D__get_dxpl_cache(H5P_DATASET_XFER_DEFAULT, &dxpl_cache) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't fill dxpl cache") /* Get datatype element size */ if (0 == (type_size = H5T_GET_SIZE(type))) HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get datatype size") /* Get number of elements in dst_buf_size */ dst_buf_nelmts = dst_buf_size / type_size; if (dst_buf_nelmts == 0) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "destination buffer is not large enough to hold one element") /* Get number of elements in dataspace */ if ((nelmts = (hssize_t)H5S_GET_SELECT_NPOINTS(src_space)) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTCOUNT, FAIL, "unable to get number of elements in selection") /* If dst_buf is not large enough to hold all the elements, make sure there * is a callback */ if (((size_t)nelmts > dst_buf_nelmts) && (op == NULL)) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no callback supplied and destination buffer too small") /* Initialize selection iterator */ if (H5S_select_iter_init(&iter, src_space, type_size) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize selection iterator information") iter_init = TRUE; /* Loop until all data has been scattered */ while (nelmts > 0) { /* Gather data */ if (0 == (nelmts_gathered = H5D__gather_mem( src_buf, src_space, &iter, MIN(dst_buf_nelmts, (size_t)nelmts), dxpl_cache, dst_buf))) HGOTO_ERROR(H5E_IO, H5E_CANTCOPY, FAIL, "gather failed") HDassert(nelmts_gathered == MIN(dst_buf_nelmts, (size_t)nelmts)); /* Make callback to process dst_buf */ if (op && op(dst_buf, nelmts_gathered * type_size, op_data) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CALLBACK, FAIL, "callback operator returned failure") nelmts -= (hssize_t)nelmts_gathered; HDassert(op || (nelmts == 0)); } /* end while */ done: /* Release selection iterator */ if (iter_init) { if (H5S_SELECT_ITER_RELEASE(&iter) < 0) HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator") } /* end if */ FUNC_LEAVE_API(ret_value) } /* H5Dgather() */