/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 | } |