GStreamer GError to boost::system::error_code? - c++

Looking for a clever way to transform a gstreamer/glib GError:
struct GError {
GQuark domain;
gint code;
gchar* message;
};
to a boost::system::error_code. Typically, you could create a category and register an enum to boost. GStreamer uses enum but the code is returned as an int. GQuark is a category.
This is mainly to standardize error handling across an application.

GQuark is a category.
I think you mean that figuratively.
Quarks are associations between strings and integer identifiers. Given either the string or the Quark identifier it is possible to retrieve the other.
That's like interned strings, aka atoms. So GQuark actually represents a string, then, that you want to treat as a category. Well then.
Categories are static
Well. Usually. At the very least categories are singleton with global object identity. So, assuming that you know statically what domains to expect, you could create categories for those.
Map them to the text representation of the domain makes for the most stable mappings.
A single category
To get started, here's a single category:
using boost::system::error_code;
using boost::system::error_condition;
enum class MyCoreError {
failed, // a general error which doesn't fit in any other category. Make sure you add a custom message to the error call.
too_lazy, // do not use this except as a placeholder for deciding where to go while developing code.
not_implemented, // use this when you do not want to implement this functionality yet.
state_change, // used for state change errors.
pad, // used for pad-related errors.
thread, // used for thread-related errors.
negotiation, // used for negotiation-related errors.
event, // used for event-related errors.
seek, // used for seek-related errors.
caps, // used for caps-related errors.
tag, // used for negotiation-related errors.
missing_plugin, // used if a plugin is missing.
clock, // used for clock related errors.
disabled, // used if functionality has been disabled at compile time.
num_errors, // the number of core error types.
};
namespace boost::system { template<> struct is_error_code_enum<MyCoreError> : std::true_type {}; }
namespace detail {
class my_core_category : public boost::system::error_category {
public:
const char* name() const noexcept override {
return g_quark_to_string(GST_CORE_ERROR);
}
std::string message(int ev) const override {
switch (static_cast<MyCoreError>(ev)) {
case MyCoreError::failed: return "a general error which doesn't fit in any other category. Make sure you add a custom message to the error call.";
case MyCoreError::too_lazy: return "do not use this except as a placeholder for deciding where to go while developing code.";
case MyCoreError::not_implemented: return "use this when you do not want to implement this functionality yet.";
case MyCoreError::state_change: return "used for state change errors.";
case MyCoreError::pad: return "used for pad-related errors.";
case MyCoreError::thread: return "used for thread-related errors.";
case MyCoreError::negotiation: return "used for negotiation-related errors.";
case MyCoreError::event: return "used for event-related errors.";
case MyCoreError::seek: return "used for seek-related errors.";
case MyCoreError::caps: return "used for caps-related errors.";
case MyCoreError::tag: return "used for negotiation-related errors.";
case MyCoreError::missing_plugin: return "used if a plugin is missing.";
case MyCoreError::clock: return "used for clock related errors.";
case MyCoreError::disabled: return "used if functionality has been disabled at compile time.";
case MyCoreError::num_errors: return "the number of core error types.";
default: return "unknown core error";
}
}
error_condition default_error_condition(int ev) const noexcept override {
return error_condition{ ev, *this };
}
bool equivalent(int ev, error_condition const& condition) const noexcept override {
return condition.value() == ev && &condition.category() == this;
}
bool equivalent(error_code const& error, int ev) const noexcept override {
return error.value() == ev && &error.category() == this;
}
};
}
error_code make_error_code(MyCoreError se)
{
static detail::my_core_category const cat{};
return error_code{static_cast<std::underlying_type<MyCoreError>::type>(se), cat};
}
Now you can just
auto code = MyCoreError::missing_plugin;
throw boost::system::system_error(make_error_code(code));
and it will magically do the right thing.
General Error Translation:
For the general case translating from API error:
boost::system::error_code make_error_code(GError const& err) {
if (err.domain == GST_CORE_ERROR) {
return make_error_code(MyCoreError(err.code));
}
if (err.domain == GST_LIBRARY_ERROR) {
return make_error_code(MyLibraryError(err.code));
}
if (err.domain == GST_RESOURCE_ERROR) {
return make_error_code(MyResourceError(err.code));
}
if (err.domain == GST_STREAM_ERROR) {
return make_error_code(MyStreamError(err.code));
}
// decide on how to represent unknown errors? Just throw, or translate into
// MyCoreError::failed?
}

Related

Bitwise comparing NaN's in C++

I have a function that returns a double. Any real number is a valid output. I'm using nan's to signal errors. I am error checking this way.
double foo();
const auto error1 = std::nan("1");
const auto error2 = std::nan("2");
const auto error3 = std::nan("3");
bool bit_equal(double d1, double d2) {
return *reinterpret_cast<long long*>(&d1) == *reinterpret_cast<long long*>(&d2);
}
const auto value = foo();
if(std::isnan(value)) {
if (bit_equal(value, error1)) /*handle error1*/;
else if (bit_equal(value, error1)) /*handle error2*/;
else if (bit_equal(value, error1)) /*handle error3*/;
else /*handle default error*/;
} else /*use value normally*/;
Alternatively, if the compiler support has caught up, I can write it this way
double foo();
constexpr auto error1 = std::nan("1");
constexpr auto error2 = std::nan("2");
constexpr auto error3 = std::nan("3");
constexpr bool bit_equal(double d1, double d2) {
return std::bit_cast<long long>(d1) == std::bit_cast<long long>(d2);
}
const auto value = foo();
if(std::isnan(value)) {
if (bit_equal(value, error1)) /*handle error1*/;
else if (bit_equal(value, error1)) /*handle error2*/;
else if (bit_equal(value, error1)) /*handle error3*/;
else /*handle default error*/;
} else /*use value normally*/;
Or even
double foo();
constexpr auto error1 = std::bit_cast<long long>(std::nan("1"));
constexpr auto error2 = std::bit_cast<long long>(std::nan("2"));
constexpr auto error3 = std::bit_cast<long long>(std::nan("3"));
const auto value = foo();
if(std::isnan(value)) {
switch(std::bit_cast<long long>(value)) {
case error1: /*handle error1*/; break;
case error1: /*handle error2*/; break;
case error1: /*handle error3*/; break;
default: /*handle default error*/;
}
} else /*use value normally*/;
I have to do this because comparing nan's with == always returns false.
Is there a standard function to perform this comparison in C++?
Are any of these 3 alternatives better than the others? Although the last option seems the most succinct, it requires me to do return std::bit_cast<double>(error1); inside foo() rather than just return error1;.
Is there a better design where I can avoid using nan as an error value?
Is there a better design where I can avoid using nan as an error value?
Yes.
Throw an exception.
Use a struct (or tuple, not really) as return value
Use an out ref parameter
Since there are better alternatives, I don't think it's worth answering question 1. and 2.
NaN error signaling
Returning NaNs as error indicators is certainly a valid design choice. If you write numeric code, I'm sure you will find many people who get annoyed when you throw exceptions on any invalid input instead of letting the error propagate through NaNs. "When in Rome, speak like the Romans", right? When in math, speak like the math.h functions ;-)
(Of course this depends on your use case and the expectations of your API users)
However, NaN payloads aren't that good. Using them as an error "hint" may work for you, so you can look at the payload in a data dump and find out where it came from. But as you certainly have noticed, there is no predefined inverse to nan(const char*). Also, NaN payloads tend not to propagate well. For example, while most math functions will return a NaN when they received a NaN input, they will give you a new one without the payload.
There is a good article by agner.org talking about this very topic: Floating point exception tracking and NAN propagation
My personal recommendation would be:
Keep returning NaN on error because it is fast to check
Keep using payloads as error hints
Use a different mechanism to signal the specific type of error
Alternative mechanisms
Options that come to mind:
Exceptions. Maybe paired up with a non-throwing variant for users that are content with just a NaN
double foo();
double foo(std::nothrow_t) noexcept;
double bar()
{
try {
double x = foo();
} except(const std::domain_error&) {
error();
}
double y;
if(std::isnan(y = foo(std::nothrow)))
error();
}
Optional error code or struct output argument: double foo(Error* error=nullptr). After the call, check for NaN. If NaN, read exact error from error struct. If the user is not interested in the exact error, they don't pass a struct to begin with
struct Error
{
int errcode;
operator bool() const noexcept
{ return errcode; }
/** throw std::domain_error with error message */
[[noreturn]] void raise() const;
void check() const
{
if(errcode)
raise();
}
}
double foo(Error* err=nullptr) noexcept;
double bar()
{
Error err;
double x;
x = foo(); // just continue on NaN
if(std::isnan(x = foo()))
return x; // abort without error explanation
if(std::isnan(x = foo(&err)))
err.raise(); // raise exception
return x;
}
std::variant<double, Error> return value. In my opinion the API is not well suited for this; too verbose. This will be fixed in C++23 with std::expected. Also less efficient because the data will likely be returned on the stack
std::pair<double, Error>. If the Error type is a simple struct without a destructor and with a maximum size of 8 byte or a primitive type (so it can be returned in a register), this will be very efficient and it is also easy to check. Building your own custom pair-like type that offers some convenience methods like get_result_or_throw_error() is also possible.
template<class T>
struct Result
{
T result;
Error err;
Result() = default;
explicit constexpr Result(T result) noexcept
: result(result),
err() // set to 0
{}
explicit constexpr Result(Error err, T result=NAN) noexcept
: result(result),
err(err)
{}
operator bool() const noexcept
{ return err; }
T check() const
{
err.check(); // may throw
return result;
}
bool unpack(T& out) const noexcept
{
if(err)
return false;
out = result;
return true;
}
};
Result<double> foo() noexcept;
double bar()
{
double x = foo().check(); // throw on error
double y = foo().result; // ignore error. Continue with NaN
}
Result<double> baz() noexcept
{
Result<double> rtrn;
double x;
if(! (rtrn = foo()).unpack(x))
return rtrn; // propagate error
rtrn.result = x + 1.; // continue operation
return rtrn;
}
Further discussion
To give a bit more of a personal opinion and also delve into a few more performance concerns:
Exceptions
Well, all the usual aspects of exception handling and when to use them apply. See for example When and how should I use exception handling?
I think at this point the general consensus on exceptions is that they should not be part of the regular control flow and should only be used for very rare, exceptional cases where you most likely want to abort the operation instead of, say mitigating the error. It is just too easy to forget catching exceptions on all call sites so they tend to travel very far up the call chain before being caught.
So their use is very situational. Do you want your users to explicitly deal with any error condition on the site where they appear? Then don't use exceptions because users of your API will definitely not be bothered using a try-except block everywhere. If you want the error to get out of the way as far as possible, use them.
As for the idea of using a second set of functions without exceptions: Well, it doesn't compose well. It's feasible for a small set of functions but do you really want to write every piece of code twice, once with and once without exceptions? Probably not.
Error output parameter
This is probably the most flexible option while remaining very efficient. Passing an additional parameter has a minor cost but it isn't too bad.
The main benefit is that this is the only option besides exceptions that allows you to compose complex error reports with dynamic memory allocation for error messages etc. without incurring extra costs in the no-error case. If you make the Result object complex enough to require a destructor, it will be passed on the stack and you need to re-read the error code and actual result value after every function call and then its destructor will run.
In contrast, the Error object will be rarely touched. Yes, its destructor will run once it goes out of scope. However, I expect that most code bases will have one error object very far up the call chain and then just pass it down and reuse that object as needed.
If you make the Error object complex you might find yourself in a situation where a caller wants the error code but not the error message, e.g. because they expect an error and want to mitigate it instead of reporting it. For this case, it might make sense to add a flag to the object to indicate that the error message should not be filled.
struct Error
{
int errcode;
bool use_message;
std::string message;
};
variant, expected
I think I've made it sufficiently clear above that I don't think std::variant has a suitable API for this task. std::expected may one day be available on every platform you target but right now it isn't and you will definitely draw the ire of your release engineers if you start using C++23 features and they have to build your code for RHEL-8 or something similarly long-lived.
Performance-wise all the points I discuss below for Result apply. In addition, the floating point result will always be returned either on the stack or in a general purpose register. Using the Result or std::pair approach will at least get double results in a floating point register on Mac/Linux/BSD, which is a minor advantage, but not huge. floats will still be packed in a GP register, though.
Result type
From an API design perspective, the nice thing about a Result object is that the caller cannot ignore the possibility of an error. They may or may not remember to check for NaN or catch exceptions but with Result, they always have to unpack the contained value and in doing so, decide on their desired error handling.
From a performance perspective, the main point when writing a Result type is that you don't want to make it more expensive to access the actual return value unless you don't care about runtime and code size. This means making sure the return value can be passed in registers instead of the stack.
On Windows this is very hard to achieve because the Windows calling convention only uses a single register for return objects and I don't think they pack two 32 bit values into one 64 bit register. At this point your only options are a) accept the cost of stack return values b) try to pack error code and result value in one scalar like you did with NaN payloads or other tricks like negative integers c) not use this approach.
On all other major x86-64 platforms, you have two registers to work with. This is far more feasible unless you regularly return 16 byte payloads like std::complex<double>.
However, for this to work, the Result must not have a non-trivial destructor or copy/move constructor. For all intents and purposes, this means you cannot have dynamic error messages in the Error type. There are ways around this, if you absolutely need: You enforce that every access to the actual result also checks the error and deallocates, either reporting or ignoring it in the process. Use [[nodiscard]] on the return values to ensure the return value is checked at all. This works, for example:
struct Error
{
std::string* message;
private:
[[noreturn]] static void raise_and_delete_msg(std::string*);
public:
/*
* Note: clang needs always_inline to generate efficient
* code here. GCC is fine
*/
[[noreturn, gnu::always_inline]] void raise() const
{ raise_and_delete_msg(message); }
void discard() const noexcept
{ delete message; }
operator bool() const noexcept
{ return message != nullptr; }
void check() const
{
if(message)
raise();
}
};
template<class T>
class Result
{
T result;
Error err;
public:
constexpr Result()
: result(),
err()
{}
explicit Result(T result)
: result(std::move(result)),
err()
{}
/** Takes ownerhip of message. Will delete */
explicit Result(std::unique_ptr<std::string>&& message)
: err(Error{message.release()})
{}
Result(std::unique_ptr<std::string>&& message, T invalid)
: result(std::move(invalid)),
err(Error{message.release()})
{}
T unchecked() noexcept
{
err.discard();
return std::move(result);
}
T checked()
{
err.check();
return std::move(result);
}
bool unpack(T& out) noexcept
{
if(err) {
err.discard();
return false;
}
out = std::move(result);
return true;
}
};
[[nodiscard]] Result<double> foo();
double bar()
{
return foo().checked() + 1.;
}
However, at this point you quickly reach the point where you exceed the 8 bytes you can reasonably use for sizeof(Error) before you go back to stack return values so I'm not sure this is worth it. For example if you want and error code plus message, you need to dynamically allocate both or do other fancy tricks. Plus, [[nodiscard]] is only a warning, so you can still easily get memory leaks.
Conclusion
If I have to make suggestions:
Use exceptions if a) they are in line with the coding style and API you normally use plus b) the expectations that both you and your API users have on these functions and c) failure should be rare, costly, and loud
Use Error output arguments if you primarily target Windows or if you want complex error reporting with dynamic messages or similar.
Use Result for simple error codes on Linux/Mac or if you want your API users to always make a conscious decision to check or ignore an error. In that case, you may also accept the additional runtime cost associated with complex Error objects or any such object on Windows.

Generic logger vs. exception pattern

Consider a class foo which has one or more functions which can report failure either through a logger or by throwing an exception if no logger was provided:
struct logger
{
// ...
};
struct foo
{
void set_logger(std::shared_ptr<logger> logger) { m_logger = std::move(logger); }
bool bar(const std::filesystem::path& path)
{
// Check path validity
if (not std::filesystem::exists(path) {
if (m_logger) {
m_logger->warn("path does not exist.");
return false;
}
else {
throw std::runtime_error("path does not exists.");
}
}
// Some random operation
try {
// Do something here that might throw
}
catch (const std::exception& e) {
if (m_logger) {
m_logger->warn("operation bar failed.");
return false;
}
else {
throw e;
}
}
return true;
}
private:
std::shared_ptr<logger> m_logger;
};
This does not only look ugly but is extremely error prone and as more functions are added to foo code will be repeditive.
Is there any kind of pattern or paradigm to abstract this logic away? Some kind of wrapper template I can construct to use inside foo's various functions when error reporting is needed?
Anything up to C++20 would be acceptable.
Is there any kind of pattern or paradigm to abstract this logic away? Some kind of wrapper template I can construct to use inside foo's various functions when error reporting is needed?
One thing you could do is to simply remove all the else { throw... } code and provide a default logger that throws an exception containing the logged message. If the client provides a different logger, fine, your code will use that; if not, it uses the default one. This scheme eliminates about half your error handling code and simplifies the flow while providing the same behavior, which seems like a positive outcome.
It's important to remember that logging a message is different from throwing an exception: it's often useful to be able to log a message that doesn't stop the flow of the program. So be sure to give your logger class methods that log without throwing as well; you might use a different log level for messages that are equivalent to exceptions.
Since your error case handling seems to follow the same structure, you could add a simple function that will do just that:
bool log_or_throw(logger * logger_, std::string const& message, std::exception const& exception) {
if (logger_) {
logger_->warn(message);
return false;
}
else {
throw exception;
}
}
And then you can change your error handling to a single line, probably making the flow a lot more readable:
if (not std::filesystem::exists(path) {
return log_or_throw(m_logger, "path does not exist.", std::runtime_error("path does not exists."));
}

Getting rid of an ugly C construct

I have inherited a (large) piece of code which has an error tracking mechanism where they pass in a boolean variable to all the methods they call and on errors at various stages of execution the method is stopped and returns, sometimes a default value.
Something like (BEFORE):
#include <iostream.h>
int fun1(int par1, bool& psuccess)
{
if(par1 == 42) return 43;
psuccess = false;
return -1;
}
int funtoo(int a, bool& psuccess)
{
int t = fun1(a, psuccess);
if(!psuccess)
{
return -1;
}
return 42;
}
void funthree(int b, bool& psuccess)
{
int h = funtoo(b, psuccess);
if(!psuccess)
{
return;
}
cout << "Yuppi" << b;
}
int main()
{
bool success = true;
funthree(43, success);
if(!success)
{
cout<< "Life, universe and everything have no meaning";
}
}
Please note, that this is a mixture of C and C++ code, exactly the way the project is in.
Now, comes a piece of C magic: "someone" somewhere defined a macro:
#define SUCCES_OR_RETURN if(!psuccess) return
And the program above becomes (AFTER):
#include<iostream.h>
int fun1(int par1, bool& psuccess)
{
if(par1 == 42) return 43;
psuccess = false;
return -1;
}
int funtoo(int a, bool& psuccess)
{
int t = fun1(a, psuccess);
SUCCES_OR_RETURN -1;
return 42;
}
void funthree(int b, bool& psuccess)
{
int h = funtoo(b, psuccess);
SUCCES_OR_RETURN ;
std::cout << "Yuppi" << b;
}
int main()
{
bool success = true;
funthree(43, success);
if(!success)
{
cout<< "Life, universe and everything have no meaning";
}
}
The question: I am wondering if there is a nicer way to handle this kind of error tracking or I have to live with this. I personally don't like the abuse of the C macro SUCCES_OR_RETURN ie. that once it is called with a parameter, and in other cases it is called without, feels like a real return statement, but I did not find any better solutions to this ancient design.
Please note that due to platform restrictions we have several restrictions, but regardless of it I am willing to hear opinions about these two:
throwing exceptions. The code is a mixture of C and C++ functions calling each other and the compiler sort of does not support throw (accepts in the syntax but does nothing with it, just a warning). This solution is sort of the standard way of solving this problem in a C++ environment.
C++11 features, this goes to a tiny embedded platform with an obscure and ancient "almost" C++ compiler which wasn't made to support the latest C++ features. However for future reference I am curios if there is anything C++11 offers.
template magic. The compiler has problems understanding complex templated issues, but again I am willing to see any solutions that you can come up with.
Edit
Also, as #BlueMoon suggested in the commend, creating a global variable is not working since at a very beginning of the function chain calling the success variable is a member variable of a class, and there are several objects of this class created, each of them needs to report its success status :)
There's a great breakdown of hybrid C and C++ error handling strategies here:
http://blog.sduto.it/2014/05/a-c-error-handling-style-that-plays.html
To quote the linked article, your options largely boil down to:
Return an error code from functions that can fail.
Provide a function like Windows's GetLastError() or OpenGL's glGetError() to retrieve the most recently occurring error code.
Provide a global (well, hopefully, thread-local) variable containing the most recent error, like POSIX's errno.
Provide a function to return more information about an error, possibly in conjunction with one of the above approaches, like POSIX's strerror function.
Allow the client to register a callback when an error occurs, like GLFW's glfwSetErrorCallback.
Use an OS-specific mechanism like structured exception handling.
Write errors out to a log file, stderr, or somewhere else.
Just assert() or somehow else terminate the program when an error occurs.
It seems like the author of the code you have inherited picked a rather strange way, passing a pointer to a boolean [sic] for the function to work with seems rather unusual.
The article has some great examples, personally I like this style:
libfoo_widget_container_t container = NULL;
libfoo_error_details_t error = NULL;
if (libfoo_create_widgets(12, &container, &error) != libfoo_success) {
printf("Error creating widgets: %s\n", libfoo_error_details_c_str(error));
libfoo_error_details_free(error);
abort(); // goodbye, cruel world!
}
Here you get a bit of everything, passed in pointer to error type, a comparison against a success constant (rather than 0|1, a painful dichotomy between C and the rest of the world!).
I don't think it would be too much of a push to say that your macro could rather better be implemented with a goto, in any case, if a function is calling SUCCES_OR_RETURN more than once, it might be a clue that the function is doing too much. Complex cleanup, or return might be a code smell, you can read more here http://eli.thegreenplace.net/2009/04/27/using-goto-for-error-handling-in-c/
I have seen this style of error handling before. I call it error-oblivious manual pseudo-exceptions.
The code flow is mostly error-oblivious: you can call 3 functions in a row with the same error flag, then look at the error flag to see if any errors have occurred.
The error flag acts as a pseudo-exception, where once set we start "skipping" over normal code flow, but this is done manually instead of automatically.
If you do something and do not care if an error occurs, you can just drop the error produced and proceed on.
The ICU library handles errors in a similar way.
A more C++1y way to do this while minimizing structural differences would be to modify code to return an expected object.
An expected<T, Err> is expected to be a T, and if something went wrong it is instead an Err type. This can be implemented as a hybrid of boost::variant and C++1y's std::optional. If you go and overload most arithmetic operations on expected< T, Err > + U to return expected< decltype( std::declval<T&>() + std::declval<U>(), Err > and did some careful auto, you could allow at least arithmetic expressions to keep their structure. You'd then check for the error after the fact.
On the other hand, if the error return values are predictable based on their type, you could create a type that when cast to a given type produced an error value. Modify functions returning void to return an error object of some kind while you are at it. And now every function can
if (berror) return error_flag_value{};
which at least gets rid of that strange ; or -1; issue.
If you want to go full C++, the answer would be changing the "invalid return values" for exceptions...
#include <iostream>
#include <exception>
using std::exception;
struct error : exception { const char* what() const throw() override { return "unsuccessful"; } };
int fun1(int par1) {
if( par1 == 42 ) return 43;
throw error();
}
int funtoo(int a) {
fun1(a);
return 42;
}
void funthree(int b) {
funtoo(b);
std::cout << "Yuppi " << b << "\n";
}
int main() {
try {
funthree(42);
} catch(exception& e) {
std::cout << "Life has no meaning, because " << e.what() << "\n";
}
}
This prints Yuppi 42 (if you change the call funthree(42) for funthree(43) it prints Life has no meaning, because unsuccessful...)
(live at coliru)

C++ Scope of Static Variable In a Static Member Function

I have a simple object which does some parsing. Inside, there is a parse function, containing a static variable that is used to limit number of error messages to print to the user:
struct CMYParsePrimitive {
static bool Parse(const std::string &s_line)
{
// do the parsing
static bool b_warned = false;
if(!b_warned) {
b_warned = true;
std::cerr << "error: token XYZ is deprecated" << std::endl;
}
// print a warning about using this token (only once)
return true;
}
};
Now these parse primitives are passed in a typelist to a parser specialization. There is some other interface which tells parser which token types should be parsed using which parse primitives.
My issue is that the warning should be displayed up to once per application run. But in my case, it is sometimes displayed multiple times, seems to be per parser instance rather than application instance.
I'm using Visual Studio 2008, I imagine this might be some bug or a deviation from the standard? Does anyone have any idea as to why this happens?
I failed to notice that the function is also a template. My bad. It is instantiated twice in the code with different parameters - hence the warning is sometimes printed twice. The real code looks more like this:
struct CMYParsePrimitive {
template <class CSink>
static bool Parse(const std::string &s_line, CSink &sink)
{
// do the parsing, results passed down to "sink"
static bool b_warned = false;
if(!b_warned) {
b_warned = true;
std::cerr << "error: token XYZ is deprecated" << std::endl;
}
// print a warning about using this token (only once)
return true;
}
};
So then there are e.g. CMYParsePrimitive::Parse<PreviewParser>::b_warned, which can print the warning once when used by PreviewParser, and then also CMYParsePrimitive::Parse<Parser>::b_warned which can print the warning when used by Parser.

Is it possible to convert a boost::system::error_code to a std:error_code?

I want to replace external libraries (like boost) as much as possible with their equivalents in standard C++ if they exist and it is possible, to minimize dependencies, therefore I wonder if there exists a safe way to convert boost::system::error_code to std::error_code. Pseudo code example:
void func(const std::error_code & err)
{
if(err) {
//error
} else {
//success
}
}
boost::system::error_code boost_err = foo(); //foo() returns a boost::system::error_code
std::error_code std_err = magic_code_here; //convert boost_err to std::error_code here
func(std_err);
The most important it is not the exactly the same error, just so close to as possible and at last if is an error or not. Are there any smart solutions?
Thanks in advance!
I had this exact same question since I wanted to use std::error_code but was also using other boost libraries that use boost::system::error_code (e.g. boost ASIO). The accepted answer works for the error codes handled by std::generic_category(), as they're a simple cast from boost's generic error codes, but it doesn't work for the general case where you want to handle custom error categories as well.
So I created the following code as a general purpose boost::system::error_code-to-std::error_code converter. It works by dynamically creating an std::error_category shim for each boost::system::error_category, forwarding the calls to the underlying Boost error category. Since error categories need to be singletons (or at least singleton-like as in this case) I don't expect there to be much of a memory explosion.
I also just convert boost::system::generic_category() object to use std::generic_category() since they should behave the same. I had wanted to do the same for system_category(), however in testing on VC++10 it printed out the wrong messages (I assume it should print out what you get from FormatMessage, but it appears to use strerror, Boost uses FormatMessage as expected).
To use it just call BoostToErrorCode(), defined below.
Just a warning, I just wrote this today so it's only had basic testing. You may use it any way you like, but you do so at your own risk.
//==================================================================================================
// These classes implement a shim for converting a boost::system::error_code to a std::error_code.
// Unfortunately this isn't straightforward since it the error_code classes use a number of
// incompatible singletons.
//
// To accomplish this we dynamically create a shim for every boost error category that passes
// the std::error_category calls on to the appropriate boost::system::error_category calls.
//==================================================================================================
#include <boost/system/error_code.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/once.hpp>
#include <boost/thread/locks.hpp>
#include <system_error>
namespace
{
// This class passes the std::error_category functions through to the
// boost::system::error_category object.
class BoostErrorCategoryShim : public std::error_category
{
public:
BoostErrorCategoryShim( const boost::system::error_category& in_boostErrorCategory )
:m_boostErrorCategory(in_boostErrorCategory), m_name(std::string("boost.") + in_boostErrorCategory.name()) {}
virtual const char *name() const;
virtual std::string message(value_type in_errorValue) const;
virtual std::error_condition default_error_condition(value_type in_errorValue) const;
private:
// The target boost error category.
const boost::system::error_category& m_boostErrorCategory;
// The modified name of the error category.
const std::string m_name;
};
// A converter class that maintains a mapping between a boost::system::error_category and a
// std::error_category.
class BoostErrorCodeConverter
{
public:
const std::error_category& GetErrorCategory( const boost::system::error_category& in_boostErrorCategory )
{
boost::lock_guard<boost::mutex> lock(m_mutex);
// Check if we already have an entry for this error category, if so we return it directly.
ConversionMapType::iterator stdErrorCategoryIt = m_conversionMap.find(&in_boostErrorCategory);
if( stdErrorCategoryIt != m_conversionMap.end() )
return *stdErrorCategoryIt->second;
// We don't have an entry for this error category, create one and add it to the map.
const std::pair<ConversionMapType::iterator, bool> insertResult = m_conversionMap.insert(
ConversionMapType::value_type(
&in_boostErrorCategory,
std::unique_ptr<const BoostErrorCategoryShim>(new BoostErrorCategoryShim(in_boostErrorCategory))) );
// Return the newly created category.
return *insertResult.first->second;
}
private:
// We keep a mapping of boost::system::error_category to our error category shims. The
// error categories are implemented as singletons so there should be relatively few of
// these.
typedef std::unordered_map<const boost::system::error_category*, std::unique_ptr<const BoostErrorCategoryShim>> ConversionMapType;
ConversionMapType m_conversionMap;
// This is accessed globally so we must manage access.
boost::mutex m_mutex;
};
namespace Private
{
// The init flag.
boost::once_flag g_onceFlag = BOOST_ONCE_INIT;
// The pointer to the converter, set in CreateOnce.
BoostErrorCodeConverter* g_converter = nullptr;
// Create the log target manager.
void CreateBoostErrorCodeConverterOnce()
{
static BoostErrorCodeConverter converter;
g_converter = &converter;
}
}
// Get the log target manager.
BoostErrorCodeConverter& GetBoostErrorCodeConverter()
{
boost::call_once( Private::g_onceFlag, &Private::CreateBoostErrorCodeConverterOnce );
return *Private::g_converter;
}
const std::error_category& GetConvertedErrorCategory( const boost::system::error_category& in_errorCategory )
{
// If we're accessing boost::system::generic_category() or boost::system::system_category()
// then just convert to the std::error_code versions.
if( in_errorCategory == boost::system::generic_category() )
return std::generic_category();
// I thought this should work, but at least in VC++10 std::error_category interprets the
// errors as generic instead of system errors. This means an error returned by
// GetLastError() like 5 (access denied) gets interpreted incorrectly as IO error.
//if( in_errorCategory == boost::system::system_category() )
// return std::system_category();
// The error_category was not one of the standard boost error categories, use a converter.
return GetBoostErrorCodeConverter().GetErrorCategory(in_errorCategory);
}
// BoostErrorCategoryShim implementation.
const char* BoostErrorCategoryShim::name() const
{
return m_name.c_str();
}
std::string BoostErrorCategoryShim::message(value_type in_errorValue) const
{
return m_boostErrorCategory.message(in_errorValue);
}
std::error_condition BoostErrorCategoryShim::default_error_condition(value_type in_errorValue) const
{
const boost::system::error_condition boostErrorCondition = m_boostErrorCategory.default_error_condition(in_errorValue);
// We have to convert the error category here since it may not have the same category as
// in_errorValue.
return std::error_condition( boostErrorCondition.value(), GetConvertedErrorCategory(boostErrorCondition.category()) );
}
}
std::error_code BoostToErrorCode( boost::system::error_code in_errorCode )
{
return std::error_code( in_errorCode.value(), GetConvertedErrorCategory(in_errorCode.category()) );
}
Since C++-11 (std::errc), boost/system/error_code.hpp maps the same error codes to std::errc, which is defined in the system header system_error.
You can compare both enums and they should be functionally equivalent because they both appear to be based on the POSIX standard. May require a cast.
For example,
namespace posix_error
{
enum posix_errno
{
success = 0,
address_family_not_supported = EAFNOSUPPORT,
address_in_use = EADDRINUSE,
address_not_available = EADDRNOTAVAIL,
already_connected = EISCONN,
argument_list_too_long = E2BIG,
argument_out_of_domain = EDOM,
bad_address = EFAULT,
bad_file_descriptor = EBADF,
bad_message = EBADMSG,
....
}
}
and std::errc
address_family_not_supported error condition corresponding to POSIX code EAFNOSUPPORT
address_in_use error condition corresponding to POSIX code EADDRINUSE
address_not_available error condition corresponding to POSIX code EADDRNOTAVAIL
already_connected error condition corresponding to POSIX code EISCONN
argument_list_too_long error condition corresponding to POSIX code E2BIG
argument_out_of_domain error condition corresponding to POSIX code EDOM
bad_address error condition corresponding to POSIX code EFAULT
I adapted the above solution into a shorter solution.
Using a thread_local std::map to map between the category name to its instance so no locking is needed.
The limitation is that you can't pass error codes between threads since the category pointer will be different.(Converting it to a locking function is simple enough if you don't want to use the thread_local storage)
Also I feed it is more compact.
#include <iostream>
#include <map>
#include <boost/system/system_error.hpp>
namespace std
{
error_code make_error_code(boost::system::error_code error)
{
struct CategoryAdapter : public error_category
{
CategoryAdapter(const boost::system::error_category& category)
: m_category(category)
{
}
const char* name() const noexcept
{
return m_category.name();
}
std::string message(int ev) const
{
return m_category.message(ev);
}
private:
const boost::system::error_category& m_category;
};
static thread_local map<std::string, CategoryAdapter> nameToCategory;
auto result = nameToCategory.emplace(error.category().name(), error.category());
auto& category = result.first->second;
return error_code(error.value(), category);
}
};
int main() {
auto a = boost::system::errc::make_error_code(boost::system::errc::address_family_not_supported);
auto b = std::make_error_code(a);
std::cout << b.message() << std::endl;
}
As of Boost version 1.65, you can convert boost::error_code to its C++11 counterpart:
On a C++11 compiler, Boost.System now provides implicit conversions from boost::system::error_category, error_code, and error_condition to their standard equivalents from <system_error>.
This allows libraries to expose a C++11 interface and report errors via std::error_code even when using Boost.System, directly or through a dependency such as Boost.ASIO.
So it should now be as simple as:
auto ec = static_cast<std::error_code>(boost_error_code);