Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/c api #57

Open
wants to merge 14 commits into
base: develop
Choose a base branch
from
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
6 changes: 4 additions & 2 deletions src/metkit/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +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.cc.in metkit_version.cc )
configure_file( metkit_version.c.in ${CMAKE_CURRENT_BINARY_DIR}/metkit_version.c )

install(FILES
${CMAKE_CURRENT_BINARY_DIR}/metkit_config.h
Expand All @@ -15,7 +15,7 @@ install(FILES
### metkit sources

list( APPEND metkit_srcs
${CMAKE_CURRENT_BINARY_DIR}/metkit_version.cc
${CMAKE_CURRENT_BINARY_DIR}/metkit_version.c
config/LibMetkit.cc
config/LibMetkit.h
mars/BaseProtocol.cc
Expand Down Expand Up @@ -100,6 +100,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
Expand Down
267 changes: 267 additions & 0 deletions src/metkit/api/metkit_c.cc
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Todo: Ensure we cover all functionality currently in fdb_c so that we can replace it with this.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good so far. The functionality of the pyfdb is the following:

struct fdb_request_t;
typedef struct fdb_request_t fdb_request_t;
int fdb_new_request(fdb_request_t** req);
int fdb_request_add(fdb_request_t* req, const char* param, const char* values[], int numValues);
int fdb_expand_request(fdb_request_t* req);
int fdb_delete_request(fdb_request_t* req);

Those are all contained in the request section. Do we need anything on top @ChrisspyB?

Original file line number Diff line number Diff line change
@@ -0,0 +1,267 @@
#include "metkit_c.h"
#include "metkit/mars/MarsExpension.h"
#include "metkit/mars/MarsRequest.h"
#include "metkit/metkit_version.h"
#include "eckit/runtime/Main.h"
#include <functional>

// ---------------------------------------------------------------------------------------------------------------------

struct metkit_marsrequest_t : public metkit::mars::MarsRequest {
using metkit::mars::MarsRequest::MarsRequest;

metkit_marsrequest_t(metkit::mars::MarsRequest&& req) :
metkit::mars::MarsRequest(std::move(req)) {}
};

struct metkit_requestiterator_t {
explicit metkit_requestiterator_t(std::vector<metkit::mars::MarsRequest>&& 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(metkit_marsrequest_t* request) {
ASSERT(iterator_ != vector_.end());
*request = std::move(*iterator_);
}

private:

std::vector<metkit::mars::MarsRequest> vector_;
std::vector<metkit::mars::MarsRequest>::iterator iterator_;
};

// ---------------------------------------------------------------------------------------------------------------------
// ERROR HANDLING

static thread_local std::string g_current_error_string;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is read-only, isn't it? Make it const.


const char* metkit_get_error_string(metkit_error_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 "<unknown>";
}
}

metkit_error_t innerWrapFn(std::function<int()> f) {
return static_cast<metkit_error_t>(f());
}

metkit_error_t innerWrapFn(std::function<void()> f) {
f();
return METKIT_SUCCESS;
}

template <typename FN>
[[nodiscard]] metkit_error_t tryCatchEnum(FN&& fn) {
try {
return innerWrapFn(std::forward<FN>(fn));
}
catch (const eckit::UserError& e) {
g_current_error_string = e.what();
return METKIT_ERROR_USER;
}
catch (const eckit::AssertionFailed& e) {
g_current_error_string = e.what();
return METKIT_ERROR_ASSERT;
}
catch (const eckit::Exception& e) {
g_current_error_string = e.what();
return METKIT_ERROR;
}
catch (const std::exception& e) {
g_current_error_string = e.what();
return METKIT_ERROR_UNKNOWN;
}
catch (...) {
return METKIT_ERROR_UNKNOWN;
}
}

// -----------------------------------------------------------------------------
// HELPERS
// -----------------------------------------------------------------------------

metkit_error_t metkit_initialise() {
return tryCatchEnum([] {
static bool initialised = false;

if (initialised) {
eckit::Log::warning()
<< "Initialising Metkit library twice" << std::endl;
}

if (!initialised) {
const char* argv[2] = {"metkit-api", 0};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nullptr instead of 0. Why is this const if a line below the const-cast takes place?

eckit::Main::initialise(1, const_cast<char**>(argv));
initialised = true;
}
});
}

// -----------------------------------------------------------------------------
// PARSING
// -----------------------------------------------------------------------------

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);
*requests = new metkit_requestiterator_t(metkit::mars::MarsRequest::parse(in, strict));
});
}

// -----------------------------------------------------------------------------
// REQUEST
// -----------------------------------------------------------------------------

metkit_error_t metkit_new_marsrequest(metkit_marsrequest_t** request) {
return tryCatchEnum([request] {
ASSERT(request);
*request = new metkit_marsrequest_t();
});
}

metkit_error_t metkit_delete_marsrequest(const metkit_marsrequest_t* request) {
return tryCatchEnum([request] {
delete request;
});
}

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);
std::string param_str(param);
std::vector<std::string> values_vec;
values_vec.reserve(numValues);
std::copy(values, values + numValues, std::back_inserter(values_vec));

request->values(param_str, values_vec);
});
}

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);
}

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);
});
}

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();
});
}

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);
*has = request->has(param);
});
}

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();
});
}

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();
});
}

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);
*count = request->countValues(param);
});
}

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();
});
}
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());
metkit::mars::MarsExpension expand(inherit, strict);
*expandedRequest = expand.expand(*request);
});
}

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);
});
}

// -----------------------------------------------------------------------------
// REQUEST ITERATOR
// -----------------------------------------------------------------------------

metkit_error_t metkit_delete_requestiterator(const metkit_requestiterator_t* it) {
return tryCatchEnum([it] {
delete it;
});
}

metkit_error_t metkit_requestiterator_next(metkit_requestiterator_t* it) {
return tryCatchEnum(std::function<int()>{[it] {
ASSERT(it);
return it->next();
}});
}

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());

it->current(request);
});
}

// ---------------------------------------------------------------------------------------------------------------------
Loading
Loading