/src/c-blosc2/blosc/b2nd.c
Line | Count | Source (jump to first uncovered line) |
1 | | /********************************************************************* |
2 | | Blosc - Blocked Shuffling and Compression Library |
3 | | |
4 | | Copyright (c) 2021 Blosc Development Team <blosc@blosc.org> |
5 | | https://blosc.org |
6 | | License: BSD 3-Clause (see LICENSE.txt) |
7 | | |
8 | | See LICENSE.txt for details about copyright and rights to use. |
9 | | **********************************************************************/ |
10 | | |
11 | | #include "b2nd.h" |
12 | | #include "context.h" |
13 | | #include "blosc2/blosc2-common.h" |
14 | | #include "blosc2.h" |
15 | | |
16 | | #include <inttypes.h> |
17 | | #include <stdlib.h> |
18 | | #include <stdint.h> |
19 | | #include <string.h> |
20 | | |
21 | | |
22 | | int b2nd_serialize_meta(int8_t ndim, const int64_t *shape, const int32_t *chunkshape, |
23 | | const int32_t *blockshape, const char *dtype, int8_t dtype_format, |
24 | 0 | uint8_t **smeta) { |
25 | 0 | if (dtype == NULL) { |
26 | 0 | dtype = B2ND_DEFAULT_DTYPE; |
27 | 0 | } |
28 | | // dtype checks |
29 | 0 | if (dtype_format < 0) { |
30 | 0 | BLOSC_TRACE_ERROR("dtype_format cannot be negative"); |
31 | 0 | BLOSC_ERROR(BLOSC2_ERROR_FAILURE); |
32 | 0 | } |
33 | 0 | size_t dtype_len0 = strlen(dtype); |
34 | 0 | if (dtype_len0 > INT32_MAX) { |
35 | 0 | BLOSC_TRACE_ERROR("dtype is too large (len > %d)", INT32_MAX); |
36 | 0 | BLOSC_ERROR(BLOSC2_ERROR_FAILURE); |
37 | 0 | } |
38 | 0 | const int32_t dtype_len = (int32_t) dtype_len0; |
39 | | // Allocate space for b2nd metalayer |
40 | 0 | int32_t max_smeta_len = (int32_t) (1 + 1 + 1 + (1 + ndim * (1 + sizeof(int64_t))) + |
41 | 0 | (1 + ndim * (1 + sizeof(int32_t))) + (1 + ndim * (1 + sizeof(int32_t))) + |
42 | 0 | 1 + 1 + sizeof(int32_t) + dtype_len); |
43 | 0 | *smeta = malloc((size_t) max_smeta_len); |
44 | 0 | BLOSC_ERROR_NULL(*smeta, BLOSC2_ERROR_MEMORY_ALLOC); |
45 | 0 | uint8_t *pmeta = *smeta; |
46 | | |
47 | | // Build an array with 7 entries (version, ndim, shape, chunkshape, blockshape, dtype_format, dtype) |
48 | 0 | *pmeta++ = 0x90 + 7; |
49 | | |
50 | | // version entry |
51 | 0 | *pmeta++ = B2ND_METALAYER_VERSION; // positive fixnum (7-bit positive integer) |
52 | | |
53 | | // ndim entry |
54 | 0 | *pmeta++ = (uint8_t) ndim; // positive fixnum (7-bit positive integer) |
55 | | |
56 | | // shape entry |
57 | 0 | *pmeta++ = (uint8_t) (0x90) + ndim; // fix array with ndim elements |
58 | 0 | for (uint8_t i = 0; i < ndim; i++) { |
59 | 0 | *pmeta++ = 0xd3; // int64 |
60 | 0 | swap_store(pmeta, shape + i, sizeof(int64_t)); |
61 | 0 | pmeta += sizeof(int64_t); |
62 | 0 | } |
63 | | |
64 | | // chunkshape entry |
65 | 0 | *pmeta++ = (uint8_t) (0x90) + ndim; // fix array with ndim elements |
66 | 0 | for (uint8_t i = 0; i < ndim; i++) { |
67 | 0 | *pmeta++ = 0xd2; // int32 |
68 | 0 | swap_store(pmeta, chunkshape + i, sizeof(int32_t)); |
69 | 0 | pmeta += sizeof(int32_t); |
70 | 0 | } |
71 | | |
72 | | // blockshape entry |
73 | 0 | *pmeta++ = (uint8_t) (0x90) + ndim; // fix array with ndim elements |
74 | 0 | for (uint8_t i = 0; i < ndim; i++) { |
75 | 0 | *pmeta++ = 0xd2; // int32 |
76 | 0 | swap_store(pmeta, blockshape + i, sizeof(int32_t)); |
77 | 0 | pmeta += sizeof(int32_t); |
78 | 0 | } |
79 | | |
80 | | // dtype entry |
81 | 0 | *pmeta++ = dtype_format; // positive fixint (7-bit positive integer) |
82 | 0 | *pmeta++ = (uint8_t) (0xdb); // str with up to 2^31 elements |
83 | 0 | swap_store(pmeta, &dtype_len, sizeof(int32_t)); |
84 | 0 | pmeta += sizeof(int32_t); |
85 | 0 | memcpy(pmeta, dtype, dtype_len); |
86 | 0 | pmeta += dtype_len; |
87 | |
|
88 | 0 | int32_t slen = (int32_t) (pmeta - *smeta); |
89 | 0 | if (max_smeta_len != slen) { |
90 | 0 | BLOSC_TRACE_ERROR("meta length is inconsistent!"); |
91 | 0 | return BLOSC2_ERROR_FAILURE; |
92 | 0 | } |
93 | | |
94 | 0 | return (int)slen; |
95 | 0 | } |
96 | | |
97 | | |
98 | | int b2nd_deserialize_meta(const uint8_t *smeta, int32_t smeta_len, int8_t *ndim, int64_t *shape, |
99 | 0 | int32_t *chunkshape, int32_t *blockshape, char **dtype, int8_t *dtype_format) { |
100 | 0 | const uint8_t *pmeta = smeta; |
101 | | |
102 | | // Check that we have an array with 7 entries (version, ndim, shape, chunkshape, blockshape, dtype_format, dtype) |
103 | 0 | pmeta += 1; |
104 | | |
105 | | // version entry |
106 | | // int8_t version = (int8_t)pmeta[0]; // positive fixnum (7-bit positive integer) commented to avoid warning |
107 | 0 | pmeta += 1; |
108 | | |
109 | | // ndim entry |
110 | 0 | *ndim = (int8_t) pmeta[0]; |
111 | 0 | int8_t ndim_aux = *ndim; // positive fixnum (7-bit positive integer) |
112 | 0 | pmeta += 1; |
113 | | |
114 | | // shape entry |
115 | | // Initialize to ones, as required by b2nd |
116 | 0 | for (int i = 0; i < ndim_aux; i++) shape[i] = 1; |
117 | 0 | pmeta += 1; |
118 | 0 | for (int8_t i = 0; i < ndim_aux; i++) { |
119 | 0 | pmeta += 1; |
120 | 0 | swap_store(shape + i, pmeta, sizeof(int64_t)); |
121 | 0 | pmeta += sizeof(int64_t); |
122 | 0 | } |
123 | | |
124 | | // chunkshape entry |
125 | | // Initialize to ones, as required by b2nd |
126 | 0 | for (int i = 0; i < ndim_aux; i++) chunkshape[i] = 1; |
127 | 0 | pmeta += 1; |
128 | 0 | for (int8_t i = 0; i < ndim_aux; i++) { |
129 | 0 | pmeta += 1; |
130 | 0 | swap_store(chunkshape + i, pmeta, sizeof(int32_t)); |
131 | 0 | pmeta += sizeof(int32_t); |
132 | 0 | } |
133 | | |
134 | | // blockshape entry |
135 | | // Initialize to ones, as required by b2nd |
136 | 0 | for (int i = 0; i < ndim_aux; i++) blockshape[i] = 1; |
137 | 0 | pmeta += 1; |
138 | 0 | for (int8_t i = 0; i < ndim_aux; i++) { |
139 | 0 | pmeta += 1; |
140 | 0 | swap_store(blockshape + i, pmeta, sizeof(int32_t)); |
141 | 0 | pmeta += sizeof(int32_t); |
142 | 0 | } |
143 | | |
144 | | // dtype entry |
145 | 0 | if (dtype_format == NULL || dtype == NULL) { |
146 | 0 | return (int32_t)(pmeta - smeta); |
147 | 0 | } |
148 | 0 | if (pmeta - smeta < smeta_len) { |
149 | | // dtype info is here |
150 | 0 | *dtype_format = (int8_t) *(pmeta++); |
151 | 0 | pmeta += 1; |
152 | 0 | int dtype_len; |
153 | 0 | swap_store(&dtype_len, pmeta, sizeof(int32_t)); |
154 | 0 | pmeta += sizeof(int32_t); |
155 | 0 | *dtype = (char*)malloc(dtype_len + 1); |
156 | 0 | char* dtype_ = *dtype; |
157 | 0 | memcpy(dtype_, (char*)pmeta, dtype_len); |
158 | 0 | dtype_[dtype_len] = '\0'; |
159 | 0 | pmeta += dtype_len; |
160 | 0 | } |
161 | 0 | else { |
162 | | // dtype is mandatory in b2nd metalayer, but this is mainly meant as |
163 | | // a fall-back for deprecated caterva headers |
164 | 0 | *dtype = NULL; |
165 | 0 | *dtype_format = 0; |
166 | 0 | } |
167 | |
|
168 | 0 | int32_t slen = (int32_t) (pmeta - smeta); |
169 | 0 | return (int)slen; |
170 | 0 | } |
171 | | |
172 | | |
173 | | |
174 | | int update_shape(b2nd_array_t *array, int8_t ndim, const int64_t *shape, |
175 | 0 | const int32_t *chunkshape, const int32_t *blockshape) { |
176 | 0 | array->ndim = ndim; |
177 | 0 | array->nitems = 1; |
178 | 0 | array->extnitems = 1; |
179 | 0 | array->extchunknitems = 1; |
180 | 0 | array->chunknitems = 1; |
181 | 0 | array->blocknitems = 1; |
182 | 0 | for (int i = 0; i < B2ND_MAX_DIM; ++i) { |
183 | 0 | if (i < ndim) { |
184 | 0 | array->shape[i] = shape[i]; |
185 | 0 | array->chunkshape[i] = chunkshape[i]; |
186 | 0 | array->blockshape[i] = blockshape[i]; |
187 | 0 | if (shape[i] != 0) { |
188 | 0 | if (shape[i] % array->chunkshape[i] == 0) { |
189 | 0 | array->extshape[i] = shape[i]; |
190 | 0 | } else { |
191 | 0 | array->extshape[i] = shape[i] + chunkshape[i] - shape[i] % chunkshape[i]; |
192 | 0 | } |
193 | 0 | if (chunkshape[i] % blockshape[i] == 0) { |
194 | 0 | array->extchunkshape[i] = chunkshape[i]; |
195 | 0 | } else { |
196 | 0 | array->extchunkshape[i] = |
197 | 0 | chunkshape[i] + blockshape[i] - chunkshape[i] % blockshape[i]; |
198 | 0 | } |
199 | 0 | } else { |
200 | 0 | array->extchunkshape[i] = chunkshape[i]; |
201 | 0 | array->extshape[i] = 0; |
202 | 0 | } |
203 | 0 | } else { |
204 | 0 | array->blockshape[i] = 1; |
205 | 0 | array->chunkshape[i] = 1; |
206 | 0 | array->extshape[i] = 1; |
207 | 0 | array->extchunkshape[i] = 1; |
208 | 0 | array->shape[i] = 1; |
209 | 0 | } |
210 | 0 | array->nitems *= array->shape[i]; |
211 | 0 | array->extnitems *= array->extshape[i]; |
212 | 0 | array->extchunknitems *= array->extchunkshape[i]; |
213 | 0 | array->chunknitems *= array->chunkshape[i]; |
214 | 0 | array->blocknitems *= array->blockshape[i]; |
215 | 0 | } |
216 | | |
217 | | // Compute strides |
218 | 0 | array->item_array_strides[ndim - 1] = 1; |
219 | 0 | array->item_extchunk_strides[ndim - 1] = 1; |
220 | 0 | array->item_chunk_strides[ndim - 1] = 1; |
221 | 0 | array->item_block_strides[ndim - 1] = 1; |
222 | 0 | array->block_chunk_strides[ndim - 1] = 1; |
223 | 0 | array->chunk_array_strides[ndim - 1] = 1; |
224 | 0 | for (int i = ndim - 2; i >= 0; --i) { |
225 | 0 | if (shape[i + 1] != 0) { |
226 | 0 | array->item_array_strides[i] = array->item_array_strides[i + 1] * array->shape[i + 1]; |
227 | 0 | array->item_extchunk_strides[i] = |
228 | 0 | array->item_extchunk_strides[i + 1] * array->extchunkshape[i + 1]; |
229 | 0 | array->item_chunk_strides[i] = |
230 | 0 | array->item_chunk_strides[i + 1] * array->chunkshape[i + 1]; |
231 | 0 | array->item_block_strides[i] = |
232 | 0 | array->item_block_strides[i + 1] * array->blockshape[i + 1]; |
233 | 0 | array->block_chunk_strides[i] = array->block_chunk_strides[i + 1] * |
234 | 0 | (array->extchunkshape[i + 1] / |
235 | 0 | array->blockshape[i + 1]); |
236 | 0 | array->chunk_array_strides[i] = array->chunk_array_strides[i + 1] * |
237 | 0 | (array->extshape[i + 1] * array->chunkshape[i + 1]); |
238 | 0 | } else { |
239 | 0 | array->item_array_strides[i] = 0; |
240 | 0 | array->item_extchunk_strides[i] = 0; |
241 | 0 | array->item_chunk_strides[i] = 0; |
242 | 0 | array->item_block_strides[i] = 0; |
243 | 0 | array->block_chunk_strides[i] = 0; |
244 | 0 | array->chunk_array_strides[i] = 0; |
245 | 0 | } |
246 | 0 | } |
247 | 0 | if (array->sc) { |
248 | 0 | uint8_t *smeta = NULL; |
249 | | // Serialize the dimension info ... |
250 | 0 | int32_t smeta_len = |
251 | 0 | b2nd_serialize_meta(array->ndim, array->shape, array->chunkshape, array->blockshape, |
252 | 0 | array->dtype, array->dtype_format, &smeta); |
253 | 0 | if (smeta_len < 0) { |
254 | 0 | BLOSC_TRACE_ERROR("Error during serializing dims info for Blosc2 NDim"); |
255 | 0 | BLOSC_ERROR(BLOSC2_ERROR_FAILURE); |
256 | 0 | } |
257 | | // ... and update it in its metalayer |
258 | 0 | if (blosc2_meta_exists(array->sc, "b2nd") < 0) { |
259 | 0 | if (blosc2_meta_add(array->sc, "b2nd", smeta, smeta_len) < 0) { |
260 | 0 | BLOSC_ERROR(BLOSC2_ERROR_FAILURE); |
261 | 0 | } |
262 | 0 | } else { |
263 | 0 | if (blosc2_meta_update(array->sc, "b2nd", smeta, smeta_len) < 0) { |
264 | 0 | BLOSC_ERROR(BLOSC2_ERROR_FAILURE); |
265 | 0 | } |
266 | 0 | } |
267 | 0 | free(smeta); |
268 | 0 | } |
269 | | |
270 | 0 | return BLOSC2_ERROR_SUCCESS; |
271 | 0 | } |
272 | | |
273 | | |
274 | 0 | int array_without_schunk(b2nd_context_t *ctx, b2nd_array_t **array) { |
275 | | /* Create a b2nd_array_t buffer */ |
276 | 0 | (*array) = (b2nd_array_t *) malloc(sizeof(b2nd_array_t)); |
277 | 0 | BLOSC_ERROR_NULL(*array, BLOSC2_ERROR_MEMORY_ALLOC); |
278 | | |
279 | 0 | (*array)->sc = NULL; |
280 | |
|
281 | 0 | (*array)->ndim = ctx->ndim; |
282 | 0 | int64_t *shape = ctx->shape; |
283 | 0 | int32_t *chunkshape = ctx->chunkshape; |
284 | 0 | int32_t *blockshape = ctx->blockshape; |
285 | 0 | BLOSC_ERROR(update_shape(*array, ctx->ndim, shape, chunkshape, blockshape)); |
286 | | |
287 | 0 | if (ctx->dtype != NULL) { |
288 | 0 | (*array)->dtype = malloc(strlen(ctx->dtype) + 1); |
289 | 0 | strcpy((*array)->dtype, ctx->dtype); |
290 | 0 | } else { |
291 | 0 | (*array)->dtype = NULL; |
292 | 0 | } |
293 | |
|
294 | 0 | (*array)->dtype_format = ctx->dtype_format; |
295 | | |
296 | | // The partition cache (empty initially) |
297 | 0 | (*array)->chunk_cache.data = NULL; |
298 | 0 | (*array)->chunk_cache.nchunk = -1; // means no valid cache yet |
299 | |
|
300 | 0 | return BLOSC2_ERROR_SUCCESS; |
301 | 0 | } |
302 | | |
303 | | |
304 | 0 | int array_new(b2nd_context_t *ctx, int special_value, b2nd_array_t **array) { |
305 | 0 | BLOSC_ERROR(array_without_schunk(ctx, array)); |
306 | | |
307 | 0 | blosc2_schunk *sc = blosc2_schunk_new(ctx->b2_storage); |
308 | 0 | if (sc == NULL) { |
309 | 0 | BLOSC_TRACE_ERROR("Pointer is NULL"); |
310 | 0 | return BLOSC2_ERROR_FAILURE; |
311 | 0 | } |
312 | | // Set the chunksize for the schunk, as it cannot be derived from storage |
313 | 0 | int32_t chunksize = (int32_t) (*array)->extchunknitems * sc->typesize; |
314 | 0 | sc->chunksize = chunksize; |
315 | | |
316 | | // Serialize the dimension info |
317 | 0 | if (sc->nmetalayers >= BLOSC2_MAX_METALAYERS) { |
318 | 0 | BLOSC_TRACE_ERROR("the number of metalayers for this schunk has been exceeded"); |
319 | 0 | return BLOSC2_ERROR_FAILURE; |
320 | 0 | } |
321 | 0 | uint8_t *smeta = NULL; |
322 | 0 | int32_t smeta_len = b2nd_serialize_meta(ctx->ndim, |
323 | 0 | (*array)->shape, |
324 | 0 | (*array)->chunkshape, |
325 | 0 | (*array)->blockshape, |
326 | 0 | (*array)->dtype, |
327 | 0 | (*array)->dtype_format, |
328 | 0 | &smeta); |
329 | 0 | if (smeta_len < 0) { |
330 | 0 | BLOSC_TRACE_ERROR("error during serializing dims info for Blosc2 NDim"); |
331 | 0 | return BLOSC2_ERROR_FAILURE; |
332 | 0 | } |
333 | | |
334 | | // And store it in b2nd metalayer |
335 | 0 | if (blosc2_meta_add(sc, "b2nd", smeta, smeta_len) < 0) { |
336 | 0 | return BLOSC2_ERROR_FAILURE; |
337 | 0 | } |
338 | | |
339 | 0 | free(smeta); |
340 | |
|
341 | 0 | for (int i = 0; i < ctx->nmetalayers; ++i) { |
342 | 0 | char *name = ctx->metalayers[i].name; |
343 | 0 | uint8_t *data = ctx->metalayers[i].content; |
344 | 0 | int32_t size = ctx->metalayers[i].content_len; |
345 | 0 | if (blosc2_meta_add(sc, name, data, size) < 0) { |
346 | 0 | BLOSC_ERROR(BLOSC2_ERROR_FAILURE); |
347 | 0 | } |
348 | 0 | } |
349 | | |
350 | 0 | if ((*array)->extchunknitems * sc->typesize > BLOSC2_MAX_BUFFERSIZE){ |
351 | 0 | BLOSC_TRACE_ERROR("Chunksize exceeds maximum of %d", BLOSC2_MAX_BUFFERSIZE); |
352 | 0 | return BLOSC2_ERROR_MAX_BUFSIZE_EXCEEDED; |
353 | 0 | } |
354 | | // Fill schunk with uninit values |
355 | 0 | if ((*array)->nitems != 0) { |
356 | 0 | int64_t nchunks = (*array)->extnitems / (*array)->chunknitems; |
357 | 0 | int64_t nitems = nchunks * (*array)->extchunknitems; |
358 | | // blosc2_schunk_fill_special(sc, nitems, BLOSC2_SPECIAL_ZERO, chunksize); |
359 | 0 | BLOSC_ERROR(blosc2_schunk_fill_special(sc, nitems, special_value, chunksize)); |
360 | 0 | } |
361 | 0 | (*array)->sc = sc; |
362 | |
|
363 | 0 | return BLOSC2_ERROR_SUCCESS; |
364 | 0 | } |
365 | | |
366 | | |
367 | 0 | int b2nd_uninit(b2nd_context_t *ctx, b2nd_array_t **array) { |
368 | 0 | BLOSC_ERROR_NULL(ctx, BLOSC2_ERROR_NULL_POINTER); |
369 | 0 | BLOSC_ERROR_NULL(array, BLOSC2_ERROR_NULL_POINTER); |
370 | | |
371 | 0 | BLOSC_ERROR(array_new(ctx, BLOSC2_SPECIAL_UNINIT, array)); |
372 | | |
373 | 0 | return BLOSC2_ERROR_SUCCESS; |
374 | 0 | } |
375 | | |
376 | | |
377 | 0 | int b2nd_empty(b2nd_context_t *ctx, b2nd_array_t **array) { |
378 | 0 | BLOSC_ERROR_NULL(ctx, BLOSC2_ERROR_NULL_POINTER); |
379 | 0 | BLOSC_ERROR_NULL(array, BLOSC2_ERROR_NULL_POINTER); |
380 | | |
381 | | // Fill with zeros to avoid variable cratios |
382 | 0 | BLOSC_ERROR(array_new(ctx, BLOSC2_SPECIAL_ZERO, array)); |
383 | | |
384 | 0 | return BLOSC2_ERROR_SUCCESS; |
385 | 0 | } |
386 | | |
387 | | |
388 | 0 | int b2nd_zeros(b2nd_context_t *ctx, b2nd_array_t **array) { |
389 | 0 | BLOSC_ERROR_NULL(ctx, BLOSC2_ERROR_NULL_POINTER); |
390 | 0 | BLOSC_ERROR_NULL(array, BLOSC2_ERROR_NULL_POINTER); |
391 | | |
392 | 0 | BLOSC_ERROR(array_new(ctx, BLOSC2_SPECIAL_ZERO, array)); |
393 | | |
394 | 0 | return BLOSC2_ERROR_SUCCESS; |
395 | 0 | } |
396 | | |
397 | | |
398 | 0 | int b2nd_nans(b2nd_context_t *ctx, b2nd_array_t **array) { |
399 | 0 | BLOSC_ERROR_NULL(ctx, BLOSC2_ERROR_NULL_POINTER); |
400 | 0 | BLOSC_ERROR_NULL(array, BLOSC2_ERROR_NULL_POINTER); |
401 | | |
402 | 0 | BLOSC_ERROR(array_new(ctx, BLOSC2_SPECIAL_NAN, array)); |
403 | | |
404 | 0 | const int32_t typesize = (*array)->sc->typesize; |
405 | 0 | if (typesize != 4 && typesize != 8) |
406 | 0 | { |
407 | 0 | BLOSC_TRACE_ERROR("Unsupported typesize for NaN"); |
408 | 0 | return BLOSC2_ERROR_DATA; |
409 | 0 | } |
410 | | |
411 | 0 | return BLOSC2_ERROR_SUCCESS; |
412 | 0 | } |
413 | | |
414 | | |
415 | 0 | int b2nd_full(b2nd_context_t *ctx, b2nd_array_t **array, const void *fill_value) { |
416 | 0 | BLOSC_ERROR_NULL(ctx, BLOSC2_ERROR_NULL_POINTER); |
417 | 0 | BLOSC_ERROR_NULL(array, BLOSC2_ERROR_NULL_POINTER); |
418 | | |
419 | 0 | BLOSC_ERROR(b2nd_empty(ctx, array)); |
420 | | |
421 | 0 | int32_t chunkbytes = (int32_t) (*array)->extchunknitems * (*array)->sc->typesize; |
422 | |
|
423 | 0 | blosc2_cparams *cparams; |
424 | 0 | if (blosc2_schunk_get_cparams((*array)->sc, &cparams) != 0) { |
425 | 0 | BLOSC_ERROR(BLOSC2_ERROR_FAILURE); |
426 | 0 | } |
427 | | |
428 | 0 | int32_t chunksize = BLOSC_EXTENDED_HEADER_LENGTH + (*array)->sc->typesize; |
429 | 0 | uint8_t *chunk = malloc(chunksize); |
430 | 0 | BLOSC_ERROR_NULL(chunk, BLOSC2_ERROR_MEMORY_ALLOC); |
431 | 0 | if (blosc2_chunk_repeatval(*cparams, chunkbytes, chunk, chunksize, fill_value) < 0) { |
432 | 0 | BLOSC_ERROR(BLOSC2_ERROR_FAILURE); |
433 | 0 | } |
434 | 0 | free(cparams); |
435 | |
|
436 | 0 | for (int i = 0; i < (*array)->sc->nchunks; ++i) { |
437 | 0 | if (blosc2_schunk_update_chunk((*array)->sc, i, chunk, true) < 0) { |
438 | 0 | BLOSC_ERROR(BLOSC2_ERROR_FAILURE); |
439 | 0 | } |
440 | 0 | } |
441 | 0 | free(chunk); |
442 | |
|
443 | 0 | return BLOSC2_ERROR_SUCCESS; |
444 | 0 | } |
445 | | |
446 | | |
447 | 0 | int b2nd_from_schunk(blosc2_schunk *schunk, b2nd_array_t **array) { |
448 | 0 | BLOSC_ERROR_NULL(schunk, BLOSC2_ERROR_NULL_POINTER); |
449 | 0 | BLOSC_ERROR_NULL(array, BLOSC2_ERROR_NULL_POINTER); |
450 | | |
451 | 0 | if (schunk == NULL) { |
452 | 0 | BLOSC_TRACE_ERROR("Schunk is null"); |
453 | 0 | return BLOSC2_ERROR_NULL_POINTER; |
454 | 0 | } |
455 | | |
456 | 0 | blosc2_cparams *cparams; |
457 | 0 | if (blosc2_schunk_get_cparams(schunk, &cparams) < 0) { |
458 | 0 | BLOSC_TRACE_ERROR("Blosc error"); |
459 | 0 | return BLOSC2_ERROR_NULL_POINTER; |
460 | 0 | } |
461 | 0 | free(cparams); |
462 | |
|
463 | 0 | b2nd_context_t params = {0}; |
464 | 0 | params.b2_storage = schunk->storage; |
465 | | |
466 | | // Deserialize the b2nd metalayer |
467 | 0 | uint8_t *smeta; |
468 | 0 | int32_t smeta_len; |
469 | 0 | if (blosc2_meta_get(schunk, "b2nd", &smeta, &smeta_len) < 0) { |
470 | | // Try with a caterva metalayer; we are meant to be backward compatible with it |
471 | 0 | if (blosc2_meta_get(schunk, "caterva", &smeta, &smeta_len) < 0) { |
472 | 0 | BLOSC_ERROR(BLOSC2_ERROR_METALAYER_NOT_FOUND); |
473 | 0 | } |
474 | 0 | } |
475 | 0 | BLOSC_ERROR(b2nd_deserialize_meta(smeta, smeta_len, ¶ms.ndim, params.shape, |
476 | 0 | params.chunkshape, params.blockshape, ¶ms.dtype, |
477 | 0 | ¶ms.dtype_format)); |
478 | 0 | free(smeta); |
479 | |
|
480 | 0 | BLOSC_ERROR(array_without_schunk(¶ms, array)); |
481 | 0 | free(params.dtype); |
482 | |
|
483 | 0 | (*array)->sc = schunk; |
484 | |
|
485 | 0 | if ((*array) == NULL) { |
486 | 0 | BLOSC_TRACE_ERROR("Error creating a b2nd container from a frame"); |
487 | 0 | return BLOSC2_ERROR_NULL_POINTER; |
488 | 0 | } |
489 | | |
490 | 0 | return BLOSC2_ERROR_SUCCESS; |
491 | 0 | } |
492 | | |
493 | | |
494 | | int b2nd_to_cframe(const b2nd_array_t *array, uint8_t **cframe, int64_t *cframe_len, |
495 | 0 | bool *needs_free) { |
496 | 0 | BLOSC_ERROR_NULL(array, BLOSC2_ERROR_NULL_POINTER); |
497 | 0 | BLOSC_ERROR_NULL(cframe, BLOSC2_ERROR_NULL_POINTER); |
498 | 0 | BLOSC_ERROR_NULL(cframe_len, BLOSC2_ERROR_NULL_POINTER); |
499 | 0 | BLOSC_ERROR_NULL(needs_free, BLOSC2_ERROR_NULL_POINTER); |
500 | | |
501 | 0 | *cframe_len = blosc2_schunk_to_buffer(array->sc, cframe, needs_free); |
502 | 0 | if (*cframe_len <= 0) { |
503 | 0 | BLOSC_TRACE_ERROR("Error serializing the b2nd array"); |
504 | 0 | return BLOSC2_ERROR_FAILURE; |
505 | 0 | } |
506 | 0 | return BLOSC2_ERROR_SUCCESS; |
507 | 0 | } |
508 | | |
509 | | |
510 | 0 | int b2nd_from_cframe(uint8_t *cframe, int64_t cframe_len, bool copy, b2nd_array_t **array) { |
511 | 0 | BLOSC_ERROR_NULL(cframe, BLOSC2_ERROR_NULL_POINTER); |
512 | 0 | BLOSC_ERROR_NULL(array, BLOSC2_ERROR_NULL_POINTER); |
513 | | |
514 | 0 | blosc2_schunk *sc = blosc2_schunk_from_buffer(cframe, cframe_len, copy); |
515 | 0 | if (sc == NULL) { |
516 | 0 | BLOSC_TRACE_ERROR("Blosc error"); |
517 | 0 | return BLOSC2_ERROR_FAILURE; |
518 | 0 | } |
519 | | // ...and create a b2nd array out of it |
520 | 0 | BLOSC_ERROR(b2nd_from_schunk(sc, array)); |
521 | | |
522 | 0 | return BLOSC2_ERROR_SUCCESS; |
523 | 0 | } |
524 | | |
525 | | |
526 | 0 | int b2nd_open(const char *urlpath, b2nd_array_t **array) { |
527 | 0 | BLOSC_ERROR_NULL(urlpath, BLOSC2_ERROR_NULL_POINTER); |
528 | 0 | BLOSC_ERROR_NULL(array, BLOSC2_ERROR_NULL_POINTER); |
529 | | |
530 | 0 | blosc2_schunk *sc = blosc2_schunk_open(urlpath); |
531 | | |
532 | | // ...and create a b2nd array out of it |
533 | 0 | BLOSC_ERROR(b2nd_from_schunk(sc, array)); |
534 | | |
535 | 0 | return BLOSC2_ERROR_SUCCESS; |
536 | 0 | } |
537 | | |
538 | | |
539 | 0 | int b2nd_open_offset(const char *urlpath, b2nd_array_t **array, int64_t offset) { |
540 | 0 | BLOSC_ERROR_NULL(urlpath, BLOSC2_ERROR_NULL_POINTER); |
541 | 0 | BLOSC_ERROR_NULL(array, BLOSC2_ERROR_NULL_POINTER); |
542 | | |
543 | 0 | blosc2_schunk *sc = blosc2_schunk_open_offset(urlpath, offset); |
544 | | |
545 | | // ...and create a b2nd array out of it |
546 | 0 | BLOSC_ERROR(b2nd_from_schunk(sc, array)); |
547 | | |
548 | 0 | return BLOSC2_ERROR_SUCCESS; |
549 | 0 | } |
550 | | |
551 | | |
552 | 0 | int b2nd_free(b2nd_array_t *array) { |
553 | 0 | BLOSC_ERROR_NULL(array, BLOSC2_ERROR_NULL_POINTER); |
554 | | |
555 | 0 | if (array) { |
556 | 0 | if (array->sc != NULL) { |
557 | 0 | blosc2_schunk_free(array->sc); |
558 | 0 | } |
559 | 0 | free(array->dtype); |
560 | 0 | free(array); |
561 | 0 | } |
562 | 0 | return BLOSC2_ERROR_SUCCESS; |
563 | 0 | } |
564 | | |
565 | | |
566 | 0 | int b2nd_from_cbuffer(b2nd_context_t *ctx, b2nd_array_t **array, const void *buffer, int64_t buffersize) { |
567 | 0 | BLOSC_ERROR_NULL(ctx, BLOSC2_ERROR_NULL_POINTER); |
568 | 0 | BLOSC_ERROR_NULL(buffer, BLOSC2_ERROR_NULL_POINTER); |
569 | 0 | BLOSC_ERROR_NULL(array, BLOSC2_ERROR_NULL_POINTER); |
570 | | |
571 | 0 | BLOSC_ERROR(b2nd_empty(ctx, array)); |
572 | | |
573 | 0 | if (buffersize < (int64_t) (*array)->nitems * (*array)->sc->typesize) { |
574 | 0 | BLOSC_TRACE_ERROR("The buffersize (%lld) is smaller than the array size (%lld)", |
575 | 0 | (long long) buffersize, (long long) (*array)->nitems * (*array)->sc->typesize); |
576 | 0 | BLOSC_ERROR(BLOSC2_ERROR_INVALID_PARAM); |
577 | 0 | } |
578 | | |
579 | 0 | if ((*array)->nitems == 0) { |
580 | 0 | return BLOSC2_ERROR_SUCCESS; |
581 | 0 | } |
582 | | |
583 | 0 | int64_t start[B2ND_MAX_DIM] = {0}; |
584 | 0 | int64_t *stop = (*array)->shape; |
585 | 0 | int64_t *shape = (*array)->shape; |
586 | 0 | BLOSC_ERROR(b2nd_set_slice_cbuffer(buffer, shape, buffersize, start, stop, *array)); |
587 | | |
588 | 0 | return BLOSC2_ERROR_SUCCESS; |
589 | 0 | } |
590 | | |
591 | | |
592 | | int b2nd_to_cbuffer(const b2nd_array_t *array, void *buffer, |
593 | 0 | int64_t buffersize) { |
594 | 0 | BLOSC_ERROR_NULL(array, BLOSC2_ERROR_NULL_POINTER); |
595 | 0 | BLOSC_ERROR_NULL(buffer, BLOSC2_ERROR_NULL_POINTER); |
596 | | |
597 | 0 | if (buffersize < (int64_t) array->nitems * array->sc->typesize) { |
598 | 0 | BLOSC_ERROR(BLOSC2_ERROR_INVALID_PARAM); |
599 | 0 | } |
600 | | |
601 | 0 | if (array->nitems == 0) { |
602 | 0 | return BLOSC2_ERROR_SUCCESS; |
603 | 0 | } |
604 | | |
605 | 0 | int64_t start[B2ND_MAX_DIM] = {0}; |
606 | 0 | const int64_t *stop = array->shape; |
607 | 0 | BLOSC_ERROR(b2nd_get_slice_cbuffer(array, start, stop, buffer, array->shape, buffersize)); |
608 | 0 | return BLOSC2_ERROR_SUCCESS; |
609 | 0 | } |
610 | | |
611 | 0 | int b2nd_get_slice_nchunks(const b2nd_array_t *array, const int64_t *start, const int64_t *stop, int64_t **chunks_idx) { |
612 | 0 | BLOSC_ERROR_NULL(array, BLOSC2_ERROR_NULL_POINTER); |
613 | 0 | BLOSC_ERROR_NULL(start, BLOSC2_ERROR_NULL_POINTER); |
614 | 0 | BLOSC_ERROR_NULL(stop, BLOSC2_ERROR_NULL_POINTER); |
615 | | |
616 | 0 | int8_t ndim = array->ndim; |
617 | | |
618 | | // 0-dim case |
619 | 0 | if (ndim == 0) { |
620 | 0 | *chunks_idx = malloc(1 * sizeof(int64_t)); |
621 | 0 | *chunks_idx[0] = 0; |
622 | 0 | return 1; |
623 | 0 | } |
624 | | |
625 | 0 | int64_t chunks_in_array[B2ND_MAX_DIM] = {0}; |
626 | 0 | for (int i = 0; i < ndim; ++i) { |
627 | 0 | chunks_in_array[i] = array->extshape[i] / array->chunkshape[i]; |
628 | 0 | } |
629 | |
|
630 | 0 | int64_t chunks_in_array_strides[B2ND_MAX_DIM]; |
631 | 0 | chunks_in_array_strides[ndim - 1] = 1; |
632 | 0 | for (int i = ndim - 2; i >= 0; --i) { |
633 | 0 | chunks_in_array_strides[i] = chunks_in_array_strides[i + 1] * chunks_in_array[i + 1]; |
634 | 0 | } |
635 | | |
636 | | // Compute the number of chunks to update |
637 | 0 | int64_t update_start[B2ND_MAX_DIM]; |
638 | 0 | int64_t update_shape[B2ND_MAX_DIM]; |
639 | |
|
640 | 0 | int64_t update_nchunks = 1; |
641 | 0 | for (int i = 0; i < ndim; ++i) { |
642 | 0 | int64_t pos = 0; |
643 | 0 | while (pos <= start[i]) { |
644 | 0 | pos += array->chunkshape[i]; |
645 | 0 | } |
646 | 0 | update_start[i] = pos / array->chunkshape[i] - 1; |
647 | 0 | while (pos < stop[i]) { |
648 | 0 | pos += array->chunkshape[i]; |
649 | 0 | } |
650 | 0 | update_shape[i] = pos / array->chunkshape[i] - update_start[i]; |
651 | 0 | update_nchunks *= update_shape[i]; |
652 | 0 | } |
653 | |
|
654 | 0 | int nchunks = 0; |
655 | | // Initially we do not know the number of chunks that will be affected |
656 | 0 | *chunks_idx = malloc(array->sc->nchunks * sizeof(int64_t)); |
657 | 0 | int64_t *ptr = *chunks_idx; |
658 | 0 | for (int update_nchunk = 0; update_nchunk < update_nchunks; ++update_nchunk) { |
659 | 0 | int64_t nchunk_ndim[B2ND_MAX_DIM] = {0}; |
660 | 0 | blosc2_unidim_to_multidim(ndim, update_shape, update_nchunk, nchunk_ndim); |
661 | 0 | for (int i = 0; i < ndim; ++i) { |
662 | 0 | nchunk_ndim[i] += update_start[i]; |
663 | 0 | } |
664 | 0 | int64_t nchunk; |
665 | 0 | blosc2_multidim_to_unidim(nchunk_ndim, ndim, chunks_in_array_strides, &nchunk); |
666 | | |
667 | | // Check if the chunk is inside the slice domain |
668 | 0 | int64_t chunk_start[B2ND_MAX_DIM] = {0}; |
669 | 0 | int64_t chunk_stop[B2ND_MAX_DIM] = {0}; |
670 | 0 | for (int i = 0; i < ndim; ++i) { |
671 | 0 | chunk_start[i] = nchunk_ndim[i] * array->chunkshape[i]; |
672 | 0 | chunk_stop[i] = chunk_start[i] + array->chunkshape[i]; |
673 | 0 | if (chunk_stop[i] > array->shape[i]) { |
674 | 0 | chunk_stop[i] = array->shape[i]; |
675 | 0 | } |
676 | 0 | } |
677 | 0 | bool chunk_empty = false; |
678 | 0 | for (int i = 0; i < ndim; ++i) { |
679 | 0 | chunk_empty |= (chunk_stop[i] <= start[i] || chunk_start[i] >= stop[i]); |
680 | 0 | } |
681 | 0 | if (chunk_empty) { |
682 | 0 | continue; |
683 | 0 | } |
684 | | |
685 | 0 | ptr[nchunks] = nchunk; |
686 | 0 | nchunks++; |
687 | 0 | } |
688 | |
|
689 | 0 | if (nchunks < array->sc->nchunks) { |
690 | 0 | *chunks_idx = realloc(ptr, nchunks * sizeof(int64_t)); |
691 | 0 | } |
692 | |
|
693 | 0 | return nchunks; |
694 | 0 | } |
695 | | |
696 | | |
697 | | // Check whether the slice defined by start and stop is a single chunk and contiguous |
698 | | // in the C order. We also need blocks inside a chunk, and chunks inside an array, |
699 | | // are C contiguous. This is a fast path for the get_slice and set_slice functions. |
700 | | int64_t nchunk_fastpath(const b2nd_array_t *array, const int64_t *start, |
701 | 0 | const int64_t *stop, const int64_t slice_size) { |
702 | 0 | if (slice_size != array->chunknitems) { |
703 | 0 | return -1; |
704 | 0 | } |
705 | | |
706 | 0 | int ndim = (int) array->ndim; |
707 | 0 | int inner_dim = ndim - 1; |
708 | 0 | int64_t partial_slice_size = 1; |
709 | 0 | int64_t partial_chunk_size = 1; |
710 | 0 | for (int i = ndim - 1; i >= 0; --i) { |
711 | | // We need to check if the slice is contiguous in the C order |
712 | 0 | if (array->extshape[i] != array->shape[i]) { |
713 | 0 | return -1; |
714 | 0 | } |
715 | 0 | if (array->extchunkshape[i] != array->chunkshape[i]) { |
716 | 0 | return -1; |
717 | 0 | } |
718 | | |
719 | | // blocks need to be C contiguous inside the chunk as well |
720 | 0 | if (array->chunkshape[i] > array->blockshape[i]) { |
721 | 0 | if (i < inner_dim) { |
722 | 0 | if (array->chunkshape[i] % array->blockshape[i] != 0) { |
723 | 0 | return -1; |
724 | 0 | } |
725 | 0 | } |
726 | 0 | else { |
727 | 0 | if (array->chunkshape[i] != array->blockshape[i]) { |
728 | 0 | return -1; |
729 | 0 | } |
730 | 0 | } |
731 | 0 | inner_dim = i; |
732 | 0 | } |
733 | | |
734 | | // We need start and stop to be aligned with the chunkshape |
735 | | // Do that by computing the slice size in reverse order and compare with the chunkshape |
736 | 0 | partial_slice_size *= stop[i] - start[i]; |
737 | 0 | partial_chunk_size *= array->chunkshape[i]; |
738 | 0 | if (partial_slice_size != partial_chunk_size) { |
739 | 0 | return -1; |
740 | 0 | } |
741 | | // Ensure that the slice starts at the beginning of the chunk |
742 | 0 | if (start[i] % array->chunkshape[i] != 0) { |
743 | 0 | return -1; |
744 | 0 | } |
745 | 0 | } |
746 | | |
747 | | // Compute the chunk number |
748 | 0 | int64_t *chunks_idx; |
749 | 0 | int nchunks = b2nd_get_slice_nchunks(array, start, stop, &chunks_idx); |
750 | 0 | if (nchunks != 1) { |
751 | 0 | free(chunks_idx); |
752 | 0 | BLOSC_TRACE_ERROR("The number of chunks to read is not 1; go fix the code"); |
753 | 0 | BLOSC_ERROR(BLOSC2_ERROR_FAILURE); |
754 | 0 | } |
755 | 0 | int64_t nchunk = chunks_idx[0]; |
756 | 0 | free(chunks_idx); |
757 | |
|
758 | 0 | return nchunk; |
759 | 0 | } |
760 | | |
761 | | |
762 | | // Setting and getting slices |
763 | | int get_set_slice(void *buffer, int64_t buffersize, const int64_t *start, const int64_t *stop, |
764 | 0 | const int64_t *shape, b2nd_array_t *array, bool set_slice) { |
765 | 0 | BLOSC_ERROR_NULL(buffer, BLOSC2_ERROR_NULL_POINTER); |
766 | 0 | BLOSC_ERROR_NULL(start, BLOSC2_ERROR_NULL_POINTER); |
767 | 0 | BLOSC_ERROR_NULL(stop, BLOSC2_ERROR_NULL_POINTER); |
768 | 0 | BLOSC_ERROR_NULL(array, BLOSC2_ERROR_NULL_POINTER); |
769 | 0 | if (buffersize < 0) { |
770 | 0 | BLOSC_TRACE_ERROR("buffersize is < 0"); |
771 | 0 | BLOSC_ERROR(BLOSC2_ERROR_INVALID_PARAM); |
772 | 0 | } |
773 | | |
774 | 0 | uint8_t *buffer_b = (uint8_t *) buffer; |
775 | 0 | const int64_t *buffer_start = start; |
776 | 0 | const int64_t *buffer_stop = stop; |
777 | 0 | const int64_t *buffer_shape = shape; |
778 | |
|
779 | 0 | int8_t ndim = array->ndim; |
780 | | |
781 | | // 0-dim case |
782 | 0 | if (ndim == 0) { |
783 | 0 | if (set_slice) { |
784 | 0 | int32_t chunk_size = array->sc->typesize + BLOSC2_MAX_OVERHEAD; |
785 | 0 | uint8_t *chunk = malloc(chunk_size); |
786 | 0 | BLOSC_ERROR_NULL(chunk, BLOSC2_ERROR_MEMORY_ALLOC); |
787 | 0 | if (blosc2_compress_ctx(array->sc->cctx, buffer_b, array->sc->typesize, chunk, chunk_size) < 0) { |
788 | 0 | BLOSC_ERROR(BLOSC2_ERROR_FAILURE); |
789 | 0 | } |
790 | 0 | if (blosc2_schunk_update_chunk(array->sc, 0, chunk, false) < 0) { |
791 | 0 | BLOSC_ERROR(BLOSC2_ERROR_FAILURE); |
792 | 0 | } |
793 | |
|
794 | 0 | } else { |
795 | 0 | if (blosc2_schunk_decompress_chunk(array->sc, 0, buffer_b, array->sc->typesize) < 0) { |
796 | 0 | BLOSC_ERROR(BLOSC2_ERROR_FAILURE); |
797 | 0 | } |
798 | 0 | } |
799 | 0 | return BLOSC2_ERROR_SUCCESS; |
800 | 0 | } |
801 | | |
802 | 0 | if (array->nitems == 0) { |
803 | 0 | return BLOSC2_ERROR_SUCCESS; |
804 | 0 | } |
805 | | |
806 | 0 | int64_t nelems_slice = 1; |
807 | 0 | for (int i = 0; i < array->ndim; ++i) { |
808 | 0 | if (stop[i] - start[i] > shape[i]) { |
809 | 0 | BLOSC_TRACE_ERROR("The buffer shape can not be smaller than the slice shape"); |
810 | 0 | return BLOSC2_ERROR_INVALID_PARAM; |
811 | 0 | } |
812 | 0 | nelems_slice *= stop[i] - start[i]; |
813 | 0 | } |
814 | 0 | int64_t slice_nbytes = nelems_slice * array->sc->typesize; |
815 | 0 | int32_t data_nbytes = (int32_t) array->extchunknitems * array->sc->typesize; |
816 | |
|
817 | 0 | if (buffersize < slice_nbytes) { |
818 | 0 | BLOSC_ERROR(BLOSC2_ERROR_INVALID_PARAM); |
819 | 0 | } |
820 | | |
821 | | // Check for fast path for aligned slices with chunks and blocks (only 1 chunk is supported) |
822 | 0 | int64_t nchunk = nchunk_fastpath(array, start, stop, nelems_slice); |
823 | 0 | if (nchunk >= 0) { |
824 | 0 | if (set_slice) { |
825 | | // Fast path for set. Let's set the chunk buffer straight into the array. |
826 | | // Compress the chunk |
827 | 0 | int32_t chunk_nbytes = data_nbytes + BLOSC2_MAX_OVERHEAD; |
828 | 0 | uint8_t *chunk = malloc(chunk_nbytes); |
829 | 0 | BLOSC_ERROR_NULL(chunk, BLOSC2_ERROR_MEMORY_ALLOC); |
830 | 0 | int brc; |
831 | | // Update current_chunk in case a prefilter is applied |
832 | 0 | array->sc->current_nchunk = nchunk; |
833 | 0 | brc = blosc2_compress_ctx(array->sc->cctx, buffer, data_nbytes, chunk, chunk_nbytes); |
834 | 0 | if (brc < 0) { |
835 | 0 | BLOSC_TRACE_ERROR("Blosc can not compress the data"); |
836 | 0 | BLOSC_ERROR(BLOSC2_ERROR_FAILURE); |
837 | 0 | } |
838 | 0 | int64_t brc_ = blosc2_schunk_update_chunk(array->sc, nchunk, chunk, false); |
839 | 0 | if (brc_ < 0) { |
840 | 0 | BLOSC_TRACE_ERROR("Blosc can not update the chunk"); |
841 | 0 | BLOSC_ERROR(BLOSC2_ERROR_FAILURE); |
842 | 0 | } |
843 | | // We are done |
844 | 0 | return BLOSC2_ERROR_SUCCESS; |
845 | 0 | } |
846 | 0 | else { |
847 | | // Fast path for get. Let's read the chunk straight into the buffer. |
848 | 0 | if (blosc2_schunk_decompress_chunk(array->sc, nchunk, buffer, (int32_t) slice_nbytes) < 0) { |
849 | 0 | BLOSC_ERROR(BLOSC2_ERROR_FAILURE); |
850 | 0 | } |
851 | 0 | return BLOSC2_ERROR_SUCCESS; |
852 | 0 | } |
853 | 0 | } |
854 | | |
855 | | // Slow path for set and get |
856 | | |
857 | 0 | uint8_t *data = malloc(data_nbytes); |
858 | 0 | BLOSC_ERROR_NULL(data, BLOSC2_ERROR_MEMORY_ALLOC); |
859 | | |
860 | 0 | int64_t chunks_in_array[B2ND_MAX_DIM] = {0}; |
861 | 0 | for (int i = 0; i < ndim; ++i) { |
862 | 0 | chunks_in_array[i] = array->extshape[i] / array->chunkshape[i]; |
863 | 0 | } |
864 | |
|
865 | 0 | int64_t chunks_in_array_strides[B2ND_MAX_DIM]; |
866 | 0 | chunks_in_array_strides[ndim - 1] = 1; |
867 | 0 | for (int i = ndim - 2; i >= 0; --i) { |
868 | 0 | chunks_in_array_strides[i] = chunks_in_array_strides[i + 1] * chunks_in_array[i + 1]; |
869 | 0 | } |
870 | |
|
871 | 0 | int64_t blocks_in_chunk[B2ND_MAX_DIM] = {0}; |
872 | 0 | for (int i = 0; i < ndim; ++i) { |
873 | 0 | blocks_in_chunk[i] = array->extchunkshape[i] / array->blockshape[i]; |
874 | 0 | } |
875 | | |
876 | | // Compute the number of chunks to update |
877 | 0 | int64_t update_start[B2ND_MAX_DIM]; |
878 | 0 | int64_t update_shape[B2ND_MAX_DIM]; |
879 | |
|
880 | 0 | int64_t update_nchunks = 1; |
881 | 0 | for (int i = 0; i < ndim; ++i) { |
882 | 0 | int64_t pos = 0; |
883 | 0 | while (pos <= buffer_start[i]) { |
884 | 0 | pos += array->chunkshape[i]; |
885 | 0 | } |
886 | 0 | update_start[i] = pos / array->chunkshape[i] - 1; |
887 | 0 | while (pos < buffer_stop[i]) { |
888 | 0 | pos += array->chunkshape[i]; |
889 | 0 | } |
890 | 0 | update_shape[i] = pos / array->chunkshape[i] - update_start[i]; |
891 | 0 | update_nchunks *= update_shape[i]; |
892 | 0 | } |
893 | |
|
894 | 0 | for (int update_nchunk = 0; update_nchunk < update_nchunks; ++update_nchunk) { |
895 | 0 | int64_t nchunk_ndim[B2ND_MAX_DIM] = {0}; |
896 | 0 | blosc2_unidim_to_multidim(ndim, update_shape, update_nchunk, nchunk_ndim); |
897 | 0 | for (int i = 0; i < ndim; ++i) { |
898 | 0 | nchunk_ndim[i] += update_start[i]; |
899 | 0 | } |
900 | 0 | int64_t nchunk; |
901 | 0 | blosc2_multidim_to_unidim(nchunk_ndim, ndim, chunks_in_array_strides, &nchunk); |
902 | | |
903 | | // Check if the chunk needs to be updated |
904 | 0 | int64_t chunk_start[B2ND_MAX_DIM] = {0}; |
905 | 0 | int64_t chunk_stop[B2ND_MAX_DIM] = {0}; |
906 | 0 | for (int i = 0; i < ndim; ++i) { |
907 | 0 | chunk_start[i] = nchunk_ndim[i] * array->chunkshape[i]; |
908 | 0 | chunk_stop[i] = chunk_start[i] + array->chunkshape[i]; |
909 | 0 | if (chunk_stop[i] > array->shape[i]) { |
910 | 0 | chunk_stop[i] = array->shape[i]; |
911 | 0 | } |
912 | 0 | } |
913 | 0 | bool chunk_empty = false; |
914 | 0 | for (int i = 0; i < ndim; ++i) { |
915 | 0 | chunk_empty |= (chunk_stop[i] <= buffer_start[i] || chunk_start[i] >= buffer_stop[i]); |
916 | 0 | } |
917 | 0 | if (chunk_empty) { |
918 | 0 | continue; |
919 | 0 | } |
920 | | |
921 | 0 | int32_t nblocks = (int32_t) array->extchunknitems / array->blocknitems; |
922 | 0 | if (set_slice) { |
923 | | // Check if all the chunk is going to be updated and avoid the decompression |
924 | 0 | bool decompress_chunk = false; |
925 | 0 | for (int i = 0; i < ndim; ++i) { |
926 | 0 | decompress_chunk |= (chunk_start[i] < buffer_start[i] || chunk_stop[i] > buffer_stop[i]); |
927 | 0 | } |
928 | |
|
929 | 0 | if (decompress_chunk) { |
930 | 0 | int err = blosc2_schunk_decompress_chunk(array->sc, nchunk, data, data_nbytes); |
931 | 0 | if (err < 0) { |
932 | 0 | BLOSC_TRACE_ERROR("Error decompressing chunk"); |
933 | 0 | BLOSC_ERROR(BLOSC2_ERROR_FAILURE); |
934 | 0 | } |
935 | 0 | } else { |
936 | | // Avoid writing non zero padding from previous chunk |
937 | 0 | memset(data, 0, data_nbytes); |
938 | 0 | } |
939 | 0 | } else { |
940 | 0 | bool *block_maskout = malloc(nblocks); |
941 | 0 | BLOSC_ERROR_NULL(block_maskout, BLOSC2_ERROR_MEMORY_ALLOC); |
942 | 0 | for (int nblock = 0; nblock < nblocks; ++nblock) { |
943 | 0 | int64_t nblock_ndim[B2ND_MAX_DIM] = {0}; |
944 | 0 | blosc2_unidim_to_multidim(ndim, blocks_in_chunk, nblock, nblock_ndim); |
945 | | |
946 | | // Check if the block needs to be updated |
947 | 0 | int64_t block_start[B2ND_MAX_DIM] = {0}; |
948 | 0 | int64_t block_stop[B2ND_MAX_DIM] = {0}; |
949 | 0 | for (int i = 0; i < ndim; ++i) { |
950 | 0 | block_start[i] = nblock_ndim[i] * array->blockshape[i]; |
951 | 0 | block_stop[i] = block_start[i] + array->blockshape[i]; |
952 | 0 | block_start[i] += chunk_start[i]; |
953 | 0 | block_stop[i] += chunk_start[i]; |
954 | |
|
955 | 0 | if (block_start[i] > chunk_stop[i]) { |
956 | 0 | block_start[i] = chunk_stop[i]; |
957 | 0 | } |
958 | 0 | if (block_stop[i] > chunk_stop[i]) { |
959 | 0 | block_stop[i] = chunk_stop[i]; |
960 | 0 | } |
961 | 0 | } |
962 | |
|
963 | 0 | bool block_empty = false; |
964 | 0 | for (int i = 0; i < ndim; ++i) { |
965 | 0 | block_empty |= (block_stop[i] <= start[i] || block_start[i] >= stop[i]); |
966 | 0 | } |
967 | 0 | block_maskout[nblock] = block_empty ? true : false; |
968 | 0 | } |
969 | |
|
970 | 0 | if (blosc2_set_maskout(array->sc->dctx, block_maskout, nblocks) != BLOSC2_ERROR_SUCCESS) { |
971 | 0 | BLOSC_TRACE_ERROR("Error setting the maskout"); |
972 | 0 | BLOSC_ERROR(BLOSC2_ERROR_FAILURE); |
973 | 0 | } |
974 | | |
975 | 0 | int err = blosc2_schunk_decompress_chunk(array->sc, nchunk, data, data_nbytes); |
976 | 0 | if (err < 0) { |
977 | 0 | BLOSC_TRACE_ERROR("Error decompressing chunk"); |
978 | 0 | BLOSC_ERROR(BLOSC2_ERROR_FAILURE); |
979 | 0 | } |
980 | | |
981 | 0 | free(block_maskout); |
982 | 0 | } |
983 | | |
984 | | // Iterate over blocks |
985 | | |
986 | 0 | for (int nblock = 0; nblock < nblocks; ++nblock) { |
987 | 0 | int64_t nblock_ndim[B2ND_MAX_DIM] = {0}; |
988 | 0 | blosc2_unidim_to_multidim(ndim, blocks_in_chunk, nblock, nblock_ndim); |
989 | | |
990 | | // Check if the block needs to be updated |
991 | 0 | int64_t block_start[B2ND_MAX_DIM] = {0}; |
992 | 0 | int64_t block_stop[B2ND_MAX_DIM] = {0}; |
993 | 0 | for (int i = 0; i < ndim; ++i) { |
994 | 0 | block_start[i] = nblock_ndim[i] * array->blockshape[i]; |
995 | 0 | block_stop[i] = block_start[i] + array->blockshape[i]; |
996 | 0 | block_start[i] += chunk_start[i]; |
997 | 0 | block_stop[i] += chunk_start[i]; |
998 | |
|
999 | 0 | if (block_start[i] > chunk_stop[i]) { |
1000 | 0 | block_start[i] = chunk_stop[i]; |
1001 | 0 | } |
1002 | 0 | if (block_stop[i] > chunk_stop[i]) { |
1003 | 0 | block_stop[i] = chunk_stop[i]; |
1004 | 0 | } |
1005 | 0 | } |
1006 | 0 | int64_t block_shape[B2ND_MAX_DIM] = {0}; |
1007 | 0 | for (int i = 0; i < ndim; ++i) { |
1008 | 0 | block_shape[i] = block_stop[i] - block_start[i]; |
1009 | 0 | } |
1010 | 0 | bool block_empty = false; |
1011 | 0 | for (int i = 0; i < ndim; ++i) { |
1012 | 0 | block_empty |= (block_stop[i] <= start[i] || block_start[i] >= stop[i]); |
1013 | 0 | } |
1014 | 0 | if (block_empty) { |
1015 | 0 | continue; |
1016 | 0 | } |
1017 | | |
1018 | | // compute the start of the slice inside the block |
1019 | 0 | int64_t slice_start[B2ND_MAX_DIM] = {0}; |
1020 | 0 | for (int i = 0; i < ndim; ++i) { |
1021 | 0 | if (block_start[i] < buffer_start[i]) { |
1022 | 0 | slice_start[i] = buffer_start[i] - block_start[i]; |
1023 | 0 | } else { |
1024 | 0 | slice_start[i] = 0; |
1025 | 0 | } |
1026 | 0 | slice_start[i] += block_start[i]; |
1027 | 0 | } |
1028 | |
|
1029 | 0 | int64_t slice_stop[B2ND_MAX_DIM] = {0}; |
1030 | 0 | for (int i = 0; i < ndim; ++i) { |
1031 | 0 | if (block_stop[i] > buffer_stop[i]) { |
1032 | 0 | slice_stop[i] = block_shape[i] - (block_stop[i] - buffer_stop[i]); |
1033 | 0 | } else { |
1034 | 0 | slice_stop[i] = block_stop[i] - block_start[i]; |
1035 | 0 | } |
1036 | 0 | slice_stop[i] += block_start[i]; |
1037 | 0 | } |
1038 | |
|
1039 | 0 | int64_t slice_shape[B2ND_MAX_DIM] = {0}; |
1040 | 0 | for (int i = 0; i < ndim; ++i) { |
1041 | 0 | slice_shape[i] = slice_stop[i] - slice_start[i]; |
1042 | 0 | } |
1043 | |
|
1044 | 0 | uint8_t *src = &buffer_b[0]; |
1045 | 0 | const int64_t *src_pad_shape = buffer_shape; |
1046 | |
|
1047 | 0 | int64_t src_start[B2ND_MAX_DIM] = {0}; |
1048 | 0 | int64_t src_stop[B2ND_MAX_DIM] = {0}; |
1049 | 0 | for (int i = 0; i < ndim; ++i) { |
1050 | 0 | src_start[i] = slice_start[i] - buffer_start[i]; |
1051 | 0 | src_stop[i] = slice_stop[i] - buffer_start[i]; |
1052 | 0 | } |
1053 | |
|
1054 | 0 | uint8_t *dst = &data[nblock * array->blocknitems * array->sc->typesize]; |
1055 | 0 | int64_t dst_pad_shape[B2ND_MAX_DIM]; |
1056 | 0 | for (int i = 0; i < ndim; ++i) { |
1057 | 0 | dst_pad_shape[i] = array->blockshape[i]; |
1058 | 0 | } |
1059 | |
|
1060 | 0 | int64_t dst_start[B2ND_MAX_DIM] = {0}; |
1061 | 0 | int64_t dst_stop[B2ND_MAX_DIM] = {0}; |
1062 | 0 | for (int i = 0; i < ndim; ++i) { |
1063 | 0 | dst_start[i] = slice_start[i] - block_start[i]; |
1064 | 0 | dst_stop[i] = dst_start[i] + slice_shape[i]; |
1065 | 0 | } |
1066 | |
|
1067 | 0 | if (set_slice) { |
1068 | 0 | b2nd_copy_buffer(ndim, array->sc->typesize, |
1069 | 0 | src, src_pad_shape, src_start, src_stop, |
1070 | 0 | dst, dst_pad_shape, dst_start); |
1071 | 0 | } else { |
1072 | 0 | b2nd_copy_buffer(ndim, array->sc->typesize, |
1073 | 0 | dst, dst_pad_shape, dst_start, dst_stop, |
1074 | 0 | src, src_pad_shape, src_start); |
1075 | 0 | } |
1076 | 0 | } |
1077 | |
|
1078 | 0 | if (set_slice) { |
1079 | | // Recompress the data |
1080 | 0 | int32_t chunk_nbytes = data_nbytes + BLOSC2_MAX_OVERHEAD; |
1081 | 0 | uint8_t *chunk = malloc(chunk_nbytes); |
1082 | 0 | BLOSC_ERROR_NULL(chunk, BLOSC2_ERROR_MEMORY_ALLOC); |
1083 | 0 | int brc; |
1084 | | // Update current_chunk in case a prefilter is applied |
1085 | 0 | array->sc->current_nchunk = nchunk; |
1086 | 0 | brc = blosc2_compress_ctx(array->sc->cctx, data, data_nbytes, chunk, chunk_nbytes); |
1087 | 0 | if (brc < 0) { |
1088 | 0 | BLOSC_TRACE_ERROR("Blosc can not compress the data"); |
1089 | 0 | BLOSC_ERROR(BLOSC2_ERROR_FAILURE); |
1090 | 0 | } |
1091 | 0 | int64_t brc_ = blosc2_schunk_update_chunk(array->sc, nchunk, chunk, false); |
1092 | 0 | if (brc_ < 0) { |
1093 | 0 | BLOSC_TRACE_ERROR("Blosc can not update the chunk"); |
1094 | 0 | BLOSC_ERROR(BLOSC2_ERROR_FAILURE); |
1095 | 0 | } |
1096 | 0 | } |
1097 | 0 | } |
1098 | | |
1099 | 0 | free(data); |
1100 | |
|
1101 | 0 | return BLOSC2_ERROR_SUCCESS; |
1102 | 0 | } |
1103 | | |
1104 | | |
1105 | | int b2nd_get_slice_cbuffer(const b2nd_array_t *array, const int64_t *start, const int64_t *stop, |
1106 | 0 | void *buffer, const int64_t *buffershape, int64_t buffersize) { |
1107 | 0 | BLOSC_ERROR_NULL(array, BLOSC2_ERROR_NULL_POINTER); |
1108 | 0 | BLOSC_ERROR_NULL(start, BLOSC2_ERROR_NULL_POINTER); |
1109 | 0 | BLOSC_ERROR_NULL(stop, BLOSC2_ERROR_NULL_POINTER); |
1110 | 0 | BLOSC_ERROR_NULL(buffershape, BLOSC2_ERROR_NULL_POINTER); |
1111 | 0 | BLOSC_ERROR_NULL(buffer, BLOSC2_ERROR_NULL_POINTER); |
1112 | | |
1113 | 0 | BLOSC_ERROR(get_set_slice(buffer, buffersize, start, stop, buffershape, (b2nd_array_t *)array, false)); |
1114 | | |
1115 | 0 | return BLOSC2_ERROR_SUCCESS; |
1116 | 0 | } |
1117 | | |
1118 | | |
1119 | | int b2nd_set_slice_cbuffer(const void *buffer, const int64_t *buffershape, int64_t buffersize, |
1120 | | const int64_t *start, const int64_t *stop, |
1121 | 0 | b2nd_array_t *array) { |
1122 | 0 | BLOSC_ERROR_NULL(buffer, BLOSC2_ERROR_NULL_POINTER); |
1123 | 0 | BLOSC_ERROR_NULL(start, BLOSC2_ERROR_NULL_POINTER); |
1124 | 0 | BLOSC_ERROR_NULL(stop, BLOSC2_ERROR_NULL_POINTER); |
1125 | 0 | BLOSC_ERROR_NULL(array, BLOSC2_ERROR_NULL_POINTER); |
1126 | | |
1127 | 0 | BLOSC_ERROR(get_set_slice((void*)buffer, buffersize, start, stop, (int64_t *)buffershape, array, true)); |
1128 | | |
1129 | 0 | return BLOSC2_ERROR_SUCCESS; |
1130 | 0 | } |
1131 | | |
1132 | | |
1133 | | int b2nd_get_slice(b2nd_context_t *ctx, b2nd_array_t **array, const b2nd_array_t *src, const int64_t *start, |
1134 | 0 | const int64_t *stop) { |
1135 | 0 | BLOSC_ERROR_NULL(src, BLOSC2_ERROR_NULL_POINTER); |
1136 | 0 | BLOSC_ERROR_NULL(start, BLOSC2_ERROR_NULL_POINTER); |
1137 | 0 | BLOSC_ERROR_NULL(stop, BLOSC2_ERROR_NULL_POINTER); |
1138 | 0 | BLOSC_ERROR_NULL(array, BLOSC2_ERROR_NULL_POINTER); |
1139 | | |
1140 | 0 | ctx->ndim = src->ndim; |
1141 | 0 | for (int i = 0; i < src->ndim; ++i) { |
1142 | 0 | ctx->shape[i] = stop[i] - start[i]; |
1143 | 0 | } |
1144 | | |
1145 | | // Add data |
1146 | 0 | BLOSC_ERROR(b2nd_empty(ctx, array)); |
1147 | | |
1148 | 0 | if ((*array)->nitems == 0) { |
1149 | 0 | return BLOSC2_ERROR_SUCCESS; |
1150 | 0 | } |
1151 | | |
1152 | 0 | int8_t ndim = (*array)->ndim; |
1153 | 0 | int64_t chunks_in_array[B2ND_MAX_DIM] = {0}; |
1154 | 0 | for (int i = 0; i < ndim; ++i) { |
1155 | 0 | chunks_in_array[i] = (*array)->extshape[i] / (*array)->chunkshape[i]; |
1156 | 0 | } |
1157 | 0 | int64_t nchunks = (*array)->sc->nchunks; |
1158 | 0 | for (int nchunk = 0; nchunk < nchunks; ++nchunk) { |
1159 | 0 | int64_t nchunk_ndim[B2ND_MAX_DIM] = {0}; |
1160 | 0 | blosc2_unidim_to_multidim(ndim, chunks_in_array, nchunk, nchunk_ndim); |
1161 | | |
1162 | | // Check if the chunk needs to be updated |
1163 | 0 | int64_t chunk_start[B2ND_MAX_DIM] = {0}; |
1164 | 0 | int64_t chunk_stop[B2ND_MAX_DIM] = {0}; |
1165 | 0 | int64_t chunk_shape[B2ND_MAX_DIM] = {0}; |
1166 | 0 | for (int i = 0; i < ndim; ++i) { |
1167 | 0 | chunk_start[i] = nchunk_ndim[i] * (*array)->chunkshape[i]; |
1168 | 0 | chunk_stop[i] = chunk_start[i] + (*array)->chunkshape[i]; |
1169 | 0 | if (chunk_stop[i] > (*array)->shape[i]) { |
1170 | 0 | chunk_stop[i] = (*array)->shape[i]; |
1171 | 0 | } |
1172 | 0 | chunk_shape[i] = chunk_stop[i] - chunk_start[i]; |
1173 | 0 | } |
1174 | |
|
1175 | 0 | int64_t src_start[B2ND_MAX_DIM] = {0}; |
1176 | 0 | int64_t src_stop[B2ND_MAX_DIM] = {0}; |
1177 | 0 | for (int i = 0; i < ndim; ++i) { |
1178 | 0 | src_start[i] = chunk_start[i] + start[i]; |
1179 | 0 | src_stop[i] = chunk_stop[i] + start[i]; |
1180 | 0 | } |
1181 | 0 | int64_t buffersize = ctx->b2_storage->cparams->typesize; |
1182 | 0 | for (int i = 0; i < ndim; ++i) { |
1183 | 0 | buffersize *= chunk_shape[i]; |
1184 | 0 | } |
1185 | 0 | uint8_t *buffer = malloc(buffersize); |
1186 | 0 | BLOSC_ERROR_NULL(buffer, BLOSC2_ERROR_MEMORY_ALLOC); |
1187 | 0 | BLOSC_ERROR(b2nd_get_slice_cbuffer(src, src_start, src_stop, buffer, chunk_shape, |
1188 | 0 | buffersize)); |
1189 | 0 | BLOSC_ERROR(b2nd_set_slice_cbuffer(buffer, chunk_shape, buffersize, chunk_start, |
1190 | 0 | chunk_stop, *array)); |
1191 | 0 | free(buffer); |
1192 | 0 | } |
1193 | | |
1194 | 0 | return BLOSC2_ERROR_SUCCESS; |
1195 | 0 | } |
1196 | | |
1197 | | |
1198 | 0 | int b2nd_squeeze(b2nd_array_t *array) { |
1199 | 0 | BLOSC_ERROR_NULL(array, BLOSC2_ERROR_NULL_POINTER); |
1200 | | |
1201 | 0 | bool index[B2ND_MAX_DIM]; |
1202 | |
|
1203 | 0 | for (int i = 0; i < array->ndim; ++i) { |
1204 | 0 | if (array->shape[i] != 1) { |
1205 | 0 | index[i] = false; |
1206 | 0 | } else { |
1207 | 0 | index[i] = true; |
1208 | 0 | } |
1209 | 0 | } |
1210 | 0 | BLOSC_ERROR(b2nd_squeeze_index(array, index)); |
1211 | | |
1212 | 0 | return BLOSC2_ERROR_SUCCESS; |
1213 | 0 | } |
1214 | | |
1215 | | |
1216 | 0 | int b2nd_squeeze_index(b2nd_array_t *array, const bool *index) { |
1217 | 0 | BLOSC_ERROR_NULL(array, BLOSC2_ERROR_NULL_POINTER); |
1218 | | |
1219 | 0 | uint8_t nones = 0; |
1220 | 0 | int64_t newshape[B2ND_MAX_DIM]; |
1221 | 0 | int32_t newchunkshape[B2ND_MAX_DIM]; |
1222 | 0 | int32_t newblockshape[B2ND_MAX_DIM]; |
1223 | |
|
1224 | 0 | for (int i = 0; i < array->ndim; ++i) { |
1225 | 0 | if (index[i] == true) { |
1226 | 0 | if (array->shape[i] != 1) { |
1227 | 0 | BLOSC_ERROR(BLOSC2_ERROR_INVALID_INDEX); |
1228 | 0 | } |
1229 | 0 | } else { |
1230 | 0 | newshape[nones] = array->shape[i]; |
1231 | 0 | newchunkshape[nones] = array->chunkshape[i]; |
1232 | 0 | newblockshape[nones] = array->blockshape[i]; |
1233 | 0 | nones += 1; |
1234 | 0 | } |
1235 | 0 | } |
1236 | | |
1237 | 0 | for (int i = 0; i < B2ND_MAX_DIM; ++i) { |
1238 | 0 | if (i < nones) { |
1239 | 0 | array->chunkshape[i] = newchunkshape[i]; |
1240 | 0 | array->blockshape[i] = newblockshape[i]; |
1241 | 0 | } else { |
1242 | 0 | array->chunkshape[i] = 1; |
1243 | 0 | array->blockshape[i] = 1; |
1244 | 0 | } |
1245 | 0 | } |
1246 | |
|
1247 | 0 | BLOSC_ERROR(update_shape(array, nones, newshape, newchunkshape, newblockshape)); |
1248 | | |
1249 | 0 | return BLOSC2_ERROR_SUCCESS; |
1250 | 0 | } |
1251 | | |
1252 | | |
1253 | 0 | int b2nd_copy(b2nd_context_t *ctx, const b2nd_array_t *src, b2nd_array_t **array) { |
1254 | 0 | BLOSC_ERROR_NULL(src, BLOSC2_ERROR_NULL_POINTER); |
1255 | 0 | BLOSC_ERROR_NULL(array, BLOSC2_ERROR_NULL_POINTER); |
1256 | | |
1257 | 0 | ctx->ndim = src->ndim; |
1258 | |
|
1259 | 0 | for (int i = 0; i < src->ndim; ++i) { |
1260 | 0 | ctx->shape[i] = src->shape[i]; |
1261 | 0 | } |
1262 | |
|
1263 | 0 | bool equals = true; |
1264 | 0 | for (int i = 0; i < src->ndim; ++i) { |
1265 | 0 | if (src->chunkshape[i] != ctx->chunkshape[i]) { |
1266 | 0 | equals = false; |
1267 | 0 | break; |
1268 | 0 | } |
1269 | 0 | if (src->blockshape[i] != ctx->blockshape[i]) { |
1270 | 0 | equals = false; |
1271 | 0 | break; |
1272 | 0 | } |
1273 | 0 | } |
1274 | |
|
1275 | 0 | if (equals) { |
1276 | 0 | BLOSC_ERROR(array_without_schunk(ctx, array)); |
1277 | | |
1278 | 0 | blosc2_schunk *new_sc = blosc2_schunk_copy(src->sc, ctx->b2_storage); |
1279 | |
|
1280 | 0 | if (new_sc == NULL) { |
1281 | 0 | return BLOSC2_ERROR_FAILURE; |
1282 | 0 | } |
1283 | 0 | (*array)->sc = new_sc; |
1284 | |
|
1285 | 0 | } else { |
1286 | 0 | int64_t start[B2ND_MAX_DIM] = {0}; |
1287 | |
|
1288 | 0 | int64_t stop[B2ND_MAX_DIM]; |
1289 | 0 | for (int i = 0; i < src->ndim; ++i) { |
1290 | 0 | stop[i] = src->shape[i]; |
1291 | 0 | } |
1292 | | // Copy metalayers |
1293 | 0 | b2nd_context_t params_meta; |
1294 | 0 | memcpy(¶ms_meta, ctx, sizeof(params_meta)); |
1295 | 0 | int j = 0; |
1296 | |
|
1297 | 0 | for (int i = 0; i < src->sc->nmetalayers; ++i) { |
1298 | 0 | if (strcmp(src->sc->metalayers[i]->name, "b2nd") == 0) { |
1299 | 0 | continue; |
1300 | 0 | } |
1301 | 0 | blosc2_metalayer *meta = ¶ms_meta.metalayers[j]; |
1302 | 0 | meta->name = src->sc->metalayers[i]->name; |
1303 | 0 | meta->content = src->sc->metalayers[i]->content; |
1304 | 0 | meta->content_len = src->sc->metalayers[i]->content_len; |
1305 | 0 | j++; |
1306 | 0 | } |
1307 | 0 | params_meta.nmetalayers = j; |
1308 | | |
1309 | | // Copy data |
1310 | 0 | BLOSC_ERROR(b2nd_get_slice(¶ms_meta, array, src, start, stop)); |
1311 | | |
1312 | | // Copy vlmetayers |
1313 | 0 | for (int i = 0; i < src->sc->nvlmetalayers; ++i) { |
1314 | 0 | uint8_t *content; |
1315 | 0 | int32_t content_len; |
1316 | 0 | if (blosc2_vlmeta_get(src->sc, src->sc->vlmetalayers[i]->name, &content, |
1317 | 0 | &content_len) < 0) { |
1318 | 0 | BLOSC_ERROR(BLOSC2_ERROR_FAILURE); |
1319 | 0 | } |
1320 | 0 | BLOSC_ERROR(blosc2_vlmeta_add((*array)->sc, src->sc->vlmetalayers[i]->name, content, content_len, |
1321 | 0 | (*array)->sc->storage->cparams)); |
1322 | 0 | free(content); |
1323 | 0 | } |
1324 | 0 | } |
1325 | 0 | return BLOSC2_ERROR_SUCCESS; |
1326 | 0 | } |
1327 | | |
1328 | | |
1329 | 0 | int b2nd_save(const b2nd_array_t *array, char *urlpath) { |
1330 | 0 | BLOSC_ERROR_NULL(array, BLOSC2_ERROR_NULL_POINTER); |
1331 | 0 | BLOSC_ERROR_NULL(urlpath, BLOSC2_ERROR_NULL_POINTER); |
1332 | | |
1333 | 0 | b2nd_array_t *tmp; |
1334 | 0 | blosc2_storage b2_storage = BLOSC2_STORAGE_DEFAULTS; |
1335 | 0 | b2nd_context_t params = {.b2_storage=&b2_storage}; |
1336 | 0 | b2_storage.urlpath = urlpath; |
1337 | 0 | b2_storage.contiguous = array->sc->storage->contiguous; |
1338 | |
|
1339 | 0 | for (int i = 0; i < array->ndim; ++i) { |
1340 | 0 | params.chunkshape[i] = array->chunkshape[i]; |
1341 | 0 | params.blockshape[i] = array->blockshape[i]; |
1342 | 0 | } |
1343 | |
|
1344 | 0 | BLOSC_ERROR(b2nd_copy(¶ms, array, &tmp)); |
1345 | 0 | BLOSC_ERROR(b2nd_free(tmp)); |
1346 | | |
1347 | 0 | return BLOSC2_ERROR_SUCCESS; |
1348 | 0 | } |
1349 | | |
1350 | | |
1351 | 0 | int b2nd_print_meta(const b2nd_array_t *array) { |
1352 | 0 | BLOSC_ERROR_NULL(array, BLOSC2_ERROR_NULL_POINTER); |
1353 | 0 | int8_t ndim; |
1354 | 0 | int64_t shape[B2ND_MAX_DIM]; |
1355 | 0 | int32_t chunkshape[B2ND_MAX_DIM]; |
1356 | 0 | int32_t blockshape[B2ND_MAX_DIM]; |
1357 | 0 | char *dtype; |
1358 | 0 | int8_t dtype_format; |
1359 | 0 | uint8_t *smeta; |
1360 | 0 | int32_t smeta_len; |
1361 | 0 | if (blosc2_meta_get(array->sc, "b2nd", &smeta, &smeta_len) < 0) { |
1362 | | // Try with a caterva metalayer; we are meant to be backward compatible with it |
1363 | 0 | if (blosc2_meta_get(array->sc, "caterva", &smeta, &smeta_len) < 0) { |
1364 | 0 | BLOSC_ERROR(BLOSC2_ERROR_METALAYER_NOT_FOUND); |
1365 | 0 | } |
1366 | 0 | } |
1367 | 0 | BLOSC_ERROR(b2nd_deserialize_meta(smeta, smeta_len, &ndim, shape, chunkshape, blockshape, |
1368 | 0 | &dtype, &dtype_format)); |
1369 | 0 | free(smeta); |
1370 | |
|
1371 | 0 | printf("b2nd metalayer parameters:\n Ndim: %d", ndim); |
1372 | 0 | printf("\n shape: %" PRId64 "", shape[0]); |
1373 | 0 | for (int i = 1; i < ndim; ++i) { |
1374 | 0 | printf(", %" PRId64 "", shape[i]); |
1375 | 0 | } |
1376 | 0 | printf("\n chunkshape: %d", chunkshape[0]); |
1377 | 0 | for (int i = 1; i < ndim; ++i) { |
1378 | 0 | printf(", %d", chunkshape[i]); |
1379 | 0 | } |
1380 | 0 | if (dtype != NULL) { |
1381 | 0 | printf("\n dtype: %s", dtype); |
1382 | 0 | free(dtype); |
1383 | 0 | } |
1384 | |
|
1385 | 0 | printf("\n blockshape: %d", blockshape[0]); |
1386 | 0 | for (int i = 1; i < ndim; ++i) { |
1387 | 0 | printf(", %d", blockshape[i]); |
1388 | 0 | } |
1389 | 0 | printf("\n"); |
1390 | |
|
1391 | 0 | return BLOSC2_ERROR_SUCCESS; |
1392 | 0 | } |
1393 | | |
1394 | | |
1395 | 0 | int extend_shape(b2nd_array_t *array, const int64_t *new_shape, const int64_t *start) { |
1396 | 0 | BLOSC_ERROR_NULL(array, BLOSC2_ERROR_NULL_POINTER); |
1397 | 0 | BLOSC_ERROR_NULL(new_shape, BLOSC2_ERROR_NULL_POINTER); |
1398 | | |
1399 | 0 | int8_t ndim = array->ndim; |
1400 | 0 | int64_t diffs_shape[B2ND_MAX_DIM]; |
1401 | 0 | int64_t diffs_sum = 0; |
1402 | 0 | for (int i = 0; i < ndim; i++) { |
1403 | 0 | diffs_shape[i] = new_shape[i] - array->shape[i]; |
1404 | 0 | diffs_sum += diffs_shape[i]; |
1405 | 0 | if (diffs_shape[i] < 0) { |
1406 | 0 | BLOSC_TRACE_ERROR("The new shape must be greater than the old one"); |
1407 | 0 | BLOSC_ERROR(BLOSC2_ERROR_INVALID_PARAM); |
1408 | 0 | } |
1409 | 0 | if (array->shape[i] == INT64_MAX) { |
1410 | 0 | BLOSC_TRACE_ERROR("Cannot extend array with shape[%d] = %" PRId64 "d", i, INT64_MAX); |
1411 | 0 | BLOSC_ERROR(BLOSC2_ERROR_INVALID_PARAM); |
1412 | 0 | } |
1413 | 0 | } |
1414 | 0 | if (diffs_sum == 0) { |
1415 | | // Shapes are equal. Do nothing. |
1416 | 0 | return BLOSC2_ERROR_SUCCESS; |
1417 | 0 | } |
1418 | | |
1419 | 0 | int64_t old_nchunks = array->sc->nchunks; |
1420 | | // aux array to keep old shapes |
1421 | 0 | b2nd_array_t *aux = malloc(sizeof(b2nd_array_t)); |
1422 | 0 | BLOSC_ERROR_NULL(aux, BLOSC2_ERROR_MEMORY_ALLOC); |
1423 | 0 | aux->sc = NULL; |
1424 | 0 | BLOSC_ERROR(update_shape(aux, ndim, array->shape, array->chunkshape, array->blockshape)); |
1425 | | |
1426 | 0 | BLOSC_ERROR(update_shape(array, ndim, new_shape, array->chunkshape, array->blockshape)); |
1427 | | |
1428 | 0 | int64_t nchunks = array->extnitems / array->chunknitems; |
1429 | 0 | int64_t nchunks_; |
1430 | 0 | int64_t nchunk_ndim[B2ND_MAX_DIM]; |
1431 | 0 | blosc2_cparams *cparams; |
1432 | 0 | BLOSC_ERROR(blosc2_schunk_get_cparams(array->sc, &cparams)); |
1433 | 0 | void *chunk; |
1434 | 0 | int64_t csize; |
1435 | 0 | if (nchunks != old_nchunks) { |
1436 | 0 | if (start == NULL) { |
1437 | 0 | start = aux->shape; |
1438 | 0 | } |
1439 | 0 | int64_t chunks_in_array[B2ND_MAX_DIM] = {0}; |
1440 | 0 | for (int i = 0; i < ndim; ++i) { |
1441 | 0 | chunks_in_array[i] = array->extshape[i] / array->chunkshape[i]; |
1442 | 0 | } |
1443 | 0 | for (int i = 0; i < nchunks; ++i) { |
1444 | 0 | blosc2_unidim_to_multidim(ndim, chunks_in_array, i, nchunk_ndim); |
1445 | 0 | for (int j = 0; j < ndim; ++j) { |
1446 | 0 | if (start[j] <= (array->chunkshape[j] * nchunk_ndim[j]) |
1447 | 0 | && (array->chunkshape[j] * nchunk_ndim[j]) < (start[j] + new_shape[j] - aux->shape[j])) { |
1448 | 0 | chunk = malloc(BLOSC_EXTENDED_HEADER_LENGTH); |
1449 | 0 | BLOSC_ERROR_NULL(chunk, BLOSC2_ERROR_MEMORY_ALLOC); |
1450 | 0 | csize = blosc2_chunk_zeros(*cparams, array->sc->chunksize, chunk, BLOSC_EXTENDED_HEADER_LENGTH); |
1451 | 0 | if (csize < 0) { |
1452 | 0 | free(aux); |
1453 | 0 | free(cparams); |
1454 | 0 | BLOSC_TRACE_ERROR("Blosc error when creating a chunk"); |
1455 | 0 | return BLOSC2_ERROR_FAILURE; |
1456 | 0 | } |
1457 | 0 | nchunks_ = blosc2_schunk_insert_chunk(array->sc, i, chunk, false); |
1458 | 0 | if (nchunks_ < 0) { |
1459 | 0 | free(aux); |
1460 | 0 | free(cparams); |
1461 | 0 | BLOSC_TRACE_ERROR("Blosc error when inserting a chunk"); |
1462 | 0 | return BLOSC2_ERROR_FAILURE; |
1463 | 0 | } |
1464 | 0 | break; |
1465 | 0 | } |
1466 | 0 | } |
1467 | 0 | } |
1468 | 0 | } |
1469 | 0 | free(aux); |
1470 | 0 | free(cparams); |
1471 | |
|
1472 | 0 | return BLOSC2_ERROR_SUCCESS; |
1473 | 0 | } |
1474 | | |
1475 | | |
1476 | 0 | int shrink_shape(b2nd_array_t *array, const int64_t *new_shape, const int64_t *start) { |
1477 | 0 | BLOSC_ERROR_NULL(array, BLOSC2_ERROR_NULL_POINTER); |
1478 | 0 | BLOSC_ERROR_NULL(new_shape, BLOSC2_ERROR_NULL_POINTER); |
1479 | | |
1480 | 0 | int8_t ndim = array->ndim; |
1481 | 0 | int64_t diffs_shape[B2ND_MAX_DIM]; |
1482 | 0 | int64_t diffs_sum = 0; |
1483 | 0 | for (int i = 0; i < ndim; i++) { |
1484 | 0 | diffs_shape[i] = new_shape[i] - array->shape[i]; |
1485 | 0 | diffs_sum += diffs_shape[i]; |
1486 | 0 | if (diffs_shape[i] > 0) { |
1487 | 0 | BLOSC_TRACE_ERROR("The new shape must be smaller than the old one"); |
1488 | 0 | BLOSC_ERROR(BLOSC2_ERROR_INVALID_PARAM); |
1489 | 0 | } |
1490 | 0 | if (array->shape[i] == 0) { |
1491 | 0 | continue; |
1492 | 0 | } |
1493 | 0 | } |
1494 | 0 | if (diffs_sum == 0) { |
1495 | | // Shapes are equal. Do nothing. |
1496 | 0 | return BLOSC2_ERROR_SUCCESS; |
1497 | 0 | } |
1498 | | |
1499 | 0 | int64_t old_nchunks = array->sc->nchunks; |
1500 | | // aux array to keep old shapes |
1501 | 0 | b2nd_array_t *aux = malloc(sizeof(b2nd_array_t)); |
1502 | 0 | BLOSC_ERROR_NULL(aux, BLOSC2_ERROR_MEMORY_ALLOC); |
1503 | 0 | aux->sc = NULL; |
1504 | 0 | BLOSC_ERROR(update_shape(aux, ndim, array->shape, array->chunkshape, array->blockshape)); |
1505 | | |
1506 | 0 | BLOSC_ERROR(update_shape(array, ndim, new_shape, array->chunkshape, array->blockshape)); |
1507 | | |
1508 | | // Delete chunks if needed |
1509 | 0 | int64_t chunks_in_array_old[B2ND_MAX_DIM] = {0}; |
1510 | 0 | for (int i = 0; i < ndim; ++i) { |
1511 | 0 | chunks_in_array_old[i] = aux->extshape[i] / aux->chunkshape[i]; |
1512 | 0 | } |
1513 | 0 | if (start == NULL) { |
1514 | 0 | start = new_shape; |
1515 | 0 | } |
1516 | |
|
1517 | 0 | int64_t nchunk_ndim[B2ND_MAX_DIM] = {0}; |
1518 | 0 | int64_t nchunks_; |
1519 | 0 | for (int i = (int) old_nchunks - 1; i >= 0; --i) { |
1520 | 0 | blosc2_unidim_to_multidim(ndim, chunks_in_array_old, i, nchunk_ndim); |
1521 | 0 | for (int j = 0; j < ndim; ++j) { |
1522 | 0 | if (start[j] <= (array->chunkshape[j] * nchunk_ndim[j]) |
1523 | 0 | && (array->chunkshape[j] * nchunk_ndim[j]) < (start[j] + aux->shape[j] - new_shape[j])) { |
1524 | 0 | nchunks_ = blosc2_schunk_delete_chunk(array->sc, i); |
1525 | 0 | if (nchunks_ < 0) { |
1526 | 0 | free(aux); |
1527 | 0 | BLOSC_TRACE_ERROR("Blosc error when deleting a chunk"); |
1528 | 0 | return BLOSC2_ERROR_FAILURE; |
1529 | 0 | } |
1530 | 0 | break; |
1531 | 0 | } |
1532 | 0 | } |
1533 | 0 | } |
1534 | 0 | free(aux); |
1535 | |
|
1536 | 0 | return BLOSC2_ERROR_SUCCESS; |
1537 | 0 | } |
1538 | | |
1539 | | |
1540 | | int b2nd_resize(b2nd_array_t *array, const int64_t *new_shape, |
1541 | 0 | const int64_t *start) { |
1542 | 0 | BLOSC_ERROR_NULL(array, BLOSC2_ERROR_NULL_POINTER); |
1543 | 0 | BLOSC_ERROR_NULL(new_shape, BLOSC2_ERROR_NULL_POINTER); |
1544 | | |
1545 | 0 | if (start != NULL) { |
1546 | 0 | for (int i = 0; i < array->ndim; ++i) { |
1547 | 0 | if (start[i] > array->shape[i]) { |
1548 | 0 | BLOSC_TRACE_ERROR("`start` must be lower or equal than old array shape in all dims"); |
1549 | 0 | BLOSC_ERROR(BLOSC2_ERROR_INVALID_PARAM); |
1550 | 0 | } |
1551 | 0 | if ((new_shape[i] > array->shape[i] && start[i] != array->shape[i]) |
1552 | 0 | || (new_shape[i] < array->shape[i] |
1553 | 0 | && (start[i] + array->shape[i] - new_shape[i]) != array->shape[i])) { |
1554 | | // Chunks cannot be cut unless they are in the last position |
1555 | 0 | if (start[i] % array->chunkshape[i] != 0) { |
1556 | 0 | BLOSC_TRACE_ERROR("If array end is not being modified " |
1557 | 0 | "`start` must be a multiple of chunkshape in all dims"); |
1558 | 0 | BLOSC_ERROR(BLOSC2_ERROR_INVALID_PARAM); |
1559 | 0 | } |
1560 | 0 | if ((new_shape[i] - array->shape[i]) % array->chunkshape[i] != 0) { |
1561 | 0 | BLOSC_TRACE_ERROR("If array end is not being modified " |
1562 | 0 | "`(new_shape - shape)` must be multiple of chunkshape in all dims"); |
1563 | 0 | BLOSC_ERROR(BLOSC2_ERROR_INVALID_PARAM); |
1564 | 0 | } |
1565 | 0 | } |
1566 | 0 | } |
1567 | 0 | } |
1568 | | |
1569 | | // Get shrunk shape |
1570 | 0 | int64_t shrunk_shape[B2ND_MAX_DIM] = {0}; |
1571 | 0 | for (int i = 0; i < array->ndim; ++i) { |
1572 | 0 | if (new_shape[i] <= array->shape[i]) { |
1573 | 0 | shrunk_shape[i] = new_shape[i]; |
1574 | 0 | } else { |
1575 | 0 | shrunk_shape[i] = array->shape[i]; |
1576 | 0 | } |
1577 | 0 | } |
1578 | |
|
1579 | 0 | BLOSC_ERROR(shrink_shape(array, shrunk_shape, start)); |
1580 | 0 | BLOSC_ERROR(extend_shape(array, new_shape, start)); |
1581 | | |
1582 | 0 | return BLOSC2_ERROR_SUCCESS; |
1583 | 0 | } |
1584 | | |
1585 | | |
1586 | | int b2nd_insert(b2nd_array_t *array, const void *buffer, int64_t buffersize, |
1587 | 0 | int8_t axis, int64_t insert_start) { |
1588 | |
|
1589 | 0 | BLOSC_ERROR_NULL(array, BLOSC2_ERROR_NULL_POINTER); |
1590 | 0 | BLOSC_ERROR_NULL(buffer, BLOSC2_ERROR_NULL_POINTER); |
1591 | | |
1592 | 0 | if (axis >= array->ndim) { |
1593 | 0 | BLOSC_TRACE_ERROR("`axis` cannot be greater than the number of dimensions"); |
1594 | 0 | BLOSC_ERROR(BLOSC2_ERROR_INVALID_PARAM); |
1595 | 0 | } |
1596 | | |
1597 | 0 | int64_t axis_size = array->sc->typesize; |
1598 | 0 | int64_t buffershape[B2ND_MAX_DIM]; |
1599 | 0 | for (int i = 0; i < array->ndim; ++i) { |
1600 | 0 | if (i != axis) { |
1601 | 0 | axis_size *= array->shape[i]; |
1602 | 0 | buffershape[i] = array->shape[i]; |
1603 | 0 | } |
1604 | 0 | } |
1605 | 0 | if (buffersize % axis_size != 0) { |
1606 | 0 | BLOSC_TRACE_ERROR("`buffersize` must be multiple of the array"); |
1607 | 0 | BLOSC_ERROR(BLOSC2_ERROR_INVALID_PARAM); |
1608 | 0 | } |
1609 | 0 | int64_t newshape[B2ND_MAX_DIM]; |
1610 | 0 | memcpy(newshape, array->shape, array->ndim * sizeof(int64_t)); |
1611 | 0 | newshape[axis] += buffersize / axis_size; |
1612 | 0 | buffershape[axis] = newshape[axis] - array->shape[axis]; |
1613 | 0 | int64_t start[B2ND_MAX_DIM] = {0}; |
1614 | 0 | start[axis] = insert_start; |
1615 | |
|
1616 | 0 | if (insert_start == array->shape[axis]) { |
1617 | 0 | BLOSC_ERROR(b2nd_resize(array, newshape, NULL)); |
1618 | 0 | } else { |
1619 | 0 | BLOSC_ERROR(b2nd_resize(array, newshape, start)); |
1620 | 0 | } |
1621 | | |
1622 | 0 | int64_t stop[B2ND_MAX_DIM]; |
1623 | 0 | memcpy(stop, array->shape, sizeof(int64_t) * array->ndim); |
1624 | 0 | stop[axis] = start[axis] + buffershape[axis]; |
1625 | 0 | BLOSC_ERROR(b2nd_set_slice_cbuffer(buffer, buffershape, buffersize, start, stop, array)); |
1626 | | |
1627 | 0 | return BLOSC2_ERROR_SUCCESS; |
1628 | 0 | } |
1629 | | |
1630 | | |
1631 | | int b2nd_append(b2nd_array_t *array, const void *buffer, int64_t buffersize, |
1632 | 0 | int8_t axis) { |
1633 | 0 | BLOSC_ERROR_NULL(array, BLOSC2_ERROR_NULL_POINTER); |
1634 | 0 | BLOSC_ERROR_NULL(buffer, BLOSC2_ERROR_NULL_POINTER); |
1635 | | |
1636 | 0 | int32_t chunksize = array->sc->chunksize; |
1637 | 0 | int64_t nchunks_append = buffersize / chunksize; |
1638 | | // Check whether chunkshape and blockshape are compatible with accelerated path. |
1639 | | // Essentially, we are checking whether the buffer is a multiple of the chunksize |
1640 | | // and that the chunkshape and blockshape are the same, except for the first axis. |
1641 | | // Also, axis needs to be the first one. |
1642 | 0 | bool compat_chunks_blocks = true; |
1643 | 0 | for (int i = 1; i < array->ndim; ++i) { |
1644 | 0 | if (array->chunkshape[i] != array->blockshape[i]) { |
1645 | 0 | compat_chunks_blocks = false; |
1646 | 0 | break; |
1647 | 0 | } |
1648 | 0 | } |
1649 | 0 | if (axis > 0) { |
1650 | 0 | compat_chunks_blocks = false; |
1651 | 0 | } |
1652 | | // General case where a buffer has a different size than the chunksize |
1653 | 0 | if (!compat_chunks_blocks || buffersize % chunksize != 0 || nchunks_append != 1) { |
1654 | 0 | BLOSC_ERROR(b2nd_insert(array, buffer, buffersize, axis, array->shape[axis])); |
1655 | 0 | return BLOSC2_ERROR_SUCCESS; |
1656 | 0 | } |
1657 | | |
1658 | | // Accelerated path for buffers that are of the same size as the chunksize |
1659 | | // printf("accelerated path\n"); |
1660 | | |
1661 | | // Append the buffer to the underlying schunk. This is very fast, as |
1662 | | // it doesn't need to do internal partitioning. |
1663 | 0 | BLOSC_ERROR(blosc2_schunk_append_buffer(array->sc, (void*)buffer, buffersize)); |
1664 | | |
1665 | | // Finally, resize the array |
1666 | 0 | int64_t newshape[B2ND_MAX_DIM]; |
1667 | 0 | memcpy(newshape, array->shape, array->ndim * sizeof(int64_t)); |
1668 | 0 | newshape[axis] += nchunks_append * array->chunkshape[axis]; |
1669 | 0 | BLOSC_ERROR(b2nd_resize(array, newshape, NULL)); |
1670 | | |
1671 | 0 | return BLOSC2_ERROR_SUCCESS; |
1672 | 0 | } |
1673 | | |
1674 | | |
1675 | | int b2nd_delete(b2nd_array_t *array, const int8_t axis, |
1676 | 0 | int64_t delete_start, int64_t delete_len) { |
1677 | 0 | BLOSC_ERROR_NULL(array, BLOSC2_ERROR_NULL_POINTER); |
1678 | | |
1679 | 0 | if (axis >= array->ndim) { |
1680 | 0 | BLOSC_TRACE_ERROR("axis cannot be greater than the number of dimensions"); |
1681 | 0 | BLOSC_ERROR(BLOSC2_ERROR_INVALID_PARAM); |
1682 | 0 | } |
1683 | | |
1684 | | |
1685 | 0 | int64_t newshape[B2ND_MAX_DIM]; |
1686 | 0 | memcpy(newshape, array->shape, array->ndim * sizeof(int64_t)); |
1687 | 0 | newshape[axis] -= delete_len; |
1688 | 0 | int64_t start[B2ND_MAX_DIM] = {0}; |
1689 | 0 | start[axis] = delete_start; |
1690 | |
|
1691 | 0 | if (delete_start == (array->shape[axis] - delete_len)) { |
1692 | 0 | BLOSC_ERROR(b2nd_resize(array, newshape, NULL)); |
1693 | 0 | } else { |
1694 | 0 | BLOSC_ERROR(b2nd_resize(array, newshape, start)); |
1695 | 0 | } |
1696 | | |
1697 | 0 | return BLOSC2_ERROR_SUCCESS; |
1698 | 0 | } |
1699 | | |
1700 | | // Indexing |
1701 | | |
1702 | | typedef struct { |
1703 | | int64_t value; |
1704 | | int64_t index; |
1705 | | } b2nd_selection_t; |
1706 | | |
1707 | | |
1708 | 0 | int compare_selection(const void *a, const void *b) { |
1709 | 0 | int res = (int) (((b2nd_selection_t *) a)->value - ((b2nd_selection_t *) b)->value); |
1710 | | // In case values are equal, sort by index |
1711 | 0 | if (res == 0) { |
1712 | 0 | res = (int) (((b2nd_selection_t *) a)->index - ((b2nd_selection_t *) b)->index); |
1713 | 0 | } |
1714 | 0 | return res; |
1715 | 0 | } |
1716 | | |
1717 | | |
1718 | | int copy_block_buffer_data(b2nd_array_t *array, |
1719 | | int8_t ndim, |
1720 | | int64_t *block_selection_size, |
1721 | | b2nd_selection_t **chunk_selection, |
1722 | | b2nd_selection_t **p_block_selection_0, |
1723 | | b2nd_selection_t **p_block_selection_1, |
1724 | | uint8_t *block, |
1725 | | uint8_t *buffer, |
1726 | | int64_t *buffershape, |
1727 | | int64_t *bufferstrides, |
1728 | 0 | bool get) { |
1729 | 0 | p_block_selection_0[ndim] = chunk_selection[ndim]; |
1730 | 0 | p_block_selection_1[ndim] = chunk_selection[ndim]; |
1731 | 0 | while (p_block_selection_1[ndim] - p_block_selection_0[ndim] < block_selection_size[ndim]) { |
1732 | 0 | if (ndim == array->ndim - 1) { |
1733 | |
|
1734 | 0 | int64_t index_in_block_n[B2ND_MAX_DIM]; |
1735 | 0 | for (int i = 0; i < array->ndim; ++i) { |
1736 | 0 | index_in_block_n[i] = p_block_selection_1[i]->value % array->chunkshape[i] % array->blockshape[i]; |
1737 | 0 | } |
1738 | 0 | int64_t index_in_block = 0; |
1739 | 0 | for (int i = 0; i < array->ndim; ++i) { |
1740 | 0 | index_in_block += index_in_block_n[i] * array->item_block_strides[i]; |
1741 | 0 | } |
1742 | |
|
1743 | 0 | int64_t index_in_buffer_n[B2ND_MAX_DIM]; |
1744 | 0 | for (int i = 0; i < array->ndim; ++i) { |
1745 | 0 | index_in_buffer_n[i] = p_block_selection_1[i]->index; |
1746 | 0 | } |
1747 | 0 | int64_t index_in_buffer = 0; |
1748 | 0 | for (int i = 0; i < array->ndim; ++i) { |
1749 | 0 | index_in_buffer += index_in_buffer_n[i] * bufferstrides[i]; |
1750 | 0 | } |
1751 | 0 | if (get) { |
1752 | 0 | memcpy(&buffer[index_in_buffer * array->sc->typesize], |
1753 | 0 | &block[index_in_block * array->sc->typesize], |
1754 | 0 | array->sc->typesize); |
1755 | 0 | } else { |
1756 | 0 | memcpy(&block[index_in_block * array->sc->typesize], |
1757 | 0 | &buffer[index_in_buffer * array->sc->typesize], |
1758 | 0 | array->sc->typesize); |
1759 | 0 | } |
1760 | 0 | } else { |
1761 | 0 | BLOSC_ERROR(copy_block_buffer_data(array, (int8_t) (ndim + 1), block_selection_size, |
1762 | 0 | chunk_selection, |
1763 | 0 | p_block_selection_0, p_block_selection_1, block, |
1764 | 0 | buffer, buffershape, bufferstrides, get) |
1765 | 0 | ); |
1766 | 0 | } |
1767 | 0 | p_block_selection_1[ndim]++; |
1768 | 0 | } |
1769 | 0 | return BLOSC2_ERROR_SUCCESS; |
1770 | 0 | } |
1771 | | |
1772 | | |
1773 | | int iter_block_copy(b2nd_array_t *array, int8_t ndim, |
1774 | | int64_t *chunk_selection_size, |
1775 | | b2nd_selection_t **ordered_selection, |
1776 | | b2nd_selection_t **chunk_selection_0, |
1777 | | b2nd_selection_t **chunk_selection_1, |
1778 | | uint8_t *data, |
1779 | | uint8_t *buffer, |
1780 | | int64_t *buffershape, |
1781 | | int64_t *bufferstrides, |
1782 | 0 | bool get) { |
1783 | 0 | chunk_selection_0[ndim] = ordered_selection[ndim]; |
1784 | 0 | chunk_selection_1[ndim] = ordered_selection[ndim]; |
1785 | 0 | while (chunk_selection_1[ndim] - ordered_selection[ndim] < chunk_selection_size[ndim]) { |
1786 | 0 | int64_t block_index_ndim = ((*chunk_selection_1[ndim]).value % array->chunkshape[ndim]) / array->blockshape[ndim]; |
1787 | 0 | while (chunk_selection_1[ndim] - ordered_selection[ndim] < chunk_selection_size[ndim] && |
1788 | 0 | block_index_ndim == ((*chunk_selection_1[ndim]).value % array->chunkshape[ndim]) / array->blockshape[ndim]) { |
1789 | 0 | chunk_selection_1[ndim]++; |
1790 | 0 | } |
1791 | 0 | if (ndim == array->ndim - 1) { |
1792 | 0 | int64_t block_chunk_strides[B2ND_MAX_DIM]; |
1793 | 0 | block_chunk_strides[array->ndim - 1] = 1; |
1794 | 0 | for (int i = array->ndim - 2; i >= 0; --i) { |
1795 | 0 | block_chunk_strides[i] = block_chunk_strides[i + 1] * (array->extchunkshape[i + 1] / array->blockshape[i + 1]); |
1796 | 0 | } |
1797 | 0 | int64_t block_index[B2ND_MAX_DIM]; |
1798 | 0 | for (int i = 0; i < array->ndim; ++i) { |
1799 | 0 | block_index[i] = ((*chunk_selection_0[i]).value % array->chunkshape[i]) / array->blockshape[i]; |
1800 | 0 | } |
1801 | 0 | int64_t nblock = 0; |
1802 | 0 | for (int i = 0; i < array->ndim; ++i) { |
1803 | 0 | nblock += block_index[i] * block_chunk_strides[i]; |
1804 | 0 | } |
1805 | 0 | b2nd_selection_t **p_block_selection_0 = malloc(array->ndim * sizeof(b2nd_selection_t *)); |
1806 | 0 | BLOSC_ERROR_NULL(p_block_selection_0, BLOSC2_ERROR_MEMORY_ALLOC); |
1807 | 0 | b2nd_selection_t **p_block_selection_1 = malloc(array->ndim * sizeof(b2nd_selection_t *)); |
1808 | 0 | BLOSC_ERROR_NULL(p_block_selection_1, BLOSC2_ERROR_MEMORY_ALLOC); |
1809 | 0 | int64_t *block_selection_size = malloc(array->ndim * sizeof(int64_t)); |
1810 | 0 | BLOSC_ERROR_NULL(block_selection_size, BLOSC2_ERROR_MEMORY_ALLOC); |
1811 | 0 | for (int i = 0; i < array->ndim; ++i) { |
1812 | 0 | block_selection_size[i] = chunk_selection_1[i] - chunk_selection_0[i]; |
1813 | 0 | } |
1814 | |
|
1815 | 0 | BLOSC_ERROR(copy_block_buffer_data(array, |
1816 | 0 | (int8_t) 0, |
1817 | 0 | block_selection_size, |
1818 | 0 | chunk_selection_0, |
1819 | 0 | p_block_selection_0, |
1820 | 0 | p_block_selection_1, |
1821 | 0 | &data[nblock * array->blocknitems * array->sc->typesize], |
1822 | 0 | buffer, |
1823 | 0 | buffershape, |
1824 | 0 | bufferstrides, |
1825 | 0 | get) |
1826 | 0 | ); |
1827 | 0 | free(p_block_selection_0); |
1828 | 0 | free(p_block_selection_1); |
1829 | 0 | free(block_selection_size); |
1830 | 0 | } else { |
1831 | 0 | BLOSC_ERROR(iter_block_copy(array, (int8_t) (ndim + 1), chunk_selection_size, |
1832 | 0 | ordered_selection, chunk_selection_0, chunk_selection_1, |
1833 | 0 | data, buffer, buffershape, bufferstrides, get) |
1834 | 0 | ); |
1835 | 0 | } |
1836 | 0 | chunk_selection_0[ndim] = chunk_selection_1[ndim]; |
1837 | |
|
1838 | 0 | } |
1839 | | |
1840 | 0 | return BLOSC2_ERROR_SUCCESS; |
1841 | 0 | } |
1842 | | |
1843 | | |
1844 | | int iter_block_maskout(b2nd_array_t *array, int8_t ndim, |
1845 | | int64_t *sel_block_size, |
1846 | | b2nd_selection_t **o_selection, |
1847 | | b2nd_selection_t **p_o_sel_block_0, |
1848 | | b2nd_selection_t **p_o_sel_block_1, |
1849 | 0 | bool *maskout) { |
1850 | 0 | p_o_sel_block_0[ndim] = o_selection[ndim]; |
1851 | 0 | p_o_sel_block_1[ndim] = o_selection[ndim]; |
1852 | 0 | while (p_o_sel_block_1[ndim] - o_selection[ndim] < sel_block_size[ndim]) { |
1853 | 0 | int64_t block_index_ndim = ((*p_o_sel_block_1[ndim]).value % array->chunkshape[ndim]) / array->blockshape[ndim]; |
1854 | 0 | while (p_o_sel_block_1[ndim] - o_selection[ndim] < sel_block_size[ndim] && |
1855 | 0 | block_index_ndim == ((*p_o_sel_block_1[ndim]).value % array->chunkshape[ndim]) / array->blockshape[ndim]) { |
1856 | 0 | p_o_sel_block_1[ndim]++; |
1857 | 0 | } |
1858 | 0 | if (ndim == array->ndim - 1) { |
1859 | 0 | int64_t block_chunk_strides[B2ND_MAX_DIM]; |
1860 | 0 | block_chunk_strides[array->ndim - 1] = 1; |
1861 | 0 | for (int i = array->ndim - 2; i >= 0; --i) { |
1862 | 0 | block_chunk_strides[i] = block_chunk_strides[i + 1] * (array->extchunkshape[i + 1] / array->blockshape[i + 1]); |
1863 | 0 | } |
1864 | 0 | int64_t block_index[B2ND_MAX_DIM]; |
1865 | 0 | for (int i = 0; i < array->ndim; ++i) { |
1866 | 0 | block_index[i] = ((*p_o_sel_block_0[i]).value % array->chunkshape[i]) / array->blockshape[i]; |
1867 | 0 | } |
1868 | 0 | int64_t nblock = 0; |
1869 | 0 | for (int i = 0; i < array->ndim; ++i) { |
1870 | 0 | nblock += block_index[i] * block_chunk_strides[i]; |
1871 | 0 | } |
1872 | 0 | maskout[nblock] = false; |
1873 | 0 | } else { |
1874 | 0 | BLOSC_ERROR(iter_block_maskout(array, (int8_t) (ndim + 1), sel_block_size, |
1875 | 0 | o_selection, p_o_sel_block_0, p_o_sel_block_1, |
1876 | 0 | maskout) |
1877 | 0 | ); |
1878 | 0 | } |
1879 | 0 | p_o_sel_block_0[ndim] = p_o_sel_block_1[ndim]; |
1880 | |
|
1881 | 0 | } |
1882 | | |
1883 | 0 | return BLOSC2_ERROR_SUCCESS; |
1884 | 0 | } |
1885 | | |
1886 | | |
1887 | | int iter_chunk(b2nd_array_t *array, int8_t ndim, |
1888 | | int64_t *selection_size, |
1889 | | b2nd_selection_t **ordered_selection, |
1890 | | b2nd_selection_t **p_ordered_selection_0, |
1891 | | b2nd_selection_t **p_ordered_selection_1, |
1892 | | uint8_t *buffer, |
1893 | | int64_t *buffershape, |
1894 | | int64_t *bufferstrides, |
1895 | 0 | bool get) { |
1896 | 0 | p_ordered_selection_0[ndim] = ordered_selection[ndim]; |
1897 | 0 | p_ordered_selection_1[ndim] = ordered_selection[ndim]; |
1898 | 0 | while (p_ordered_selection_1[ndim] - ordered_selection[ndim] < selection_size[ndim]) { |
1899 | 0 | int64_t chunk_index_ndim = (*p_ordered_selection_1[ndim]).value / array->chunkshape[ndim]; |
1900 | 0 | while (p_ordered_selection_1[ndim] - ordered_selection[ndim] < selection_size[ndim] && |
1901 | 0 | chunk_index_ndim == (*p_ordered_selection_1[ndim]).value / array->chunkshape[ndim]) { |
1902 | 0 | p_ordered_selection_1[ndim]++; |
1903 | 0 | } |
1904 | 0 | if (ndim == array->ndim - 1) { |
1905 | 0 | int64_t chunk_array_strides[B2ND_MAX_DIM]; |
1906 | 0 | chunk_array_strides[array->ndim - 1] = 1; |
1907 | 0 | for (int i = array->ndim - 2; i >= 0; --i) { |
1908 | 0 | chunk_array_strides[i] = chunk_array_strides[i + 1] * |
1909 | 0 | (array->extshape[i + 1] / array->chunkshape[i + 1]); |
1910 | 0 | } |
1911 | 0 | int64_t chunk_index[B2ND_MAX_DIM]; |
1912 | 0 | for (int i = 0; i < array->ndim; ++i) { |
1913 | 0 | chunk_index[i] = (*p_ordered_selection_0[i]).value / array->chunkshape[i]; |
1914 | 0 | } |
1915 | 0 | int64_t nchunk = 0; |
1916 | 0 | for (int i = 0; i < array->ndim; ++i) { |
1917 | 0 | nchunk += chunk_index[i] * chunk_array_strides[i]; |
1918 | 0 | } |
1919 | |
|
1920 | 0 | int64_t nblocks = array->extchunknitems / array->blocknitems; |
1921 | 0 | b2nd_selection_t **p_chunk_selection_0 = malloc(array->ndim * sizeof(b2nd_selection_t *)); |
1922 | 0 | BLOSC_ERROR_NULL(p_chunk_selection_0, BLOSC2_ERROR_MEMORY_ALLOC); |
1923 | 0 | b2nd_selection_t **p_chunk_selection_1 = malloc(array->ndim * sizeof(b2nd_selection_t *)); |
1924 | 0 | BLOSC_ERROR_NULL(p_chunk_selection_1, BLOSC2_ERROR_MEMORY_ALLOC); |
1925 | 0 | int64_t *chunk_selection_size = malloc(array->ndim * sizeof(int64_t)); |
1926 | 0 | BLOSC_ERROR_NULL(chunk_selection_size, BLOSC2_ERROR_MEMORY_ALLOC); |
1927 | 0 | for (int i = 0; i < array->ndim; ++i) { |
1928 | 0 | chunk_selection_size[i] = p_ordered_selection_1[i] - p_ordered_selection_0[i]; |
1929 | 0 | } |
1930 | |
|
1931 | 0 | if (get) { |
1932 | 0 | bool *maskout = calloc(nblocks, sizeof(bool)); |
1933 | 0 | for (int i = 0; i < nblocks; ++i) { |
1934 | 0 | maskout[i] = true; |
1935 | 0 | } |
1936 | |
|
1937 | 0 | BLOSC_ERROR(iter_block_maskout(array, (int8_t) 0, |
1938 | 0 | chunk_selection_size, |
1939 | 0 | p_ordered_selection_0, |
1940 | 0 | p_chunk_selection_0, |
1941 | 0 | p_chunk_selection_1, |
1942 | 0 | maskout)); |
1943 | | |
1944 | 0 | if (blosc2_set_maskout(array->sc->dctx, maskout, (int) nblocks) != |
1945 | 0 | BLOSC2_ERROR_SUCCESS) { |
1946 | 0 | BLOSC_TRACE_ERROR("Error setting the maskout"); |
1947 | 0 | BLOSC_ERROR(BLOSC2_ERROR_FAILURE); |
1948 | 0 | } |
1949 | 0 | free(maskout); |
1950 | 0 | } |
1951 | 0 | int data_nitems = (int) array->extchunknitems; |
1952 | 0 | int data_nbytes = data_nitems * array->sc->typesize; |
1953 | 0 | uint8_t *data = malloc(data_nitems * array->sc->typesize); |
1954 | 0 | BLOSC_ERROR_NULL(data, BLOSC2_ERROR_MEMORY_ALLOC); |
1955 | 0 | int err = blosc2_schunk_decompress_chunk(array->sc, nchunk, data, data_nbytes); |
1956 | 0 | if (err < 0) { |
1957 | 0 | BLOSC_TRACE_ERROR("Error decompressing chunk"); |
1958 | 0 | BLOSC_ERROR(BLOSC2_ERROR_FAILURE); |
1959 | 0 | } |
1960 | 0 | BLOSC_ERROR(iter_block_copy(array, 0, chunk_selection_size, |
1961 | 0 | p_ordered_selection_0, p_chunk_selection_0, p_chunk_selection_1, |
1962 | 0 | data, buffer, buffershape, bufferstrides, get)); |
1963 | | |
1964 | 0 | if (!get) { |
1965 | 0 | int32_t chunk_size = data_nbytes + BLOSC_EXTENDED_HEADER_LENGTH; |
1966 | 0 | uint8_t *chunk = malloc(chunk_size); |
1967 | 0 | BLOSC_ERROR_NULL(chunk, BLOSC2_ERROR_MEMORY_ALLOC); |
1968 | 0 | err = blosc2_compress_ctx(array->sc->cctx, data, data_nbytes, chunk, chunk_size); |
1969 | 0 | if (err < 0) { |
1970 | 0 | BLOSC_TRACE_ERROR("Error compressing data"); |
1971 | 0 | BLOSC_ERROR(BLOSC2_ERROR_FAILURE); |
1972 | 0 | } |
1973 | 0 | err = (int) blosc2_schunk_update_chunk(array->sc, nchunk, chunk, false); |
1974 | 0 | if (err < 0) { |
1975 | 0 | BLOSC_TRACE_ERROR("Error updating chunk"); |
1976 | 0 | BLOSC_ERROR(BLOSC2_ERROR_FAILURE); |
1977 | 0 | } |
1978 | 0 | } |
1979 | 0 | free(data); |
1980 | 0 | free(chunk_selection_size); |
1981 | 0 | free(p_chunk_selection_0); |
1982 | 0 | free(p_chunk_selection_1); |
1983 | 0 | } else { |
1984 | 0 | BLOSC_ERROR(iter_chunk(array, (int8_t) (ndim + 1), selection_size, |
1985 | 0 | ordered_selection, p_ordered_selection_0, p_ordered_selection_1, |
1986 | 0 | buffer, buffershape, bufferstrides, get)); |
1987 | 0 | } |
1988 | | |
1989 | 0 | p_ordered_selection_0[ndim] = p_ordered_selection_1[ndim]; |
1990 | 0 | } |
1991 | 0 | return BLOSC2_ERROR_SUCCESS; |
1992 | 0 | } |
1993 | | |
1994 | | |
1995 | | int orthogonal_selection(b2nd_array_t *array, int64_t **selection, int64_t *selection_size, void *buffer, |
1996 | 0 | int64_t *buffershape, int64_t buffersize, bool get) { |
1997 | 0 | BLOSC_ERROR_NULL(array, BLOSC2_ERROR_NULL_POINTER); |
1998 | 0 | BLOSC_ERROR_NULL(selection, BLOSC2_ERROR_NULL_POINTER); |
1999 | 0 | BLOSC_ERROR_NULL(selection_size, BLOSC2_ERROR_NULL_POINTER); |
2000 | | |
2001 | 0 | int8_t ndim = array->ndim; |
2002 | |
|
2003 | 0 | for (int i = 0; i < ndim; ++i) { |
2004 | 0 | BLOSC_ERROR_NULL(selection[i], BLOSC2_ERROR_NULL_POINTER); |
2005 | | // Check that indexes are not larger than array shape |
2006 | 0 | for (int j = 0; j < selection_size[i]; ++j) { |
2007 | 0 | if (selection[i][j] > array->shape[i]) { |
2008 | 0 | BLOSC_ERROR(BLOSC2_ERROR_INVALID_INDEX); |
2009 | 0 | } |
2010 | 0 | } |
2011 | 0 | } |
2012 | | |
2013 | | // Check buffer size |
2014 | 0 | int64_t sel_size = array->sc->typesize; |
2015 | 0 | for (int i = 0; i < ndim; ++i) { |
2016 | 0 | sel_size *= selection_size[i]; |
2017 | 0 | } |
2018 | |
|
2019 | 0 | if (sel_size < buffersize) { |
2020 | 0 | BLOSC_ERROR(BLOSC2_ERROR_INVALID_PARAM); |
2021 | 0 | } |
2022 | | |
2023 | | // Sort selections |
2024 | 0 | b2nd_selection_t **ordered_selection = malloc(ndim * sizeof(b2nd_selection_t *)); |
2025 | 0 | BLOSC_ERROR_NULL(ordered_selection, BLOSC2_ERROR_MEMORY_ALLOC); |
2026 | 0 | for (int i = 0; i < ndim; ++i) { |
2027 | 0 | ordered_selection[i] = malloc(selection_size[i] * sizeof(b2nd_selection_t)); |
2028 | 0 | for (int j = 0; j < selection_size[i]; ++j) { |
2029 | 0 | ordered_selection[i][j].index = j; |
2030 | 0 | ordered_selection[i][j].value = selection[i][j]; |
2031 | 0 | } |
2032 | 0 | qsort(ordered_selection[i], selection_size[i], sizeof(b2nd_selection_t), compare_selection); |
2033 | 0 | } |
2034 | | |
2035 | | // Define pointers to iterate over ordered_selection data |
2036 | 0 | b2nd_selection_t **p_ordered_selection_0 = malloc(ndim * sizeof(b2nd_selection_t *)); |
2037 | 0 | BLOSC_ERROR_NULL(p_ordered_selection_0, BLOSC2_ERROR_MEMORY_ALLOC); |
2038 | 0 | b2nd_selection_t **p_ordered_selection_1 = malloc(ndim * sizeof(b2nd_selection_t *)); |
2039 | 0 | BLOSC_ERROR_NULL(p_ordered_selection_1, BLOSC2_ERROR_MEMORY_ALLOC); |
2040 | | |
2041 | 0 | int64_t bufferstrides[B2ND_MAX_DIM]; |
2042 | 0 | bufferstrides[array->ndim - 1] = 1; |
2043 | 0 | for (int i = array->ndim - 2; i >= 0; --i) { |
2044 | 0 | bufferstrides[i] = bufferstrides[i + 1] * buffershape[i + 1]; |
2045 | 0 | } |
2046 | |
|
2047 | 0 | BLOSC_ERROR(iter_chunk(array, 0, |
2048 | 0 | selection_size, ordered_selection, |
2049 | 0 | p_ordered_selection_0, |
2050 | 0 | p_ordered_selection_1, |
2051 | 0 | buffer, buffershape, bufferstrides, get)); |
2052 | | |
2053 | | // Free allocated memory |
2054 | 0 | free(p_ordered_selection_0); |
2055 | 0 | free(p_ordered_selection_1); |
2056 | 0 | for (int i = 0; i < ndim; ++i) { |
2057 | 0 | free(ordered_selection[i]); |
2058 | 0 | } |
2059 | 0 | free(ordered_selection); |
2060 | |
|
2061 | 0 | return BLOSC2_ERROR_SUCCESS; |
2062 | 0 | } |
2063 | | |
2064 | | |
2065 | | int b2nd_get_orthogonal_selection(const b2nd_array_t *array, int64_t **selection, int64_t *selection_size, void *buffer, |
2066 | 0 | int64_t *buffershape, int64_t buffersize) { |
2067 | 0 | return orthogonal_selection((b2nd_array_t *)array, selection, selection_size, buffer, buffershape, buffersize, true); |
2068 | 0 | } |
2069 | | |
2070 | | |
2071 | | int b2nd_set_orthogonal_selection(b2nd_array_t *array, int64_t **selection, int64_t *selection_size, const void *buffer, |
2072 | 0 | int64_t *buffershape, int64_t buffersize) { |
2073 | 0 | return orthogonal_selection(array, selection, selection_size, (void*)buffer, buffershape, buffersize, false); |
2074 | 0 | } |
2075 | | |
2076 | | |
2077 | | b2nd_context_t * |
2078 | | b2nd_create_ctx(const blosc2_storage *b2_storage, int8_t ndim, const int64_t *shape, const int32_t *chunkshape, |
2079 | | const int32_t *blockshape, const char *dtype, int8_t dtype_format, const blosc2_metalayer *metalayers, |
2080 | 0 | int32_t nmetalayers) { |
2081 | 0 | b2nd_context_t *ctx = malloc(sizeof(b2nd_context_t)); |
2082 | 0 | BLOSC_ERROR_NULL(ctx, NULL); |
2083 | 0 | blosc2_storage *params_b2_storage = malloc(sizeof(blosc2_storage)); |
2084 | 0 | BLOSC_ERROR_NULL(params_b2_storage, NULL); |
2085 | 0 | if (b2_storage == NULL) { |
2086 | 0 | memcpy(params_b2_storage, &BLOSC2_STORAGE_DEFAULTS, sizeof(blosc2_storage)); |
2087 | 0 | } |
2088 | 0 | else { |
2089 | 0 | memcpy(params_b2_storage, b2_storage, sizeof(blosc2_storage)); |
2090 | 0 | } |
2091 | 0 | blosc2_cparams *cparams = malloc(sizeof(blosc2_cparams)); |
2092 | 0 | BLOSC_ERROR_NULL(cparams, NULL); |
2093 | | // We need a copy of cparams mainly to be able to modify blocksize |
2094 | 0 | if (b2_storage->cparams == NULL) { |
2095 | 0 | memcpy(cparams, &BLOSC2_CPARAMS_DEFAULTS, sizeof(blosc2_cparams)); |
2096 | 0 | } |
2097 | 0 | else { |
2098 | 0 | memcpy(cparams, b2_storage->cparams, sizeof(blosc2_cparams)); |
2099 | 0 | } |
2100 | |
|
2101 | 0 | if (dtype == NULL) { |
2102 | 0 | ctx->dtype = strdup(B2ND_DEFAULT_DTYPE); |
2103 | 0 | ctx->dtype_format = 0; // The default is NumPy format |
2104 | 0 | } |
2105 | 0 | else { |
2106 | 0 | ctx->dtype = strdup(dtype); |
2107 | 0 | ctx->dtype_format = dtype_format; |
2108 | 0 | } |
2109 | |
|
2110 | 0 | params_b2_storage->cparams = cparams; |
2111 | 0 | ctx->b2_storage = params_b2_storage; |
2112 | 0 | ctx->ndim = ndim; |
2113 | 0 | int32_t blocknitems = 1; |
2114 | 0 | for (int i = 0; i < ndim; i++) { |
2115 | 0 | ctx->shape[i] = shape[i]; |
2116 | 0 | ctx->chunkshape[i] = chunkshape[i]; |
2117 | 0 | ctx->blockshape[i] = blockshape[i]; |
2118 | 0 | blocknitems *= ctx->blockshape[i]; |
2119 | 0 | } |
2120 | 0 | cparams->blocksize = blocknitems * cparams->typesize; |
2121 | |
|
2122 | 0 | ctx->nmetalayers = nmetalayers; |
2123 | 0 | for (int i = 0; i < nmetalayers; ++i) { |
2124 | 0 | ctx->metalayers[i] = metalayers[i]; |
2125 | 0 | } |
2126 | |
|
2127 | | #if defined(HAVE_PLUGINS) |
2128 | | #include "blosc2/codecs-registry.h" |
2129 | | if ((ctx->b2_storage->cparams->compcode >= BLOSC_CODEC_ZFP_FIXED_ACCURACY) && |
2130 | | (ctx->b2_storage->cparams->compcode <= BLOSC_CODEC_ZFP_FIXED_RATE)) { |
2131 | | for (int i = 0; i < BLOSC2_MAX_FILTERS; ++i) { |
2132 | | if ((ctx->b2_storage->cparams->filters[i] == BLOSC_SHUFFLE) || |
2133 | | (ctx->b2_storage->cparams->filters[i] == BLOSC_BITSHUFFLE)) { |
2134 | | BLOSC_TRACE_ERROR("ZFP cannot be run in presence of SHUFFLE / BITSHUFFLE"); |
2135 | | return NULL; |
2136 | | } |
2137 | | } |
2138 | | } |
2139 | | #endif /* HAVE_PLUGINS */ |
2140 | |
|
2141 | 0 | return ctx; |
2142 | 0 | } |
2143 | | |
2144 | | |
2145 | 0 | int b2nd_free_ctx(b2nd_context_t *ctx) { |
2146 | 0 | ctx->b2_storage->cparams->schunk = NULL; |
2147 | 0 | free(ctx->b2_storage->cparams); |
2148 | 0 | free(ctx->b2_storage); |
2149 | 0 | free(ctx->dtype); |
2150 | 0 | free(ctx); |
2151 | |
|
2152 | 0 | return BLOSC2_ERROR_SUCCESS; |
2153 | 0 | } |