/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright by The HDF Group. * * 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. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "H5Zmodule.h" /* This source code file is part of the H5Z module */ #include "H5private.h" /* Generic Functions */ #include "H5Eprivate.h" /* Error handling */ #include "H5Iprivate.h" /* IDs */ #include "H5MMprivate.h" /* Memory management */ #include "H5Pprivate.h" /* Property lists */ #include "H5Tprivate.h" /* Datatypes */ #include "H5Zpkg.h" /* Data filters */ /* Local function prototypes */ static herr_t H5Z__set_local_shuffle(hid_t dcpl_id, hid_t type_id, hid_t space_id); static size_t H5Z__filter_shuffle(unsigned flags, size_t cd_nelmts, const unsigned cd_values[], size_t nbytes, size_t *buf_size, void **buf); /* This message derives from H5Z */ const H5Z_class2_t H5Z_SHUFFLE[1] = {{ H5Z_CLASS_T_VERS, /* H5Z_class_t version */ H5Z_FILTER_SHUFFLE, /* Filter id number */ 1, /* encoder_present flag (set to true) */ 1, /* decoder_present flag (set to true) */ "shuffle", /* Filter name for debugging */ NULL, /* The "can apply" callback */ H5Z__set_local_shuffle, /* The "set local" callback */ H5Z__filter_shuffle, /* The actual filter function */ }}; /* Local macros */ #define H5Z_SHUFFLE_PARM_SIZE 0 /* "Local" parameter for shuffling size */ /*------------------------------------------------------------------------- * Function: H5Z__set_local_shuffle * * Purpose: Set the "local" dataset parameter for data shuffling to be * the size of the datatype. * * Return: Success: Non-negative * Failure: Negative * *------------------------------------------------------------------------- */ static herr_t H5Z__set_local_shuffle(hid_t dcpl_id, hid_t type_id, hid_t H5_ATTR_UNUSED space_id) { H5P_genplist_t *dcpl_plist; /* Property list pointer */ const H5T_t *type; /* Datatype */ unsigned flags; /* Filter flags */ size_t cd_nelmts = H5Z_SHUFFLE_USER_NPARMS; /* Number of filter parameters */ unsigned cd_values[H5Z_SHUFFLE_TOTAL_NPARMS]; /* Filter parameters */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE /* Get the plist structure */ if (NULL == (dcpl_plist = H5P_object_verify(dcpl_id, H5P_DATASET_CREATE))) HGOTO_ERROR(H5E_ID, H5E_BADID, FAIL, "can't find object for ID"); /* Get datatype */ if (NULL == (type = (const H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype"); /* Get the filter's current parameters */ if (H5P_get_filter_by_id(dcpl_plist, H5Z_FILTER_SHUFFLE, &flags, &cd_nelmts, cd_values, (size_t)0, NULL, NULL) < 0) HGOTO_ERROR(H5E_PLINE, H5E_CANTGET, FAIL, "can't get shuffle parameters"); /* Set "local" parameter for this dataset */ if ((cd_values[H5Z_SHUFFLE_PARM_SIZE] = (unsigned)H5T_get_size(type)) == 0) HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad datatype size"); /* Modify the filter's parameters for this dataset */ if (H5P_modify_filter(dcpl_plist, H5Z_FILTER_SHUFFLE, flags, (size_t)H5Z_SHUFFLE_TOTAL_NPARMS, cd_values) < 0) HGOTO_ERROR(H5E_PLINE, H5E_CANTSET, FAIL, "can't set local shuffle parameters"); done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5Z__set_local_shuffle() */ /*------------------------------------------------------------------------- * Function: H5Z__filter_shuffle * * Purpose: Implement an I/O filter which "de-interlaces" a block of data * by putting all the bytes in a byte-position for each element * together in the block. For example, for 4-byte elements stored * as: 012301230123, shuffling will store them as: 000111222333 * Usually, the bytes in each byte position are more related to * each other and putting them together will increase compression. * * Return: Success: Size of buffer filtered * Failure: 0 * *------------------------------------------------------------------------- */ static size_t H5Z__filter_shuffle(unsigned flags, size_t cd_nelmts, const unsigned cd_values[], size_t nbytes, size_t *buf_size, void **buf) { void *dest = NULL; /* Buffer to deposit [un]shuffled bytes into */ unsigned char *_src = NULL; /* Alias for source buffer */ unsigned char *_dest = NULL; /* Alias for destination buffer */ unsigned bytesoftype; /* Number of bytes per element */ size_t numofelements; /* Number of elements in buffer */ size_t i; /* Local index variables */ #ifdef NO_DUFFS_DEVICE size_t j; /* Local index variable */ #endif /* NO_DUFFS_DEVICE */ size_t leftover; /* Extra bytes at end of buffer */ size_t ret_value = 0; /* Return value */ FUNC_ENTER_PACKAGE /* Check arguments */ if (cd_nelmts != H5Z_SHUFFLE_TOTAL_NPARMS || cd_values[H5Z_SHUFFLE_PARM_SIZE] == 0) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "invalid shuffle parameters"); /* Get the number of bytes per element from the parameter block */ bytesoftype = cd_values[H5Z_SHUFFLE_PARM_SIZE]; /* Compute the number of elements in buffer */ numofelements = nbytes / bytesoftype; /* Don't do anything for 1-byte elements, or "fractional" elements */ if (bytesoftype > 1 && numofelements > 1) { /* Compute the leftover bytes if there are any */ leftover = nbytes % bytesoftype; /* Allocate the destination buffer */ if (NULL == (dest = H5MM_malloc(nbytes))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 0, "memory allocation failed for shuffle buffer"); if (flags & H5Z_FLAG_REVERSE) { /* Get the pointer to the source buffer */ _src = (unsigned char *)(*buf); /* Input; unshuffle */ for (i = 0; i < bytesoftype; i++) { _dest = ((unsigned char *)dest) + i; #define DUFF_GUTS \ *_dest = *_src++; \ _dest += bytesoftype; #ifdef NO_DUFFS_DEVICE j = numofelements; while (j > 0) { DUFF_GUTS; j--; } /* end for */ #else /* NO_DUFFS_DEVICE */ { size_t duffs_index; /* Counting index for Duff's device */ duffs_index = (numofelements + 7) / 8; switch (numofelements % 8) { default: assert(0 && "This Should never be executed!"); break; case 0: do { DUFF_GUTS /* FALLTHROUGH */ H5_ATTR_FALLTHROUGH case 7: DUFF_GUTS /* FALLTHROUGH */ H5_ATTR_FALLTHROUGH case 6: DUFF_GUTS /* FALLTHROUGH */ H5_ATTR_FALLTHROUGH case 5: DUFF_GUTS /* FALLTHROUGH */ H5_ATTR_FALLTHROUGH case 4: DUFF_GUTS /* FALLTHROUGH */ H5_ATTR_FALLTHROUGH case 3: DUFF_GUTS /* FALLTHROUGH */ H5_ATTR_FALLTHROUGH case 2: DUFF_GUTS /* FALLTHROUGH */ H5_ATTR_FALLTHROUGH case 1: DUFF_GUTS } while (--duffs_index > 0); } /* end switch */ } #endif /* NO_DUFFS_DEVICE */ #undef DUFF_GUTS } /* end for */ /* Add leftover to the end of data */ if (leftover > 0) { /* Adjust back to end of shuffled bytes */ _dest -= (bytesoftype - 1); H5MM_memcpy((void *)_dest, (void *)_src, leftover); } } /* end if */ else { /* Get the pointer to the destination buffer */ _dest = (unsigned char *)dest; /* Output; shuffle */ for (i = 0; i < bytesoftype; i++) { _src = ((unsigned char *)(*buf)) + i; #define DUFF_GUTS \ *_dest++ = *_src; \ _src += bytesoftype; #ifdef NO_DUFFS_DEVICE j = numofelements; while (j > 0) { DUFF_GUTS; j--; } /* end for */ #else /* NO_DUFFS_DEVICE */ { size_t duffs_index; /* Counting index for Duff's device */ duffs_index = (numofelements + 7) / 8; switch (numofelements % 8) { default: assert(0 && "This Should never be executed!"); break; case 0: do { DUFF_GUTS /* FALLTHROUGH */ H5_ATTR_FALLTHROUGH case 7: DUFF_GUTS /* FALLTHROUGH */ H5_ATTR_FALLTHROUGH case 6: DUFF_GUTS /* FALLTHROUGH */ H5_ATTR_FALLTHROUGH case 5: DUFF_GUTS /* FALLTHROUGH */ H5_ATTR_FALLTHROUGH case 4: DUFF_GUTS /* FALLTHROUGH */ H5_ATTR_FALLTHROUGH case 3: DUFF_GUTS /* FALLTHROUGH */ H5_ATTR_FALLTHROUGH case 2: DUFF_GUTS /* FALLTHROUGH */ H5_ATTR_FALLTHROUGH case 1: DUFF_GUTS } while (--duffs_index > 0); } /* end switch */ } #endif /* NO_DUFFS_DEVICE */ #undef DUFF_GUTS } /* end for */ /* Add leftover to the end of data */ if (leftover > 0) { /* Adjust back to end of shuffled bytes */ _src -= (bytesoftype - 1); H5MM_memcpy((void *)_dest, (void *)_src, leftover); } } /* end else */ /* Free the input buffer */ H5MM_xfree(*buf); /* Set the buffer information to return */ *buf = dest; *buf_size = nbytes; } /* end else */ /* Set the return value */ ret_value = nbytes; done: FUNC_LEAVE_NOAPI(ret_value) }