From 53d5324df60bd7c67cf006aaf521e84ca4724cdc Mon Sep 17 00:00:00 2001 From: Jenny Wong Date: Wed, 24 Jan 2024 13:20:21 +0000 Subject: [PATCH 01/13] Initial C API for Python interface --- src/metkit/CMakeLists.txt | 4 +- src/metkit/api/metkit_c.cc | 271 ++++++++++++++++++++++++++++++++ src/metkit/api/metkit_c.h | 104 ++++++++++++ src/metkit/metkit_version.cc.in | 20 --- src/metkit/metkit_version.h.in | 18 +-- 5 files changed, 383 insertions(+), 34 deletions(-) create mode 100644 src/metkit/api/metkit_c.cc create mode 100644 src/metkit/api/metkit_c.h delete mode 100644 src/metkit/metkit_version.cc.in diff --git a/src/metkit/CMakeLists.txt b/src/metkit/CMakeLists.txt index c798ac6a..4bb88898 100644 --- a/src/metkit/CMakeLists.txt +++ b/src/metkit/CMakeLists.txt @@ -4,7 +4,6 @@ ecbuild_generate_config_headers( DESTINATION ${INSTALL_INCLUDE_DIR}/metkit ) configure_file( metkit_config.h.in metkit_config.h ) configure_file( metkit_version.h.in metkit_version.h ) -configure_file( metkit_version.cc.in metkit_version.cc ) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/metkit_config.h @@ -15,7 +14,6 @@ install(FILES ### metkit sources list( APPEND metkit_srcs - ${CMAKE_CURRENT_BINARY_DIR}/metkit_version.cc config/LibMetkit.cc config/LibMetkit.h mars/BaseProtocol.cc @@ -98,6 +96,8 @@ list( APPEND metkit_srcs hypercube/HyperCube.cc hypercube/HyperCube.h hypercube/HyperCubePayloaded.h + api/metkit_c.cc + api/metkit_c.h ) list( APPEND metkit_persistent_srcs diff --git a/src/metkit/api/metkit_c.cc b/src/metkit/api/metkit_c.cc new file mode 100644 index 00000000..bcff22cc --- /dev/null +++ b/src/metkit/api/metkit_c.cc @@ -0,0 +1,271 @@ +#include "metkit_c.h" +#include "metkit/mars/MarsRequest.h" +#include "metkit/metkit_version.h" + +#include "eckit/exception/Exceptions.h" +#include "eckit/runtime/Main.h" +#include "eckit/utils/Optional.h" + +#include + +extern "C" { + +// --------------------------------------------------------------------------------------------------------------------- + +struct Request : public metkit::mars::MarsRequest { + using metkit::mars::MarsRequest::MarsRequest; + Request(const metkit::mars::MarsRequest& k) : metkit::mars::MarsRequest(k) {} +}; + +struct metkit_requestiterator_t { + metkit_requestiterator_t(std::vector vec): first(true), vector(std::move(vec)), iterator(vector.begin()) {} + + int next() { + if (first) { first = false; } + else { ++iterator; } + if (iterator == vector.end()) { + return METKIT_ITERATION_COMPLETE; + } + return METKIT_SUCCESS; + } + + bool first; + std::vector vector; + std::vector::const_iterator iterator; +}; + +struct StringVecIterator { + StringVecIterator(std::vector vec): first(true), vector(std::move(vec)), iterator(vector.begin()) {} + + int next() { + if (first) { first = false; } + else { ++iterator; } + if (iterator == vector.end()) { + return METKIT_ITERATION_COMPLETE; + } + return METKIT_SUCCESS; + } + + bool first; + std::vector vector; + std::vector::const_iterator iterator; +}; + +// --------------------------------------------------------------------------------------------------------------------- +// ERROR HANDLING + +} // extern "C" + +static thread_local std::string g_current_error_string; + +const char* metkit_get_error_string(int) { + return g_current_error_string.c_str(); +} + +int innerWrapFn(std::function f) { + return f(); +} + +int innerWrapFn(std::function f) { + f(); + return METKIT_SUCCESS; +} + +template +[[nodiscard]] int tryCatch(FN&& fn) { + try { + return innerWrapFn(fn); + } + catch (const eckit::UserError& e) { + eckit::Log::error() << "User Error: " << e.what() << std::endl; + g_current_error_string = e.what(); + return METKIT_ERROR_USER; + } + catch (const eckit::AssertionFailed& e) { + eckit::Log::error() << "Assertion Failed: " << e.what() << std::endl; + g_current_error_string = e.what(); + return METKIT_ERROR_ASSERT; + } + catch (const eckit::Exception& e) { + eckit::Log::error() << "METKIT Error: " << e.what() << std::endl; + g_current_error_string = e.what(); + return METKIT_ERROR; + } + catch (const std::exception& e) { + eckit::Log::error() << "Unknown Error: " << e.what() << std::endl; + g_current_error_string = e.what(); + return METKIT_ERROR_UNKNOWN; + } + catch (...) { + eckit::Log::error() << "Unknown Error!" << std::endl; + g_current_error_string = ""; + return METKIT_ERROR_UNKNOWN; + } +} + +extern "C" { + +// ----------------------------------------------------------------------------- +// HELPERS +// ----------------------------------------------------------------------------- + +int metkit_version(const char** version) { + *version = metkit_version_str(); + return METKIT_SUCCESS; +} + +int metkit_vcs_version(const char** sha1) { + *sha1 = metkit_git_sha1(); + return METKIT_SUCCESS; +} + +int metkit_initialise() { + return tryCatch([] { + static bool initialised = false; + + if (initialised) { + eckit::Log::warning() + << "Initialising Metkit library twice" << std::endl; + } + + if (!initialised) { + const char* argv[2] = {"metkit-api", 0}; + eckit::Main::initialise(1, const_cast(argv)); + initialised = true; + } + }); +} + +// ----------------------------------------------------------------------------- +// PARSING +// ----------------------------------------------------------------------------- + +int metkit_parse_mars(metkit_requestiterator_t** requests, const char* str) { + return tryCatch([requests, str] { + ASSERT(requests); + ASSERT(str); + std::istringstream in(str); + *requests = new metkit_requestiterator_t(metkit::mars::MarsRequest::parse(in)); + }); +} + +// ----------------------------------------------------------------------------- +// REQUEST +// ----------------------------------------------------------------------------- + +int metkit_free_request(const metkit_request_t* request) { + return tryCatch([request] { + ASSERT(request); + delete request; + }); +} + +int metkit_request_get_verb(const metkit_request_t* request, const char** verb) { + return tryCatch([request, verb] { + ASSERT(request); + ASSERT(verb); + *verb = request->verb().c_str(); + }); +} + +int metkit_request_get_params(const metkit_request_t* request, metkit_paramiterator_t** params) { + return tryCatch([request, params] { + ASSERT(request); + ASSERT(params); + *params = new metkit_paramiterator_t(request->params()); + }); +} + +int metkit_request_get_values(const metkit_request_t* request, const char* param, metkit_valueiterator_t** values) { + return tryCatch([request, param, values] { + ASSERT(request); + ASSERT(param); + ASSERT(values); + *values = new metkit_valueiterator_t(request->values(param)); + }); +} + +// ----------------------------------------------------------------------------- +// REQUEST ITERATOR +// ----------------------------------------------------------------------------- + +int metkit_free_requestiterator(const metkit_requestiterator_t* list) { + return tryCatch([list] { + ASSERT(list); + delete list; + }); +} + +int metkit_requestiterator_next(metkit_requestiterator_t* list) { + return tryCatch(std::function{[list] { + ASSERT(list); + return list->next(); + }}); +} + +int metkit_requestiterator_request(const metkit_requestiterator_t* list, metkit_request_t** request) { + return tryCatch([list, request] { + ASSERT(list); + ASSERT(request); + ASSERT(list->iterator != list->vector.end()); + *request = new Request(*(list->iterator)); + }); +} + +// ----------------------------------------------------------------------------- +// PARAM ITERATOR +// ----------------------------------------------------------------------------- + +int metkit_free_paramiterator(const metkit_paramiterator_t* list) { + return tryCatch([list] { + ASSERT(list); + delete list; + }); +} + +int metkit_paramiterator_next(metkit_paramiterator_t* list) { + return tryCatch(std::function{[list] { + ASSERT(list); + return list->next(); + }}); +} + +int metkit_paramiterator_param(const metkit_paramiterator_t* list, const char** param) { + return tryCatch([list, param] { + ASSERT(list); + ASSERT(param); + ASSERT(list->iterator != list->vector.end()); + *param = list->iterator->c_str(); + }); +} + +// ----------------------------------------------------------------------------- +// VALUE ITERATOR +// ----------------------------------------------------------------------------- + +int metkit_free_valueiterator(const metkit_valueiterator_t* list) { + return tryCatch([list] { + ASSERT(list); + delete list; + }); +} + +int metkit_valueiterator_next(metkit_valueiterator_t* list) { + return tryCatch(std::function{[list] { + ASSERT(list); + return list->next(); + }}); +} + +int metkit_valueiterator_value(const metkit_valueiterator_t* list, const char** value) { + return tryCatch([list, value] { + ASSERT(list); + ASSERT(value); + ASSERT(list->iterator != list->vector.end()); + *value = list->iterator->c_str(); + }); +} + +// --------------------------------------------------------------------------------------------------------------------- + +} // extern "C" \ No newline at end of file diff --git a/src/metkit/api/metkit_c.h b/src/metkit/api/metkit_c.h new file mode 100644 index 00000000..232469d5 --- /dev/null +++ b/src/metkit/api/metkit_c.h @@ -0,0 +1,104 @@ +#ifndef METKIT_API_METKIT_C_H +#define METKIT_API_METKIT_C_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* --------------------------------------------------------------------------------------------------------------------- + * TYPES + * -----*/ + +struct Request; +typedef struct Request metkit_request_t; + +struct metkit_requestiterator_t; +typedef struct metkit_requestiterator_t metkit_requestiterator_t; + +struct StringVecIterator; +typedef struct StringVecIterator metkit_paramiterator_t; +typedef struct StringVecIterator metkit_valueiterator_t; + +/* --------------------------------------------------------------------------------------------------------------------- + * ERROR HANDLING + * -------------- */ + +typedef enum metkit_error_values_t +{ + METKIT_SUCCESS = 0, /* Operation succeded. */ + METKIT_ITERATION_COMPLETE = 1, /* All elements have been returned */ + METKIT_ERROR = 2, /* Operation failed. */ + METKIT_ERROR_UNKNOWN = 3, /* Failed with an unknown error. */ + METKIT_ERROR_USER = 4, /* Failed with an user error. */ + METKIT_ERROR_ASSERT = 5 /* Failed with an assert() */ +} metkit_error_enum_t; + +const char* metkit_get_error_string(int err); + +/* ----------------------------------------------------------------------------- + * HELPERS + * ------- */ + +int metkit_version(const char** version); + +int metkit_vcs_version(const char** sha1); + +int metkit_initialise(); + +/* --------------------------------------------------------------------------------------------------------------------- + * PARSING + * --- */ + +int metkit_parse_mars(metkit_requestiterator_t** requests, const char* str); + +/* --------------------------------------------------------------------------------------------------------------------- + * REQUEST + * --- */ + +int metkit_free_request(const metkit_request_t* request); + +int metkit_request_get_verb(const metkit_request_t* request, const char** verb); + +int metkit_request_get_params(const metkit_request_t* request, metkit_paramiterator_t** params); + +int metkit_request_get_values(const metkit_request_t* request, const char* param, metkit_valueiterator_t** values); + +/* --------------------------------------------------------------------------------------------------------------------- + * REQUEST ITERATOR + * --- */ + +int metkit_free_requestiterator(const metkit_requestiterator_t* list); + +int metkit_requestiterator_next(metkit_requestiterator_t* list); + +int metkit_requestiterator_request(const metkit_requestiterator_t* list, metkit_request_t** request); + +/* --------------------------------------------------------------------------------------------------------------------- + * PARAM ITERATOR + * --- */ + +int metkit_free_paramiterator(const metkit_paramiterator_t* list); + +int metkit_paramiterator_next(metkit_paramiterator_t* list); + +int metkit_paramiterator_param(const metkit_paramiterator_t* list, const char** param); + +/* --------------------------------------------------------------------------------------------------------------------- + * VALUE ITERATOR + * --- */ + +int metkit_free_valueiterator(const metkit_valueiterator_t* list); + +int metkit_valueiterator_next(metkit_valueiterator_t* list); + +int metkit_valueiterator_value(const metkit_valueiterator_t* list, const char** value); + +/* -------------------------------------------------------------------------------------------------------------------*/ + +#ifdef __cplusplus +} +#endif + +#endif /* METKIT_API_METKIT_C_H */ \ No newline at end of file diff --git a/src/metkit/metkit_version.cc.in b/src/metkit/metkit_version.cc.in deleted file mode 100644 index 60a39ecc..00000000 --- a/src/metkit/metkit_version.cc.in +++ /dev/null @@ -1,20 +0,0 @@ -#include "metkit/metkit_version.h" - -#ifdef __cplusplus -extern "C" { -#endif - -const char * metkit_version() { return metkit_VERSION; } - -const char * metkit_version_str() { return metkit_VERSION_STR; } - -unsigned int metkit_version_int() -{ - return 10000*metkit_VERSION_MAJOR + 100*metkit_VERSION_MINOR + 1*metkit_VERSION_PATCH; -} - -const char * metkit_git_sha1() { return "@metkit_GIT_SHA1@"; } - -#ifdef __cplusplus -} -#endif \ No newline at end of file diff --git a/src/metkit/metkit_version.h.in b/src/metkit/metkit_version.h.in index 5f42d64b..658a5be7 100644 --- a/src/metkit/metkit_version.h.in +++ b/src/metkit/metkit_version.h.in @@ -8,20 +8,14 @@ #define metkit_VERSION_MINOR @metkit_VERSION_MINOR@ #define metkit_VERSION_PATCH @metkit_VERSION_PATCH@ -#ifdef __cplusplus -extern "C" { -#endif +inline const char * metkit_version() { return metkit_VERSION; } -const char * metkit_version(); - -unsigned int metkit_version_int(); - -const char * metkit_version_str(); +inline unsigned int metkit_version_int() { + return 10000*metkit_VERSION_MAJOR + 100*metkit_VERSION_MINOR + 1*metkit_VERSION_PATCH; +} -const char * metkit_git_sha1(); +inline const char * metkit_version_str() { return metkit_VERSION_STR; } -#ifdef __cplusplus -} -#endif +inline const char * metkit_git_sha1() { return "@metkit_GIT_SHA1@"; } #endif // metkit_version_h From 5bdb1e16fb1f573225a22d9a8484c90f1ac88462 Mon Sep 17 00:00:00 2001 From: Jenny Wong Date: Thu, 25 Jan 2024 10:05:03 +0000 Subject: [PATCH 02/13] Add comments --- src/metkit/api/metkit_c.h | 87 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/src/metkit/api/metkit_c.h b/src/metkit/api/metkit_c.h index 232469d5..13e27d45 100644 --- a/src/metkit/api/metkit_c.h +++ b/src/metkit/api/metkit_c.h @@ -15,9 +15,11 @@ struct Request; typedef struct Request metkit_request_t; struct metkit_requestiterator_t; +/** RequestIterator for iterating over vector of Request instances */ typedef struct metkit_requestiterator_t metkit_requestiterator_t; struct StringVecIterator; +/** Iterators for vector of std::string for iterating over parameters and values in Request */ typedef struct StringVecIterator metkit_paramiterator_t; typedef struct StringVecIterator metkit_valueiterator_t; @@ -41,58 +43,143 @@ const char* metkit_get_error_string(int err); * HELPERS * ------- */ +/** + * @brief Set MetKit version. + * + * @param version Version string + * @return int Error code + */ int metkit_version(const char** version); +/** + * @brief Set MetKit git sha1 version. + * + * @param sha1 SHA1 version string + * @return int Error code + */ int metkit_vcs_version(const char** sha1); +/** + * @brief Initialise Main() context. + * + * @note This is ONLY required when Main() is NOT initialised, such as loading + * the MetKit as shared library in Python. + * @return int Error code + */ int metkit_initialise(); /* --------------------------------------------------------------------------------------------------------------------- * PARSING * --- */ +/** + * @brief Parse MARS requests into RequestIterator of MarsRequest instances + * + * @param requests RequestIterator instance + * @param str MARS requests + * @return int Error code + */ int metkit_parse_mars(metkit_requestiterator_t** requests, const char* str); /* --------------------------------------------------------------------------------------------------------------------- * REQUEST * --- */ +/** Deallocates Request object and associated resources. + * @param request Request instance + * @return int Error code + */ int metkit_free_request(const metkit_request_t* request); +/** Returns the verb in Request object + * @param request Request instance + * @param verb verb in request + * @return int Error code + */ int metkit_request_get_verb(const metkit_request_t* request, const char** verb); +/** Returns list of parameter names in Request object + * @param request Request instance + * @param params ParamIterator instance for parameter names in request + * @return int Error code + */ int metkit_request_get_params(const metkit_request_t* request, metkit_paramiterator_t** params); +/** Returns list of values for specific parameter in Request object + * @param request Request instance + * @param param parameter name in request + * @param values ValueIterator instance for values for param in request + * @return int Error code + */ int metkit_request_get_values(const metkit_request_t* request, const char* param, metkit_valueiterator_t** values); /* --------------------------------------------------------------------------------------------------------------------- * REQUEST ITERATOR * --- */ +/** Deallocates RequestIterator object and associated resources. + * @param list RequestIterator instance + * @return int Error code + */ int metkit_free_requestiterator(const metkit_requestiterator_t* list); +/** Moves to the next Request element in RequestIterator + * @param list RequestIterator instance + * @return int Error code + */ int metkit_requestiterator_next(metkit_requestiterator_t* list); +/** Returns the current Request element in RequestIterator + * @param list RequestIterator instance + * @param request current Request element in list + * @return int Error code + */ int metkit_requestiterator_request(const metkit_requestiterator_t* list, metkit_request_t** request); /* --------------------------------------------------------------------------------------------------------------------- * PARAM ITERATOR * --- */ +/** Deallocates ParamIterator object and associated resources. + * @param list ParamIterator instance + * @return int Error code + */ int metkit_free_paramiterator(const metkit_paramiterator_t* list); +/** Moves to the next string element in ParamIterator + * @param list ParamIterator instance + * @return int Error code + */ int metkit_paramiterator_next(metkit_paramiterator_t* list); +/** Returns the current parameter name in ParamIterator + * @param list ParamIterator instance + * @param param current parameter name in list + * @return int Error code + */ int metkit_paramiterator_param(const metkit_paramiterator_t* list, const char** param); /* --------------------------------------------------------------------------------------------------------------------- * VALUE ITERATOR * --- */ +/** Deallocates ValueIterator object and associated resources. + * @param list ValueIterator instance + * @returns int Error code + */ int metkit_free_valueiterator(const metkit_valueiterator_t* list); +/** Moves to the next string element in ValueIterator + * @param list ValueIterator instance + * @return int Error code + */ int metkit_valueiterator_next(metkit_valueiterator_t* list); +/** Returns the current value in ValueIterator + * @param list ValueIterator instance + * @param value current value in list + * @return int Error code + */ int metkit_valueiterator_value(const metkit_valueiterator_t* list, const char** value); /* -------------------------------------------------------------------------------------------------------------------*/ From e7523ae434be9f7eaed7fb8e9b0d8ec291fa83a2 Mon Sep 17 00:00:00 2001 From: Jenny Wong Date: Thu, 25 Jan 2024 12:13:58 +0000 Subject: [PATCH 03/13] clang format --- src/metkit/api/metkit_c.cc | 53 +++++++++++++++++++++++--------------- src/metkit/api/metkit_c.h | 34 ++++++++++++------------ 2 files changed, 49 insertions(+), 38 deletions(-) diff --git a/src/metkit/api/metkit_c.cc b/src/metkit/api/metkit_c.cc index bcff22cc..9ed70bde 100644 --- a/src/metkit/api/metkit_c.cc +++ b/src/metkit/api/metkit_c.cc @@ -14,19 +14,25 @@ extern "C" { struct Request : public metkit::mars::MarsRequest { using metkit::mars::MarsRequest::MarsRequest; - Request(const metkit::mars::MarsRequest& k) : metkit::mars::MarsRequest(k) {} + Request(const metkit::mars::MarsRequest& k) : + metkit::mars::MarsRequest(k) {} }; struct metkit_requestiterator_t { - metkit_requestiterator_t(std::vector vec): first(true), vector(std::move(vec)), iterator(vector.begin()) {} + metkit_requestiterator_t(std::vector vec) : + first(true), vector(std::move(vec)), iterator(vector.begin()) {} int next() { - if (first) { first = false; } - else { ++iterator; } - if (iterator == vector.end()) { - return METKIT_ITERATION_COMPLETE; - } - return METKIT_SUCCESS; + if (first) { + first = false; + } + else { + ++iterator; + } + if (iterator == vector.end()) { + return METKIT_ITERATION_COMPLETE; + } + return METKIT_SUCCESS; } bool first; @@ -35,15 +41,20 @@ struct metkit_requestiterator_t { }; struct StringVecIterator { - StringVecIterator(std::vector vec): first(true), vector(std::move(vec)), iterator(vector.begin()) {} + StringVecIterator(std::vector vec) : + first(true), vector(std::move(vec)), iterator(vector.begin()) {} int next() { - if (first) { first = false; } - else { ++iterator; } - if (iterator == vector.end()) { - return METKIT_ITERATION_COMPLETE; - } - return METKIT_SUCCESS; + if (first) { + first = false; + } + else { + ++iterator; + } + if (iterator == vector.end()) { + return METKIT_ITERATION_COMPLETE; + } + return METKIT_SUCCESS; } bool first; @@ -141,12 +152,12 @@ int metkit_initialise() { // ----------------------------------------------------------------------------- int metkit_parse_mars(metkit_requestiterator_t** requests, const char* str) { - return tryCatch([requests, str] { + return tryCatch([requests, str] { ASSERT(requests); ASSERT(str); std::istringstream in(str); *requests = new metkit_requestiterator_t(metkit::mars::MarsRequest::parse(in)); - }); + }); } // ----------------------------------------------------------------------------- @@ -154,7 +165,7 @@ int metkit_parse_mars(metkit_requestiterator_t** requests, const char* str) { // ----------------------------------------------------------------------------- int metkit_free_request(const metkit_request_t* request) { - return tryCatch([request] { + return tryCatch([request] { ASSERT(request); delete request; }); @@ -190,7 +201,7 @@ int metkit_request_get_values(const metkit_request_t* request, const char* param // ----------------------------------------------------------------------------- int metkit_free_requestiterator(const metkit_requestiterator_t* list) { - return tryCatch([list] { + return tryCatch([list] { ASSERT(list); delete list; }); @@ -217,7 +228,7 @@ int metkit_requestiterator_request(const metkit_requestiterator_t* list, metkit_ // ----------------------------------------------------------------------------- int metkit_free_paramiterator(const metkit_paramiterator_t* list) { - return tryCatch([list] { + return tryCatch([list] { ASSERT(list); delete list; }); @@ -244,7 +255,7 @@ int metkit_paramiterator_param(const metkit_paramiterator_t* list, const char** // ----------------------------------------------------------------------------- int metkit_free_valueiterator(const metkit_valueiterator_t* list) { - return tryCatch([list] { + return tryCatch([list] { ASSERT(list); delete list; }); diff --git a/src/metkit/api/metkit_c.h b/src/metkit/api/metkit_c.h index 13e27d45..20083151 100644 --- a/src/metkit/api/metkit_c.h +++ b/src/metkit/api/metkit_c.h @@ -49,7 +49,7 @@ const char* metkit_get_error_string(int err); * @param version Version string * @return int Error code */ -int metkit_version(const char** version); +int metkit_version(const char** version); /** * @brief Set MetKit git sha1 version. @@ -73,11 +73,11 @@ int metkit_initialise(); * --- */ /** - * @brief Parse MARS requests into RequestIterator of MarsRequest instances - * + * @brief Parse MARS requests into RequestIterator of MarsRequest instances + * * @param requests RequestIterator instance * @param str MARS requests - * @return int Error code + * @return int Error code */ int metkit_parse_mars(metkit_requestiterator_t** requests, const char* str); @@ -87,21 +87,21 @@ int metkit_parse_mars(metkit_requestiterator_t** requests, const char* str); /** Deallocates Request object and associated resources. * @param request Request instance - * @return int Error code + * @return int Error code */ int metkit_free_request(const metkit_request_t* request); /** Returns the verb in Request object * @param request Request instance * @param verb verb in request - * @return int Error code + * @return int Error code */ int metkit_request_get_verb(const metkit_request_t* request, const char** verb); /** Returns list of parameter names in Request object * @param request Request instance * @param params ParamIterator instance for parameter names in request - * @return int Error code + * @return int Error code */ int metkit_request_get_params(const metkit_request_t* request, metkit_paramiterator_t** params); @@ -109,7 +109,7 @@ int metkit_request_get_params(const metkit_request_t* request, metkit_paramitera * @param request Request instance * @param param parameter name in request * @param values ValueIterator instance for values for param in request - * @return int Error code + * @return int Error code */ int metkit_request_get_values(const metkit_request_t* request, const char* param, metkit_valueiterator_t** values); @@ -119,20 +119,20 @@ int metkit_request_get_values(const metkit_request_t* request, const char* param /** Deallocates RequestIterator object and associated resources. * @param list RequestIterator instance - * @return int Error code + * @return int Error code */ int metkit_free_requestiterator(const metkit_requestiterator_t* list); /** Moves to the next Request element in RequestIterator * @param list RequestIterator instance - * @return int Error code + * @return int Error code */ int metkit_requestiterator_next(metkit_requestiterator_t* list); /** Returns the current Request element in RequestIterator * @param list RequestIterator instance * @param request current Request element in list - * @return int Error code + * @return int Error code */ int metkit_requestiterator_request(const metkit_requestiterator_t* list, metkit_request_t** request); @@ -142,20 +142,20 @@ int metkit_requestiterator_request(const metkit_requestiterator_t* list, metkit_ /** Deallocates ParamIterator object and associated resources. * @param list ParamIterator instance - * @return int Error code + * @return int Error code */ int metkit_free_paramiterator(const metkit_paramiterator_t* list); /** Moves to the next string element in ParamIterator * @param list ParamIterator instance - * @return int Error code + * @return int Error code */ int metkit_paramiterator_next(metkit_paramiterator_t* list); /** Returns the current parameter name in ParamIterator * @param list ParamIterator instance * @param param current parameter name in list - * @return int Error code + * @return int Error code */ int metkit_paramiterator_param(const metkit_paramiterator_t* list, const char** param); @@ -165,20 +165,20 @@ int metkit_paramiterator_param(const metkit_paramiterator_t* list, const char** /** Deallocates ValueIterator object and associated resources. * @param list ValueIterator instance - * @returns int Error code + * @returns int Error code */ int metkit_free_valueiterator(const metkit_valueiterator_t* list); /** Moves to the next string element in ValueIterator * @param list ValueIterator instance - * @return int Error code + * @return int Error code */ int metkit_valueiterator_next(metkit_valueiterator_t* list); /** Returns the current value in ValueIterator * @param list ValueIterator instance * @param value current value in list - * @return int Error code + * @return int Error code */ int metkit_valueiterator_value(const metkit_valueiterator_t* list, const char** value); From 9a2313dc221665bce6216ec63d1138651143910e Mon Sep 17 00:00:00 2001 From: Jenny Wong Date: Fri, 9 Feb 2024 11:49:19 +0000 Subject: [PATCH 04/13] Review comments and expand API --- src/metkit/api/metkit_c.cc | 115 ++++++++++++++++++++++++------------- src/metkit/api/metkit_c.h | 107 ++++++++++++++++++++-------------- 2 files changed, 139 insertions(+), 83 deletions(-) diff --git a/src/metkit/api/metkit_c.cc b/src/metkit/api/metkit_c.cc index 9ed70bde..787ec0d1 100644 --- a/src/metkit/api/metkit_c.cc +++ b/src/metkit/api/metkit_c.cc @@ -1,4 +1,5 @@ #include "metkit_c.h" +#include "metkit/mars/MarsExpension.h" #include "metkit/mars/MarsRequest.h" #include "metkit/metkit_version.h" @@ -12,9 +13,9 @@ extern "C" { // --------------------------------------------------------------------------------------------------------------------- -struct Request : public metkit::mars::MarsRequest { +struct metkit_request_t : public metkit::mars::MarsRequest { using metkit::mars::MarsRequest::MarsRequest; - Request(const metkit::mars::MarsRequest& k) : + metkit_request_t(const metkit::mars::MarsRequest& k) : metkit::mars::MarsRequest(k) {} }; @@ -40,8 +41,8 @@ struct metkit_requestiterator_t { std::vector::const_iterator iterator; }; -struct StringVecIterator { - StringVecIterator(std::vector vec) : +struct metkit_paramiterator_t { + metkit_paramiterator_t(std::vector vec) : first(true), vector(std::move(vec)), iterator(vector.begin()) {} int next() { @@ -151,12 +152,12 @@ int metkit_initialise() { // PARSING // ----------------------------------------------------------------------------- -int metkit_parse_mars(metkit_requestiterator_t** requests, const char* str) { - return tryCatch([requests, str] { +int metkit_parse_mars_request(const char* str, metkit_requestiterator_t** requests, bool strict) { + return tryCatch([requests, str, strict] { ASSERT(requests); ASSERT(str); std::istringstream in(str); - *requests = new metkit_requestiterator_t(metkit::mars::MarsRequest::parse(in)); + *requests = new metkit_requestiterator_t(metkit::mars::MarsRequest::parse(in, strict)); }); } @@ -164,6 +165,13 @@ int metkit_parse_mars(metkit_requestiterator_t** requests, const char* str) { // REQUEST // ----------------------------------------------------------------------------- +int metkit_new_request(metkit_request_t** request) { + return tryCatch([request] { + ASSERT(request); + *request = new metkit_request_t(); + }); +} + int metkit_free_request(const metkit_request_t* request) { return tryCatch([request] { ASSERT(request); @@ -171,7 +179,29 @@ int metkit_free_request(const metkit_request_t* request) { }); } -int metkit_request_get_verb(const metkit_request_t* request, const char** verb) { +int metkit_request_add(metkit_request_t* request, const char* param, const char* values[], int numValues) { + return tryCatch([request, param, values, numValues] { + ASSERT(request); + ASSERT(param); + ASSERT(values); + std::string n(param); + std::vector vv; + for (int i = 0; i < numValues; i++) { + vv.push_back(std::string(values[i])); + } + request->values(n, vv); + }); +} + +int metkit_request_set_verb(metkit_request_t* request, const char* verb) { + return tryCatch([request, verb] { + ASSERT(request); + ASSERT(verb); + request->verb(verb); + }); +} + +int metkit_request_verb(const metkit_request_t* request, const char** verb) { return tryCatch([request, verb] { ASSERT(request); ASSERT(verb); @@ -179,7 +209,16 @@ int metkit_request_get_verb(const metkit_request_t* request, const char** verb) }); } -int metkit_request_get_params(const metkit_request_t* request, metkit_paramiterator_t** params) { +int metkit_request_has_param(const metkit_request_t* request, const char* param, bool* has) { + return tryCatch([request, param, has] { + ASSERT(request); + ASSERT(param); + ASSERT(has); + *has = request->has(param); + }); +} + +int metkit_request_params(const metkit_request_t* request, metkit_paramiterator_t** params) { return tryCatch([request, params] { ASSERT(request); ASSERT(params); @@ -187,12 +226,31 @@ int metkit_request_get_params(const metkit_request_t* request, metkit_paramitera }); } -int metkit_request_get_values(const metkit_request_t* request, const char* param, metkit_valueiterator_t** values) { - return tryCatch([request, param, values] { +int metkit_request_count_values(const metkit_request_t* request, const char* param, size_t* count) { + return tryCatch([request, param, count] { ASSERT(request); ASSERT(param); - ASSERT(values); - *values = new metkit_valueiterator_t(request->values(param)); + ASSERT(count); + *count = request->countValues(param); + }); +} + +int metkit_request_value(const metkit_request_t* request, const char* param, int index, const char** value) { + return tryCatch([request, param, index, value] { + ASSERT(request); + ASSERT(param); + ASSERT(value); + *value = (request->values(param, false))[index].c_str(); + }); +} + +int metkit_request_expand(const metkit_request_t* request, metkit_request_t* expandedRequest, bool inherit, bool strict) { + return tryCatch([request, expandedRequest, inherit, strict] { + ASSERT(request); + ASSERT(expandedRequest); + ASSERT(expandedRequest->empty()); + metkit::mars::MarsExpension expand(inherit, strict); + *expandedRequest = std::move(expand.expand(*request)); }); } @@ -214,12 +272,13 @@ int metkit_requestiterator_next(metkit_requestiterator_t* list) { }}); } -int metkit_requestiterator_request(const metkit_requestiterator_t* list, metkit_request_t** request) { +int metkit_requestiterator_request(const metkit_requestiterator_t* list, metkit_request_t* request) { return tryCatch([list, request] { ASSERT(list); ASSERT(request); ASSERT(list->iterator != list->vector.end()); - *request = new Request(*(list->iterator)); + ASSERT(request->empty()); + *request = std::move(*(list->iterator)); }); } @@ -250,32 +309,6 @@ int metkit_paramiterator_param(const metkit_paramiterator_t* list, const char** }); } -// ----------------------------------------------------------------------------- -// VALUE ITERATOR -// ----------------------------------------------------------------------------- - -int metkit_free_valueiterator(const metkit_valueiterator_t* list) { - return tryCatch([list] { - ASSERT(list); - delete list; - }); -} - -int metkit_valueiterator_next(metkit_valueiterator_t* list) { - return tryCatch(std::function{[list] { - ASSERT(list); - return list->next(); - }}); -} - -int metkit_valueiterator_value(const metkit_valueiterator_t* list, const char** value) { - return tryCatch([list, value] { - ASSERT(list); - ASSERT(value); - ASSERT(list->iterator != list->vector.end()); - *value = list->iterator->c_str(); - }); -} // --------------------------------------------------------------------------------------------------------------------- diff --git a/src/metkit/api/metkit_c.h b/src/metkit/api/metkit_c.h index 20083151..7fe23833 100644 --- a/src/metkit/api/metkit_c.h +++ b/src/metkit/api/metkit_c.h @@ -11,17 +11,16 @@ extern "C" { * TYPES * -----*/ -struct Request; -typedef struct Request metkit_request_t; +struct metkit_request_t; +typedef struct metkit_request_t metkit_request_t; struct metkit_requestiterator_t; /** RequestIterator for iterating over vector of Request instances */ typedef struct metkit_requestiterator_t metkit_requestiterator_t; -struct StringVecIterator; -/** Iterators for vector of std::string for iterating over parameters and values in Request */ -typedef struct StringVecIterator metkit_paramiterator_t; -typedef struct StringVecIterator metkit_valueiterator_t; +struct metkit_paramiterator_t; +/** Iterator for iterating over parameters in Request */ +typedef struct metkit_paramiterator_t metkit_paramiterator_t; /* --------------------------------------------------------------------------------------------------------------------- * ERROR HANDLING @@ -73,45 +72,94 @@ int metkit_initialise(); * --- */ /** - * @brief Parse MARS requests into RequestIterator of MarsRequest instances + * Parse MARS requests into RequestIterator of Request instances. Resulting RequestIterator + * must be deallocated with metkit_free_requestiterator * - * @param requests RequestIterator instance * @param str MARS requests + * @param requests Allocates RequestIterator object * @return int Error code */ -int metkit_parse_mars(metkit_requestiterator_t** requests, const char* str); +int metkit_parse_mars_request(const char* str, metkit_requestiterator_t** requests, bool strict = false); /* --------------------------------------------------------------------------------------------------------------------- * REQUEST * --- */ +/** Allocates new Request object. Must be deallocated with mekit_free_request + * @param request new Request instance + * @return int Error code + */ +int metkit_new_request(metkit_request_t** request); + /** Deallocates Request object and associated resources. * @param request Request instance * @return int Error code */ int metkit_free_request(const metkit_request_t* request); +/** Add parameter and values to request + * @param request Request instance + * @param param parameter name + * @param values list of values for parameter + * @param numValues number of values + * @return int Error code + */ +int metkit_request_add(metkit_request_t* request, const char* param, const char* values[], int numValues); + +/** Set verb in Request object + * @param request Request instance + * @param verb verb to set + * @return int Error code + */ +int metkit_request_set_verb(metkit_request_t* request, const char* verb); + /** Returns the verb in Request object * @param request Request instance * @param verb verb in request * @return int Error code */ -int metkit_request_get_verb(const metkit_request_t* request, const char** verb); +int metkit_request_verb(const metkit_request_t* request, const char** verb); + +/** Returns whether parameter is in Request object + * @param request Request instance + * @param param parameter name + * @param has whether parameter exists in request + * @return int Error code + */ +int metkit_request_has_param(const metkit_request_t* request, const char* param, bool* has); /** Returns list of parameter names in Request object * @param request Request instance * @param params ParamIterator instance for parameter names in request * @return int Error code */ -int metkit_request_get_params(const metkit_request_t* request, metkit_paramiterator_t** params); +int metkit_request_params(const metkit_request_t* request, metkit_paramiterator_t** params); -/** Returns list of values for specific parameter in Request object +/** Returns number of values for specific parameter in Request object * @param request Request instance * @param param parameter name in request - * @param values ValueIterator instance for values for param in request + * @param count number of values for param in request * @return int Error code */ -int metkit_request_get_values(const metkit_request_t* request, const char* param, metkit_valueiterator_t** values); +int metkit_request_count_values(const metkit_request_t* request, const char* param, size_t* count); + +/** Returns value for specific parameter and index in Request object + * @param request Request instance + * @param param parameter name in request + * @param index index of value to retrieve for param in request + * @param value retrieved value + * @return int Error code + */ +int metkit_request_value(const metkit_request_t* request, const char* param, int index, const char** value); + +/** Populates empty Request object by expanding existing request + * @param request Request instance to be expanded + * @param expandedRequest empty Request instance to be populated + * @param inherit if true, populate expanded request with default values + * @param strict it true, raise error rather than warning on invalid values + * @return int Error code + */ +int metkit_request_expand(const metkit_request_t* request, metkit_request_t* expandedRequest, bool inherit = true, bool strict = false); /* --------------------------------------------------------------------------------------------------------------------- * REQUEST ITERATOR @@ -129,12 +177,12 @@ int metkit_free_requestiterator(const metkit_requestiterator_t* list); */ int metkit_requestiterator_next(metkit_requestiterator_t* list); -/** Returns the current Request element in RequestIterator +/** Populates empty Requestion object with data from current element in RequestIterator * @param list RequestIterator instance - * @param request current Request element in list + * @param request empty Request instance to populate with data * @return int Error code */ -int metkit_requestiterator_request(const metkit_requestiterator_t* list, metkit_request_t** request); +int metkit_requestiterator_request(const metkit_requestiterator_t* list, metkit_request_t* request); /* --------------------------------------------------------------------------------------------------------------------- * PARAM ITERATOR @@ -159,31 +207,6 @@ int metkit_paramiterator_next(metkit_paramiterator_t* list); */ int metkit_paramiterator_param(const metkit_paramiterator_t* list, const char** param); -/* --------------------------------------------------------------------------------------------------------------------- - * VALUE ITERATOR - * --- */ - -/** Deallocates ValueIterator object and associated resources. - * @param list ValueIterator instance - * @returns int Error code - */ -int metkit_free_valueiterator(const metkit_valueiterator_t* list); - -/** Moves to the next string element in ValueIterator - * @param list ValueIterator instance - * @return int Error code - */ -int metkit_valueiterator_next(metkit_valueiterator_t* list); - -/** Returns the current value in ValueIterator - * @param list ValueIterator instance - * @param value current value in list - * @return int Error code - */ -int metkit_valueiterator_value(const metkit_valueiterator_t* list, const char** value); - -/* -------------------------------------------------------------------------------------------------------------------*/ - #ifdef __cplusplus } #endif From 8549509c201e1118f4080a91d5991c082a6d2549 Mon Sep 17 00:00:00 2001 From: Jenny Wong Date: Tue, 20 Feb 2024 11:47:46 +0000 Subject: [PATCH 05/13] Add merge to C API --- src/metkit/api/metkit_c.cc | 8 ++++++++ src/metkit/api/metkit_c.h | 15 +++++++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/metkit/api/metkit_c.cc b/src/metkit/api/metkit_c.cc index 787ec0d1..09d4168d 100644 --- a/src/metkit/api/metkit_c.cc +++ b/src/metkit/api/metkit_c.cc @@ -254,6 +254,14 @@ int metkit_request_expand(const metkit_request_t* request, metkit_request_t* exp }); } +int metkit_request_merge(metkit_request_t* request, const metkit_request_t* otherRequest) { + return tryCatch([request, otherRequest] { + ASSERT(request); + ASSERT(otherRequest); + request->merge(*otherRequest); + }); +} + // ----------------------------------------------------------------------------- // REQUEST ITERATOR // ----------------------------------------------------------------------------- diff --git a/src/metkit/api/metkit_c.h b/src/metkit/api/metkit_c.h index 7fe23833..9bc7bbab 100644 --- a/src/metkit/api/metkit_c.h +++ b/src/metkit/api/metkit_c.h @@ -74,7 +74,6 @@ int metkit_initialise(); /** * Parse MARS requests into RequestIterator of Request instances. Resulting RequestIterator * must be deallocated with metkit_free_requestiterator - * * @param str MARS requests * @param requests Allocates RequestIterator object * @return int Error code @@ -128,9 +127,10 @@ int metkit_request_verb(const metkit_request_t* request, const char** verb); */ int metkit_request_has_param(const metkit_request_t* request, const char* param, bool* has); -/** Returns list of parameter names in Request object +/** Returns ParamIterator of parameters in request. Resulting ParamIterator + * must be deallocated with metkit_free_paramiterator * @param request Request instance - * @param params ParamIterator instance for parameter names in request + * @param params Allocates ParamIterator object for parameter names in request * @return int Error code */ int metkit_request_params(const metkit_request_t* request, metkit_paramiterator_t** params); @@ -155,12 +155,19 @@ int metkit_request_value(const metkit_request_t* request, const char* param, int /** Populates empty Request object by expanding existing request * @param request Request instance to be expanded * @param expandedRequest empty Request instance to be populated - * @param inherit if true, populate expanded request with default values + * @param inherit if true, populate expanded request with default values * @param strict it true, raise error rather than warning on invalid values * @return int Error code */ int metkit_request_expand(const metkit_request_t* request, metkit_request_t* expandedRequest, bool inherit = true, bool strict = false); +/** Merges other Request object into existing request + * @param request Request instance to contain result of merge + * @param otherRequest other Request instance to merge + * @return int Error code + */ +int metkit_request_merge(metkit_request_t* request, const metkit_request_t* otherRequest); + /* --------------------------------------------------------------------------------------------------------------------- * REQUEST ITERATOR * --- */ From 1b038518cec9227ce919422b6bef5b13f2126005 Mon Sep 17 00:00:00 2001 From: Chris Bradley Date: Wed, 11 Dec 2024 15:33:06 +0000 Subject: [PATCH 06/13] Add some C-API test coverage, and add request_values --- src/metkit/api/metkit_c.cc | 15 +++++++ src/metkit/api/metkit_c.h | 9 +++++ tests/CMakeLists.txt | 2 +- tests/test_c_api.cc | 81 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 tests/test_c_api.cc diff --git a/src/metkit/api/metkit_c.cc b/src/metkit/api/metkit_c.cc index 09d4168d..85bbe1e3 100644 --- a/src/metkit/api/metkit_c.cc +++ b/src/metkit/api/metkit_c.cc @@ -244,6 +244,21 @@ int metkit_request_value(const metkit_request_t* request, const char* param, int }); } +int metkit_request_values(const metkit_request_t* request, const char* param, const char** values[], size_t* numValues) { + return tryCatch([request, param, values, numValues] { + ASSERT(request); + ASSERT(param); + ASSERT(values); + ASSERT(numValues); + const std::vector& v = request->values(param); + *numValues = v.size(); + *values = new const char*[v.size()]; + for (size_t i = 0; i < v.size(); i++) { + (*values)[i] = v[i].c_str(); + } + }); +} + int metkit_request_expand(const metkit_request_t* request, metkit_request_t* expandedRequest, bool inherit, bool strict) { return tryCatch([request, expandedRequest, inherit, strict] { ASSERT(request); diff --git a/src/metkit/api/metkit_c.h b/src/metkit/api/metkit_c.h index 9bc7bbab..6ccb75cc 100644 --- a/src/metkit/api/metkit_c.h +++ b/src/metkit/api/metkit_c.h @@ -152,6 +152,15 @@ int metkit_request_count_values(const metkit_request_t* request, const char* par */ int metkit_request_value(const metkit_request_t* request, const char* param, int index, const char** value); +/** Returns values for specific parameter Request object + * @param request Request instance + * @param param parameter name in request + * @param values list of values for param in request + * @param numValues number of values for param in request + * @return int Error code + */ +int metkit_request_values(const metkit_request_t* request, const char* param, const char** values[], size_t* numValues); + /** Populates empty Request object by expanding existing request * @param request Request instance to be expanded * @param expandedRequest empty Request instance to be populated diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index e59524ae..c175786e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -71,7 +71,7 @@ ecbuild_add_test( TARGET metkit_test_gribhandle NO_AS_NEEDED ENVIRONMENT "${metkit_env}") -list(APPEND testFileSuffixes typesfactory expand request param_axis steprange_axis time hypercube type_levelist ) +list(APPEND testFileSuffixes typesfactory expand request param_axis steprange_axis time hypercube type_levelist c_api ) foreach(test IN LISTS testFileSuffixes) ecbuild_add_test( TARGET "metkit_test_${test}" diff --git a/tests/test_c_api.cc b/tests/test_c_api.cc new file mode 100644 index 00000000..f97db4e6 --- /dev/null +++ b/tests/test_c_api.cc @@ -0,0 +1,81 @@ +/* + * (C) Copyright 1996- ECMWF. + * + * This software is licensed under the terms of the Apache Licence Version 2.0 + * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. + * In applying this licence, ECMWF does not waive the privileges and immunities + * granted to it by virtue of its status as an intergovernmental organisation + * nor does it submit to any jurisdiction. + */ + +/// @file test_c_api.cc +/// @date Dec 2024 +/// @author Christopher Bradley + +#include "metkit/api/metkit_c.h" +#include "eckit/testing/Test.h" + +using namespace eckit::testing; +namespace metkit::test { + +CASE( "Request get/set" ) { + + metkit_request_t* request = nullptr; + + metkit_new_request(&request); + EXPECT(request); + + // set/get verb + metkit_request_set_verb(request, "retrieve"); + const char* verb = nullptr; + metkit_request_verb(request, &verb); + EXPECT(strcmp(verb, "retrieve") == 0); + + // set array of values + const char* dates[] = {"20200101", "20200102", "20200103"}; + metkit_request_add(request, "date", dates, 3); + + // set single value + const char* expver = "xxxx"; + metkit_request_add(request, "expver", &expver, 1); + + // check values + bool has = false; + metkit_request_has_param(request, "date", &has); + EXPECT(has); + + metkit_request_has_param(request, "random", &has); + EXPECT(!has); + + size_t count = 0; + metkit_request_count_values(request, "date", &count); + EXPECT_EQUAL(count, 3); + + for (size_t i = 0; i < count; i++) { + const char* value = nullptr; + metkit_request_value(request, "date", i, &value); + EXPECT(strcmp(value, dates[i]) == 0); + } + + // all values + const char** values = nullptr; + count = 0; + metkit_request_values(request, "date", &values, &count); + EXPECT_EQUAL(count, 3); + + for (size_t i = 0; i < count; i++) { + EXPECT(strcmp(values[i], dates[i]) == 0); + } + + // done + metkit_free_request(request); +} + +//----------------------------------------------------------------------------- + +} // namespace metkit::test + +int main(int argc, char **argv) +{ + return run_tests ( argc, argv ); +} From 390751147ed355480def29a728ec0487048c5c6d Mon Sep 17 00:00:00 2001 From: Chris Bradley Date: Wed, 11 Dec 2024 17:32:18 +0000 Subject: [PATCH 07/13] Rename metkit_request to metkit_marsrequest --- src/metkit/api/metkit_c.cc | 34 +++++++++++++++++----------------- src/metkit/api/metkit_c.h | 32 ++++++++++++++++---------------- tests/test_c_api.cc | 24 ++++++++++++------------ 3 files changed, 45 insertions(+), 45 deletions(-) diff --git a/src/metkit/api/metkit_c.cc b/src/metkit/api/metkit_c.cc index 85bbe1e3..271222ec 100644 --- a/src/metkit/api/metkit_c.cc +++ b/src/metkit/api/metkit_c.cc @@ -13,9 +13,9 @@ extern "C" { // --------------------------------------------------------------------------------------------------------------------- -struct metkit_request_t : public metkit::mars::MarsRequest { +struct metkit_marsrequest_t : public metkit::mars::MarsRequest { using metkit::mars::MarsRequest::MarsRequest; - metkit_request_t(const metkit::mars::MarsRequest& k) : + metkit_marsrequest_t(const metkit::mars::MarsRequest& k) : metkit::mars::MarsRequest(k) {} }; @@ -152,7 +152,7 @@ int metkit_initialise() { // PARSING // ----------------------------------------------------------------------------- -int metkit_parse_mars_request(const char* str, metkit_requestiterator_t** requests, bool strict) { +int metkit_parse_marsrequest(const char* str, metkit_requestiterator_t** requests, bool strict) { return tryCatch([requests, str, strict] { ASSERT(requests); ASSERT(str); @@ -165,21 +165,21 @@ int metkit_parse_mars_request(const char* str, metkit_requestiterator_t** reques // REQUEST // ----------------------------------------------------------------------------- -int metkit_new_request(metkit_request_t** request) { +int metkit_new_marsrequest(metkit_marsrequest_t** request) { return tryCatch([request] { ASSERT(request); - *request = new metkit_request_t(); + *request = new metkit_marsrequest_t(); }); } -int metkit_free_request(const metkit_request_t* request) { +int metkit_free_marsrequest(const metkit_marsrequest_t* request) { return tryCatch([request] { ASSERT(request); delete request; }); } -int metkit_request_add(metkit_request_t* request, const char* param, const char* values[], int numValues) { +int metkit_marsrequest_add(metkit_marsrequest_t* request, const char* param, const char* values[], int numValues) { return tryCatch([request, param, values, numValues] { ASSERT(request); ASSERT(param); @@ -193,7 +193,7 @@ int metkit_request_add(metkit_request_t* request, const char* param, const char* }); } -int metkit_request_set_verb(metkit_request_t* request, const char* verb) { +int metkit_marsrequest_set_verb(metkit_marsrequest_t* request, const char* verb) { return tryCatch([request, verb] { ASSERT(request); ASSERT(verb); @@ -201,7 +201,7 @@ int metkit_request_set_verb(metkit_request_t* request, const char* verb) { }); } -int metkit_request_verb(const metkit_request_t* request, const char** verb) { +int metkit_marsrequest_verb(const metkit_marsrequest_t* request, const char** verb) { return tryCatch([request, verb] { ASSERT(request); ASSERT(verb); @@ -209,7 +209,7 @@ int metkit_request_verb(const metkit_request_t* request, const char** verb) { }); } -int metkit_request_has_param(const metkit_request_t* request, const char* param, bool* has) { +int metkit_marsrequest_has_param(const metkit_marsrequest_t* request, const char* param, bool* has) { return tryCatch([request, param, has] { ASSERT(request); ASSERT(param); @@ -218,7 +218,7 @@ int metkit_request_has_param(const metkit_request_t* request, const char* param, }); } -int metkit_request_params(const metkit_request_t* request, metkit_paramiterator_t** params) { +int metkit_marsrequest_params(const metkit_marsrequest_t* request, metkit_paramiterator_t** params) { return tryCatch([request, params] { ASSERT(request); ASSERT(params); @@ -226,7 +226,7 @@ int metkit_request_params(const metkit_request_t* request, metkit_paramiterator_ }); } -int metkit_request_count_values(const metkit_request_t* request, const char* param, size_t* count) { +int metkit_marsrequest_count_values(const metkit_marsrequest_t* request, const char* param, size_t* count) { return tryCatch([request, param, count] { ASSERT(request); ASSERT(param); @@ -235,7 +235,7 @@ int metkit_request_count_values(const metkit_request_t* request, const char* par }); } -int metkit_request_value(const metkit_request_t* request, const char* param, int index, const char** value) { +int metkit_marsrequest_value(const metkit_marsrequest_t* request, const char* param, int index, const char** value) { return tryCatch([request, param, index, value] { ASSERT(request); ASSERT(param); @@ -244,7 +244,7 @@ int metkit_request_value(const metkit_request_t* request, const char* param, int }); } -int metkit_request_values(const metkit_request_t* request, const char* param, const char** values[], size_t* numValues) { +int metkit_marsrequest_values(const metkit_marsrequest_t* request, const char* param, const char** values[], size_t* numValues) { return tryCatch([request, param, values, numValues] { ASSERT(request); ASSERT(param); @@ -259,7 +259,7 @@ int metkit_request_values(const metkit_request_t* request, const char* param, co }); } -int metkit_request_expand(const metkit_request_t* request, metkit_request_t* expandedRequest, bool inherit, bool strict) { +int metkit_marsrequest_expand(const metkit_marsrequest_t* request, metkit_marsrequest_t* expandedRequest, bool inherit, bool strict) { return tryCatch([request, expandedRequest, inherit, strict] { ASSERT(request); ASSERT(expandedRequest); @@ -269,7 +269,7 @@ int metkit_request_expand(const metkit_request_t* request, metkit_request_t* exp }); } -int metkit_request_merge(metkit_request_t* request, const metkit_request_t* otherRequest) { +int metkit_marsrequest_merge(metkit_marsrequest_t* request, const metkit_marsrequest_t* otherRequest) { return tryCatch([request, otherRequest] { ASSERT(request); ASSERT(otherRequest); @@ -295,7 +295,7 @@ int metkit_requestiterator_next(metkit_requestiterator_t* list) { }}); } -int metkit_requestiterator_request(const metkit_requestiterator_t* list, metkit_request_t* request) { +int metkit_requestiterator_request(const metkit_requestiterator_t* list, metkit_marsrequest_t* request) { return tryCatch([list, request] { ASSERT(list); ASSERT(request); diff --git a/src/metkit/api/metkit_c.h b/src/metkit/api/metkit_c.h index 6ccb75cc..6a1249fb 100644 --- a/src/metkit/api/metkit_c.h +++ b/src/metkit/api/metkit_c.h @@ -11,8 +11,8 @@ extern "C" { * TYPES * -----*/ -struct metkit_request_t; -typedef struct metkit_request_t metkit_request_t; +struct metkit_marsrequest_t; +typedef struct metkit_marsrequest_t metkit_marsrequest_t; struct metkit_requestiterator_t; /** RequestIterator for iterating over vector of Request instances */ @@ -78,7 +78,7 @@ int metkit_initialise(); * @param requests Allocates RequestIterator object * @return int Error code */ -int metkit_parse_mars_request(const char* str, metkit_requestiterator_t** requests, bool strict = false); +int metkit_parse_marsrequest(const char* str, metkit_requestiterator_t** requests, bool strict = false); /* --------------------------------------------------------------------------------------------------------------------- * REQUEST @@ -88,13 +88,13 @@ int metkit_parse_mars_request(const char* str, metkit_requestiterator_t** reques * @param request new Request instance * @return int Error code */ -int metkit_new_request(metkit_request_t** request); +int metkit_new_marsrequest(metkit_marsrequest_t** request); /** Deallocates Request object and associated resources. * @param request Request instance * @return int Error code */ -int metkit_free_request(const metkit_request_t* request); +int metkit_free_marsrequest(const metkit_marsrequest_t* request); /** Add parameter and values to request * @param request Request instance @@ -103,21 +103,21 @@ int metkit_free_request(const metkit_request_t* request); * @param numValues number of values * @return int Error code */ -int metkit_request_add(metkit_request_t* request, const char* param, const char* values[], int numValues); +int metkit_marsrequest_add(metkit_marsrequest_t* request, const char* param, const char* values[], int numValues); /** Set verb in Request object * @param request Request instance * @param verb verb to set * @return int Error code */ -int metkit_request_set_verb(metkit_request_t* request, const char* verb); +int metkit_marsrequest_set_verb(metkit_marsrequest_t* request, const char* verb); /** Returns the verb in Request object * @param request Request instance * @param verb verb in request * @return int Error code */ -int metkit_request_verb(const metkit_request_t* request, const char** verb); +int metkit_marsrequest_verb(const metkit_marsrequest_t* request, const char** verb); /** Returns whether parameter is in Request object * @param request Request instance @@ -125,7 +125,7 @@ int metkit_request_verb(const metkit_request_t* request, const char** verb); * @param has whether parameter exists in request * @return int Error code */ -int metkit_request_has_param(const metkit_request_t* request, const char* param, bool* has); +int metkit_marsrequest_has_param(const metkit_marsrequest_t* request, const char* param, bool* has); /** Returns ParamIterator of parameters in request. Resulting ParamIterator * must be deallocated with metkit_free_paramiterator @@ -133,7 +133,7 @@ int metkit_request_has_param(const metkit_request_t* request, const char* param, * @param params Allocates ParamIterator object for parameter names in request * @return int Error code */ -int metkit_request_params(const metkit_request_t* request, metkit_paramiterator_t** params); +int metkit_marsrequest_params(const metkit_marsrequest_t* request, metkit_paramiterator_t** params); /** Returns number of values for specific parameter in Request object * @param request Request instance @@ -141,7 +141,7 @@ int metkit_request_params(const metkit_request_t* request, metkit_paramiterator_ * @param count number of values for param in request * @return int Error code */ -int metkit_request_count_values(const metkit_request_t* request, const char* param, size_t* count); +int metkit_marsrequest_count_values(const metkit_marsrequest_t* request, const char* param, size_t* count); /** Returns value for specific parameter and index in Request object * @param request Request instance @@ -150,7 +150,7 @@ int metkit_request_count_values(const metkit_request_t* request, const char* par * @param value retrieved value * @return int Error code */ -int metkit_request_value(const metkit_request_t* request, const char* param, int index, const char** value); +int metkit_marsrequest_value(const metkit_marsrequest_t* request, const char* param, int index, const char** value); /** Returns values for specific parameter Request object * @param request Request instance @@ -159,7 +159,7 @@ int metkit_request_value(const metkit_request_t* request, const char* param, int * @param numValues number of values for param in request * @return int Error code */ -int metkit_request_values(const metkit_request_t* request, const char* param, const char** values[], size_t* numValues); +int metkit_marsrequest_values(const metkit_marsrequest_t* request, const char* param, const char** values[], size_t* numValues); /** Populates empty Request object by expanding existing request * @param request Request instance to be expanded @@ -168,14 +168,14 @@ int metkit_request_values(const metkit_request_t* request, const char* param, co * @param strict it true, raise error rather than warning on invalid values * @return int Error code */ -int metkit_request_expand(const metkit_request_t* request, metkit_request_t* expandedRequest, bool inherit = true, bool strict = false); +int metkit_marsrequest_expand(const metkit_marsrequest_t* request, metkit_marsrequest_t* expandedRequest, bool inherit = true, bool strict = false); /** Merges other Request object into existing request * @param request Request instance to contain result of merge * @param otherRequest other Request instance to merge * @return int Error code */ -int metkit_request_merge(metkit_request_t* request, const metkit_request_t* otherRequest); +int metkit_marsrequest_merge(metkit_marsrequest_t* request, const metkit_marsrequest_t* otherRequest); /* --------------------------------------------------------------------------------------------------------------------- * REQUEST ITERATOR @@ -198,7 +198,7 @@ int metkit_requestiterator_next(metkit_requestiterator_t* list); * @param request empty Request instance to populate with data * @return int Error code */ -int metkit_requestiterator_request(const metkit_requestiterator_t* list, metkit_request_t* request); +int metkit_requestiterator_request(const metkit_requestiterator_t* list, metkit_marsrequest_t* request); /* --------------------------------------------------------------------------------------------------------------------- * PARAM ITERATOR diff --git a/tests/test_c_api.cc b/tests/test_c_api.cc index f97db4e6..bef7aa40 100644 --- a/tests/test_c_api.cc +++ b/tests/test_c_api.cc @@ -20,47 +20,47 @@ namespace metkit::test { CASE( "Request get/set" ) { - metkit_request_t* request = nullptr; + metkit_marsrequest_t* request = nullptr; - metkit_new_request(&request); + metkit_new_marsrequest(&request); EXPECT(request); // set/get verb - metkit_request_set_verb(request, "retrieve"); + metkit_marsrequest_set_verb(request, "retrieve"); const char* verb = nullptr; - metkit_request_verb(request, &verb); + metkit_marsrequest_verb(request, &verb); EXPECT(strcmp(verb, "retrieve") == 0); // set array of values const char* dates[] = {"20200101", "20200102", "20200103"}; - metkit_request_add(request, "date", dates, 3); + metkit_marsrequest_add(request, "date", dates, 3); // set single value const char* expver = "xxxx"; - metkit_request_add(request, "expver", &expver, 1); + metkit_marsrequest_add(request, "expver", &expver, 1); // check values bool has = false; - metkit_request_has_param(request, "date", &has); + metkit_marsrequest_has_param(request, "date", &has); EXPECT(has); - metkit_request_has_param(request, "random", &has); + metkit_marsrequest_has_param(request, "random", &has); EXPECT(!has); size_t count = 0; - metkit_request_count_values(request, "date", &count); + metkit_marsrequest_count_values(request, "date", &count); EXPECT_EQUAL(count, 3); for (size_t i = 0; i < count; i++) { const char* value = nullptr; - metkit_request_value(request, "date", i, &value); + metkit_marsrequest_value(request, "date", i, &value); EXPECT(strcmp(value, dates[i]) == 0); } // all values const char** values = nullptr; count = 0; - metkit_request_values(request, "date", &values, &count); + metkit_marsrequest_values(request, "date", &values, &count); EXPECT_EQUAL(count, 3); for (size_t i = 0; i < count; i++) { @@ -68,7 +68,7 @@ CASE( "Request get/set" ) { } // done - metkit_free_request(request); + metkit_free_marsrequest(request); } //----------------------------------------------------------------------------- From e050cd5844a76f2e13bb77d22f94966da8fa255d Mon Sep 17 00:00:00 2001 From: Chris Bradley Date: Fri, 13 Dec 2024 18:11:56 +0000 Subject: [PATCH 08/13] (c api) - expand test coverage, fix iterator skipping first element --- src/metkit/api/metkit_c.cc | 34 +++++----- src/metkit/api/metkit_c.h | 8 +++ tests/test_c_api.cc | 130 ++++++++++++++++++++++++++++++++----- 3 files changed, 136 insertions(+), 36 deletions(-) diff --git a/src/metkit/api/metkit_c.cc b/src/metkit/api/metkit_c.cc index 271222ec..a39df969 100644 --- a/src/metkit/api/metkit_c.cc +++ b/src/metkit/api/metkit_c.cc @@ -21,41 +21,35 @@ struct metkit_marsrequest_t : public metkit::mars::MarsRequest { struct metkit_requestiterator_t { metkit_requestiterator_t(std::vector vec) : - first(true), vector(std::move(vec)), iterator(vector.begin()) {} + vector(std::move(vec)), iterator(vector.begin()) {} int next() { - if (first) { - first = false; - } - else { - ++iterator; - } if (iterator == vector.end()) { return METKIT_ITERATION_COMPLETE; } - return METKIT_SUCCESS; + ++iterator; + return iterator == vector.end() ? METKIT_ITERATION_COMPLETE : METKIT_SUCCESS; } - bool first; std::vector vector; std::vector::const_iterator iterator; }; +/// @comment: (maby) +/// Not sure if there is much value in having a param iterator. We could just return an array of +/// strings (char**) using metkit_marsrequest_params. +/// I think we should metkit_paramiterator_t. struct metkit_paramiterator_t { metkit_paramiterator_t(std::vector vec) : first(true), vector(std::move(vec)), iterator(vector.begin()) {} int next() { - if (first) { - first = false; - } - else { - ++iterator; - } if (iterator == vector.end()) { return METKIT_ITERATION_COMPLETE; } - return METKIT_SUCCESS; + ++iterator; + + return iterator == vector.end() ? METKIT_ITERATION_COMPLETE : METKIT_SUCCESS; } bool first; @@ -177,7 +171,7 @@ int metkit_free_marsrequest(const metkit_marsrequest_t* request) { ASSERT(request); delete request; }); -} +} int metkit_marsrequest_add(metkit_marsrequest_t* request, const char* param, const char* values[], int numValues) { return tryCatch([request, param, values, numValues] { @@ -193,6 +187,10 @@ int metkit_marsrequest_add(metkit_marsrequest_t* request, const char* param, con }); } +int metkit_marsrequest_add1(metkit_marsrequest_t* request, const char* param, const char* value) { + return metkit_marsrequest_add(request, param, &value, 1); +} + int metkit_marsrequest_set_verb(metkit_marsrequest_t* request, const char* verb) { return tryCatch([request, verb] { ASSERT(request); @@ -265,7 +263,7 @@ int metkit_marsrequest_expand(const metkit_marsrequest_t* request, metkit_marsre ASSERT(expandedRequest); ASSERT(expandedRequest->empty()); metkit::mars::MarsExpension expand(inherit, strict); - *expandedRequest = std::move(expand.expand(*request)); + *expandedRequest = expand.expand(*request); }); } diff --git a/src/metkit/api/metkit_c.h b/src/metkit/api/metkit_c.h index 6a1249fb..21654186 100644 --- a/src/metkit/api/metkit_c.h +++ b/src/metkit/api/metkit_c.h @@ -105,6 +105,14 @@ int metkit_free_marsrequest(const metkit_marsrequest_t* request); */ int metkit_marsrequest_add(metkit_marsrequest_t* request, const char* param, const char* values[], int numValues); +/** Add parameter and values to request + * @param request Request instance + * @param param parameter name + * @param values value to add + * @return int Error code + */ +int metkit_marsrequest_add1(metkit_marsrequest_t* request, const char* param, const char* value); + /** Set verb in Request object * @param request Request instance * @param verb verb to set diff --git a/tests/test_c_api.cc b/tests/test_c_api.cc index bef7aa40..5a729565 100644 --- a/tests/test_c_api.cc +++ b/tests/test_c_api.cc @@ -14,68 +14,162 @@ #include "metkit/api/metkit_c.h" #include "eckit/testing/Test.h" +#include "eckit/types/Date.h" using namespace eckit::testing; namespace metkit::test { -CASE( "Request get/set" ) { +// Wrapper around the C function calls that will throw an exception if the function fails +// i.e. if the return value is not METKIT_SUCCESS +#define METKIT_TEST_C(expr) \ + do { \ + int err = expr; \ + if (err != METKIT_SUCCESS) { \ + throw TestException("C-API error: " + std::string(metkit_get_error_string(err)), Here()); \ + } \ + } while (false) + +// Wrapper around EXPECT(strcmp(a, b) == 0) that will throw an exception if the comparison fails +#define EXPECT_STR_EQUAL(a, b) \ + do { \ + if (strcmp(a, b) != 0) { \ + throw TestException("Expected: " + std::string(a) + " == " + std::string(b), Here()); \ + } \ + } while (false) + +// Fairly minimal test coverage +CASE( "metkit_marsrequest" ) { + + // ----------------------------------------------------------------- + // Basics + // ----------------------------------------------------------------- metkit_marsrequest_t* request = nullptr; - metkit_new_marsrequest(&request); + METKIT_TEST_C(metkit_new_marsrequest(&request)); EXPECT(request); // set/get verb - metkit_marsrequest_set_verb(request, "retrieve"); + METKIT_TEST_C(metkit_marsrequest_set_verb(request, "retrieve")); const char* verb = nullptr; - metkit_marsrequest_verb(request, &verb); - EXPECT(strcmp(verb, "retrieve") == 0); + METKIT_TEST_C(metkit_marsrequest_verb(request, &verb)); + EXPECT_STR_EQUAL(verb, "retrieve"); // set array of values - const char* dates[] = {"20200101", "20200102", "20200103"}; - metkit_marsrequest_add(request, "date", dates, 3); + const char* dates[] = {"20200101", "20200102", "-1"}; + METKIT_TEST_C(metkit_marsrequest_add(request, "date", dates, 3)); // set single value const char* expver = "xxxx"; - metkit_marsrequest_add(request, "expver", &expver, 1); + METKIT_TEST_C(metkit_marsrequest_add1(request, "expver", expver)); + METKIT_TEST_C(metkit_marsrequest_add1(request, "param", "2t")); // check values bool has = false; - metkit_marsrequest_has_param(request, "date", &has); + METKIT_TEST_C(metkit_marsrequest_has_param(request, "date", &has)); EXPECT(has); - metkit_marsrequest_has_param(request, "random", &has); + METKIT_TEST_C(metkit_marsrequest_has_param(request, "random", &has)); EXPECT(!has); size_t count = 0; - metkit_marsrequest_count_values(request, "date", &count); + METKIT_TEST_C(metkit_marsrequest_count_values(request, "date", &count)); EXPECT_EQUAL(count, 3); for (size_t i = 0; i < count; i++) { const char* value = nullptr; - metkit_marsrequest_value(request, "date", i, &value); - EXPECT(strcmp(value, dates[i]) == 0); + METKIT_TEST_C(metkit_marsrequest_value(request, "date", i, &value)); + EXPECT_STR_EQUAL(value, dates[i]); } // all values const char** values = nullptr; count = 0; - metkit_marsrequest_values(request, "date", &values, &count); + METKIT_TEST_C(metkit_marsrequest_values(request, "date", &values, &count)); EXPECT_EQUAL(count, 3); for (size_t i = 0; i < count; i++) { - EXPECT(strcmp(values[i], dates[i]) == 0); + EXPECT_STR_EQUAL(values[i], dates[i]); } + // ----------------------------------------------------------------- + // Expand + // ----------------------------------------------------------------- + + metkit_marsrequest_t* expandedRequest = nullptr; + METKIT_TEST_C(metkit_new_marsrequest(&expandedRequest)); + METKIT_TEST_C(metkit_marsrequest_expand(request, expandedRequest, false, true)); + + // Check date expanded -1 -> yesterday + const char** dates_expanded = nullptr; + METKIT_TEST_C(metkit_marsrequest_values(expandedRequest, "date", &dates_expanded, &count)); + EXPECT_EQUAL(count, 3); + EXPECT_STR_EQUAL(dates_expanded[2], std::to_string(eckit::Date(-1).yyyymmdd()).c_str()); + // check param expanded 2t -> 167 + const char* param = nullptr; + METKIT_TEST_C(metkit_marsrequest_value(expandedRequest, "param", 0, ¶m)); + EXPECT_STR_EQUAL(param, "167"); + + // ----------------------------------------------------------------- + // Merge + // ----------------------------------------------------------------- + + metkit_marsrequest_t* req_manydates = nullptr; + METKIT_TEST_C(metkit_new_marsrequest(&req_manydates)); + const char* dates_many[] = {"19000101", "19000102", "19000103"}; + METKIT_TEST_C(metkit_marsrequest_add(req_manydates, "date", dates_many, 3)); + + METKIT_TEST_C(metkit_marsrequest_merge(request, req_manydates)); + METKIT_TEST_C(metkit_marsrequest_count_values(request, "date", &count)); + EXPECT_EQUAL(count, 6); + + // ----------------------------------------------------------------- // done + metkit_free_marsrequest(request); + metkit_free_marsrequest(expandedRequest); + metkit_free_marsrequest(req_manydates); } - //----------------------------------------------------------------------------- +CASE( "metkit_requestiterator_t parsing" ) { + + metkit_marsrequest_t* request0 = nullptr; + metkit_marsrequest_t* request1 = nullptr; + metkit_marsrequest_t* request2 = nullptr; + METKIT_TEST_C(metkit_new_marsrequest(&request0)); + METKIT_TEST_C(metkit_new_marsrequest(&request1)); + METKIT_TEST_C(metkit_new_marsrequest(&request2)); + + metkit_requestiterator_t* it = nullptr; + METKIT_TEST_C(metkit_parse_marsrequest("retrieve,date=-1,param=2t \n retrieve,date=20200102,param=2t,step=10/to/20/by/2", &it, true)); // two requests + + METKIT_TEST_C(metkit_requestiterator_request(it, request0)); + METKIT_TEST_C(metkit_requestiterator_next(it)); + METKIT_TEST_C(metkit_requestiterator_request(it, request1)); + EXPECT_EQUAL(metkit_requestiterator_next(it), METKIT_ITERATION_COMPLETE); + EXPECT_NOT_EQUAL(metkit_requestiterator_request(it, request2), METKIT_SUCCESS); // Error to get request after iteration complete + + // check the date + const char* date = nullptr; + METKIT_TEST_C(metkit_marsrequest_value(request0, "date", 0, &date)); + EXPECT_STR_EQUAL(date, std::to_string(eckit::Date(-1).yyyymmdd()).c_str()); // parser also calls expand + + METKIT_TEST_C(metkit_marsrequest_value(request1, "date", 0, &date)); + EXPECT_STR_EQUAL(date, "20200102"); + + // Check steps have been parsed + const char** steps = nullptr; + size_t count = 0; + METKIT_TEST_C(metkit_marsrequest_values(request1, "step", &steps, &count)); + for (size_t i = 0; i < count; i++) { + EXPECT_STR_EQUAL(steps[i], std::to_string(10 + i*2).c_str()); + } + +} + } // namespace metkit::test -int main(int argc, char **argv) -{ +int main(int argc, char **argv) { return run_tests ( argc, argv ); } From fd1d8b18f1242172524e1aed0980d37b68ddd65b Mon Sep 17 00:00:00 2001 From: Chris Bradley Date: Fri, 13 Dec 2024 19:57:24 +0000 Subject: [PATCH 09/13] Refactor private members and move semantics --- src/metkit/api/metkit_c.cc | 96 +++++++++++++++++++++----------------- src/metkit/api/metkit_c.h | 30 ++++++------ 2 files changed, 69 insertions(+), 57 deletions(-) diff --git a/src/metkit/api/metkit_c.cc b/src/metkit/api/metkit_c.cc index a39df969..f0d3b6fd 100644 --- a/src/metkit/api/metkit_c.cc +++ b/src/metkit/api/metkit_c.cc @@ -15,24 +15,32 @@ extern "C" { struct metkit_marsrequest_t : public metkit::mars::MarsRequest { using metkit::mars::MarsRequest::MarsRequest; - metkit_marsrequest_t(const metkit::mars::MarsRequest& k) : - metkit::mars::MarsRequest(k) {} + + metkit_marsrequest_t(metkit::mars::MarsRequest&& k) : + metkit::mars::MarsRequest(std::move(k)) {} }; struct metkit_requestiterator_t { - metkit_requestiterator_t(std::vector vec) : - vector(std::move(vec)), iterator(vector.begin()) {} + metkit_requestiterator_t(std::vector&& vec) : + vector_(std::move(vec)), iterator_(vector_.begin()) {} int next() { - if (iterator == vector.end()) { + if (iterator_ == vector_.end()) { return METKIT_ITERATION_COMPLETE; } - ++iterator; - return iterator == vector.end() ? METKIT_ITERATION_COMPLETE : METKIT_SUCCESS; + ++iterator_; + return iterator_ == vector_.end() ? METKIT_ITERATION_COMPLETE : METKIT_SUCCESS; + } + + void current(metkit_marsrequest_t* request) { + ASSERT(iterator_ != vector_.end()); + *request = std::move(*iterator_); } - std::vector vector; - std::vector::const_iterator iterator; +private: + + std::vector vector_; + std::vector::iterator iterator_; }; /// @comment: (maby) @@ -41,20 +49,25 @@ struct metkit_requestiterator_t { /// I think we should metkit_paramiterator_t. struct metkit_paramiterator_t { metkit_paramiterator_t(std::vector vec) : - first(true), vector(std::move(vec)), iterator(vector.begin()) {} + vector_(std::move(vec)), iterator_(vector_.begin()) {} int next() { - if (iterator == vector.end()) { + if (iterator_ == vector_.end()) { return METKIT_ITERATION_COMPLETE; } - ++iterator; + ++iterator_; - return iterator == vector.end() ? METKIT_ITERATION_COMPLETE : METKIT_SUCCESS; + return iterator_ == vector_.end() ? METKIT_ITERATION_COMPLETE : METKIT_SUCCESS; } - bool first; - std::vector vector; - std::vector::const_iterator iterator; + void current(const char** param) { + ASSERT(iterator_ != vector_.end()); + *param = iterator_->c_str(); + } + +private: + std::vector vector_; + std::vector::iterator iterator_; }; // --------------------------------------------------------------------------------------------------------------------- @@ -279,27 +292,27 @@ int metkit_marsrequest_merge(metkit_marsrequest_t* request, const metkit_marsreq // REQUEST ITERATOR // ----------------------------------------------------------------------------- -int metkit_free_requestiterator(const metkit_requestiterator_t* list) { - return tryCatch([list] { - ASSERT(list); - delete list; +int metkit_free_requestiterator(const metkit_requestiterator_t* it) { + return tryCatch([it] { + ASSERT(it); + delete it; }); } -int metkit_requestiterator_next(metkit_requestiterator_t* list) { - return tryCatch(std::function{[list] { - ASSERT(list); - return list->next(); +int metkit_requestiterator_next(metkit_requestiterator_t* it) { + return tryCatch(std::function{[it] { + ASSERT(it); + return it->next(); }}); } -int metkit_requestiterator_request(const metkit_requestiterator_t* list, metkit_marsrequest_t* request) { - return tryCatch([list, request] { - ASSERT(list); +int metkit_requestiterator_request(metkit_requestiterator_t* it, metkit_marsrequest_t* request) { + return tryCatch([it, request] { + ASSERT(it); ASSERT(request); - ASSERT(list->iterator != list->vector.end()); ASSERT(request->empty()); - *request = std::move(*(list->iterator)); + + it->current(request); }); } @@ -307,26 +320,25 @@ int metkit_requestiterator_request(const metkit_requestiterator_t* list, metkit_ // PARAM ITERATOR // ----------------------------------------------------------------------------- -int metkit_free_paramiterator(const metkit_paramiterator_t* list) { - return tryCatch([list] { - ASSERT(list); - delete list; +int metkit_free_paramiterator(const metkit_paramiterator_t* it) { + return tryCatch([it] { + ASSERT(it); + delete it; }); } -int metkit_paramiterator_next(metkit_paramiterator_t* list) { - return tryCatch(std::function{[list] { - ASSERT(list); - return list->next(); +int metkit_paramiterator_next(metkit_paramiterator_t* it) { + return tryCatch(std::function{[it] { + ASSERT(it); + return it->next(); }}); } -int metkit_paramiterator_param(const metkit_paramiterator_t* list, const char** param) { - return tryCatch([list, param] { - ASSERT(list); +int metkit_paramiterator_param(metkit_paramiterator_t* it, const char** param) { + return tryCatch([it, param] { + ASSERT(it); ASSERT(param); - ASSERT(list->iterator != list->vector.end()); - *param = list->iterator->c_str(); + it->current(param); }); } diff --git a/src/metkit/api/metkit_c.h b/src/metkit/api/metkit_c.h index 21654186..33a1b9d3 100644 --- a/src/metkit/api/metkit_c.h +++ b/src/metkit/api/metkit_c.h @@ -99,7 +99,7 @@ int metkit_free_marsrequest(const metkit_marsrequest_t* request); /** Add parameter and values to request * @param request Request instance * @param param parameter name - * @param values list of values for parameter + * @param values array of values for parameter * @param numValues number of values * @return int Error code */ @@ -163,7 +163,7 @@ int metkit_marsrequest_value(const metkit_marsrequest_t* request, const char* pa /** Returns values for specific parameter Request object * @param request Request instance * @param param parameter name in request - * @param values list of values for param in request + * @param values array of values for param in request * @param numValues number of values for param in request * @return int Error code */ @@ -190,46 +190,46 @@ int metkit_marsrequest_merge(metkit_marsrequest_t* request, const metkit_marsreq * --- */ /** Deallocates RequestIterator object and associated resources. - * @param list RequestIterator instance + * @param it RequestIterator instance * @return int Error code */ -int metkit_free_requestiterator(const metkit_requestiterator_t* list); +int metkit_free_requestiterator(const metkit_requestiterator_t* it); /** Moves to the next Request element in RequestIterator - * @param list RequestIterator instance + * @param it RequestIterator instance * @return int Error code */ -int metkit_requestiterator_next(metkit_requestiterator_t* list); +int metkit_requestiterator_next(metkit_requestiterator_t* it); /** Populates empty Requestion object with data from current element in RequestIterator - * @param list RequestIterator instance + * @param it RequestIterator instance * @param request empty Request instance to populate with data * @return int Error code */ -int metkit_requestiterator_request(const metkit_requestiterator_t* list, metkit_marsrequest_t* request); +int metkit_requestiterator_request(metkit_requestiterator_t* it, metkit_marsrequest_t* request); /* --------------------------------------------------------------------------------------------------------------------- * PARAM ITERATOR * --- */ /** Deallocates ParamIterator object and associated resources. - * @param list ParamIterator instance + * @param it ParamIterator instance * @return int Error code */ -int metkit_free_paramiterator(const metkit_paramiterator_t* list); +int metkit_free_paramiterator(const metkit_paramiterator_t* it); /** Moves to the next string element in ParamIterator - * @param list ParamIterator instance + * @param it ParamIterator instance * @return int Error code */ -int metkit_paramiterator_next(metkit_paramiterator_t* list); +int metkit_paramiterator_next(metkit_paramiterator_t* it); /** Returns the current parameter name in ParamIterator - * @param list ParamIterator instance - * @param param current parameter name in list + * @param it ParamIterator instance + * @param param current parameter name in iterator * @return int Error code */ -int metkit_paramiterator_param(const metkit_paramiterator_t* list, const char** param); +int metkit_paramiterator_param(metkit_paramiterator_t* it, const char** param); #ifdef __cplusplus } From bf9f48889670e3d2e05b798b52f6df77348ca263 Mon Sep 17 00:00:00 2001 From: Chris Bradley Date: Fri, 13 Dec 2024 20:08:26 +0000 Subject: [PATCH 10/13] Add header --- tests/test_c_api.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_c_api.cc b/tests/test_c_api.cc index 5a729565..9bf3e8ff 100644 --- a/tests/test_c_api.cc +++ b/tests/test_c_api.cc @@ -15,6 +15,7 @@ #include "metkit/api/metkit_c.h" #include "eckit/testing/Test.h" #include "eckit/types/Date.h" +#include using namespace eckit::testing; namespace metkit::test { From 1b324a31d0c9bceefbf7b087e008431a69b717cb Mon Sep 17 00:00:00 2001 From: Chris Bradley Date: Fri, 20 Dec 2024 17:47:10 +0000 Subject: [PATCH 11/13] Respond to subset of review comments --- src/metkit/api/metkit_c.cc | 75 +++++++++++++++++--------------------- src/metkit/api/metkit_c.h | 28 +++++++------- tests/CMakeLists.txt | 9 +++++ tests/test_c_api.c | 26 +++++++++++++ tests/test_c_api.cc | 69 +++++++++++++++++------------------ 5 files changed, 115 insertions(+), 92 deletions(-) create mode 100644 tests/test_c_api.c diff --git a/src/metkit/api/metkit_c.cc b/src/metkit/api/metkit_c.cc index f0d3b6fd..b792bd7b 100644 --- a/src/metkit/api/metkit_c.cc +++ b/src/metkit/api/metkit_c.cc @@ -2,26 +2,20 @@ #include "metkit/mars/MarsExpension.h" #include "metkit/mars/MarsRequest.h" #include "metkit/metkit_version.h" - -#include "eckit/exception/Exceptions.h" #include "eckit/runtime/Main.h" -#include "eckit/utils/Optional.h" - #include -extern "C" { - // --------------------------------------------------------------------------------------------------------------------- struct metkit_marsrequest_t : public metkit::mars::MarsRequest { using metkit::mars::MarsRequest::MarsRequest; - metkit_marsrequest_t(metkit::mars::MarsRequest&& k) : - metkit::mars::MarsRequest(std::move(k)) {} + metkit_marsrequest_t(metkit::mars::MarsRequest&& req) : + metkit::mars::MarsRequest(std::move(req)) {} }; struct metkit_requestiterator_t { - metkit_requestiterator_t(std::vector&& vec) : + explicit metkit_requestiterator_t(std::vector&& vec) : vector_(std::move(vec)), iterator_(vector_.begin()) {} int next() { @@ -48,7 +42,7 @@ struct metkit_requestiterator_t { /// strings (char**) using metkit_marsrequest_params. /// I think we should metkit_paramiterator_t. struct metkit_paramiterator_t { - metkit_paramiterator_t(std::vector vec) : + explicit metkit_paramiterator_t(std::vector vec) : vector_(std::move(vec)), iterator_(vector_.begin()) {} int next() { @@ -73,12 +67,21 @@ struct metkit_paramiterator_t { // --------------------------------------------------------------------------------------------------------------------- // ERROR HANDLING -} // extern "C" - static thread_local std::string g_current_error_string; -const char* metkit_get_error_string(int) { - return g_current_error_string.c_str(); +const char* metkit_get_error_string(enum metkit_error_values_t err) { + switch (err) { + case METKIT_SUCCESS: + return "Success"; + case METKIT_ITERATION_COMPLETE: + return "Iteration complete"; + case METKIT_ERROR: + case METKIT_ERROR_USER: + case METKIT_ERROR_ASSERT: + return g_current_error_string.c_str(); + default: + return ""; + } } int innerWrapFn(std::function f) { @@ -117,13 +120,10 @@ template } catch (...) { eckit::Log::error() << "Unknown Error!" << std::endl; - g_current_error_string = ""; return METKIT_ERROR_UNKNOWN; } } -extern "C" { - // ----------------------------------------------------------------------------- // HELPERS // ----------------------------------------------------------------------------- @@ -179,29 +179,28 @@ int metkit_new_marsrequest(metkit_marsrequest_t** request) { }); } -int metkit_free_marsrequest(const metkit_marsrequest_t* request) { +int metkit_delete_marsrequest(const metkit_marsrequest_t* request) { return tryCatch([request] { - ASSERT(request); delete request; }); } -int metkit_marsrequest_add(metkit_marsrequest_t* request, const char* param, const char* values[], int numValues) { +int metkit_marsrequest_set(metkit_marsrequest_t* request, const char* param, const char* values[], int numValues) { return tryCatch([request, param, values, numValues] { ASSERT(request); ASSERT(param); ASSERT(values); - std::string n(param); - std::vector vv; - for (int i = 0; i < numValues; i++) { - vv.push_back(std::string(values[i])); - } - request->values(n, vv); + std::string param_str(param); + std::vector values_vec; + values_vec.reserve(numValues); + std::copy(values, values + numValues, std::back_inserter(values_vec)); + + request->values(param_str, values_vec); }); } -int metkit_marsrequest_add1(metkit_marsrequest_t* request, const char* param, const char* value) { - return metkit_marsrequest_add(request, param, &value, 1); +int metkit_marsrequest_set_one(metkit_marsrequest_t* request, const char* param, const char* value) { + return metkit_marsrequest_set(request, param, &value, 1); } int metkit_marsrequest_set_verb(metkit_marsrequest_t* request, const char* verb) { @@ -261,12 +260,10 @@ int metkit_marsrequest_values(const metkit_marsrequest_t* request, const char* p ASSERT(param); ASSERT(values); ASSERT(numValues); - const std::vector& v = request->values(param); - *numValues = v.size(); - *values = new const char*[v.size()]; - for (size_t i = 0; i < v.size(); i++) { - (*values)[i] = v[i].c_str(); - } + const std::vector& values_str = request->values(param); + *numValues = values_str.size(); + *values = new const char*[values_str.size()]; + std::transform(values_str.begin(), values_str.end(), *values, [](const std::string& s) { return s.c_str(); }); }); } @@ -292,9 +289,8 @@ int metkit_marsrequest_merge(metkit_marsrequest_t* request, const metkit_marsreq // REQUEST ITERATOR // ----------------------------------------------------------------------------- -int metkit_free_requestiterator(const metkit_requestiterator_t* it) { +int metkit_delete_requestiterator(const metkit_requestiterator_t* it) { return tryCatch([it] { - ASSERT(it); delete it; }); } @@ -320,9 +316,8 @@ int metkit_requestiterator_request(metkit_requestiterator_t* it, metkit_marsrequ // PARAM ITERATOR // ----------------------------------------------------------------------------- -int metkit_free_paramiterator(const metkit_paramiterator_t* it) { +int metkit_delete_paramiterator(const metkit_paramiterator_t* it) { return tryCatch([it] { - ASSERT(it); delete it; }); } @@ -343,6 +338,4 @@ int metkit_paramiterator_param(metkit_paramiterator_t* it, const char** param) { } -// --------------------------------------------------------------------------------------------------------------------- - -} // extern "C" \ No newline at end of file +// --------------------------------------------------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/metkit/api/metkit_c.h b/src/metkit/api/metkit_c.h index 33a1b9d3..edcde0a4 100644 --- a/src/metkit/api/metkit_c.h +++ b/src/metkit/api/metkit_c.h @@ -1,7 +1,7 @@ -#ifndef METKIT_API_METKIT_C_H -#define METKIT_API_METKIT_C_H +#pragma once #include +#include #ifdef __cplusplus extern "C" { @@ -36,7 +36,7 @@ typedef enum metkit_error_values_t METKIT_ERROR_ASSERT = 5 /* Failed with an assert() */ } metkit_error_enum_t; -const char* metkit_get_error_string(int err); +const char* metkit_get_error_string(enum metkit_error_values_t err); /* ----------------------------------------------------------------------------- * HELPERS @@ -73,18 +73,18 @@ int metkit_initialise(); /** * Parse MARS requests into RequestIterator of Request instances. Resulting RequestIterator - * must be deallocated with metkit_free_requestiterator + * must be deallocated with metkit_delete_requestiterator * @param str MARS requests * @param requests Allocates RequestIterator object * @return int Error code */ -int metkit_parse_marsrequest(const char* str, metkit_requestiterator_t** requests, bool strict = false); +int metkit_parse_marsrequest(const char* str, metkit_requestiterator_t** requests, bool strict); /* --------------------------------------------------------------------------------------------------------------------- * REQUEST * --- */ -/** Allocates new Request object. Must be deallocated with mekit_free_request +/** Allocates new Request object. Must be deallocated with mekit_delete_request * @param request new Request instance * @return int Error code */ @@ -94,7 +94,7 @@ int metkit_new_marsrequest(metkit_marsrequest_t** request); * @param request Request instance * @return int Error code */ -int metkit_free_marsrequest(const metkit_marsrequest_t* request); +int metkit_delete_marsrequest(const metkit_marsrequest_t* request); /** Add parameter and values to request * @param request Request instance @@ -103,7 +103,7 @@ int metkit_free_marsrequest(const metkit_marsrequest_t* request); * @param numValues number of values * @return int Error code */ -int metkit_marsrequest_add(metkit_marsrequest_t* request, const char* param, const char* values[], int numValues); +int metkit_marsrequest_set(metkit_marsrequest_t* request, const char* param, const char* values[], int numValues); /** Add parameter and values to request * @param request Request instance @@ -111,7 +111,7 @@ int metkit_marsrequest_add(metkit_marsrequest_t* request, const char* param, con * @param values value to add * @return int Error code */ -int metkit_marsrequest_add1(metkit_marsrequest_t* request, const char* param, const char* value); +int metkit_marsrequest_set_one(metkit_marsrequest_t* request, const char* param, const char* value); /** Set verb in Request object * @param request Request instance @@ -136,7 +136,7 @@ int metkit_marsrequest_verb(const metkit_marsrequest_t* request, const char** ve int metkit_marsrequest_has_param(const metkit_marsrequest_t* request, const char* param, bool* has); /** Returns ParamIterator of parameters in request. Resulting ParamIterator - * must be deallocated with metkit_free_paramiterator + * must be deallocated with metkit_delete_paramiterator * @param request Request instance * @param params Allocates ParamIterator object for parameter names in request * @return int Error code @@ -176,7 +176,7 @@ int metkit_marsrequest_values(const metkit_marsrequest_t* request, const char* p * @param strict it true, raise error rather than warning on invalid values * @return int Error code */ -int metkit_marsrequest_expand(const metkit_marsrequest_t* request, metkit_marsrequest_t* expandedRequest, bool inherit = true, bool strict = false); +int metkit_marsrequest_expand(const metkit_marsrequest_t* request, metkit_marsrequest_t* expandedRequest, bool inherit, bool strict); /** Merges other Request object into existing request * @param request Request instance to contain result of merge @@ -193,7 +193,7 @@ int metkit_marsrequest_merge(metkit_marsrequest_t* request, const metkit_marsreq * @param it RequestIterator instance * @return int Error code */ -int metkit_free_requestiterator(const metkit_requestiterator_t* it); +int metkit_delete_requestiterator(const metkit_requestiterator_t* it); /** Moves to the next Request element in RequestIterator * @param it RequestIterator instance @@ -216,7 +216,7 @@ int metkit_requestiterator_request(metkit_requestiterator_t* it, metkit_marsrequ * @param it ParamIterator instance * @return int Error code */ -int metkit_free_paramiterator(const metkit_paramiterator_t* it); +int metkit_delete_paramiterator(const metkit_paramiterator_t* it); /** Moves to the next string element in ParamIterator * @param it ParamIterator instance @@ -234,5 +234,3 @@ int metkit_paramiterator_param(metkit_paramiterator_t* it, const char** param); #ifdef __cplusplus } #endif - -#endif /* METKIT_API_METKIT_C_H */ \ No newline at end of file diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index c175786e..ec06cb12 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -82,6 +82,15 @@ foreach(test IN LISTS testFileSuffixes) LIBS metkit) endforeach() +# Compile C test +ecbuild_add_test( TARGET metkit_test_c_compiled + SOURCES test_c_api.c + INCLUDES "${ECKIT_INCLUDE_DIRS}" + LIBS metkit + NO_AS_NEEDED + ENVIRONMENT "${metkit_env}" + LINKER_LANGUAGE C) + # if ( HAVE_NETCDF ) # add_subdirectory(netcdf) # endif() diff --git a/tests/test_c_api.c b/tests/test_c_api.c new file mode 100644 index 00000000..977a965a --- /dev/null +++ b/tests/test_c_api.c @@ -0,0 +1,26 @@ +/* + * (C) Copyright 1996- ECMWF. + * + * This software is licensed under the terms of the Apache Licence Version 2.0 + * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. + * In applying this licence, ECMWF does not waive the privileges and immunities + * granted to it by virtue of its status as an intergovernmental organisation + * nor does it submit to any jurisdiction. + */ + +/// @file test_c_api.c +/// @date Dec 2024 +/// @author Christopher Bradley + +#include "metkit/api/metkit_c.h" +#include + +int main(int argc, char **argv) { + + const char* version; + int errno = metkit_version(&version); + + fprintf(stdout, "MetKit version: %s\n", version); + + return 0; +} diff --git a/tests/test_c_api.cc b/tests/test_c_api.cc index 9bf3e8ff..fa3e58b7 100644 --- a/tests/test_c_api.cc +++ b/tests/test_c_api.cc @@ -22,21 +22,17 @@ namespace metkit::test { // Wrapper around the C function calls that will throw an exception if the function fails // i.e. if the return value is not METKIT_SUCCESS -#define METKIT_TEST_C(expr) \ - do { \ - int err = expr; \ - if (err != METKIT_SUCCESS) { \ - throw TestException("C-API error: " + std::string(metkit_get_error_string(err)), Here()); \ - } \ - } while (false) - -// Wrapper around EXPECT(strcmp(a, b) == 0) that will throw an exception if the comparison fails -#define EXPECT_STR_EQUAL(a, b) \ - do { \ - if (strcmp(a, b) != 0) { \ - throw TestException("Expected: " + std::string(a) + " == " + std::string(b), Here()); \ - } \ - } while (false) + +void METKIT_TEST_C(int e) { + metkit_error_values_t err = static_cast(e); + if (err != METKIT_SUCCESS) + throw TestException("C-API error: " + std::string(metkit_get_error_string(err)), Here()); +} + +void EXPECT_STR_EQUAL(const char* a, const char* b) { + if (strcmp(a, b) != 0) + throw TestException("Expected: " + std::string(a) + " == " + std::string(b), Here()); +} // Fairly minimal test coverage CASE( "metkit_marsrequest" ) { @@ -45,25 +41,25 @@ CASE( "metkit_marsrequest" ) { // Basics // ----------------------------------------------------------------- - metkit_marsrequest_t* request = nullptr; + metkit_marsrequest_t* request{}; METKIT_TEST_C(metkit_new_marsrequest(&request)); EXPECT(request); // set/get verb METKIT_TEST_C(metkit_marsrequest_set_verb(request, "retrieve")); - const char* verb = nullptr; + const char* verb{}; METKIT_TEST_C(metkit_marsrequest_verb(request, &verb)); EXPECT_STR_EQUAL(verb, "retrieve"); // set array of values const char* dates[] = {"20200101", "20200102", "-1"}; - METKIT_TEST_C(metkit_marsrequest_add(request, "date", dates, 3)); + METKIT_TEST_C(metkit_marsrequest_set(request, "date", dates, 3)); // set single value const char* expver = "xxxx"; - METKIT_TEST_C(metkit_marsrequest_add1(request, "expver", expver)); - METKIT_TEST_C(metkit_marsrequest_add1(request, "param", "2t")); + METKIT_TEST_C(metkit_marsrequest_set_one(request, "expver", expver)); + METKIT_TEST_C(metkit_marsrequest_set_one(request, "param", "2t")); // check values bool has = false; @@ -78,13 +74,13 @@ CASE( "metkit_marsrequest" ) { EXPECT_EQUAL(count, 3); for (size_t i = 0; i < count; i++) { - const char* value = nullptr; + const char* value{}; METKIT_TEST_C(metkit_marsrequest_value(request, "date", i, &value)); EXPECT_STR_EQUAL(value, dates[i]); } // all values - const char** values = nullptr; + const char** values{}; count = 0; METKIT_TEST_C(metkit_marsrequest_values(request, "date", &values, &count)); EXPECT_EQUAL(count, 3); @@ -97,17 +93,17 @@ CASE( "metkit_marsrequest" ) { // Expand // ----------------------------------------------------------------- - metkit_marsrequest_t* expandedRequest = nullptr; + metkit_marsrequest_t* expandedRequest{}; METKIT_TEST_C(metkit_new_marsrequest(&expandedRequest)); METKIT_TEST_C(metkit_marsrequest_expand(request, expandedRequest, false, true)); // Check date expanded -1 -> yesterday - const char** dates_expanded = nullptr; + const char** dates_expanded{}; METKIT_TEST_C(metkit_marsrequest_values(expandedRequest, "date", &dates_expanded, &count)); EXPECT_EQUAL(count, 3); EXPECT_STR_EQUAL(dates_expanded[2], std::to_string(eckit::Date(-1).yyyymmdd()).c_str()); // check param expanded 2t -> 167 - const char* param = nullptr; + const char* param{}; METKIT_TEST_C(metkit_marsrequest_value(expandedRequest, "param", 0, ¶m)); EXPECT_STR_EQUAL(param, "167"); @@ -115,10 +111,10 @@ CASE( "metkit_marsrequest" ) { // Merge // ----------------------------------------------------------------- - metkit_marsrequest_t* req_manydates = nullptr; + metkit_marsrequest_t* req_manydates{}; METKIT_TEST_C(metkit_new_marsrequest(&req_manydates)); const char* dates_many[] = {"19000101", "19000102", "19000103"}; - METKIT_TEST_C(metkit_marsrequest_add(req_manydates, "date", dates_many, 3)); + METKIT_TEST_C(metkit_marsrequest_set(req_manydates, "date", dates_many, 3)); METKIT_TEST_C(metkit_marsrequest_merge(request, req_manydates)); METKIT_TEST_C(metkit_marsrequest_count_values(request, "date", &count)); @@ -127,32 +123,33 @@ CASE( "metkit_marsrequest" ) { // ----------------------------------------------------------------- // done - metkit_free_marsrequest(request); - metkit_free_marsrequest(expandedRequest); - metkit_free_marsrequest(req_manydates); + metkit_delete_marsrequest(request); + metkit_delete_marsrequest(expandedRequest); + metkit_delete_marsrequest(req_manydates); } //----------------------------------------------------------------------------- CASE( "metkit_requestiterator_t parsing" ) { - metkit_marsrequest_t* request0 = nullptr; - metkit_marsrequest_t* request1 = nullptr; - metkit_marsrequest_t* request2 = nullptr; + metkit_marsrequest_t* request0{}; + metkit_marsrequest_t* request1{}; + metkit_marsrequest_t* request2{}; METKIT_TEST_C(metkit_new_marsrequest(&request0)); METKIT_TEST_C(metkit_new_marsrequest(&request1)); METKIT_TEST_C(metkit_new_marsrequest(&request2)); - metkit_requestiterator_t* it = nullptr; + metkit_requestiterator_t* it{}; METKIT_TEST_C(metkit_parse_marsrequest("retrieve,date=-1,param=2t \n retrieve,date=20200102,param=2t,step=10/to/20/by/2", &it, true)); // two requests METKIT_TEST_C(metkit_requestiterator_request(it, request0)); METKIT_TEST_C(metkit_requestiterator_next(it)); METKIT_TEST_C(metkit_requestiterator_request(it, request1)); + EXPECT_EQUAL(metkit_requestiterator_next(it), METKIT_ITERATION_COMPLETE); EXPECT_NOT_EQUAL(metkit_requestiterator_request(it, request2), METKIT_SUCCESS); // Error to get request after iteration complete // check the date - const char* date = nullptr; + const char* date{}; METKIT_TEST_C(metkit_marsrequest_value(request0, "date", 0, &date)); EXPECT_STR_EQUAL(date, std::to_string(eckit::Date(-1).yyyymmdd()).c_str()); // parser also calls expand @@ -160,7 +157,7 @@ CASE( "metkit_requestiterator_t parsing" ) { EXPECT_STR_EQUAL(date, "20200102"); // Check steps have been parsed - const char** steps = nullptr; + const char** steps{}; size_t count = 0; METKIT_TEST_C(metkit_marsrequest_values(request1, "step", &steps, &count)); for (size_t i = 0; i < count; i++) { From 0c206775a255d7b244ca922ddecde58978a40162 Mon Sep 17 00:00:00 2001 From: Chris Bradley Date: Thu, 9 Jan 2025 17:13:20 +0000 Subject: [PATCH 12/13] Refine C api --- CMakeLists.txt | 2 +- src/metkit/CMakeLists.txt | 2 + src/metkit/api/metkit_c.cc | 106 +++++---------------------------- src/metkit/api/metkit_c.h | 81 +++++++++---------------- src/metkit/metkit_version.c.in | 19 ++++++ src/metkit/metkit_version.h.in | 20 +++++-- tests/test_c_api.c | 3 +- tests/test_c_api.cc | 30 ++++------ 8 files changed, 94 insertions(+), 169 deletions(-) create mode 100644 src/metkit/metkit_version.c.in diff --git a/CMakeLists.txt b/CMakeLists.txt index 46f9040d..c9def1af 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,7 @@ cmake_minimum_required( VERSION 3.12 FATAL_ERROR ) find_package( ecbuild 3.7.2 REQUIRED HINTS ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../ecbuild) -project( metkit LANGUAGES CXX ) +project( metkit LANGUAGES CXX C ) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) diff --git a/src/metkit/CMakeLists.txt b/src/metkit/CMakeLists.txt index 5303e8b5..766e4548 100644 --- a/src/metkit/CMakeLists.txt +++ b/src/metkit/CMakeLists.txt @@ -4,6 +4,7 @@ ecbuild_generate_config_headers( DESTINATION ${INSTALL_INCLUDE_DIR}/metkit ) configure_file( metkit_config.h.in metkit_config.h ) configure_file( metkit_version.h.in metkit_version.h ) +configure_file( metkit_version.c.in ${CMAKE_CURRENT_BINARY_DIR}/metkit_version.c ) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/metkit_config.h @@ -14,6 +15,7 @@ install(FILES ### metkit sources list( APPEND metkit_srcs + ${CMAKE_CURRENT_BINARY_DIR}/metkit_version.c config/LibMetkit.cc config/LibMetkit.h mars/BaseProtocol.cc diff --git a/src/metkit/api/metkit_c.cc b/src/metkit/api/metkit_c.cc index b792bd7b..e1390990 100644 --- a/src/metkit/api/metkit_c.cc +++ b/src/metkit/api/metkit_c.cc @@ -37,33 +37,6 @@ struct metkit_requestiterator_t { std::vector::iterator iterator_; }; -/// @comment: (maby) -/// Not sure if there is much value in having a param iterator. We could just return an array of -/// strings (char**) using metkit_marsrequest_params. -/// I think we should metkit_paramiterator_t. -struct metkit_paramiterator_t { - explicit metkit_paramiterator_t(std::vector vec) : - vector_(std::move(vec)), iterator_(vector_.begin()) {} - - int next() { - if (iterator_ == vector_.end()) { - return METKIT_ITERATION_COMPLETE; - } - ++iterator_; - - return iterator_ == vector_.end() ? METKIT_ITERATION_COMPLETE : METKIT_SUCCESS; - } - - void current(const char** param) { - ASSERT(iterator_ != vector_.end()); - *param = iterator_->c_str(); - } - -private: - std::vector vector_; - std::vector::iterator iterator_; -}; - // --------------------------------------------------------------------------------------------------------------------- // ERROR HANDLING @@ -99,27 +72,22 @@ template return innerWrapFn(fn); } catch (const eckit::UserError& e) { - eckit::Log::error() << "User Error: " << e.what() << std::endl; g_current_error_string = e.what(); return METKIT_ERROR_USER; } catch (const eckit::AssertionFailed& e) { - eckit::Log::error() << "Assertion Failed: " << e.what() << std::endl; g_current_error_string = e.what(); return METKIT_ERROR_ASSERT; } catch (const eckit::Exception& e) { - eckit::Log::error() << "METKIT Error: " << e.what() << std::endl; g_current_error_string = e.what(); return METKIT_ERROR; } catch (const std::exception& e) { - eckit::Log::error() << "Unknown Error: " << e.what() << std::endl; g_current_error_string = e.what(); return METKIT_ERROR_UNKNOWN; } catch (...) { - eckit::Log::error() << "Unknown Error!" << std::endl; return METKIT_ERROR_UNKNOWN; } } @@ -128,16 +96,6 @@ template // HELPERS // ----------------------------------------------------------------------------- -int metkit_version(const char** version) { - *version = metkit_version_str(); - return METKIT_SUCCESS; -} - -int metkit_vcs_version(const char** sha1) { - *sha1 = metkit_git_sha1(); - return METKIT_SUCCESS; -} - int metkit_initialise() { return tryCatch([] { static bool initialised = false; @@ -159,7 +117,7 @@ int metkit_initialise() { // PARSING // ----------------------------------------------------------------------------- -int metkit_parse_marsrequest(const char* str, metkit_requestiterator_t** requests, bool strict) { +int metkit_parse_marsrequests(const char* str, metkit_requestiterator_t** requests, bool strict) { return tryCatch([requests, str, strict] { ASSERT(requests); ASSERT(str); @@ -198,7 +156,7 @@ int metkit_marsrequest_set(metkit_marsrequest_t* request, const char* param, con request->values(param_str, values_vec); }); } - + int metkit_marsrequest_set_one(metkit_marsrequest_t* request, const char* param, const char* value) { return metkit_marsrequest_set(request, param, &value, 1); } @@ -228,11 +186,19 @@ int metkit_marsrequest_has_param(const metkit_marsrequest_t* request, const char }); } -int metkit_marsrequest_params(const metkit_marsrequest_t* request, metkit_paramiterator_t** params) { - return tryCatch([request, params] { +int metkit_marsrequest_count_params(const metkit_marsrequest_t* request, size_t* count) { + return tryCatch([request, count] { ASSERT(request); - ASSERT(params); - *params = new metkit_paramiterator_t(request->params()); + ASSERT(count); + *count = request->params().size(); + }); +} + +int metkit_marsrequest_param(const metkit_marsrequest_t* request, size_t index, const char** param) { + return tryCatch([request, index, param] { + ASSERT(request); + ASSERT(param); + *param = request->params()[index].c_str(); }); } @@ -250,24 +216,10 @@ int metkit_marsrequest_value(const metkit_marsrequest_t* request, const char* pa ASSERT(request); ASSERT(param); ASSERT(value); - *value = (request->values(param, false))[index].c_str(); + *value = request->values(param, false)[index].c_str(); }); } - -int metkit_marsrequest_values(const metkit_marsrequest_t* request, const char* param, const char** values[], size_t* numValues) { - return tryCatch([request, param, values, numValues] { - ASSERT(request); - ASSERT(param); - ASSERT(values); - ASSERT(numValues); - const std::vector& values_str = request->values(param); - *numValues = values_str.size(); - *values = new const char*[values_str.size()]; - std::transform(values_str.begin(), values_str.end(), *values, [](const std::string& s) { return s.c_str(); }); - }); -} - -int metkit_marsrequest_expand(const metkit_marsrequest_t* request, metkit_marsrequest_t* expandedRequest, bool inherit, bool strict) { +int metkit_marsrequest_expand(const metkit_marsrequest_t* request, bool inherit, bool strict, metkit_marsrequest_t* expandedRequest) { return tryCatch([request, expandedRequest, inherit, strict] { ASSERT(request); ASSERT(expandedRequest); @@ -312,30 +264,4 @@ int metkit_requestiterator_request(metkit_requestiterator_t* it, metkit_marsrequ }); } -// ----------------------------------------------------------------------------- -// PARAM ITERATOR -// ----------------------------------------------------------------------------- - -int metkit_delete_paramiterator(const metkit_paramiterator_t* it) { - return tryCatch([it] { - delete it; - }); -} - -int metkit_paramiterator_next(metkit_paramiterator_t* it) { - return tryCatch(std::function{[it] { - ASSERT(it); - return it->next(); - }}); -} - -int metkit_paramiterator_param(metkit_paramiterator_t* it, const char** param) { - return tryCatch([it, param] { - ASSERT(it); - ASSERT(param); - it->current(param); - }); -} - - // --------------------------------------------------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/metkit/api/metkit_c.h b/src/metkit/api/metkit_c.h index edcde0a4..40b29554 100644 --- a/src/metkit/api/metkit_c.h +++ b/src/metkit/api/metkit_c.h @@ -43,20 +43,18 @@ const char* metkit_get_error_string(enum metkit_error_values_t err); * ------- */ /** - * @brief Set MetKit version. + * @brief Get metkit version. * - * @param version Version string - * @return int Error code + * @return const char* version string */ -int metkit_version(const char** version); +const char* metkit_version(); /** - * @brief Set MetKit git sha1 version. + * @brief Get metkit git sha1 version. * - * @param sha1 SHA1 version string - * @return int Error code + * @return const char* git sha1 version string */ -int metkit_vcs_version(const char** sha1); +const char* metkit_git_sha1(); /** * @brief Initialise Main() context. @@ -75,17 +73,17 @@ int metkit_initialise(); * Parse MARS requests into RequestIterator of Request instances. Resulting RequestIterator * must be deallocated with metkit_delete_requestiterator * @param str MARS requests - * @param requests Allocates RequestIterator object + * @param[out] requests Allocates RequestIterator object * @return int Error code */ -int metkit_parse_marsrequest(const char* str, metkit_requestiterator_t** requests, bool strict); +int metkit_parse_marsrequests(const char* str, metkit_requestiterator_t** requests, bool strict); /* --------------------------------------------------------------------------------------------------------------------- * REQUEST * --- */ /** Allocates new Request object. Must be deallocated with mekit_delete_request - * @param request new Request instance + * @param[out] request new Request instance * @return int Error code */ int metkit_new_marsrequest(metkit_marsrequest_t** request); @@ -122,7 +120,7 @@ int metkit_marsrequest_set_verb(metkit_marsrequest_t* request, const char* verb) /** Returns the verb in Request object * @param request Request instance - * @param verb verb in request + * @param[out] verb verb in request * @return int Error code */ int metkit_marsrequest_verb(const metkit_marsrequest_t* request, const char** verb); @@ -130,23 +128,32 @@ int metkit_marsrequest_verb(const metkit_marsrequest_t* request, const char** ve /** Returns whether parameter is in Request object * @param request Request instance * @param param parameter name - * @param has whether parameter exists in request + * @param[out] has whether parameter exists in request * @return int Error code */ int metkit_marsrequest_has_param(const metkit_marsrequest_t* request, const char* param, bool* has); -/** Returns ParamIterator of parameters in request. Resulting ParamIterator - * must be deallocated with metkit_delete_paramiterator + +/** Returns number of parameters in Request object + * @param request Request instance + * @param[out] count number of parameters in request + * @return int Error code + */ +int metkit_marsrequest_count_params(const metkit_marsrequest_t* request, size_t* count); + +/** Returns parameter name for specific index in Request object * @param request Request instance - * @param params Allocates ParamIterator object for parameter names in request + * @param index index of parameter to retrieve + * @param[out] param parameter name * @return int Error code */ -int metkit_marsrequest_params(const metkit_marsrequest_t* request, metkit_paramiterator_t** params); +int metkit_marsrequest_param(const metkit_marsrequest_t* request, size_t index, const char** param); + /** Returns number of values for specific parameter in Request object * @param request Request instance * @param param parameter name in request - * @param count number of values for param in request + * @param[out] count number of values for param in request * @return int Error code */ int metkit_marsrequest_count_values(const metkit_marsrequest_t* request, const char* param, size_t* count); @@ -155,28 +162,19 @@ int metkit_marsrequest_count_values(const metkit_marsrequest_t* request, const c * @param request Request instance * @param param parameter name in request * @param index index of value to retrieve for param in request - * @param value retrieved value + * @param[out] value retrieved value * @return int Error code */ int metkit_marsrequest_value(const metkit_marsrequest_t* request, const char* param, int index, const char** value); -/** Returns values for specific parameter Request object - * @param request Request instance - * @param param parameter name in request - * @param values array of values for param in request - * @param numValues number of values for param in request - * @return int Error code - */ -int metkit_marsrequest_values(const metkit_marsrequest_t* request, const char* param, const char** values[], size_t* numValues); - /** Populates empty Request object by expanding existing request * @param request Request instance to be expanded - * @param expandedRequest empty Request instance to be populated * @param inherit if true, populate expanded request with default values * @param strict it true, raise error rather than warning on invalid values + * @param[out] expandedRequest empty Request instance to be populated * @return int Error code */ -int metkit_marsrequest_expand(const metkit_marsrequest_t* request, metkit_marsrequest_t* expandedRequest, bool inherit, bool strict); +int metkit_marsrequest_expand(const metkit_marsrequest_t* request, bool inherit, bool strict, metkit_marsrequest_t* expandedRequest); /** Merges other Request object into existing request * @param request Request instance to contain result of merge @@ -208,29 +206,6 @@ int metkit_requestiterator_next(metkit_requestiterator_t* it); */ int metkit_requestiterator_request(metkit_requestiterator_t* it, metkit_marsrequest_t* request); -/* --------------------------------------------------------------------------------------------------------------------- - * PARAM ITERATOR - * --- */ - -/** Deallocates ParamIterator object and associated resources. - * @param it ParamIterator instance - * @return int Error code - */ -int metkit_delete_paramiterator(const metkit_paramiterator_t* it); - -/** Moves to the next string element in ParamIterator - * @param it ParamIterator instance - * @return int Error code - */ -int metkit_paramiterator_next(metkit_paramiterator_t* it); - -/** Returns the current parameter name in ParamIterator - * @param it ParamIterator instance - * @param param current parameter name in iterator - * @return int Error code - */ -int metkit_paramiterator_param(metkit_paramiterator_t* it, const char** param); - #ifdef __cplusplus } #endif diff --git a/src/metkit/metkit_version.c.in b/src/metkit/metkit_version.c.in new file mode 100644 index 00000000..13b34cde --- /dev/null +++ b/src/metkit/metkit_version.c.in @@ -0,0 +1,19 @@ +#include "metkit_version.h" + +#ifdef __cplusplus +extern "C" { +#endif + +const char * metkit_version() { return metkit_VERSION; } + +unsigned int metkit_version_int() { + return 10000*metkit_VERSION_MAJOR + 100*metkit_VERSION_MINOR + 1*metkit_VERSION_PATCH; +} + +const char * metkit_version_str() { return metkit_VERSION_STR; } + +const char * metkit_git_sha1() { return "@metkit_GIT_SHA1@"; } + +#ifdef __cplusplus +} +#endif diff --git a/src/metkit/metkit_version.h.in b/src/metkit/metkit_version.h.in index 658a5be7..8d5d65b9 100644 --- a/src/metkit/metkit_version.h.in +++ b/src/metkit/metkit_version.h.in @@ -8,14 +8,22 @@ #define metkit_VERSION_MINOR @metkit_VERSION_MINOR@ #define metkit_VERSION_PATCH @metkit_VERSION_PATCH@ -inline const char * metkit_version() { return metkit_VERSION; } -inline unsigned int metkit_version_int() { - return 10000*metkit_VERSION_MAJOR + 100*metkit_VERSION_MINOR + 1*metkit_VERSION_PATCH; -} +#ifdef __cplusplus +extern "C" { +#endif + +const char * metkit_version(); + +unsigned int metkit_version_int(); -inline const char * metkit_version_str() { return metkit_VERSION_STR; } +const char * metkit_version_str(); + +const char * metkit_git_sha1(); + +#ifdef __cplusplus +} +#endif -inline const char * metkit_git_sha1() { return "@metkit_GIT_SHA1@"; } #endif // metkit_version_h diff --git a/tests/test_c_api.c b/tests/test_c_api.c index 977a965a..9ba93750 100644 --- a/tests/test_c_api.c +++ b/tests/test_c_api.c @@ -17,8 +17,7 @@ int main(int argc, char **argv) { - const char* version; - int errno = metkit_version(&version); + const char* version = metkit_version(); fprintf(stdout, "MetKit version: %s\n", version); diff --git a/tests/test_c_api.cc b/tests/test_c_api.cc index fa3e58b7..992aa571 100644 --- a/tests/test_c_api.cc +++ b/tests/test_c_api.cc @@ -79,28 +79,22 @@ CASE( "metkit_marsrequest" ) { EXPECT_STR_EQUAL(value, dates[i]); } - // all values - const char** values{}; - count = 0; - METKIT_TEST_C(metkit_marsrequest_values(request, "date", &values, &count)); - EXPECT_EQUAL(count, 3); - - for (size_t i = 0; i < count; i++) { - EXPECT_STR_EQUAL(values[i], dates[i]); - } - // ----------------------------------------------------------------- // Expand // ----------------------------------------------------------------- metkit_marsrequest_t* expandedRequest{}; METKIT_TEST_C(metkit_new_marsrequest(&expandedRequest)); - METKIT_TEST_C(metkit_marsrequest_expand(request, expandedRequest, false, true)); + METKIT_TEST_C(metkit_marsrequest_expand(request, false, true, expandedRequest)); // Check date expanded -1 -> yesterday - const char** dates_expanded{}; - METKIT_TEST_C(metkit_marsrequest_values(expandedRequest, "date", &dates_expanded, &count)); + METKIT_TEST_C(metkit_marsrequest_count_values(expandedRequest, "date", &count)); EXPECT_EQUAL(count, 3); + const char** dates_expanded = new const char*[count]; + for (size_t i = 0; i < count; i++) { + METKIT_TEST_C(metkit_marsrequest_value(expandedRequest, "date", i, &dates_expanded[i])); + } + EXPECT_STR_EQUAL(dates_expanded[2], std::to_string(eckit::Date(-1).yyyymmdd()).c_str()); // check param expanded 2t -> 167 const char* param{}; @@ -139,7 +133,7 @@ CASE( "metkit_requestiterator_t parsing" ) { METKIT_TEST_C(metkit_new_marsrequest(&request2)); metkit_requestiterator_t* it{}; - METKIT_TEST_C(metkit_parse_marsrequest("retrieve,date=-1,param=2t \n retrieve,date=20200102,param=2t,step=10/to/20/by/2", &it, true)); // two requests + METKIT_TEST_C(metkit_parse_marsrequests("retrieve,date=-1,param=2t \n retrieve,date=20200102,param=2t,step=10/to/20/by/2", &it, true)); // two requests METKIT_TEST_C(metkit_requestiterator_request(it, request0)); METKIT_TEST_C(metkit_requestiterator_next(it)); @@ -157,11 +151,13 @@ CASE( "metkit_requestiterator_t parsing" ) { EXPECT_STR_EQUAL(date, "20200102"); // Check steps have been parsed - const char** steps{}; size_t count = 0; - METKIT_TEST_C(metkit_marsrequest_values(request1, "step", &steps, &count)); + METKIT_TEST_C(metkit_marsrequest_count_values(request1, "step", &count)); + EXPECT_EQUAL(count, 6); for (size_t i = 0; i < count; i++) { - EXPECT_STR_EQUAL(steps[i], std::to_string(10 + i*2).c_str()); + const char* step{}; + METKIT_TEST_C(metkit_marsrequest_value(request1, "step", i, &step)); + EXPECT_STR_EQUAL(step, std::to_string(10 + i*2).c_str()); } } From 9938d6a45e03e1a1c0588039475efd19bcae47c5 Mon Sep 17 00:00:00 2001 From: Chris Bradley Date: Thu, 9 Jan 2025 17:56:15 +0000 Subject: [PATCH 13/13] Return metkit_error_t instead of int on C API --- src/metkit/api/metkit_c.cc | 82 +++++++++++++++++++------------------- src/metkit/api/metkit_c.h | 74 +++++++++++++++++----------------- tests/test_c_api.c | 2 + 3 files changed, 80 insertions(+), 78 deletions(-) diff --git a/src/metkit/api/metkit_c.cc b/src/metkit/api/metkit_c.cc index e1390990..8577aded 100644 --- a/src/metkit/api/metkit_c.cc +++ b/src/metkit/api/metkit_c.cc @@ -42,7 +42,7 @@ struct metkit_requestiterator_t { static thread_local std::string g_current_error_string; -const char* metkit_get_error_string(enum metkit_error_values_t err) { +const char* metkit_get_error_string(metkit_error_t err) { switch (err) { case METKIT_SUCCESS: return "Success"; @@ -57,19 +57,19 @@ const char* metkit_get_error_string(enum metkit_error_values_t err) { } } -int innerWrapFn(std::function f) { - return f(); +metkit_error_t innerWrapFn(std::function f) { + return static_cast(f()); } -int innerWrapFn(std::function f) { +metkit_error_t innerWrapFn(std::function f) { f(); return METKIT_SUCCESS; } template -[[nodiscard]] int tryCatch(FN&& fn) { +[[nodiscard]] metkit_error_t tryCatchEnum(FN&& fn) { try { - return innerWrapFn(fn); + return innerWrapFn(std::forward(fn)); } catch (const eckit::UserError& e) { g_current_error_string = e.what(); @@ -96,8 +96,8 @@ template // HELPERS // ----------------------------------------------------------------------------- -int metkit_initialise() { - return tryCatch([] { +metkit_error_t metkit_initialise() { + return tryCatchEnum([] { static bool initialised = false; if (initialised) { @@ -117,8 +117,8 @@ int metkit_initialise() { // PARSING // ----------------------------------------------------------------------------- -int metkit_parse_marsrequests(const char* str, metkit_requestiterator_t** requests, bool strict) { - return tryCatch([requests, str, strict] { +metkit_error_t metkit_parse_marsrequests(const char* str, metkit_requestiterator_t** requests, bool strict) { + return tryCatchEnum([requests, str, strict] { ASSERT(requests); ASSERT(str); std::istringstream in(str); @@ -130,21 +130,21 @@ int metkit_parse_marsrequests(const char* str, metkit_requestiterator_t** reques // REQUEST // ----------------------------------------------------------------------------- -int metkit_new_marsrequest(metkit_marsrequest_t** request) { - return tryCatch([request] { +metkit_error_t metkit_new_marsrequest(metkit_marsrequest_t** request) { + return tryCatchEnum([request] { ASSERT(request); *request = new metkit_marsrequest_t(); }); } -int metkit_delete_marsrequest(const metkit_marsrequest_t* request) { - return tryCatch([request] { +metkit_error_t metkit_delete_marsrequest(const metkit_marsrequest_t* request) { + return tryCatchEnum([request] { delete request; }); } -int metkit_marsrequest_set(metkit_marsrequest_t* request, const char* param, const char* values[], int numValues) { - return tryCatch([request, param, values, numValues] { +metkit_error_t metkit_marsrequest_set(metkit_marsrequest_t* request, const char* param, const char* values[], int numValues) { + return tryCatchEnum([request, param, values, numValues] { ASSERT(request); ASSERT(param); ASSERT(values); @@ -157,28 +157,28 @@ int metkit_marsrequest_set(metkit_marsrequest_t* request, const char* param, con }); } -int metkit_marsrequest_set_one(metkit_marsrequest_t* request, const char* param, const char* value) { +metkit_error_t metkit_marsrequest_set_one(metkit_marsrequest_t* request, const char* param, const char* value) { return metkit_marsrequest_set(request, param, &value, 1); } -int metkit_marsrequest_set_verb(metkit_marsrequest_t* request, const char* verb) { - return tryCatch([request, verb] { +metkit_error_t metkit_marsrequest_set_verb(metkit_marsrequest_t* request, const char* verb) { + return tryCatchEnum([request, verb] { ASSERT(request); ASSERT(verb); request->verb(verb); }); } -int metkit_marsrequest_verb(const metkit_marsrequest_t* request, const char** verb) { - return tryCatch([request, verb] { +metkit_error_t metkit_marsrequest_verb(const metkit_marsrequest_t* request, const char** verb) { + return tryCatchEnum([request, verb] { ASSERT(request); ASSERT(verb); *verb = request->verb().c_str(); }); } -int metkit_marsrequest_has_param(const metkit_marsrequest_t* request, const char* param, bool* has) { - return tryCatch([request, param, has] { +metkit_error_t metkit_marsrequest_has_param(const metkit_marsrequest_t* request, const char* param, bool* has) { + return tryCatchEnum([request, param, has] { ASSERT(request); ASSERT(param); ASSERT(has); @@ -186,24 +186,24 @@ int metkit_marsrequest_has_param(const metkit_marsrequest_t* request, const char }); } -int metkit_marsrequest_count_params(const metkit_marsrequest_t* request, size_t* count) { - return tryCatch([request, count] { +metkit_error_t metkit_marsrequest_count_params(const metkit_marsrequest_t* request, size_t* count) { + return tryCatchEnum([request, count] { ASSERT(request); ASSERT(count); *count = request->params().size(); }); } -int metkit_marsrequest_param(const metkit_marsrequest_t* request, size_t index, const char** param) { - return tryCatch([request, index, param] { +metkit_error_t metkit_marsrequest_param(const metkit_marsrequest_t* request, size_t index, const char** param) { + return tryCatchEnum([request, index, param] { ASSERT(request); ASSERT(param); *param = request->params()[index].c_str(); }); } -int metkit_marsrequest_count_values(const metkit_marsrequest_t* request, const char* param, size_t* count) { - return tryCatch([request, param, count] { +metkit_error_t metkit_marsrequest_count_values(const metkit_marsrequest_t* request, const char* param, size_t* count) { + return tryCatchEnum([request, param, count] { ASSERT(request); ASSERT(param); ASSERT(count); @@ -211,16 +211,16 @@ int metkit_marsrequest_count_values(const metkit_marsrequest_t* request, const c }); } -int metkit_marsrequest_value(const metkit_marsrequest_t* request, const char* param, int index, const char** value) { - return tryCatch([request, param, index, value] { +metkit_error_t metkit_marsrequest_value(const metkit_marsrequest_t* request, const char* param, int index, const char** value) { + return tryCatchEnum([request, param, index, value] { ASSERT(request); ASSERT(param); ASSERT(value); *value = request->values(param, false)[index].c_str(); }); } -int metkit_marsrequest_expand(const metkit_marsrequest_t* request, bool inherit, bool strict, metkit_marsrequest_t* expandedRequest) { - return tryCatch([request, expandedRequest, inherit, strict] { +metkit_error_t metkit_marsrequest_expand(const metkit_marsrequest_t* request, bool inherit, bool strict, metkit_marsrequest_t* expandedRequest) { + return tryCatchEnum([request, expandedRequest, inherit, strict] { ASSERT(request); ASSERT(expandedRequest); ASSERT(expandedRequest->empty()); @@ -229,8 +229,8 @@ int metkit_marsrequest_expand(const metkit_marsrequest_t* request, bool inherit, }); } -int metkit_marsrequest_merge(metkit_marsrequest_t* request, const metkit_marsrequest_t* otherRequest) { - return tryCatch([request, otherRequest] { +metkit_error_t metkit_marsrequest_merge(metkit_marsrequest_t* request, const metkit_marsrequest_t* otherRequest) { + return tryCatchEnum([request, otherRequest] { ASSERT(request); ASSERT(otherRequest); request->merge(*otherRequest); @@ -241,21 +241,21 @@ int metkit_marsrequest_merge(metkit_marsrequest_t* request, const metkit_marsreq // REQUEST ITERATOR // ----------------------------------------------------------------------------- -int metkit_delete_requestiterator(const metkit_requestiterator_t* it) { - return tryCatch([it] { +metkit_error_t metkit_delete_requestiterator(const metkit_requestiterator_t* it) { + return tryCatchEnum([it] { delete it; }); } -int metkit_requestiterator_next(metkit_requestiterator_t* it) { - return tryCatch(std::function{[it] { +metkit_error_t metkit_requestiterator_next(metkit_requestiterator_t* it) { + return tryCatchEnum(std::function{[it] { ASSERT(it); return it->next(); }}); } -int metkit_requestiterator_request(metkit_requestiterator_t* it, metkit_marsrequest_t* request) { - return tryCatch([it, request] { +metkit_error_t metkit_requestiterator_request(metkit_requestiterator_t* it, metkit_marsrequest_t* request) { + return tryCatchEnum([it, request] { ASSERT(it); ASSERT(request); ASSERT(request->empty()); diff --git a/src/metkit/api/metkit_c.h b/src/metkit/api/metkit_c.h index 40b29554..35af1ebe 100644 --- a/src/metkit/api/metkit_c.h +++ b/src/metkit/api/metkit_c.h @@ -34,7 +34,7 @@ typedef enum metkit_error_values_t METKIT_ERROR_UNKNOWN = 3, /* Failed with an unknown error. */ METKIT_ERROR_USER = 4, /* Failed with an user error. */ METKIT_ERROR_ASSERT = 5 /* Failed with an assert() */ -} metkit_error_enum_t; +} metkit_error_t; const char* metkit_get_error_string(enum metkit_error_values_t err); @@ -61,9 +61,9 @@ const char* metkit_git_sha1(); * * @note This is ONLY required when Main() is NOT initialised, such as loading * the MetKit as shared library in Python. - * @return int Error code + * @return metkit_error_t Error code */ -int metkit_initialise(); +metkit_error_t metkit_initialise(); /* --------------------------------------------------------------------------------------------------------------------- * PARSING @@ -74,9 +74,9 @@ int metkit_initialise(); * must be deallocated with metkit_delete_requestiterator * @param str MARS requests * @param[out] requests Allocates RequestIterator object - * @return int Error code + * @return metkit_error_t Error code */ -int metkit_parse_marsrequests(const char* str, metkit_requestiterator_t** requests, bool strict); +metkit_error_t metkit_parse_marsrequests(const char* str, metkit_requestiterator_t** requests, bool strict); /* --------------------------------------------------------------------------------------------------------------------- * REQUEST @@ -84,104 +84,104 @@ int metkit_parse_marsrequests(const char* str, metkit_requestiterator_t** reques /** Allocates new Request object. Must be deallocated with mekit_delete_request * @param[out] request new Request instance - * @return int Error code + * @return metkit_error_t Error code */ -int metkit_new_marsrequest(metkit_marsrequest_t** request); +metkit_error_t metkit_new_marsrequest(metkit_marsrequest_t** request); /** Deallocates Request object and associated resources. * @param request Request instance - * @return int Error code + * @return metkit_error_t Error code */ -int metkit_delete_marsrequest(const metkit_marsrequest_t* request); +metkit_error_t metkit_delete_marsrequest(const metkit_marsrequest_t* request); /** Add parameter and values to request * @param request Request instance * @param param parameter name * @param values array of values for parameter * @param numValues number of values - * @return int Error code + * @return metkit_error_t Error code */ -int metkit_marsrequest_set(metkit_marsrequest_t* request, const char* param, const char* values[], int numValues); +metkit_error_t metkit_marsrequest_set(metkit_marsrequest_t* request, const char* param, const char* values[], int numValues); /** Add parameter and values to request * @param request Request instance * @param param parameter name * @param values value to add - * @return int Error code + * @return metkit_error_t Error code */ -int metkit_marsrequest_set_one(metkit_marsrequest_t* request, const char* param, const char* value); +metkit_error_t metkit_marsrequest_set_one(metkit_marsrequest_t* request, const char* param, const char* value); /** Set verb in Request object * @param request Request instance * @param verb verb to set - * @return int Error code + * @return metkit_error_t Error code */ -int metkit_marsrequest_set_verb(metkit_marsrequest_t* request, const char* verb); +metkit_error_t metkit_marsrequest_set_verb(metkit_marsrequest_t* request, const char* verb); /** Returns the verb in Request object * @param request Request instance * @param[out] verb verb in request - * @return int Error code + * @return metkit_error_t Error code */ -int metkit_marsrequest_verb(const metkit_marsrequest_t* request, const char** verb); +metkit_error_t metkit_marsrequest_verb(const metkit_marsrequest_t* request, const char** verb); /** Returns whether parameter is in Request object * @param request Request instance * @param param parameter name * @param[out] has whether parameter exists in request - * @return int Error code + * @return metkit_error_t Error code */ -int metkit_marsrequest_has_param(const metkit_marsrequest_t* request, const char* param, bool* has); +metkit_error_t metkit_marsrequest_has_param(const metkit_marsrequest_t* request, const char* param, bool* has); /** Returns number of parameters in Request object * @param request Request instance * @param[out] count number of parameters in request - * @return int Error code + * @return metkit_error_t Error code */ -int metkit_marsrequest_count_params(const metkit_marsrequest_t* request, size_t* count); +metkit_error_t metkit_marsrequest_count_params(const metkit_marsrequest_t* request, size_t* count); /** Returns parameter name for specific index in Request object * @param request Request instance * @param index index of parameter to retrieve * @param[out] param parameter name - * @return int Error code + * @return metkit_error_t Error code */ -int metkit_marsrequest_param(const metkit_marsrequest_t* request, size_t index, const char** param); +metkit_error_t metkit_marsrequest_param(const metkit_marsrequest_t* request, size_t index, const char** param); /** Returns number of values for specific parameter in Request object * @param request Request instance * @param param parameter name in request * @param[out] count number of values for param in request - * @return int Error code + * @return metkit_error_t Error code */ -int metkit_marsrequest_count_values(const metkit_marsrequest_t* request, const char* param, size_t* count); +metkit_error_t metkit_marsrequest_count_values(const metkit_marsrequest_t* request, const char* param, size_t* count); /** Returns value for specific parameter and index in Request object * @param request Request instance * @param param parameter name in request * @param index index of value to retrieve for param in request * @param[out] value retrieved value - * @return int Error code + * @return metkit_error_t Error code */ -int metkit_marsrequest_value(const metkit_marsrequest_t* request, const char* param, int index, const char** value); +metkit_error_t metkit_marsrequest_value(const metkit_marsrequest_t* request, const char* param, int index, const char** value); /** Populates empty Request object by expanding existing request * @param request Request instance to be expanded * @param inherit if true, populate expanded request with default values * @param strict it true, raise error rather than warning on invalid values * @param[out] expandedRequest empty Request instance to be populated - * @return int Error code + * @return metkit_error_t Error code */ -int metkit_marsrequest_expand(const metkit_marsrequest_t* request, bool inherit, bool strict, metkit_marsrequest_t* expandedRequest); +metkit_error_t metkit_marsrequest_expand(const metkit_marsrequest_t* request, bool inherit, bool strict, metkit_marsrequest_t* expandedRequest); /** Merges other Request object into existing request * @param request Request instance to contain result of merge * @param otherRequest other Request instance to merge - * @return int Error code + * @return metkit_error_t Error code */ -int metkit_marsrequest_merge(metkit_marsrequest_t* request, const metkit_marsrequest_t* otherRequest); +metkit_error_t metkit_marsrequest_merge(metkit_marsrequest_t* request, const metkit_marsrequest_t* otherRequest); /* --------------------------------------------------------------------------------------------------------------------- * REQUEST ITERATOR @@ -189,22 +189,22 @@ int metkit_marsrequest_merge(metkit_marsrequest_t* request, const metkit_marsreq /** Deallocates RequestIterator object and associated resources. * @param it RequestIterator instance - * @return int Error code + * @return metkit_error_t Error code */ -int metkit_delete_requestiterator(const metkit_requestiterator_t* it); +metkit_error_t metkit_delete_requestiterator(const metkit_requestiterator_t* it); /** Moves to the next Request element in RequestIterator * @param it RequestIterator instance - * @return int Error code + * @return metkit_error_t Error code */ -int metkit_requestiterator_next(metkit_requestiterator_t* it); +metkit_error_t metkit_requestiterator_next(metkit_requestiterator_t* it); /** Populates empty Requestion object with data from current element in RequestIterator * @param it RequestIterator instance * @param request empty Request instance to populate with data - * @return int Error code + * @return metkit_error_t Error code */ -int metkit_requestiterator_request(metkit_requestiterator_t* it, metkit_marsrequest_t* request); +metkit_error_t metkit_requestiterator_request(metkit_requestiterator_t* it, metkit_marsrequest_t* request); #ifdef __cplusplus } diff --git a/tests/test_c_api.c b/tests/test_c_api.c index 9ba93750..d15dd508 100644 --- a/tests/test_c_api.c +++ b/tests/test_c_api.c @@ -19,6 +19,8 @@ int main(int argc, char **argv) { const char* version = metkit_version(); + metkit_error_t err = metkit_initialise(); + fprintf(stdout, "MetKit version: %s\n", version); return 0;