Coverage Report

Created: 2026-03-04 00:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hdf5/src/H5Zshuffle.c
Line
Count
Source
1
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2
 * Copyright by The HDF Group.                                               *
3
 * All rights reserved.                                                      *
4
 *                                                                           *
5
 * This file is part of HDF5.  The full HDF5 copyright notice, including     *
6
 * terms governing use, modification, and redistribution, is contained in    *
7
 * the LICENSE file, which can be found at the root of the source code       *
8
 * distribution tree, or in https://www.hdfgroup.org/licenses.               *
9
 * If you do not have access to either file, you may request a copy from     *
10
 * help@hdfgroup.org.                                                        *
11
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
12
13
#include "H5Zmodule.h" /* This source code file is part of the H5Z module */
14
15
#include "H5private.h"   /* Generic Functions     */
16
#include "H5Eprivate.h"  /* Error handling        */
17
#include "H5Iprivate.h"  /* IDs           */
18
#include "H5MMprivate.h" /* Memory management     */
19
#include "H5Pprivate.h"  /* Property lists                       */
20
#include "H5Tprivate.h"  /* Datatypes               */
21
#include "H5Zpkg.h"      /* Data filters        */
22
23
/* Local function prototypes */
24
static herr_t H5Z__set_local_shuffle(hid_t dcpl_id, hid_t type_id, hid_t space_id);
25
static size_t H5Z__filter_shuffle(unsigned flags, size_t cd_nelmts, const unsigned cd_values[], size_t nbytes,
26
                                  size_t *buf_size, void **buf);
27
28
/* This message derives from H5Z */
29
const H5Z_class2_t H5Z_SHUFFLE[1] = {{
30
    H5Z_CLASS_T_VERS,       /* H5Z_class_t version */
31
    H5Z_FILTER_SHUFFLE,     /* Filter id number   */
32
    1,                      /* encoder_present flag (set to true) */
33
    1,                      /* decoder_present flag (set to true) */
34
    "shuffle",              /* Filter name for debugging  */
35
    NULL,                   /* The "can apply" callback     */
36
    H5Z__set_local_shuffle, /* The "set local" callback     */
37
    H5Z__filter_shuffle,    /* The actual filter function */
38
}};
39
40
/* Local macros */
41
0
#define H5Z_SHUFFLE_PARM_SIZE 0 /* "Local" parameter for shuffling size */
42
43
/*-------------------------------------------------------------------------
44
 * Function:  H5Z__set_local_shuffle
45
 *
46
 * Purpose: Set the "local" dataset parameter for data shuffling to be
47
 *              the size of the datatype.
48
 *
49
 * Return:  Success: Non-negative
50
 *    Failure: Negative
51
 *
52
 *-------------------------------------------------------------------------
53
 */
54
static herr_t
55
H5Z__set_local_shuffle(hid_t dcpl_id, hid_t type_id, hid_t H5_ATTR_UNUSED space_id)
56
0
{
57
0
    H5P_genplist_t *dcpl_plist;                          /* Property list pointer */
58
0
    const H5T_t    *type;                                /* Datatype */
59
0
    unsigned        flags;                               /* Filter flags */
60
0
    size_t          cd_nelmts = H5Z_SHUFFLE_USER_NPARMS; /* Number of filter parameters */
61
0
    unsigned        cd_values[H5Z_SHUFFLE_TOTAL_NPARMS]; /* Filter parameters */
62
0
    herr_t          ret_value = SUCCEED;                 /* Return value */
63
64
0
    FUNC_ENTER_PACKAGE
65
66
    /* Get the plist structure */
67
0
    if (NULL == (dcpl_plist = H5P_object_verify(dcpl_id, H5P_DATASET_CREATE, false)))
68
0
        HGOTO_ERROR(H5E_ID, H5E_BADID, FAIL, "can't find object for ID");
69
70
    /* Get datatype */
71
0
    if (NULL == (type = (const H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)))
72
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype");
73
74
    /* Get the filter's current parameters */
75
0
    if (H5P_get_filter_by_id(dcpl_plist, H5Z_FILTER_SHUFFLE, &flags, &cd_nelmts, cd_values, (size_t)0, NULL,
76
0
                             NULL) < 0)
77
0
        HGOTO_ERROR(H5E_PLINE, H5E_CANTGET, FAIL, "can't get shuffle parameters");
78
79
    /* Set "local" parameter for this dataset */
80
0
    if ((cd_values[H5Z_SHUFFLE_PARM_SIZE] = (unsigned)H5T_get_size(type)) == 0)
81
0
        HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad datatype size");
82
83
    /* Modify the filter's parameters for this dataset */
84
0
    if (H5P_modify_filter(dcpl_plist, H5Z_FILTER_SHUFFLE, flags, (size_t)H5Z_SHUFFLE_TOTAL_NPARMS,
85
0
                          cd_values) < 0)
86
0
        HGOTO_ERROR(H5E_PLINE, H5E_CANTSET, FAIL, "can't set local shuffle parameters");
87
88
0
done:
89
0
    FUNC_LEAVE_NOAPI(ret_value)
90
0
} /* end H5Z__set_local_shuffle() */
91
92
/*-------------------------------------------------------------------------
93
 * Function:  H5Z__filter_shuffle
94
 *
95
 * Purpose: Implement an I/O filter which "de-interlaces" a block of data
96
 *              by putting all the bytes in a byte-position for each element
97
 *              together in the block.  For example, for 4-byte elements stored
98
 *              as: 012301230123, shuffling will store them as: 000111222333
99
 *              Usually, the bytes in each byte position are more related to
100
 *              each other and putting them together will increase compression.
101
 *
102
 * Return:  Success: Size of buffer filtered
103
 *    Failure: 0
104
 *
105
 *-------------------------------------------------------------------------
106
 */
107
static size_t
108
H5Z__filter_shuffle(unsigned flags, size_t cd_nelmts, const unsigned cd_values[], size_t nbytes,
109
                    size_t *buf_size, void **buf)
110
0
{
111
0
    void          *dest  = NULL;  /* Buffer to deposit [un]shuffled bytes into */
112
0
    unsigned char *_src  = NULL;  /* Alias for source buffer */
113
0
    unsigned char *_dest = NULL;  /* Alias for destination buffer */
114
0
    unsigned       bytesoftype;   /* Number of bytes per element */
115
0
    size_t         numofelements; /* Number of elements in buffer */
116
0
    size_t         i;             /* Local index variables */
117
#ifdef NO_DUFFS_DEVICE
118
    size_t j;             /* Local index variable */
119
#endif                    /* NO_DUFFS_DEVICE */
120
0
    size_t leftover;      /* Extra bytes at end of buffer */
121
0
    size_t ret_value = 0; /* Return value */
122
123
0
    FUNC_ENTER_PACKAGE
124
125
    /* Check arguments */
126
0
    if (cd_nelmts != H5Z_SHUFFLE_TOTAL_NPARMS || cd_values[H5Z_SHUFFLE_PARM_SIZE] == 0)
127
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "invalid shuffle parameters");
128
129
    /* Get the number of bytes per element from the parameter block */
130
0
    bytesoftype = cd_values[H5Z_SHUFFLE_PARM_SIZE];
131
132
    /* Compute the number of elements in buffer */
133
0
    numofelements = nbytes / bytesoftype;
134
135
    /* Don't do anything for 1-byte elements, or "fractional" elements */
136
0
    if (bytesoftype > 1 && numofelements > 1) {
137
        /* Compute the leftover bytes if there are any */
138
0
        leftover = nbytes % bytesoftype;
139
140
        /* Allocate the destination buffer */
141
0
        if (NULL == (dest = H5MM_malloc(nbytes)))
142
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 0, "memory allocation failed for shuffle buffer");
143
144
0
        if (flags & H5Z_FLAG_REVERSE) {
145
            /* Get the pointer to the source buffer */
146
0
            _src = (unsigned char *)(*buf);
147
148
            /* Input; unshuffle */
149
0
            for (i = 0; i < bytesoftype; i++) {
150
0
                _dest = ((unsigned char *)dest) + i;
151
0
#define DUFF_GUTS                                                                                            \
152
0
    *_dest = *_src++;                                                                                        \
153
0
    _dest += bytesoftype;
154
#ifdef NO_DUFFS_DEVICE
155
                j = numofelements;
156
                while (j > 0) {
157
                    DUFF_GUTS;
158
159
                    j--;
160
                } /* end for */
161
#else             /* NO_DUFFS_DEVICE */
162
0
                {
163
0
                    size_t duffs_index; /* Counting index for Duff's device */
164
165
0
                    duffs_index = (numofelements + 7) / 8;
166
0
                    switch (numofelements % 8) {
167
0
                        default:
168
0
                            assert(0 && "This Should never be executed!");
169
0
                            break;
170
0
                        case 0:
171
0
                            do {
172
0
                                DUFF_GUTS
173
                                /* FALLTHROUGH */
174
0
                                H5_ATTR_FALLTHROUGH
175
0
                                case 7:
176
0
                                    DUFF_GUTS
177
                                    /* FALLTHROUGH */
178
0
                                    H5_ATTR_FALLTHROUGH
179
0
                                case 6:
180
0
                                    DUFF_GUTS
181
                                    /* FALLTHROUGH */
182
0
                                    H5_ATTR_FALLTHROUGH
183
0
                                case 5:
184
0
                                    DUFF_GUTS
185
                                    /* FALLTHROUGH */
186
0
                                    H5_ATTR_FALLTHROUGH
187
0
                                case 4:
188
0
                                    DUFF_GUTS
189
                                    /* FALLTHROUGH */
190
0
                                    H5_ATTR_FALLTHROUGH
191
0
                                case 3:
192
0
                                    DUFF_GUTS
193
                                    /* FALLTHROUGH */
194
0
                                    H5_ATTR_FALLTHROUGH
195
0
                                case 2:
196
0
                                    DUFF_GUTS
197
                                    /* FALLTHROUGH */
198
0
                                    H5_ATTR_FALLTHROUGH
199
0
                                case 1:
200
0
                                    DUFF_GUTS
201
0
                            } while (--duffs_index > 0);
202
0
                    } /* end switch */
203
0
                }
204
0
#endif            /* NO_DUFFS_DEVICE */
205
0
#undef DUFF_GUTS
206
0
            } /* end for */
207
208
            /* Add leftover to the end of data */
209
0
            if (leftover > 0) {
210
                /* Adjust back to end of shuffled bytes */
211
0
                _dest -= (bytesoftype - 1);
212
0
                H5MM_memcpy((void *)_dest, (void *)_src, leftover);
213
0
            }
214
0
        } /* end if */
215
0
        else {
216
            /* Get the pointer to the destination buffer */
217
0
            _dest = (unsigned char *)dest;
218
219
            /* Output; shuffle */
220
0
            for (i = 0; i < bytesoftype; i++) {
221
0
                _src = ((unsigned char *)(*buf)) + i;
222
0
#define DUFF_GUTS                                                                                            \
223
0
    *_dest++ = *_src;                                                                                        \
224
0
    _src += bytesoftype;
225
#ifdef NO_DUFFS_DEVICE
226
                j = numofelements;
227
                while (j > 0) {
228
                    DUFF_GUTS;
229
230
                    j--;
231
                } /* end for */
232
#else             /* NO_DUFFS_DEVICE */
233
0
                {
234
0
                    size_t duffs_index; /* Counting index for Duff's device */
235
236
0
                    duffs_index = (numofelements + 7) / 8;
237
0
                    switch (numofelements % 8) {
238
0
                        default:
239
0
                            assert(0 && "This Should never be executed!");
240
0
                            break;
241
0
                        case 0:
242
0
                            do {
243
0
                                DUFF_GUTS
244
                                /* FALLTHROUGH */
245
0
                                H5_ATTR_FALLTHROUGH
246
0
                                case 7:
247
0
                                    DUFF_GUTS
248
                                    /* FALLTHROUGH */
249
0
                                    H5_ATTR_FALLTHROUGH
250
0
                                case 6:
251
0
                                    DUFF_GUTS
252
                                    /* FALLTHROUGH */
253
0
                                    H5_ATTR_FALLTHROUGH
254
0
                                case 5:
255
0
                                    DUFF_GUTS
256
                                    /* FALLTHROUGH */
257
0
                                    H5_ATTR_FALLTHROUGH
258
0
                                case 4:
259
0
                                    DUFF_GUTS
260
                                    /* FALLTHROUGH */
261
0
                                    H5_ATTR_FALLTHROUGH
262
0
                                case 3:
263
0
                                    DUFF_GUTS
264
                                    /* FALLTHROUGH */
265
0
                                    H5_ATTR_FALLTHROUGH
266
0
                                case 2:
267
0
                                    DUFF_GUTS
268
                                    /* FALLTHROUGH */
269
0
                                    H5_ATTR_FALLTHROUGH
270
0
                                case 1:
271
0
                                    DUFF_GUTS
272
0
                            } while (--duffs_index > 0);
273
0
                    } /* end switch */
274
0
                }
275
0
#endif            /* NO_DUFFS_DEVICE */
276
0
#undef DUFF_GUTS
277
0
            } /* end for */
278
279
            /* Add leftover to the end of data */
280
0
            if (leftover > 0) {
281
                /* Adjust back to end of shuffled bytes */
282
0
                _src -= (bytesoftype - 1);
283
0
                H5MM_memcpy((void *)_dest, (void *)_src, leftover);
284
0
            }
285
0
        } /* end else */
286
287
        /* Free the input buffer */
288
0
        H5MM_xfree(*buf);
289
290
        /* Set the buffer information to return */
291
0
        *buf      = dest;
292
0
        *buf_size = nbytes;
293
0
    } /* end else */
294
295
    /* Set the return value */
296
0
    ret_value = nbytes;
297
298
0
done:
299
0
    FUNC_LEAVE_NOAPI(ret_value)
300
0
}