-
Notifications
You must be signed in to change notification settings - Fork 9
Feature/c api #57
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
Changes from 12 commits
53d5324
5bdb1e1
e7523ae
9a2313d
8549509
d066c18
1b03851
3907511
e050cd5
fd1d8b1
bf9f488
1b324a3
0c20677
9938d6a
18562ae
a080058
5acf662
8fd70d0
eac030c
5fe7179
3597d60
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,341 @@ | ||
#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_; | ||
}; | ||
|
||
/// @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. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here the comment is lacking some words. Do this need to be addressed before merging? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. a todo left for me by me |
||
struct metkit_paramiterator_t { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Lifetimes of returned values in this iterator differ from the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I initially resolved this by simply getting rid of the paramiterator. But it turns out it's not so straight forward as the C++ marsrequest object does not provide a nice way to iterate over the params so I need to revisit this. |
||
explicit metkit_paramiterator_t(std::vector<std::string> 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<std::string> vector_; | ||
std::vector<std::string>::iterator iterator_; | ||
}; | ||
|
||
// --------------------------------------------------------------------------------------------------------------------- | ||
// ERROR HANDLING | ||
|
||
static thread_local std::string g_current_error_string; | ||
ChrisspyB marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
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 "<unknown>"; | ||
} | ||
} | ||
|
||
int innerWrapFn(std::function<int()> f) { | ||
return f(); | ||
} | ||
|
||
int innerWrapFn(std::function<void()> f) { | ||
f(); | ||
return METKIT_SUCCESS; | ||
} | ||
|
||
template <typename FN> | ||
[[nodiscard]] int tryCatch(FN&& fn) { | ||
try { | ||
return innerWrapFn(fn); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should probably contain an std::forward? |
||
} | ||
catch (const eckit::UserError& e) { | ||
eckit::Log::error() << "User Error: " << e.what() << std::endl; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Streams and the usage of std::endl can be problematic. In case of being unbuffered or line buffered this is fine. In case of a more sophisticated buffering strategy this can lead to additional effort. |
||
g_current_error_string = e.what(); | ||
return METKIT_ERROR_USER; | ||
} | ||
catch (const eckit::AssertionFailed& e) { | ||
eckit::Log::error() << "Assertion Failed: " << e.what() << std::endl; | ||
ChrisspyB marked this conversation as resolved.
Show resolved
Hide resolved
|
||
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; | ||
} | ||
} | ||
|
||
// ----------------------------------------------------------------------------- | ||
// 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; | ||
} | ||
ChrisspyB marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
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}; | ||
ChrisspyB marked this conversation as resolved.
Show resolved
Hide resolved
|
||
eckit::Main::initialise(1, const_cast<char**>(argv)); | ||
initialised = true; | ||
} | ||
}); | ||
} | ||
|
||
// ----------------------------------------------------------------------------- | ||
// PARSING | ||
// ----------------------------------------------------------------------------- | ||
|
||
int metkit_parse_marsrequest(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, strict)); | ||
}); | ||
} | ||
|
||
// ----------------------------------------------------------------------------- | ||
// REQUEST | ||
// ----------------------------------------------------------------------------- | ||
|
||
int metkit_new_marsrequest(metkit_marsrequest_t** request) { | ||
return tryCatch([request] { | ||
ASSERT(request); | ||
*request = new metkit_marsrequest_t(); | ||
}); | ||
} | ||
|
||
int metkit_delete_marsrequest(const metkit_marsrequest_t* request) { | ||
return tryCatch([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] { | ||
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); | ||
}); | ||
} | ||
|
||
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) { | ||
return tryCatch([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] { | ||
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] { | ||
ASSERT(request); | ||
ASSERT(param); | ||
ASSERT(has); | ||
*has = request->has(param); | ||
}); | ||
} | ||
|
||
int metkit_marsrequest_params(const metkit_marsrequest_t* request, metkit_paramiterator_t** params) { | ||
return tryCatch([request, params] { | ||
ASSERT(request); | ||
ASSERT(params); | ||
*params = new metkit_paramiterator_t(request->params()); | ||
}); | ||
} | ||
|
||
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); | ||
ASSERT(count); | ||
*count = request->countValues(param); | ||
}); | ||
} | ||
|
||
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); | ||
ASSERT(value); | ||
*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<std::string>& 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) { | ||
return tryCatch([request, expandedRequest, inherit, strict] { | ||
ASSERT(request); | ||
ASSERT(expandedRequest); | ||
ASSERT(expandedRequest->empty()); | ||
metkit::mars::MarsExpension expand(inherit, strict); | ||
*expandedRequest = expand.expand(*request); | ||
}); | ||
} | ||
|
||
int metkit_marsrequest_merge(metkit_marsrequest_t* request, const metkit_marsrequest_t* otherRequest) { | ||
return tryCatch([request, otherRequest] { | ||
ASSERT(request); | ||
ASSERT(otherRequest); | ||
request->merge(*otherRequest); | ||
}); | ||
} | ||
|
||
// ----------------------------------------------------------------------------- | ||
// REQUEST ITERATOR | ||
// ----------------------------------------------------------------------------- | ||
|
||
int metkit_delete_requestiterator(const metkit_requestiterator_t* it) { | ||
return tryCatch([it] { | ||
delete it; | ||
}); | ||
} | ||
|
||
int metkit_requestiterator_next(metkit_requestiterator_t* it) { | ||
return tryCatch(std::function<int()>{[it] { | ||
ASSERT(it); | ||
return it->next(); | ||
}}); | ||
} | ||
|
||
int metkit_requestiterator_request(metkit_requestiterator_t* it, metkit_marsrequest_t* request) { | ||
return tryCatch([it, request] { | ||
ASSERT(it); | ||
ASSERT(request); | ||
ASSERT(request->empty()); | ||
|
||
it->current(request); | ||
}); | ||
} | ||
|
||
// ----------------------------------------------------------------------------- | ||
// 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<int()>{[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); | ||
}); | ||
} | ||
|
||
|
||
// --------------------------------------------------------------------------------------------------------------------- |
Uh oh!
There was an error while loading. Please reload this page.