From 3669c5c4cbe25e321b8bfd3bdca3e8083bd54ca9 Mon Sep 17 00:00:00 2001 From: waynegm Date: Tue, 9 Jul 2024 15:16:05 +1000 Subject: [PATCH] Add b2nd_nans method #624 --- blosc/b2nd.c | 17 ++++++ doc/reference/b2nd.rst | 1 + include/b2nd.h | 13 +++++ tests/b2nd/test_b2nd_nans.c | 105 ++++++++++++++++++++++++++++++++++++ 4 files changed, 136 insertions(+) create mode 100644 tests/b2nd/test_b2nd_nans.c diff --git a/blosc/b2nd.c b/blosc/b2nd.c index 33eb95e2..b76e14b3 100644 --- a/blosc/b2nd.c +++ b/blosc/b2nd.c @@ -395,6 +395,23 @@ int b2nd_zeros(b2nd_context_t *ctx, b2nd_array_t **array) { } +int b2nd_nans(b2nd_context_t *ctx, b2nd_array_t **array) { + BLOSC_ERROR_NULL(ctx, BLOSC2_ERROR_NULL_POINTER); + BLOSC_ERROR_NULL(array, BLOSC2_ERROR_NULL_POINTER); + + BLOSC_ERROR(array_new(ctx, BLOSC2_SPECIAL_NAN, array)); + + const int32_t typesize = (*array)->sc->typesize; + if (typesize != 4 && typesize != 8) + { + BLOSC_TRACE_ERROR("Unsupported typesize for NaN"); + return BLOSC2_ERROR_DATA; + } + + return BLOSC2_ERROR_SUCCESS; +} + + int b2nd_full(b2nd_context_t *ctx, b2nd_array_t **array, const void *fill_value) { BLOSC_ERROR_NULL(ctx, BLOSC2_ERROR_NULL_POINTER); BLOSC_ERROR_NULL(array, BLOSC2_ERROR_NULL_POINTER); diff --git a/doc/reference/b2nd.rst b/doc/reference/b2nd.rst index e247e344..2b90dd1c 100644 --- a/doc/reference/b2nd.rst +++ b/doc/reference/b2nd.rst @@ -41,6 +41,7 @@ Constructors .. doxygenfunction:: b2nd_uninit .. doxygenfunction:: b2nd_empty .. doxygenfunction:: b2nd_zeros +.. doxygenfunction:: b2nd_nans .. doxygenfunction:: b2nd_full From/To buffer diff --git a/include/b2nd.h b/include/b2nd.h index 16ff3c32..d3a5f071 100644 --- a/include/b2nd.h +++ b/include/b2nd.h @@ -193,6 +193,19 @@ BLOSC_EXPORT int b2nd_empty(b2nd_context_t *ctx, b2nd_array_t **array); BLOSC_EXPORT int b2nd_zeros(b2nd_context_t *ctx, b2nd_array_t **array); +/** + * Create an array, with NaN being used as the default value for + * uninitialized portions of the array. Should only be used with type sizes + * of either 4 or 8. Other sizes generate an error. + * + * @param ctx The b2nd context for the new array. + * @param array The memory pointer where the array will be created. + * + * @return An error code. + */ +BLOSC_EXPORT int b2nd_nans(b2nd_context_t *ctx, b2nd_array_t **array); + + /** * Create an array, with @p fill_value being used as the default value for * uninitialized portions of the array. diff --git a/tests/b2nd/test_b2nd_nans.c b/tests/b2nd/test_b2nd_nans.c new file mode 100644 index 00000000..f6da150c --- /dev/null +++ b/tests/b2nd/test_b2nd_nans.c @@ -0,0 +1,105 @@ +/********************************************************************* + Blosc - Blocked Shuffling and Compression Library + + Copyright (c) 2021 Blosc Development Team + https://blosc.org + License: BSD 3-Clause (see LICENSE.txt) + + See LICENSE.txt for details about copyright and rights to use. +**********************************************************************/ + +#include "test_common.h" +#include + +CUTEST_TEST_SETUP(nans) { + blosc2_init(); + + // Add parametrizations + CUTEST_PARAMETRIZE(typesize, uint8_t, CUTEST_DATA( + 4, 8 + )); + CUTEST_PARAMETRIZE(shapes, _test_shapes, CUTEST_DATA( + {0, {0}, {0}, {0}}, // 0-dim + {1, {5}, {3}, {2}}, // 1-idim + {2, {20, 0}, {7, 0}, {3, 0}}, // 0-shape + {2, {20, 10}, {7, 5}, {3, 5}}, // 0-shape + {2, {14, 10}, {8, 5}, {2, 2}}, // general, + {3, {12, 10, 14}, {3, 5, 9}, {3, 4, 4}}, // general + {3, {10, 21, 30, 55}, {8, 7, 15, 3}, {5, 5, 10, 1}}, // general, + )); + CUTEST_PARAMETRIZE(backend, _test_backend, CUTEST_DATA( + {false, false}, + {true, false}, + {true, true}, + {false, true}, + )); +} + + +CUTEST_TEST_TEST(nans) { + CUTEST_GET_PARAMETER(backend, _test_backend); + CUTEST_GET_PARAMETER(shapes, _test_shapes); + CUTEST_GET_PARAMETER(typesize, uint8_t); + + char *urlpath = "test_nans.b2frame"; + blosc2_remove_urlpath(urlpath); + + blosc2_cparams cparams = BLOSC2_CPARAMS_DEFAULTS; + cparams.nthreads = 2; + cparams.typesize = typesize; + blosc2_storage b2_storage = {.cparams=&cparams}; + if (backend.persistent) { + b2_storage.urlpath = urlpath; + } + b2_storage.contiguous = backend.contiguous; + + b2nd_context_t *ctx = b2nd_create_ctx(&b2_storage, shapes.ndim, shapes.shape, + shapes.chunkshape, shapes.blockshape, NULL, 0, NULL, 0); + + /* Create original data */ + int64_t buffersize = typesize; + for (int i = 0; i < shapes.ndim; ++i) { + buffersize *= shapes.shape[i]; + } + + /* Create b2nd_array_t with original data */ + b2nd_array_t *src; + B2ND_TEST_ASSERT(b2nd_nans(ctx, &src)); + + /* Fill dest array with b2nd_array_t data */ + uint8_t *buffer_dest = malloc(buffersize); + B2ND_TEST_ASSERT(b2nd_to_cbuffer(src, buffer_dest, buffersize)); + + /* Testing */ + for (int i = 0; i < buffersize / typesize; ++i) { + bool is_true = false; + switch (typesize) { + case 8: + is_true = isnan(((double *) buffer_dest)[i]); + break; + case 4: + is_true = isnan(((float *) buffer_dest)[i]); + break; + default: + break; + } + CUTEST_ASSERT("Elements are not equals", is_true); + } + + /* Free mallocs */ + free(buffer_dest); + B2ND_TEST_ASSERT(b2nd_free(src)); + B2ND_TEST_ASSERT(b2nd_free_ctx(ctx)); + blosc2_remove_urlpath(urlpath); + + return BLOSC2_ERROR_SUCCESS; +} + + +CUTEST_TEST_TEARDOWN(nans) { + blosc2_destroy(); +} + +int main() { + CUTEST_TEST_RUN(nans); +}