From e83e90e033301241fce0cb3e4706d1101956ed1c Mon Sep 17 00:00:00 2001 From: Benjamin Brock Date: Thu, 24 Oct 2024 16:05:48 -0700 Subject: [PATCH] Make `bsp_read_matrix` statically linked instead of header-only. --- CMakeLists.txt | 15 +- include/CMakeLists.txt | 3 +- include/binsparse/hdf5_wrapper.h | 15 +- .../matrix_market/matrix_market_inspector.h | 2 +- .../matrix_market/matrix_market_read.h | 20 +- .../matrix_market/matrix_market_write.h | 2 +- include/binsparse/read_matrix.h | 275 +---------------- src/CMakeLists.txt | 7 + src/read_matrix.c | 279 ++++++++++++++++++ 9 files changed, 333 insertions(+), 285 deletions(-) create mode 100644 src/CMakeLists.txt create mode 100644 src/read_matrix.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 5ad2478..a0c78b7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,11 +13,18 @@ set(CMAKE_CXX_STANDARD 20) set(CMAKE_C_FLAGS "-O3 -march=native") +add_library(binsparse-rc STATIC) + add_subdirectory(include) +add_subdirectory(src) + +# NOTE: For now, both HDF5 and cJSON are `PUBLIC`, meaning that anything that +# depends on `binsparse-rc` will also link/include HDF5 and cJSON. We can change +# these to `PRIVATE` to use them only when building binsparse-rc. find_package(HDF5 REQUIRED COMPONENTS C) -target_link_libraries(binsparse-rc INTERFACE ${HDF5_C_LIBRARIES}) -target_include_directories(binsparse-rc INTERFACE . ${HDF5_INCLUDE_DIRS}) +target_link_libraries(binsparse-rc PUBLIC ${HDF5_C_LIBRARIES}) +target_include_directories(binsparse-rc PUBLIC . ${HDF5_INCLUDE_DIRS}) include(FetchContent) FetchContent_Declare( @@ -28,8 +35,8 @@ FetchContent_Declare( FetchContent_MakeAvailable(cJSON) configure_file(${cJSON_SOURCE_DIR}/cJSON.h ${CMAKE_BINARY_DIR}/include/cJSON/cJSON.h) -target_include_directories(${PROJECT_NAME} INTERFACE ${CMAKE_BINARY_DIR}/include) -target_link_libraries(${PROJECT_NAME} INTERFACE cjson) +target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_BINARY_DIR}/include) +target_link_libraries(${PROJECT_NAME} PUBLIC cjson) if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) add_subdirectory(examples) diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index a423da1..f8ebad3 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -2,5 +2,4 @@ # # SPDX-License-Identifier: BSD-3-Clause -add_library(binsparse-rc INTERFACE) -target_include_directories(binsparse-rc INTERFACE .) +target_include_directories(binsparse-rc PUBLIC .) diff --git a/include/binsparse/hdf5_wrapper.h b/include/binsparse/hdf5_wrapper.h index f3f6763..5aded28 100644 --- a/include/binsparse/hdf5_wrapper.h +++ b/include/binsparse/hdf5_wrapper.h @@ -21,8 +21,8 @@ // Write an array to a dataset / file // Returns 0 on success, nonzero on error. -int bsp_write_array(hid_t f, const char* label, bsp_array_t array, - int compression_level) { +static inline int bsp_write_array(hid_t f, const char* label, bsp_array_t array, + int compression_level) { if (array.type == BSP_COMPLEX_FLOAT32 || array.type == BSP_COMPLEX_FLOAT64) { array = bsp_complex_array_to_fp(array); } @@ -76,8 +76,8 @@ int bsp_write_array(hid_t f, const char* label, bsp_array_t array, } #if __STDC_VERSION__ >= 201112L -bsp_array_t bsp_read_array_parallel(hid_t f, const char* label, - int num_threads) { +static inline bsp_array_t bsp_read_array_parallel(hid_t f, const char* label, + int num_threads) { hid_t dset = H5Dopen2(f, label, H5P_DEFAULT); if (dset == H5I_INVALID_HID) { @@ -173,7 +173,7 @@ bsp_array_t bsp_read_array_parallel(hid_t f, const char* label, } #endif -bsp_array_t bsp_read_array(hid_t f, const char* label) { +static inline bsp_array_t bsp_read_array(hid_t f, const char* label) { hid_t dset = H5Dopen2(f, label, H5P_DEFAULT); if (dset == H5I_INVALID_HID) { @@ -212,7 +212,8 @@ bsp_array_t bsp_read_array(hid_t f, const char* label) { return array; } -void bsp_write_attribute(hid_t f, const char* label, const char* string) { +static inline void bsp_write_attribute(hid_t f, const char* label, + const char* string) { hid_t strtype = H5Tcopy(H5T_C_S1); H5Tset_size(strtype, strlen(string)); H5Tset_cset(strtype, H5T_CSET_UTF8); @@ -228,7 +229,7 @@ void bsp_write_attribute(hid_t f, const char* label, const char* string) { H5Sclose(dataspace); } -char* bsp_read_attribute(hid_t f, const char* label) { +static inline char* bsp_read_attribute(hid_t f, const char* label) { hid_t attribute = H5Aopen(f, label, H5P_DEFAULT); hid_t strtype = H5Aget_type(attribute); diff --git a/include/binsparse/matrix_market/matrix_market_inspector.h b/include/binsparse/matrix_market/matrix_market_inspector.h index 3bae696..8811a89 100644 --- a/include/binsparse/matrix_market/matrix_market_inspector.h +++ b/include/binsparse/matrix_market/matrix_market_inspector.h @@ -32,7 +32,7 @@ typedef struct bsp_mm_metadata { char* comments; } bsp_mm_metadata; -bsp_mm_metadata bsp_mmread_metadata(const char* file_path) { +static inline bsp_mm_metadata bsp_mmread_metadata(const char* file_path) { FILE* f = fopen(file_path, "r"); assert(f != NULL); diff --git a/include/binsparse/matrix_market/matrix_market_read.h b/include/binsparse/matrix_market/matrix_market_read.h index 5013ab9..c3eb8a0 100644 --- a/include/binsparse/matrix_market/matrix_market_read.h +++ b/include/binsparse/matrix_market/matrix_market_read.h @@ -11,13 +11,14 @@ #include #include +#include #include #include #include -bsp_matrix_t bsp_mmread_explicit_array(const char* file_path, - bsp_type_t value_type, - bsp_type_t index_type) { +static inline bsp_matrix_t bsp_mmread_explicit_array(const char* file_path, + bsp_type_t value_type, + bsp_type_t index_type) { bsp_mm_metadata metadata = bsp_mmread_metadata(file_path); bsp_matrix_market_type_t mm_type; @@ -103,9 +104,9 @@ bsp_matrix_t bsp_mmread_explicit_array(const char* file_path, return matrix; } -bsp_matrix_t bsp_mmread_explicit_coordinate(const char* file_path, - bsp_type_t value_type, - bsp_type_t index_type) { +static inline bsp_matrix_t +bsp_mmread_explicit_coordinate(const char* file_path, bsp_type_t value_type, + bsp_type_t index_type) { bsp_mm_metadata metadata = bsp_mmread_metadata(file_path); bsp_matrix_market_type_t mm_type; @@ -261,8 +262,9 @@ bsp_matrix_t bsp_mmread_explicit_coordinate(const char* file_path, return matrix; } -bsp_matrix_t bsp_mmread_explicit(const char* file_path, bsp_type_t value_type, - bsp_type_t index_type) { +static inline bsp_matrix_t bsp_mmread_explicit(const char* file_path, + bsp_type_t value_type, + bsp_type_t index_type) { bsp_mm_metadata metadata = bsp_mmread_metadata(file_path); if (strcmp(metadata.format, "array") == 0) { @@ -274,7 +276,7 @@ bsp_matrix_t bsp_mmread_explicit(const char* file_path, bsp_type_t value_type, } } -bsp_matrix_t bsp_mmread(const char* file_path) { +static inline bsp_matrix_t bsp_mmread(const char* file_path) { bsp_mm_metadata metadata = bsp_mmread_metadata(file_path); bsp_type_t value_type; diff --git a/include/binsparse/matrix_market/matrix_market_write.h b/include/binsparse/matrix_market/matrix_market_write.h index 1a4a5e2..afb4706 100644 --- a/include/binsparse/matrix_market/matrix_market_write.h +++ b/include/binsparse/matrix_market/matrix_market_write.h @@ -12,7 +12,7 @@ #include -void bsp_mmwrite(const char* file_path, bsp_matrix_t matrix) { +static inline void bsp_mmwrite(const char* file_path, bsp_matrix_t matrix) { FILE* f = fopen(file_path, "w"); assert(f != NULL); diff --git a/include/binsparse/read_matrix.h b/include/binsparse/read_matrix.h index 0730bb9..948ffba 100644 --- a/include/binsparse/read_matrix.h +++ b/include/binsparse/read_matrix.h @@ -6,274 +6,27 @@ #pragma once -#include -#include -#include - -#if __STDC_VERSION__ >= 201112L -bsp_matrix_t bsp_read_matrix_from_group_parallel(hid_t f, int num_threads) { - bsp_matrix_t matrix = bsp_construct_default_matrix_t(); - - char* json_string = bsp_read_attribute(f, (char*) "binsparse"); - - cJSON* j = cJSON_Parse(json_string); - - assert(j != NULL); - assert(cJSON_IsObject(j)); - - cJSON* binsparse = cJSON_GetObjectItemCaseSensitive(j, "binsparse"); - assert(cJSON_IsObject(binsparse)); - - cJSON* version_ = cJSON_GetObjectItemCaseSensitive(binsparse, "version"); - - assert(version_ != NULL); - - assert(cJSON_IsString(version_)); - - // TODO: check version. - - cJSON* format_ = cJSON_GetObjectItemCaseSensitive(binsparse, "format"); - assert(format_ != NULL); - char* format_string = cJSON_GetStringValue(format_); - - bsp_matrix_format_t format = bsp_get_matrix_format(format_string); - - assert(format != 0); - - matrix.format = format; - - cJSON* nnz_ = - cJSON_GetObjectItemCaseSensitive(binsparse, "number_of_stored_values"); - assert(nnz_ != NULL); - size_t nnz = cJSON_GetNumberValue(nnz_); - - cJSON* shape_ = cJSON_GetObjectItemCaseSensitive(binsparse, "shape"); - assert(shape_ != NULL); - - assert(cJSON_GetArraySize(shape_) == 2); - - cJSON* nrows_ = cJSON_GetArrayItem(shape_, 0); - assert(nrows_ != NULL); - - size_t nrows = cJSON_GetNumberValue(nrows_); - - cJSON* ncols_ = cJSON_GetArrayItem(shape_, 1); - assert(ncols_ != NULL); - - size_t ncols = cJSON_GetNumberValue(ncols_); - - matrix.nrows = nrows; - matrix.ncols = ncols; - matrix.nnz = nnz; - matrix.format = format; - - cJSON* data_types_ = - cJSON_GetObjectItemCaseSensitive(binsparse, "data_types"); - assert(data_types_ != NULL); - - if (cJSON_HasObjectItem(data_types_, "values")) { - matrix.values = bsp_read_array_parallel(f, (char*) "values", num_threads); - - cJSON* value_type = cJSON_GetObjectItemCaseSensitive(data_types_, "values"); - char* type_string = cJSON_GetStringValue(value_type); - - if (strlen(type_string) >= 4 && strncmp(type_string, "iso[", 4) == 0) { - matrix.is_iso = true; - type_string += 4; - } - - if (strlen(type_string) >= 8 && strncmp(type_string, "complex[", 8) == 0) { - matrix.values = bsp_fp_array_to_complex(matrix.values); - } - } - - if (cJSON_HasObjectItem(data_types_, "indices_0")) { - matrix.indices_0 = - bsp_read_array_parallel(f, (char*) "indices_0", num_threads); - } - - if (cJSON_HasObjectItem(data_types_, "indices_1")) { - matrix.indices_1 = - bsp_read_array_parallel(f, (char*) "indices_1", num_threads); - } - - if (cJSON_HasObjectItem(data_types_, "pointers_to_1")) { - matrix.pointers_to_1 = - bsp_read_array_parallel(f, (char*) "pointers_to_1", num_threads); - } - - if (cJSON_HasObjectItem(binsparse, "structure")) { - cJSON* structure_ = - cJSON_GetObjectItemCaseSensitive(binsparse, "structure"); - char* structure = cJSON_GetStringValue(structure_); - matrix.structure = bsp_get_structure(structure); - } - - cJSON_Delete(j); - free(json_string); - - return matrix; -} +#ifdef __cplusplus +extern "C" { #endif -bsp_matrix_t bsp_read_matrix_from_group(hid_t f) { - bsp_matrix_t matrix = bsp_construct_default_matrix_t(); - - char* json_string = bsp_read_attribute(f, (char*) "binsparse"); - - cJSON* j = cJSON_Parse(json_string); +#ifdef BSP_USE_HDF5 +#include - assert(j != NULL); - assert(cJSON_IsObject(j)); - - cJSON* binsparse = cJSON_GetObjectItemCaseSensitive(j, "binsparse"); - assert(cJSON_IsObject(binsparse)); - - cJSON* version_ = cJSON_GetObjectItemCaseSensitive(binsparse, "version"); - - assert(version_ != NULL); - - assert(cJSON_IsString(version_)); - - // TODO: check version. - - cJSON* format_ = cJSON_GetObjectItemCaseSensitive(binsparse, "format"); - assert(format_ != NULL); - char* format_string = cJSON_GetStringValue(format_); - - bsp_matrix_format_t format = bsp_get_matrix_format(format_string); - - assert(format != 0); - - matrix.format = format; - - cJSON* nnz_ = - cJSON_GetObjectItemCaseSensitive(binsparse, "number_of_stored_values"); - assert(nnz_ != NULL); - size_t nnz = cJSON_GetNumberValue(nnz_); - - cJSON* shape_ = cJSON_GetObjectItemCaseSensitive(binsparse, "shape"); - assert(shape_ != NULL); - - assert(cJSON_GetArraySize(shape_) == 2); - - cJSON* nrows_ = cJSON_GetArrayItem(shape_, 0); - assert(nrows_ != NULL); - - size_t nrows = cJSON_GetNumberValue(nrows_); - - cJSON* ncols_ = cJSON_GetArrayItem(shape_, 1); - assert(ncols_ != NULL); - - size_t ncols = cJSON_GetNumberValue(ncols_); - - matrix.nrows = nrows; - matrix.ncols = ncols; - matrix.nnz = nnz; - matrix.format = format; - - cJSON* data_types_ = - cJSON_GetObjectItemCaseSensitive(binsparse, "data_types"); - assert(data_types_ != NULL); - - if (cJSON_HasObjectItem(data_types_, "values")) { - matrix.values = bsp_read_array(f, (char*) "values"); - - cJSON* value_type = cJSON_GetObjectItemCaseSensitive(data_types_, "values"); - char* type_string = cJSON_GetStringValue(value_type); - - if (strlen(type_string) >= 4 && strncmp(type_string, "iso[", 4) == 0) { - matrix.is_iso = true; - type_string += 4; - } - - if (strlen(type_string) >= 8 && strncmp(type_string, "complex[", 8) == 0) { - matrix.values = bsp_fp_array_to_complex(matrix.values); - } - } - - if (cJSON_HasObjectItem(data_types_, "indices_0")) { - matrix.indices_0 = bsp_read_array(f, (char*) "indices_0"); - } - - if (cJSON_HasObjectItem(data_types_, "indices_1")) { - matrix.indices_1 = bsp_read_array(f, (char*) "indices_1"); - } - - if (cJSON_HasObjectItem(data_types_, "pointers_to_1")) { - matrix.pointers_to_1 = bsp_read_array(f, (char*) "pointers_to_1"); - } - - if (cJSON_HasObjectItem(binsparse, "structure")) { - cJSON* structure_ = - cJSON_GetObjectItemCaseSensitive(binsparse, "structure"); - char* structure = cJSON_GetStringValue(structure_); - matrix.structure = bsp_get_structure(structure); - } - - cJSON_Delete(j); - free(json_string); - - return matrix; -} +#if __STDC_VERSION__ >= 201112L +bsp_matrix_t bsp_read_matrix_from_group_parallel(hid_t f, int num_threads); +#endif -size_t bsp_final_dot(const char* str) { - size_t dot_idx = 0; - for (size_t i = 0; str[i] != '\0'; i++) { - if (str[i] == '.') { - dot_idx = i; - } - } - return dot_idx; -} +bsp_matrix_t bsp_read_matrix_from_group(hid_t f); +#endif #if __STDC_VERSION__ >= 201112L bsp_matrix_t bsp_read_matrix_parallel(const char* file_name, const char* group, - int num_threads) { - if (group == NULL) { - size_t idx = bsp_final_dot(file_name); - if (strcmp(file_name + idx, ".hdf5") == 0 || - strcmp(file_name + idx, ".h5") == 0) { - hid_t f = H5Fopen(file_name, H5F_ACC_RDONLY, H5P_DEFAULT); - bsp_matrix_t matrix = bsp_read_matrix_from_group_parallel(f, num_threads); - H5Fclose(f); - return matrix; - } else if (strcmp(file_name + idx, ".mtx") == 0) { - return bsp_mmread(file_name); - } else { - assert(false); - } - } else { - hid_t f = H5Fopen(file_name, H5F_ACC_RDONLY, H5P_DEFAULT); - hid_t g = H5Gopen1(f, group); - bsp_matrix_t matrix = bsp_read_matrix_from_group_parallel(g, num_threads); - H5Gclose(g); - H5Fclose(f); - return matrix; - } -} + int num_threads); #endif -bsp_matrix_t bsp_read_matrix(const char* file_name, const char* group) { - if (group == NULL) { - size_t idx = bsp_final_dot(file_name); - if (strcmp(file_name + idx, ".hdf5") == 0 || - strcmp(file_name + idx, ".h5") == 0) { - hid_t f = H5Fopen(file_name, H5F_ACC_RDONLY, H5P_DEFAULT); - bsp_matrix_t matrix = bsp_read_matrix_from_group(f); - H5Fclose(f); - return matrix; - } else if (strcmp(file_name + idx, ".mtx") == 0) { - return bsp_mmread(file_name); - } else { - assert(false); - } - } else { - hid_t f = H5Fopen(file_name, H5F_ACC_RDONLY, H5P_DEFAULT); - hid_t g = H5Gopen1(f, group); - bsp_matrix_t matrix = bsp_read_matrix_from_group(g); - H5Gclose(g); - H5Fclose(f); - return matrix; - } +bsp_matrix_t bsp_read_matrix(const char* file_name, const char* group); + +#ifdef __cplusplus } +#endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..7f0bbcb --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,7 @@ +# SPDX-FileCopyrightText: 2024 Binsparse Developers +# +# SPDX-License-Identifier: BSD-3-Clause + +target_sources(binsparse-rc PRIVATE + src/read_matrix.c +) diff --git a/src/read_matrix.c b/src/read_matrix.c new file mode 100644 index 0000000..464210c --- /dev/null +++ b/src/read_matrix.c @@ -0,0 +1,279 @@ +/* + * SPDX-FileCopyrightText: 2024 Binsparse Developers + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include + +#if __STDC_VERSION__ >= 201112L +bsp_matrix_t bsp_read_matrix_from_group_parallel(hid_t f, int num_threads) { + bsp_matrix_t matrix = bsp_construct_default_matrix_t(); + + char* json_string = bsp_read_attribute(f, (char*) "binsparse"); + + cJSON* j = cJSON_Parse(json_string); + + assert(j != NULL); + assert(cJSON_IsObject(j)); + + cJSON* binsparse = cJSON_GetObjectItemCaseSensitive(j, "binsparse"); + assert(cJSON_IsObject(binsparse)); + + cJSON* version_ = cJSON_GetObjectItemCaseSensitive(binsparse, "version"); + + assert(version_ != NULL); + + assert(cJSON_IsString(version_)); + + // TODO: check version. + + cJSON* format_ = cJSON_GetObjectItemCaseSensitive(binsparse, "format"); + assert(format_ != NULL); + char* format_string = cJSON_GetStringValue(format_); + + bsp_matrix_format_t format = bsp_get_matrix_format(format_string); + + assert(format != 0); + + matrix.format = format; + + cJSON* nnz_ = + cJSON_GetObjectItemCaseSensitive(binsparse, "number_of_stored_values"); + assert(nnz_ != NULL); + size_t nnz = cJSON_GetNumberValue(nnz_); + + cJSON* shape_ = cJSON_GetObjectItemCaseSensitive(binsparse, "shape"); + assert(shape_ != NULL); + + assert(cJSON_GetArraySize(shape_) == 2); + + cJSON* nrows_ = cJSON_GetArrayItem(shape_, 0); + assert(nrows_ != NULL); + + size_t nrows = cJSON_GetNumberValue(nrows_); + + cJSON* ncols_ = cJSON_GetArrayItem(shape_, 1); + assert(ncols_ != NULL); + + size_t ncols = cJSON_GetNumberValue(ncols_); + + matrix.nrows = nrows; + matrix.ncols = ncols; + matrix.nnz = nnz; + matrix.format = format; + + cJSON* data_types_ = + cJSON_GetObjectItemCaseSensitive(binsparse, "data_types"); + assert(data_types_ != NULL); + + if (cJSON_HasObjectItem(data_types_, "values")) { + matrix.values = bsp_read_array_parallel(f, (char*) "values", num_threads); + + cJSON* value_type = cJSON_GetObjectItemCaseSensitive(data_types_, "values"); + char* type_string = cJSON_GetStringValue(value_type); + + if (strlen(type_string) >= 4 && strncmp(type_string, "iso[", 4) == 0) { + matrix.is_iso = true; + type_string += 4; + } + + if (strlen(type_string) >= 8 && strncmp(type_string, "complex[", 8) == 0) { + matrix.values = bsp_fp_array_to_complex(matrix.values); + } + } + + if (cJSON_HasObjectItem(data_types_, "indices_0")) { + matrix.indices_0 = + bsp_read_array_parallel(f, (char*) "indices_0", num_threads); + } + + if (cJSON_HasObjectItem(data_types_, "indices_1")) { + matrix.indices_1 = + bsp_read_array_parallel(f, (char*) "indices_1", num_threads); + } + + if (cJSON_HasObjectItem(data_types_, "pointers_to_1")) { + matrix.pointers_to_1 = + bsp_read_array_parallel(f, (char*) "pointers_to_1", num_threads); + } + + if (cJSON_HasObjectItem(binsparse, "structure")) { + cJSON* structure_ = + cJSON_GetObjectItemCaseSensitive(binsparse, "structure"); + char* structure = cJSON_GetStringValue(structure_); + matrix.structure = bsp_get_structure(structure); + } + + cJSON_Delete(j); + free(json_string); + + return matrix; +} +#endif + +bsp_matrix_t bsp_read_matrix_from_group(hid_t f) { + bsp_matrix_t matrix = bsp_construct_default_matrix_t(); + + char* json_string = bsp_read_attribute(f, (char*) "binsparse"); + + cJSON* j = cJSON_Parse(json_string); + + assert(j != NULL); + assert(cJSON_IsObject(j)); + + cJSON* binsparse = cJSON_GetObjectItemCaseSensitive(j, "binsparse"); + assert(cJSON_IsObject(binsparse)); + + cJSON* version_ = cJSON_GetObjectItemCaseSensitive(binsparse, "version"); + + assert(version_ != NULL); + + assert(cJSON_IsString(version_)); + + // TODO: check version. + + cJSON* format_ = cJSON_GetObjectItemCaseSensitive(binsparse, "format"); + assert(format_ != NULL); + char* format_string = cJSON_GetStringValue(format_); + + bsp_matrix_format_t format = bsp_get_matrix_format(format_string); + + assert(format != 0); + + matrix.format = format; + + cJSON* nnz_ = + cJSON_GetObjectItemCaseSensitive(binsparse, "number_of_stored_values"); + assert(nnz_ != NULL); + size_t nnz = cJSON_GetNumberValue(nnz_); + + cJSON* shape_ = cJSON_GetObjectItemCaseSensitive(binsparse, "shape"); + assert(shape_ != NULL); + + assert(cJSON_GetArraySize(shape_) == 2); + + cJSON* nrows_ = cJSON_GetArrayItem(shape_, 0); + assert(nrows_ != NULL); + + size_t nrows = cJSON_GetNumberValue(nrows_); + + cJSON* ncols_ = cJSON_GetArrayItem(shape_, 1); + assert(ncols_ != NULL); + + size_t ncols = cJSON_GetNumberValue(ncols_); + + matrix.nrows = nrows; + matrix.ncols = ncols; + matrix.nnz = nnz; + matrix.format = format; + + cJSON* data_types_ = + cJSON_GetObjectItemCaseSensitive(binsparse, "data_types"); + assert(data_types_ != NULL); + + if (cJSON_HasObjectItem(data_types_, "values")) { + matrix.values = bsp_read_array(f, (char*) "values"); + + cJSON* value_type = cJSON_GetObjectItemCaseSensitive(data_types_, "values"); + char* type_string = cJSON_GetStringValue(value_type); + + if (strlen(type_string) >= 4 && strncmp(type_string, "iso[", 4) == 0) { + matrix.is_iso = true; + type_string += 4; + } + + if (strlen(type_string) >= 8 && strncmp(type_string, "complex[", 8) == 0) { + matrix.values = bsp_fp_array_to_complex(matrix.values); + } + } + + if (cJSON_HasObjectItem(data_types_, "indices_0")) { + matrix.indices_0 = bsp_read_array(f, (char*) "indices_0"); + } + + if (cJSON_HasObjectItem(data_types_, "indices_1")) { + matrix.indices_1 = bsp_read_array(f, (char*) "indices_1"); + } + + if (cJSON_HasObjectItem(data_types_, "pointers_to_1")) { + matrix.pointers_to_1 = bsp_read_array(f, (char*) "pointers_to_1"); + } + + if (cJSON_HasObjectItem(binsparse, "structure")) { + cJSON* structure_ = + cJSON_GetObjectItemCaseSensitive(binsparse, "structure"); + char* structure = cJSON_GetStringValue(structure_); + matrix.structure = bsp_get_structure(structure); + } + + cJSON_Delete(j); + free(json_string); + + return matrix; +} + +static inline size_t bsp_final_dot(const char* str) { + size_t dot_idx = 0; + for (size_t i = 0; str[i] != '\0'; i++) { + if (str[i] == '.') { + dot_idx = i; + } + } + return dot_idx; +} + +#if __STDC_VERSION__ >= 201112L +bsp_matrix_t bsp_read_matrix_parallel(const char* file_name, const char* group, + int num_threads) { + if (group == NULL) { + size_t idx = bsp_final_dot(file_name); + if (strcmp(file_name + idx, ".hdf5") == 0 || + strcmp(file_name + idx, ".h5") == 0) { + hid_t f = H5Fopen(file_name, H5F_ACC_RDONLY, H5P_DEFAULT); + bsp_matrix_t matrix = bsp_read_matrix_from_group_parallel(f, num_threads); + H5Fclose(f); + return matrix; + } else if (strcmp(file_name + idx, ".mtx") == 0) { + return bsp_mmread(file_name); + } else { + assert(false); + } + } else { + hid_t f = H5Fopen(file_name, H5F_ACC_RDONLY, H5P_DEFAULT); + hid_t g = H5Gopen1(f, group); + bsp_matrix_t matrix = bsp_read_matrix_from_group_parallel(g, num_threads); + H5Gclose(g); + H5Fclose(f); + return matrix; + } +} +#endif + +bsp_matrix_t bsp_read_matrix(const char* file_name, const char* group) { + if (group == NULL) { + size_t idx = bsp_final_dot(file_name); + if (strcmp(file_name + idx, ".hdf5") == 0 || + strcmp(file_name + idx, ".h5") == 0) { + hid_t f = H5Fopen(file_name, H5F_ACC_RDONLY, H5P_DEFAULT); + bsp_matrix_t matrix = bsp_read_matrix_from_group(f); + H5Fclose(f); + return matrix; + } else if (strcmp(file_name + idx, ".mtx") == 0) { + return bsp_mmread(file_name); + } else { + assert(false); + } + } else { + hid_t f = H5Fopen(file_name, H5F_ACC_RDONLY, H5P_DEFAULT); + hid_t g = H5Gopen1(f, group); + bsp_matrix_t matrix = bsp_read_matrix_from_group(g); + H5Gclose(g); + H5Fclose(f); + return matrix; + } +}