1 /*
2  * Copyright (C) 2018 Francesc Alted, Aleix Alcacer.
3  * Copyright (C) 2019-present Blosc Development team <blosc@blosc.org>
4  * All rights reserved.
5  *
6  * This source code is licensed under both the BSD-style license (found in the
7  * LICENSE file in the root directory of this source tree) and the GPLv2 (found
8  * in the COPYING file in the root directory of this source tree).
9  * You may select, at your option, one of the above-listed licenses.
10  */
11 
12 #include <caterva.h>
13 
14 #include "caterva_utils.h"
15 
16 
caterva_ctx_new(caterva_config_t * cfg,caterva_ctx_t ** ctx)17 int caterva_ctx_new(caterva_config_t *cfg, caterva_ctx_t **ctx) {
18     CATERVA_ERROR_NULL(cfg);
19     CATERVA_ERROR_NULL(ctx);
20 
21     (*ctx) = (caterva_ctx_t *) cfg->alloc(sizeof(caterva_ctx_t));
22     CATERVA_ERROR_NULL(ctx);
23     if (!(*ctx)) {
24         CATERVA_TRACE_ERROR("Allocation fails");
25         return CATERVA_ERR_NULL_POINTER;
26     }
27 
28     (*ctx)->cfg = (caterva_config_t *) cfg->alloc(sizeof(caterva_config_t));
29     CATERVA_ERROR_NULL((*ctx)->cfg);
30     if (!(*ctx)->cfg) {
31         CATERVA_TRACE_ERROR("Allocation fails");
32         return CATERVA_ERR_NULL_POINTER;
33     }
34     memcpy((*ctx)->cfg, cfg, sizeof(caterva_config_t));
35 
36     return CATERVA_SUCCEED;
37 }
38 
caterva_ctx_free(caterva_ctx_t ** ctx)39 int caterva_ctx_free(caterva_ctx_t **ctx) {
40     CATERVA_ERROR_NULL(ctx);
41 
42     void (*auxfree)(void *) = (*ctx)->cfg->free;
43     auxfree((*ctx)->cfg);
44     auxfree(*ctx);
45 
46     return CATERVA_SUCCEED;
47 }
48 
49 // Only for internal use
caterva_update_shape(caterva_array_t * array,int8_t ndim,int64_t * shape,int32_t * chunkshape,int32_t * blockshape)50 int caterva_update_shape(caterva_array_t *array, int8_t ndim, int64_t *shape,
51                                int32_t *chunkshape, int32_t *blockshape) {
52     array->ndim = ndim;
53     array->nitems = 1;
54     array->extnitems = 1;
55     array->extchunknitems = 1;
56     array->chunknitems = 1;
57     array->blocknitems = 1;
58     for (int i = 0; i < CATERVA_MAX_DIM; ++i) {
59         if (i < ndim) {
60             array->shape[i] = shape[i];
61             array->chunkshape[i] = chunkshape[i];
62             array->blockshape[i] = blockshape[i];
63             if (shape[i] != 0) {
64                 if (shape[i] % array->chunkshape[i] == 0) {
65                     array->extshape[i] = shape[i];
66                 } else {
67                     array->extshape[i] = shape[i] + chunkshape[i] - shape[i] % chunkshape[i];
68                 }
69                 if (chunkshape[i] % blockshape[i] == 0) {
70                     array->extchunkshape[i] = chunkshape[i];
71                 } else {
72                     array->extchunkshape[i] =
73                             chunkshape[i] + blockshape[i] - chunkshape[i] % blockshape[i];
74                 }
75             } else {
76                 array->extchunkshape[i] = 0;
77                 array->extshape[i] = 0;
78             }
79         } else {
80             array->blockshape[i] = 1;
81             array->chunkshape[i] = 1;
82             array->extshape[i] = 1;
83             array->extchunkshape[i] = 1;
84             array->shape[i] = 1;
85         }
86         array->nitems *= array->shape[i];
87         array->extnitems *= array->extshape[i];
88         array->extchunknitems *= array->extchunkshape[i];
89         array->chunknitems *= array->chunkshape[i];
90         array->blocknitems *= array->blockshape[i];
91     }
92 
93 
94     if (array->sc) {
95         uint8_t *smeta = NULL;
96         // Serialize the dimension info ...
97         int32_t smeta_len =
98                 serialize_meta(array->ndim, array->shape, array->chunkshape, array->blockshape,
99                                &smeta);
100         if (smeta_len < 0) {
101             fprintf(stderr, "error during serializing dims info for Caterva");
102             return -1;
103         }
104         // ... and update it in its metalayer
105         if (blosc2_meta_exists(array->sc, "caterva") < 0) {
106             if (blosc2_meta_add(array->sc, "caterva", smeta, (uint32_t) smeta_len) < 0) {
107                 CATERVA_ERROR(CATERVA_ERR_BLOSC_FAILED);
108             }
109         } else {
110             if (blosc2_meta_update(array->sc, "caterva", smeta, (uint32_t) smeta_len) < 0) {
111                 CATERVA_ERROR(CATERVA_ERR_BLOSC_FAILED);
112             }
113         }
114         free(smeta);
115     }
116 
117     return CATERVA_SUCCEED;
118 }
119 
120 // Only for internal use
caterva_array_without_schunk(caterva_ctx_t * ctx,caterva_params_t * params,caterva_storage_t * storage,caterva_array_t ** array)121 int caterva_array_without_schunk(caterva_ctx_t *ctx, caterva_params_t *params,
122                                        caterva_storage_t *storage, caterva_array_t **array) {
123     /* Create a caterva_array_t buffer */
124     (*array) = (caterva_array_t *) ctx->cfg->alloc(sizeof(caterva_array_t));
125     CATERVA_ERROR_NULL(*array);
126 
127     (*array)->cfg = (caterva_config_t *) ctx->cfg->alloc(sizeof(caterva_config_t));
128     memcpy((*array)->cfg, ctx->cfg, sizeof(caterva_config_t));
129 
130     (*array)->sc = NULL;
131 
132     (*array)->ndim = params->ndim;
133     (*array)->itemsize = params->itemsize;
134 
135     int64_t *shape = params->shape;
136     int32_t *chunkshape = storage->chunkshape;
137     int32_t *blockshape = storage->blockshape;
138 
139     caterva_update_shape(*array, params->ndim, shape, chunkshape, blockshape);
140 
141     // The partition cache (empty initially)
142     (*array)->chunk_cache.data = NULL;
143     (*array)->chunk_cache.nchunk = -1;  // means no valid cache yet
144 
145     if ((*array)->nitems != 0) {
146         (*array)->nchunks = (*array)->extnitems / (*array)->chunknitems;
147     } else {
148         (*array)->nchunks = 0;
149     }
150 
151     return CATERVA_SUCCEED;
152 }
153 
154 // Only for internal use
caterva_blosc_array_new(caterva_ctx_t * ctx,caterva_params_t * params,caterva_storage_t * storage,int special_value,caterva_array_t ** array)155 int caterva_blosc_array_new(caterva_ctx_t *ctx, caterva_params_t *params,
156                             caterva_storage_t *storage,
157                             int special_value, caterva_array_t **array) {
158     CATERVA_ERROR(caterva_array_without_schunk(ctx, params, storage, array));
159     blosc2_storage b_storage;
160     blosc2_cparams b_cparams;
161     blosc2_dparams b_dparams;
162     CATERVA_ERROR(create_blosc_params(ctx, params, storage, &b_cparams, &b_dparams, &b_storage));
163 
164     blosc2_schunk *sc = blosc2_schunk_new(&b_storage);
165     if (sc == NULL) {
166         CATERVA_TRACE_ERROR("Pointer is NULL");
167         return CATERVA_ERR_BLOSC_FAILED;
168     }
169 
170     // Serialize the dimension info
171     if (sc->nmetalayers >= BLOSC2_MAX_METALAYERS) {
172         CATERVA_TRACE_ERROR("the number of metalayers for this schunk has been exceeded");
173         return CATERVA_ERR_BLOSC_FAILED;
174     }
175     uint8_t *smeta = NULL;
176     int32_t smeta_len = serialize_meta(params->ndim,
177                                        (*array)->shape,
178                                        (*array)->chunkshape,
179                                        (*array)->blockshape, &smeta);
180     if (smeta_len < 0) {
181         CATERVA_TRACE_ERROR("error during serializing dims info for Caterva");
182         return CATERVA_ERR_BLOSC_FAILED;
183     }
184 
185     // And store it in caterva metalayer
186     if (blosc2_meta_add(sc, "caterva", smeta, (uint32_t) smeta_len) < 0) {
187         return CATERVA_ERR_BLOSC_FAILED;
188     }
189 
190     free(smeta);
191 
192     for (int i = 0; i < storage->nmetalayers; ++i) {
193         char *name = storage->metalayers[i].name;
194         uint8_t *data = storage->metalayers[i].sdata;
195         int32_t size = storage->metalayers[i].size;
196         if (blosc2_meta_add(sc, name, data, size) < 0) {
197             CATERVA_ERROR(CATERVA_ERR_BLOSC_FAILED);
198         }
199     }
200 
201     // Fill schunk with uninit values
202     if ((*array)->nitems != 0) {
203         int32_t chunksize = (int32_t) (*array)->extchunknitems * (*array)->itemsize;
204         int64_t nchunks = (*array)->extnitems / (*array)->chunknitems;
205         int64_t nitems = nchunks * (*array)->extchunknitems;
206         // blosc2_schunk_fill_special(sc, nitems, BLOSC2_SPECIAL_ZERO, chunksize);
207         blosc2_schunk_fill_special(sc, nitems, special_value, chunksize);
208     }
209     (*array)->sc = sc;
210     (*array)->nchunks = sc->nchunks;
211 
212     return CATERVA_SUCCEED;
213 }
214 
caterva_empty(caterva_ctx_t * ctx,caterva_params_t * params,caterva_storage_t * storage,caterva_array_t ** array)215 int caterva_empty(caterva_ctx_t *ctx, caterva_params_t *params,
216                   caterva_storage_t *storage, caterva_array_t **array) {
217     CATERVA_ERROR_NULL(ctx);
218     CATERVA_ERROR_NULL(params);
219     CATERVA_ERROR_NULL(storage);
220     CATERVA_ERROR_NULL(array);
221 
222     // CATERVA_ERROR(caterva_blosc_array_new(ctx, params, storage, BLOSC2_SPECIAL_UNINIT, array));
223     // Avoid variable cratios
224     CATERVA_ERROR(caterva_blosc_array_new(ctx, params, storage, BLOSC2_SPECIAL_ZERO, array));
225 
226     return CATERVA_SUCCEED;
227 }
228 
caterva_zeros(caterva_ctx_t * ctx,caterva_params_t * params,caterva_storage_t * storage,caterva_array_t ** array)229 int caterva_zeros(caterva_ctx_t *ctx, caterva_params_t *params,
230                   caterva_storage_t *storage, caterva_array_t **array) {
231     CATERVA_ERROR_NULL(ctx);
232     CATERVA_ERROR_NULL(params);
233     CATERVA_ERROR_NULL(storage);
234     CATERVA_ERROR_NULL(array);
235 
236     CATERVA_ERROR(caterva_blosc_array_new(ctx, params, storage, BLOSC2_SPECIAL_ZERO, array));
237 
238     return CATERVA_SUCCEED;
239 }
240 
caterva_full(caterva_ctx_t * ctx,caterva_params_t * params,caterva_storage_t * storage,void * fill_value,caterva_array_t ** array)241 int caterva_full(caterva_ctx_t *ctx, caterva_params_t *params,
242                  caterva_storage_t *storage, void *fill_value, caterva_array_t **array) {
243     CATERVA_ERROR_NULL(ctx);
244     CATERVA_ERROR_NULL(params);
245     CATERVA_ERROR_NULL(storage);
246     CATERVA_ERROR_NULL(array);
247 
248     CATERVA_ERROR(caterva_empty(ctx, params, storage, array));
249 
250     int64_t chunkbytes = (*array)->extchunknitems * (*array)->itemsize;
251 
252     blosc2_cparams *cparams;
253     if (blosc2_schunk_get_cparams((*array)->sc, &cparams) != 0) {
254         CATERVA_ERROR(CATERVA_ERR_BLOSC_FAILED);
255     }
256 
257     int32_t chunksize = BLOSC_EXTENDED_HEADER_LENGTH + (*array)->itemsize;
258     uint8_t *chunk = malloc(chunksize);
259     if (blosc2_chunk_repeatval(*cparams, chunkbytes, chunk, chunksize, fill_value) < 0) {
260         CATERVA_ERROR(CATERVA_ERR_BLOSC_FAILED);
261     }
262     free(cparams);
263 
264     for (int i = 0; i < (*array)->sc->nchunks; ++i) {
265         if (blosc2_schunk_update_chunk((*array)->sc, i, chunk, true) < 0) {
266             CATERVA_ERROR(CATERVA_ERR_BLOSC_FAILED);
267         }
268     }
269     free(chunk);
270 
271     return CATERVA_SUCCEED;
272 }
273 
caterva_from_schunk(caterva_ctx_t * ctx,blosc2_schunk * schunk,caterva_array_t ** array)274 int caterva_from_schunk(caterva_ctx_t *ctx, blosc2_schunk *schunk, caterva_array_t **array) {
275     CATERVA_ERROR_NULL(ctx);
276     CATERVA_ERROR_NULL(schunk);
277     CATERVA_ERROR_NULL(array);
278 
279     if (ctx == NULL) {
280         CATERVA_TRACE_ERROR("Context is null");
281         return CATERVA_ERR_NULL_POINTER;
282     }
283     if (schunk == NULL) {
284         CATERVA_TRACE_ERROR("Schunk is null");
285         return CATERVA_ERR_NULL_POINTER;
286     }
287 
288     blosc2_cparams *cparams;
289     if (blosc2_schunk_get_cparams(schunk, &cparams) < 0) {
290         CATERVA_TRACE_ERROR("Blosc error");
291         return CATERVA_ERR_NULL_POINTER;
292     }
293     uint8_t itemsize = (int8_t) cparams->typesize;
294     free(cparams);
295 
296     caterva_params_t params = {0};
297     params.itemsize = itemsize;
298     caterva_storage_t storage = {0};
299     storage.urlpath = schunk->storage->urlpath;
300     storage.sequencial = schunk->storage->contiguous;
301 
302     // Deserialize the caterva metalayer
303     uint8_t *smeta;
304     uint32_t smeta_len;
305     if (blosc2_meta_get(schunk, "caterva", &smeta, &smeta_len) < 0) {
306         CATERVA_TRACE_ERROR("Blosc error");
307         return CATERVA_ERR_BLOSC_FAILED;
308     }
309     deserialize_meta(smeta, smeta_len, &params.ndim,
310                      params.shape,
311                      storage.chunkshape,
312                      storage.blockshape);
313     free(smeta);
314 
315     caterva_config_t cfg = CATERVA_CONFIG_DEFAULTS;
316     caterva_config_from_schunk(ctx, schunk, &cfg);
317 
318     caterva_ctx_t *ctx_sc;
319     caterva_ctx_new(&cfg, &ctx_sc);
320 
321     caterva_array_without_schunk(ctx_sc, &params, &storage, array);
322 
323     caterva_ctx_free(&ctx_sc);
324 
325     (*array)->sc = schunk;
326 
327     if ((*array) == NULL) {
328         CATERVA_TRACE_ERROR("Error creating a caterva container from a frame");
329         return CATERVA_ERR_NULL_POINTER;
330     }
331 
332     return CATERVA_SUCCEED;
333 }
334 
caterva_from_serial_schunk(caterva_ctx_t * ctx,uint8_t * serial_schunk,int64_t len,caterva_array_t ** array)335 int caterva_from_serial_schunk(caterva_ctx_t *ctx, uint8_t *serial_schunk, int64_t len,
336                                caterva_array_t **array) {
337     CATERVA_ERROR_NULL(ctx);
338     CATERVA_ERROR_NULL(serial_schunk);
339     CATERVA_ERROR_NULL(array);
340 
341     blosc2_schunk *sc = blosc2_schunk_from_buffer(serial_schunk, len, true);
342     if (sc == NULL) {
343         CATERVA_TRACE_ERROR("Blosc error");
344         return CATERVA_ERR_BLOSC_FAILED;
345     }
346     // ...and create a caterva array out of it
347     CATERVA_ERROR(caterva_from_schunk(ctx, sc, array));
348 
349     return CATERVA_SUCCEED;
350 }
351 
caterva_open(caterva_ctx_t * ctx,const char * urlpath,caterva_array_t ** array)352 int caterva_open(caterva_ctx_t *ctx, const char *urlpath, caterva_array_t **array) {
353     CATERVA_ERROR_NULL(ctx);
354     CATERVA_ERROR_NULL(urlpath);
355     CATERVA_ERROR_NULL(array);
356 
357     blosc2_schunk *sc = blosc2_schunk_open(urlpath);
358 
359     // ...and create a caterva array out of it
360     CATERVA_ERROR(caterva_from_schunk(ctx, sc, array));
361 
362     return CATERVA_SUCCEED;
363 }
364 
caterva_free(caterva_ctx_t * ctx,caterva_array_t ** array)365 int caterva_free(caterva_ctx_t *ctx, caterva_array_t **array) {
366     CATERVA_ERROR_NULL(ctx);
367     CATERVA_ERROR_NULL(array);
368     void (*free)(void *) = (*array)->cfg->free;
369 
370     free((*array)->cfg);
371     if (*array) {
372         if ((*array)->sc != NULL) {
373             blosc2_schunk_free((*array)->sc);
374         }
375         free(*array);
376     }
377     return CATERVA_SUCCEED;
378 }
379 
caterva_from_buffer(caterva_ctx_t * ctx,void * buffer,int64_t buffersize,caterva_params_t * params,caterva_storage_t * storage,caterva_array_t ** array)380 int caterva_from_buffer(caterva_ctx_t *ctx, void *buffer, int64_t buffersize,
381                         caterva_params_t *params, caterva_storage_t *storage,
382                         caterva_array_t **array) {
383     CATERVA_ERROR_NULL(ctx);
384     CATERVA_ERROR_NULL(params);
385     CATERVA_ERROR_NULL(storage);
386     CATERVA_ERROR_NULL(buffer);
387     CATERVA_ERROR_NULL(array);
388 
389     CATERVA_ERROR(caterva_empty(ctx, params, storage, array));
390 
391     if (buffersize < (int64_t)(*array)->nitems * (*array)->itemsize) {
392         CATERVA_TRACE_ERROR("The buffersize (%lld) is smaller than the array size (%lld)",
393                             buffersize, (int64_t)(*array)->nitems * (*array)->itemsize);
394         CATERVA_ERROR(CATERVA_ERR_INVALID_ARGUMENT);
395     }
396 
397     if ((*array)->nitems == 0) {
398         return CATERVA_SUCCEED;
399     }
400 
401     int64_t start[CATERVA_MAX_DIM] = {0};
402     int64_t *stop = (*array)->shape;
403     int64_t *shape = (*array)->shape;
404     CATERVA_ERROR(caterva_set_slice_buffer(ctx, buffer, shape, buffersize, start, stop, *array));
405 
406     return CATERVA_SUCCEED;
407 }
408 
caterva_to_buffer(caterva_ctx_t * ctx,caterva_array_t * array,void * buffer,int64_t buffersize)409 int caterva_to_buffer(caterva_ctx_t *ctx, caterva_array_t *array, void *buffer,
410                       int64_t buffersize) {
411     CATERVA_ERROR_NULL(ctx);
412     CATERVA_ERROR_NULL(array);
413     CATERVA_ERROR_NULL(buffer);
414 
415     if (buffersize < (int64_t) array->nitems * array->itemsize) {
416         CATERVA_ERROR(CATERVA_ERR_INVALID_ARGUMENT);
417     }
418 
419     if (array->nitems == 0) {
420         return CATERVA_SUCCEED;
421     }
422 
423     int64_t start[CATERVA_MAX_DIM] = {0};
424     int64_t *stop = array->shape;
425     CATERVA_ERROR(caterva_get_slice_buffer(ctx, array, start, stop,
426                                            buffer, array->shape, buffersize));
427     return CATERVA_SUCCEED;
428 }
429 
430 
431 // Only for internal use: It is used for setting slices and for getting slices.
caterva_blosc_slice(caterva_ctx_t * ctx,void * buffer,int64_t buffersize,int64_t * start,int64_t * stop,int64_t * shape,caterva_array_t * array,bool set_slice)432 int caterva_blosc_slice(caterva_ctx_t *ctx, void *buffer,
433                         int64_t buffersize, int64_t *start, int64_t *stop, int64_t *shape,
434                         caterva_array_t *array, bool set_slice) {
435     CATERVA_ERROR_NULL(ctx);
436     CATERVA_ERROR_NULL(buffer);
437     CATERVA_ERROR_NULL(start);
438     CATERVA_ERROR_NULL(stop);
439     CATERVA_ERROR_NULL(array);
440     if (buffersize < 0) {
441         CATERVA_TRACE_ERROR("buffersize is < 0");
442         CATERVA_ERROR(CATERVA_ERR_INVALID_ARGUMENT);
443     }
444 
445     uint8_t *buffer_b = (uint8_t *) buffer;
446     int64_t *buffer_start = start;
447     int64_t *buffer_stop = stop;
448     int64_t *buffer_shape = shape;
449 
450     int8_t ndim = array->ndim;
451     int64_t nchunks = array->extnitems / array->chunknitems;
452 
453     // 0-dim case
454     if (ndim == 0) {
455         if (set_slice) {
456             uint32_t chunk_size = array->itemsize + BLOSC_MAX_OVERHEAD;
457             uint8_t *chunk = malloc(chunk_size);
458             if (blosc2_compress_ctx(array->sc->cctx, buffer_b, array->itemsize, chunk, chunk_size) < 0) {
459                 CATERVA_ERROR(CATERVA_ERR_BLOSC_FAILED);
460             }
461             if (blosc2_schunk_update_chunk(array->sc, 0, chunk, false) < 0) {
462                 CATERVA_ERROR(CATERVA_ERR_BLOSC_FAILED);
463             }
464 
465         } else {
466             if (blosc2_schunk_decompress_chunk(array->sc, 0, buffer_b, array->itemsize) < 0) {
467                 CATERVA_ERROR(CATERVA_ERR_BLOSC_FAILED);
468             }
469         }
470         return CATERVA_SUCCEED;
471     }
472 
473     int32_t data_nbytes = array->extchunknitems * array->itemsize;
474     uint8_t *data = malloc(data_nbytes);
475 
476     int64_t chunks_in_array[CATERVA_MAX_DIM] = {0};
477     for (int i = 0; i < ndim; ++i) {
478         chunks_in_array[i] = array->extshape[i] / array->chunkshape[i];
479     }
480 
481     int64_t chunks_in_array_strides[CATERVA_MAX_DIM];
482     chunks_in_array_strides[ndim - 1] = 1;
483     for (int i = ndim - 2; i >= 0; --i) {
484         chunks_in_array_strides[i] = chunks_in_array_strides[i + 1] * chunks_in_array[i + 1];
485     }
486 
487     int64_t blocks_in_chunk[CATERVA_MAX_DIM] = {0};
488     for (int i = 0; i < ndim; ++i) {
489         blocks_in_chunk[i] = array->extchunkshape[i] / array->blockshape[i];
490     }
491 
492     // Compute the number of chunks to update
493     int64_t update_start[CATERVA_MAX_DIM];
494     int64_t update_shape[CATERVA_MAX_DIM];
495 
496     int64_t update_nchunks = 1;
497     for (int i = 0; i < ndim; ++i) {
498         int64_t pos = 0;
499         while (pos <= buffer_start[i]) {
500             pos += array->chunkshape[i];
501         }
502         update_start[i] = pos / array->chunkshape[i] - 1;
503         while (pos < buffer_stop[i]) {
504             pos += array->chunkshape[i];
505         }
506         update_shape[i] = pos / array->chunkshape[i] - update_start[i];
507         update_nchunks *= update_shape[i];
508     }
509 
510     for (int update_nchunk = 0; update_nchunk < update_nchunks; ++update_nchunk) {
511         int64_t nchunk_ndim[CATERVA_MAX_DIM] = {0};
512         index_unidim_to_multidim(ndim, update_shape, update_nchunk, nchunk_ndim);
513         for (int i = 0; i < ndim; ++i) {
514             nchunk_ndim[i] += update_start[i];
515         }
516         int64_t nchunk;
517         index_multidim_to_unidim(nchunk_ndim, ndim, chunks_in_array_strides, &nchunk);
518 
519         // check if the chunk needs to be updated
520         int64_t chunk_start[CATERVA_MAX_DIM] = {0};
521         int64_t chunk_stop[CATERVA_MAX_DIM] = {0};
522         for (int i = 0; i < ndim; ++i) {
523             chunk_start[i] = nchunk_ndim[i] * array->chunkshape[i];
524             chunk_stop[i] = chunk_start[i] + array->chunkshape[i];
525             if (chunk_stop[i] > array->shape[i]) {
526                 chunk_stop[i] = array->shape[i];
527             }
528         }
529         bool chunk_empty = false;
530         for (int i = 0; i < ndim; ++i) {
531             chunk_empty |= (chunk_stop[i] <= buffer_start[i] || chunk_start[i] >= buffer_stop[i]);
532         }
533         if (chunk_empty) {
534             continue;
535         }
536 
537         int64_t nblocks = array->extchunknitems / array->blocknitems;
538 
539 
540 
541         if (set_slice) {
542             // Check if all the chunk is going to be updated and avoid the decompression
543             bool decompress_chunk = false;
544             for (int i = 0; i < ndim; ++i) {
545                 decompress_chunk |= (chunk_start[i] < buffer_start[i] || chunk_stop[i] > buffer_stop[i]);
546             }
547 
548             if (decompress_chunk) {
549                 int err = blosc2_schunk_decompress_chunk(array->sc, nchunk, data, data_nbytes);
550                 if (err < 0) {
551                     CATERVA_TRACE_ERROR("Error decompressing chunk");
552                     CATERVA_ERROR(CATERVA_ERR_BLOSC_FAILED);
553                 }
554             } else {
555                 // memset(data, 0, data_nbytes);
556             }
557         } else {
558             bool *block_maskout = ctx->cfg->alloc(nblocks);
559             CATERVA_ERROR_NULL(block_maskout);
560             for (int nblock = 0; nblock < nblocks; ++nblock) {
561                 int64_t nblock_ndim[CATERVA_MAX_DIM] = {0};
562                 index_unidim_to_multidim(ndim, blocks_in_chunk, nblock, nblock_ndim);
563 
564                 // check if the block needs to be updated
565                 int64_t block_start[CATERVA_MAX_DIM] = {0};
566                 int64_t block_stop[CATERVA_MAX_DIM] = {0};
567                 for (int i = 0; i < ndim; ++i) {
568                     block_start[i] = nblock_ndim[i] * array->blockshape[i];
569                     block_stop[i] = block_start[i] + array->blockshape[i];
570                     block_start[i] += chunk_start[i];
571                     block_stop[i] += chunk_start[i];
572 
573                     if (block_start[i] > chunk_stop[i]) {
574                         block_start[i] = chunk_stop[i];
575                     }
576                     if (block_stop[i] > chunk_stop[i]) {
577                         block_stop[i] = chunk_stop[i];
578                     }
579                 }
580 
581                 bool block_empty = false;
582                 for (int i = 0; i < ndim; ++i) {
583                     block_empty |= (block_stop[i] <= start[i] || block_start[i] >= stop[i]);
584                 }
585                 block_maskout[nblock] = block_empty ? true : false;
586             }
587 
588             if (blosc2_set_maskout(array->sc->dctx, block_maskout, nblocks) != BLOSC2_ERROR_SUCCESS) {
589                 CATERVA_TRACE_ERROR("Error setting the maskout");
590                 CATERVA_ERROR(CATERVA_ERR_BLOSC_FAILED);
591             }
592 
593             int err = blosc2_schunk_decompress_chunk(array->sc, nchunk, data, data_nbytes);
594             if (err < 0) {
595                 CATERVA_TRACE_ERROR("Error decompressing chunk");
596                 CATERVA_ERROR(CATERVA_ERR_BLOSC_FAILED);
597             }
598 
599             ctx->cfg->free(block_maskout);
600         }
601 
602         // Iterate over blocks
603 
604         for (int nblock = 0; nblock < nblocks; ++nblock) {
605             int64_t nblock_ndim[CATERVA_MAX_DIM] = {0};
606             index_unidim_to_multidim(ndim, blocks_in_chunk, nblock, nblock_ndim);
607 
608             // check if the block needs to be updated
609             int64_t block_start[CATERVA_MAX_DIM] = {0};
610             int64_t block_stop[CATERVA_MAX_DIM] = {0};
611             for (int i = 0; i < ndim; ++i) {
612                 block_start[i] = nblock_ndim[i] * array->blockshape[i];
613                 block_stop[i] = block_start[i] + array->blockshape[i];
614                 block_start[i] += chunk_start[i];
615                 block_stop[i] += chunk_start[i];
616 
617                 if (block_start[i] > chunk_stop[i]) {
618                     block_start[i] = chunk_stop[i];
619                 }
620                 if (block_stop[i] > chunk_stop[i]) {
621                     block_stop[i] = chunk_stop[i];
622                 }
623             }
624             int64_t block_shape[CATERVA_MAX_DIM] = {0};
625             for (int i = 0; i < ndim; ++i) {
626                 block_shape[i] = block_stop[i] - block_start[i];
627             }
628             bool block_empty = false;
629             for (int i = 0; i < ndim; ++i) {
630                 block_empty |= (block_stop[i] <= start[i] || block_start[i] >= stop[i]);
631             }
632             if (block_empty) {
633                 continue;
634             }
635 
636             // compute the start of the slice inside the block
637             int64_t slice_start[CATERVA_MAX_DIM] = {0};
638             for (int i = 0; i < ndim; ++i) {
639                 if (block_start[i] < buffer_start[i]) {
640                     slice_start[i] = buffer_start[i] - block_start[i];
641                 } else {
642                     slice_start[i] = 0;
643                 }
644                 slice_start[i] += block_start[i];
645             }
646 
647             int64_t slice_stop[CATERVA_MAX_DIM] = {0};
648             for (int i = 0; i < ndim; ++i) {
649                 if (block_stop[i] > buffer_stop[i]) {
650                     slice_stop[i] = block_shape[i] - (block_stop[i] - buffer_stop[i]);
651                 } else {
652                     slice_stop[i] = block_stop[i] - block_start[i];
653                 }
654                 slice_stop[i] += block_start[i];
655             }
656 
657             int64_t slice_shape[CATERVA_MAX_DIM] = {0};
658             for (int i = 0; i < ndim; ++i) {
659                 slice_shape[i] = slice_stop[i] - slice_start[i];
660             }
661 
662 
663             uint8_t *src = &buffer_b[0];
664             int64_t *src_pad_shape = buffer_shape;
665 
666             int64_t src_start[CATERVA_MAX_DIM] = {0};
667             int64_t src_stop[CATERVA_MAX_DIM] = {0};
668             for (int i = 0; i < ndim; ++i) {
669                 src_start[i] = slice_start[i] - buffer_start[i];
670                 src_stop[i] = slice_stop[i] - buffer_start[i];
671             }
672 
673             uint8_t *dst = &data[nblock * array->blocknitems * array->itemsize];
674             int64_t dst_pad_shape[CATERVA_MAX_DIM];
675             for (int i = 0; i < ndim; ++i) {
676                 dst_pad_shape[i] = array->blockshape[i];
677             }
678 
679             int64_t dst_start[CATERVA_MAX_DIM] = {0};
680             int64_t dst_stop[CATERVA_MAX_DIM] = {0};
681             for (int i = 0; i < ndim; ++i) {
682                 dst_start[i] = slice_start[i] - block_start[i];
683                 dst_stop[i] = dst_start[i] + slice_shape[i];
684             }
685 
686             if (set_slice) {
687                 caterva_copy_buffer(ndim, array->itemsize,
688                                     src, src_pad_shape, src_start, src_stop,
689                                     dst, dst_pad_shape, dst_start);
690             } else {
691                 caterva_copy_buffer(ndim, array->itemsize,
692                                     dst, dst_pad_shape, dst_start, dst_stop,
693                                     src, src_pad_shape, src_start);
694             }
695         }
696 
697         if (set_slice) {
698             // Recompress the data
699             int32_t chunk_nbytes = data_nbytes + BLOSC_MAX_OVERHEAD;
700             uint8_t *chunk = malloc(chunk_nbytes);
701             int brc;
702             brc = blosc2_compress_ctx(array->sc->cctx, data, data_nbytes, chunk, chunk_nbytes);
703             if (brc < 0) {
704                 CATERVA_TRACE_ERROR("Blosc can not compress the data");
705                 CATERVA_ERROR(CATERVA_ERR_BLOSC_FAILED);
706             }
707             brc = blosc2_schunk_update_chunk(array->sc, nchunk, chunk, false);
708             if (brc < 0) {
709                 CATERVA_TRACE_ERROR("Blosc can not update the chunk");
710                 CATERVA_ERROR(CATERVA_ERR_BLOSC_FAILED);
711             }
712         }
713     }
714 
715     free(data);
716 
717 
718     return CATERVA_SUCCEED;
719 }
720 
caterva_get_slice_buffer(caterva_ctx_t * ctx,caterva_array_t * array,int64_t * start,int64_t * stop,void * buffer,int64_t * buffershape,int64_t buffersize)721 int caterva_get_slice_buffer(caterva_ctx_t *ctx,
722                              caterva_array_t *array,
723                              int64_t *start, int64_t *stop,
724                              void *buffer, int64_t *buffershape, int64_t buffersize) {
725     CATERVA_ERROR_NULL(ctx);
726     CATERVA_ERROR_NULL(array);
727     CATERVA_ERROR_NULL(start);
728     CATERVA_ERROR_NULL(stop);
729     CATERVA_ERROR_NULL(buffershape);
730     CATERVA_ERROR_NULL(buffer);
731 
732     int64_t size = array->itemsize;
733     for (int i = 0; i < array->ndim; ++i) {
734         if (stop[i] - start[i] > buffershape[i]) {
735             CATERVA_TRACE_ERROR("The buffer shape can not be smaller than the slice shape");
736             return CATERVA_ERR_INVALID_ARGUMENT;
737         }
738         size *= buffershape[i];
739     }
740 
741     if (array->nitems == 0) {
742         return CATERVA_SUCCEED;
743     }
744 
745     if (buffersize < size) {
746         CATERVA_ERROR(CATERVA_ERR_INVALID_ARGUMENT);
747     }
748     CATERVA_ERROR(caterva_blosc_slice(ctx, buffer, buffersize, start, stop, buffershape, array, false));
749 
750     return CATERVA_SUCCEED;
751 }
752 
caterva_set_slice_buffer(caterva_ctx_t * ctx,void * buffer,int64_t * buffershape,int64_t buffersize,int64_t * start,int64_t * stop,caterva_array_t * array)753 int caterva_set_slice_buffer(caterva_ctx_t *ctx,
754                              void *buffer, int64_t *buffershape, int64_t buffersize,
755                              int64_t *start, int64_t *stop,
756                              caterva_array_t *array) {
757     CATERVA_ERROR_NULL(ctx);
758     CATERVA_ERROR_NULL(buffer);
759     CATERVA_ERROR_NULL(start);
760     CATERVA_ERROR_NULL(stop);
761     CATERVA_ERROR_NULL(array);
762 
763     int64_t size = array->itemsize;
764     for (int i = 0; i < array->ndim; ++i) {
765         size *= stop[i] - start[i];
766     }
767 
768     if (buffersize < size) {
769         CATERVA_ERROR(CATERVA_ERR_INVALID_ARGUMENT);
770     }
771 
772     if (array->nitems == 0) {
773         return CATERVA_SUCCEED;
774     }
775 
776     CATERVA_ERROR(caterva_blosc_slice(ctx, buffer, buffersize, start, stop, buffershape, array, true));
777 
778     return CATERVA_SUCCEED;
779 }
780 
caterva_get_slice(caterva_ctx_t * ctx,caterva_array_t * src,int64_t * start,int64_t * stop,caterva_storage_t * storage,caterva_array_t ** array)781 int caterva_get_slice(caterva_ctx_t *ctx, caterva_array_t *src, int64_t *start,
782                       int64_t *stop, caterva_storage_t *storage, caterva_array_t **array) {
783     CATERVA_ERROR_NULL(ctx);
784     CATERVA_ERROR_NULL(storage);
785     CATERVA_ERROR_NULL(src);
786     CATERVA_ERROR_NULL(start);
787     CATERVA_ERROR_NULL(stop);
788     CATERVA_ERROR_NULL(array);
789 
790     caterva_params_t params;
791     params.ndim = src->ndim;
792     params.itemsize = src->itemsize;
793     for (int i = 0; i < src->ndim; ++i) {
794         params.shape[i] = stop[i] - start[i];
795     }
796 
797     // Add data
798     CATERVA_ERROR(caterva_empty(ctx, &params, storage, array));
799 
800     if ((*array)->nitems == 0) {
801         return CATERVA_SUCCEED;
802     }
803 
804     uint8_t ndim = (*array)->ndim;
805     int64_t chunks_in_array[CATERVA_MAX_DIM] = {0};
806     for (int i = 0; i < ndim; ++i) {
807         chunks_in_array[i] = (*array)->extshape[i] / (*array)->chunkshape[i];
808     }
809     int64_t nchunks = (*array)->sc->nchunks;
810     for (int nchunk = 0; nchunk < nchunks; ++nchunk) {
811         int64_t nchunk_ndim[CATERVA_MAX_DIM] = {0};
812         index_unidim_to_multidim(ndim, chunks_in_array, nchunk, nchunk_ndim);
813 
814         // check if the chunk needs to be updated
815         int64_t chunk_start[CATERVA_MAX_DIM] = {0};
816         int64_t chunk_stop[CATERVA_MAX_DIM] = {0};
817         int64_t chunk_shape[CATERVA_MAX_DIM] = {0};
818         for (int i = 0; i < ndim; ++i) {
819             chunk_start[i] = nchunk_ndim[i] * (*array)->chunkshape[i];
820             chunk_stop[i] = chunk_start[i] + (*array)->chunkshape[i];
821             if (chunk_stop[i] > (*array)->shape[i]) {
822                 chunk_stop[i] = (*array)->shape[i];
823             }
824             chunk_shape[i] = chunk_stop[i] - chunk_start[i];
825         }
826 
827         int64_t src_start[CATERVA_MAX_DIM] = {0};
828         int64_t src_stop[CATERVA_MAX_DIM] = {0};
829         for (int i = 0; i < ndim; ++i) {
830             src_start[i] = chunk_start[i] + start[i];
831             src_stop[i] = chunk_stop[i] + start[i];
832         }
833         int64_t buffersize = params.itemsize;
834         for (int i = 0; i < ndim; ++i) {
835             buffersize *= chunk_shape[i];
836         }
837         uint8_t *buffer = ctx->cfg->alloc(buffersize);
838         CATERVA_ERROR(caterva_get_slice_buffer(ctx, src, src_start, src_stop, buffer, chunk_shape,
839                                                buffersize));
840         CATERVA_ERROR(caterva_set_slice_buffer(ctx, buffer, chunk_shape, buffersize, chunk_start,
841                                                chunk_stop, *array));
842         ctx->cfg->free(buffer);
843     }
844 
845     return CATERVA_SUCCEED;
846 }
847 
caterva_squeeze(caterva_ctx_t * ctx,caterva_array_t * array)848 int caterva_squeeze(caterva_ctx_t *ctx, caterva_array_t *array) {
849     CATERVA_ERROR_NULL(ctx);
850     CATERVA_ERROR_NULL(array);
851 
852     bool index[CATERVA_MAX_DIM];
853 
854     for (int i = 0; i < array->ndim; ++i) {
855         if (array->shape[i] != 1) {
856             index[i] = false;
857         } else {
858             index[i] = true;
859         }
860     }
861     CATERVA_ERROR(caterva_squeeze_index(ctx, array, index));
862 
863     return CATERVA_SUCCEED;
864 }
865 
caterva_squeeze_index(caterva_ctx_t * ctx,caterva_array_t * array,bool * index)866 int caterva_squeeze_index(caterva_ctx_t *ctx, caterva_array_t *array, bool *index) {
867     CATERVA_ERROR_NULL(ctx);
868     CATERVA_ERROR_NULL(array);
869 
870     uint8_t nones = 0;
871     int64_t newshape[CATERVA_MAX_DIM];
872     int32_t newchunkshape[CATERVA_MAX_DIM];
873     int32_t newblockshape[CATERVA_MAX_DIM];
874 
875     for (int i = 0; i < array->ndim; ++i) {
876         if (index[i] == true) {
877             if (array->shape[i] != 1) {
878                 CATERVA_ERROR(CATERVA_ERR_INVALID_INDEX);
879             }
880         } else {
881             newshape[nones] = array->shape[i];
882             newchunkshape[nones] = array->chunkshape[i];
883             newblockshape[nones] = array->blockshape[i];
884             nones += 1;
885         }
886     }
887 
888     for (int i = 0; i < CATERVA_MAX_DIM; ++i) {
889         if (i < nones) {
890             array->chunkshape[i] = newchunkshape[i];
891             array->blockshape[i] = newblockshape[i];
892         } else {
893             array->chunkshape[i] = 1;
894             array->blockshape[i] = 1;
895         }
896     }
897 
898     CATERVA_ERROR(caterva_update_shape(array, nones, newshape, newchunkshape, newblockshape));
899 
900     return CATERVA_SUCCEED;
901 }
902 
caterva_copy(caterva_ctx_t * ctx,caterva_array_t * src,caterva_storage_t * storage,caterva_array_t ** array)903 int caterva_copy(caterva_ctx_t *ctx, caterva_array_t *src, caterva_storage_t *storage,
904                  caterva_array_t **array) {
905     CATERVA_ERROR_NULL(ctx);
906     CATERVA_ERROR_NULL(src);
907     CATERVA_ERROR_NULL(storage);
908     CATERVA_ERROR_NULL(array);
909 
910 
911     caterva_params_t params;
912     params.itemsize = src->itemsize;
913     params.ndim = src->ndim;
914     for (int i = 0; i < src->ndim; ++i) {
915         params.shape[i] = src->shape[i];
916     }
917 
918     bool equals = true;
919     for (int i = 0; i < src->ndim; ++i) {
920         if (src->chunkshape[i] != storage->chunkshape[i]) {
921             equals = false;
922             break;
923         }
924         if (src->blockshape[i] != storage->blockshape[i]) {
925             equals = false;
926             break;
927         }
928     }
929 
930     if (equals) {
931         CATERVA_ERROR(caterva_array_without_schunk(ctx, &params, storage, array));
932         blosc2_storage b_storage;
933         blosc2_cparams cparams;
934         blosc2_dparams dparams;
935         CATERVA_ERROR(
936                 create_blosc_params(ctx, &params, storage, &cparams, &dparams, &b_storage));
937         blosc2_schunk *new_sc = blosc2_schunk_copy(src->sc, &b_storage);
938 
939         if (new_sc == NULL) {
940             return CATERVA_ERR_BLOSC_FAILED;
941         }
942         (*array)->sc = new_sc;
943 
944     } else {
945         int64_t start[CATERVA_MAX_DIM] = {0, 0, 0, 0, 0, 0, 0, 0};
946 
947         int64_t stop[CATERVA_MAX_DIM];
948         for (int i = 0; i < src->ndim; ++i) {
949             stop[i] = src->shape[i];
950         }
951         // Copy metalayers
952         caterva_storage_t storage_meta;
953         memcpy(&storage_meta, storage, sizeof(storage_meta));
954         int j = 0;
955 
956         for (int i = 0; i < src->sc->nmetalayers; ++i) {
957             if (strcmp(src->sc->metalayers[i]->name, "caterva") == 0) {
958                 continue;
959             }
960             caterva_metalayer_t *meta = &storage_meta.metalayers[j];
961             meta->name = src->sc->metalayers[i]->name;
962             meta->sdata = src->sc->metalayers[i]->content;
963             meta->size = src->sc->metalayers[i]->content_len;
964             j++;
965         }
966         storage_meta.nmetalayers = j;
967 
968         // Copy data
969         CATERVA_ERROR(caterva_get_slice(ctx, src, start, stop, &storage_meta, array));
970 
971         // Copy vlmetayers
972         for (int i = 0; i < src->sc->nvlmetalayers; ++i) {
973             uint8_t *content;
974             uint32_t content_len;
975             if (blosc2_vlmeta_get(src->sc, src->sc->vlmetalayers[i]->name, &content,
976                                   &content_len) < 0) {
977                 CATERVA_ERROR(CATERVA_ERR_BLOSC_FAILED);
978             }
979             caterva_metalayer_t vlmeta;
980             vlmeta.name = src->sc->vlmetalayers[i]->name;
981             vlmeta.sdata = content;
982             vlmeta.size = (int32_t) content_len;
983             CATERVA_ERROR(caterva_vlmeta_add(ctx, *array, &vlmeta));
984             free(content);
985         }
986 
987     }
988     return CATERVA_SUCCEED;
989 }
990 
caterva_save(caterva_ctx_t * ctx,caterva_array_t * array,char * urlpath)991 int caterva_save(caterva_ctx_t *ctx, caterva_array_t *array, char *urlpath) {
992     CATERVA_ERROR_NULL(ctx);
993     CATERVA_ERROR_NULL(array);
994     CATERVA_ERROR_NULL(urlpath);
995 
996     caterva_array_t *tmp;
997     caterva_storage_t storage;
998     storage.urlpath = urlpath;
999     storage.sequencial = array->sc->storage->contiguous;
1000 
1001     for (int i = 0; i < array->ndim; ++i) {
1002         storage.chunkshape[i] = array->chunkshape[i];
1003         storage.blockshape[i] = array->blockshape[i];
1004     }
1005 
1006     caterva_copy(ctx, array, &storage, &tmp);
1007     caterva_free(ctx, &tmp);
1008 
1009     return CATERVA_SUCCEED;
1010 }
1011 
caterva_remove(caterva_ctx_t * ctx,char * urlpath)1012 int caterva_remove(caterva_ctx_t *ctx, char *urlpath) {
1013     CATERVA_ERROR_NULL(ctx);
1014     CATERVA_ERROR_NULL(urlpath);
1015 
1016     int rc = blosc2_remove_urlpath(urlpath);
1017     if (rc != BLOSC2_ERROR_SUCCESS) {
1018         CATERVA_ERROR(CATERVA_ERR_BLOSC_FAILED);
1019     }
1020     return CATERVA_SUCCEED;
1021 }
1022 
1023 
caterva_vlmeta_add(caterva_ctx_t * ctx,caterva_array_t * array,caterva_metalayer_t * vlmeta)1024 int caterva_vlmeta_add(caterva_ctx_t *ctx, caterva_array_t *array, caterva_metalayer_t *vlmeta) {
1025     CATERVA_ERROR_NULL(ctx);
1026     CATERVA_ERROR_NULL(array);
1027     CATERVA_ERROR_NULL(vlmeta);
1028     CATERVA_ERROR_NULL(vlmeta->name);
1029     CATERVA_ERROR_NULL(vlmeta->sdata);
1030     if (vlmeta->size < 0) {
1031         CATERVA_TRACE_ERROR("metalayer size must be hgreater than 0");
1032         CATERVA_ERROR(CATERVA_ERR_INVALID_ARGUMENT);
1033     }
1034     blosc2_cparams cparams = BLOSC2_CPARAMS_DEFAULTS;
1035     if (blosc2_vlmeta_add(array->sc, vlmeta->name, vlmeta->sdata, vlmeta->size, &cparams) < 0) {
1036         CATERVA_ERROR(CATERVA_ERR_BLOSC_FAILED);
1037     }
1038 
1039     return CATERVA_SUCCEED;
1040 }
1041 
1042 
caterva_vlmeta_get(caterva_ctx_t * ctx,caterva_array_t * array,const char * name,caterva_metalayer_t * vlmeta)1043 int caterva_vlmeta_get(caterva_ctx_t *ctx, caterva_array_t *array,
1044                              const char *name, caterva_metalayer_t *vlmeta) {
1045     CATERVA_ERROR_NULL(ctx);
1046     CATERVA_ERROR_NULL(array);
1047     CATERVA_ERROR_NULL(name);
1048     CATERVA_ERROR_NULL(vlmeta);
1049 
1050     if (blosc2_vlmeta_get(array->sc, name, &vlmeta->sdata, &vlmeta->size) < 0) {
1051         CATERVA_ERROR(CATERVA_ERR_BLOSC_FAILED);
1052     }
1053     vlmeta->name = strdup(name);
1054 
1055     return CATERVA_SUCCEED;
1056 }
1057 
caterva_vlmeta_exists(caterva_ctx_t * ctx,caterva_array_t * array,const char * name,bool * exists)1058 int caterva_vlmeta_exists(caterva_ctx_t *ctx, caterva_array_t *array,
1059                                 const char *name, bool *exists) {
1060     CATERVA_ERROR_NULL(ctx);
1061     CATERVA_ERROR_NULL(array);
1062     CATERVA_ERROR_NULL(name);
1063     CATERVA_ERROR_NULL(exists);
1064 
1065     if (blosc2_vlmeta_exists(array->sc, name) < 0) {
1066         *exists = false;
1067     } else {
1068         *exists = true;
1069     }
1070 
1071     return CATERVA_SUCCEED;
1072 }
1073 
1074 
caterva_vlmeta_update(caterva_ctx_t * ctx,caterva_array_t * array,caterva_metalayer_t * vlmeta)1075 int caterva_vlmeta_update(caterva_ctx_t *ctx, caterva_array_t *array,
1076                           caterva_metalayer_t *vlmeta) {
1077     CATERVA_ERROR_NULL(ctx);
1078     CATERVA_ERROR_NULL(array);
1079     CATERVA_ERROR_NULL(vlmeta);
1080     CATERVA_ERROR_NULL(vlmeta->name);
1081     CATERVA_ERROR_NULL(vlmeta->sdata);
1082     if (vlmeta->size < 0) {
1083         CATERVA_TRACE_ERROR("metalayer size must be hgreater than 0");
1084         CATERVA_ERROR(CATERVA_ERR_INVALID_ARGUMENT);
1085     }
1086 
1087     blosc2_cparams cparams = BLOSC2_CPARAMS_DEFAULTS;
1088     if (blosc2_vlmeta_update(array->sc, vlmeta->name, vlmeta->sdata, vlmeta->size, &cparams) < 0) {
1089         CATERVA_ERROR(CATERVA_ERR_BLOSC_FAILED);
1090     }
1091 
1092     return CATERVA_SUCCEED;
1093 }
1094 
caterva_meta_get(caterva_ctx_t * ctx,caterva_array_t * array,const char * name,caterva_metalayer_t * meta)1095 int caterva_meta_get(caterva_ctx_t *ctx, caterva_array_t *array,
1096                        const char *name, caterva_metalayer_t *meta) {
1097     CATERVA_ERROR_NULL(ctx);
1098     CATERVA_ERROR_NULL(array);
1099     CATERVA_ERROR_NULL(name);
1100     CATERVA_ERROR_NULL(meta);
1101 
1102     if (blosc2_meta_get(array->sc, name, &meta->sdata, &meta->size) < 0) {
1103         CATERVA_ERROR(CATERVA_ERR_BLOSC_FAILED);
1104     }
1105     meta->name = strdup(name);
1106     return CATERVA_SUCCEED;
1107 }
1108 
caterva_meta_exists(caterva_ctx_t * ctx,caterva_array_t * array,const char * name,bool * exists)1109 int caterva_meta_exists(caterva_ctx_t *ctx, caterva_array_t *array,
1110                           const char *name, bool *exists) {
1111     CATERVA_ERROR_NULL(ctx);
1112     CATERVA_ERROR_NULL(array);
1113     CATERVA_ERROR_NULL(name);
1114     CATERVA_ERROR_NULL(exists);
1115 
1116     if (blosc2_meta_exists(array->sc, name) < 0) {
1117         *exists = false;
1118     } else {
1119         *exists = true;
1120     }
1121     return CATERVA_SUCCEED;
1122 }
1123 
1124 
caterva_meta_update(caterva_ctx_t * ctx,caterva_array_t * array,caterva_metalayer_t * meta)1125 int caterva_meta_update(caterva_ctx_t *ctx, caterva_array_t *array,
1126                           caterva_metalayer_t *meta) {
1127     CATERVA_ERROR_NULL(ctx);
1128     CATERVA_ERROR_NULL(array);
1129     CATERVA_ERROR_NULL(meta);
1130     CATERVA_ERROR_NULL(meta->name);
1131     CATERVA_ERROR_NULL(meta->sdata);
1132     if (meta->size < 0) {
1133         CATERVA_TRACE_ERROR("metalayer size must be hgreater than 0");
1134         CATERVA_ERROR(CATERVA_ERR_INVALID_ARGUMENT);
1135     }
1136 
1137     if (blosc2_meta_update(array->sc, meta->name, meta->sdata, meta->size) < 0) {
1138         CATERVA_ERROR(CATERVA_ERR_BLOSC_FAILED);
1139     }
1140     return CATERVA_SUCCEED;
1141 }
1142