Flow 2.0.0
Flow project: Full implementation reference.
Classes | Namespaces | Macros | Functions
error.hpp File Reference
#include "flow/error/error_fwd.hpp"
#include "flow/log/log.hpp"
#include "flow/util/detail/util.hpp"
#include <boost/system/system_error.hpp>
#include <stdexcept>

Go to the source code of this file.

Classes

class  flow::error::Runtime_error
 An std::runtime_error (which is an std::exception) that stores an Error_code. More...
 

Namespaces

namespace  flow
 Catch-all namespace for the Flow project: A collection of various production-quality modules written in modern C++17, originally by ygoldfel.
 
namespace  flow::error
 Flow module that facilitates working with error codes and exceptions; essentially comprised of niceties on top boost.system's error facility.
 

Macros

#define FLOW_ERROR_EMIT_ERROR(ARG_val)
 Sets *err_code to ARG_val and logs a warning about the error using FLOW_LOG_WARNING(). More...
 
#define FLOW_ERROR_EMIT_ERROR_LOG_INFO(ARG_val)
 Identical to FLOW_ERROR_EMIT_ERROR(), but the message logged has flow::log::Sev::S_INFO severity instead of S_WARNING. More...
 
#define FLOW_ERROR_LOG_ERROR(ARG_val)
 Logs a warning about the given error code using FLOW_LOG_WARNING(). More...
 
#define FLOW_ERROR_SYS_ERROR_LOG_WARNING()    FLOW_LOG_WARNING("System error occurred: [" << sys_err_code << "] [" << sys_err_code.message() << "].")
 Logs a warning about the (often errno-based or from a library) error code in sys_err_code. More...
 
#define FLOW_ERROR_SYS_ERROR_LOG_FATAL()    FLOW_LOG_FATAL("System error occurred: [" << sys_err_code << "] [" << sys_err_code.message() << "].")
 Logs a log::Sev::S_FATAL message about the (often errno-based or from a library) error code in sys_err_code, usually just before aborting the process or otherwise entering undefined-behavior land such as via assert(false). More...
 
#define FLOW_ERROR_EXEC_AND_THROW_ON_ERROR(ARG_ret_type, ARG_function_name, ...)
 Narrow-use macro that implements the error code/exception semantics expected of most public-facing Flow (and Flow-like) class method APIs. More...
 

Functions

template<typename Func , typename Ret >
bool flow::error::exec_and_throw_on_error (const Func &func, Ret *ret, Error_code *err_code, util::String_view context)
 Helper for FLOW_ERROR_EXEC_AND_THROW_ON_ERROR() macro that does everything in the latter not needing a preprocessor. More...
 
template<typename Func >
bool flow::error::exec_void_and_throw_on_error (const Func &func, Error_code *err_code, util::String_view context)
 Equivalent of exec_and_throw_on_error() for operations with void return type. More...
 

Macro Definition Documentation

◆ FLOW_ERROR_EMIT_ERROR

#define FLOW_ERROR_EMIT_ERROR (   ARG_val)
Value:
( \
::flow::Error_code FLOW_ERROR_EMIT_ERR_val(ARG_val); \
FLOW_LOG_WARNING("Error code emitted: [" << FLOW_ERROR_EMIT_ERR_val << "] " \
"[" << FLOW_ERROR_EMIT_ERR_val.message() << "]."); \
*err_code = FLOW_ERROR_EMIT_ERR_val; \
)
boost::system::error_code Error_code
Short-hand for a boost.system error code (which basically encapsulates an integer/enum error code and...
Definition: common.hpp:508
#define FLOW_UTIL_SEMICOLON_SAFE(ARG_func_macro_definition)
Use this to create a semicolon-safe version of a "void" functional macro definition consisting of at ...
Definition: util_fwd.hpp:1079

Sets *err_code to ARG_val and logs a warning about the error using FLOW_LOG_WARNING().

An err_code variable of type that is pointer to flow::Error_code must be declared at the point where the macro is invoked.

Parameters
ARG_valValue convertible to flow::Error_code. Reminder: Error_code is trivially/implicitly convertible from any error code set (such as errnos and boost.asio network error code set) that has been boost.system-enabled.

Definition at line 202 of file error.hpp.

◆ FLOW_ERROR_EMIT_ERROR_LOG_INFO

#define FLOW_ERROR_EMIT_ERROR_LOG_INFO (   ARG_val)
Value:
( \
::flow::Error_code FLOW_ERROR_EMIT_ERR_LOG_val(ARG_val); \
FLOW_LOG_INFO("Error code emitted: [" << FLOW_ERROR_EMIT_ERR_LOG_val << "] " \
"[" << FLOW_ERROR_EMIT_ERR_LOG_val.message() << "]."); \
*err_code = FLOW_ERROR_EMIT_ERR_LOG_val; \
)

Identical to FLOW_ERROR_EMIT_ERROR(), but the message logged has flow::log::Sev::S_INFO severity instead of S_WARNING.

Parameters
ARG_valSee FLOW_ERROR_EMIT_ERROR().

Definition at line 218 of file error.hpp.

◆ FLOW_ERROR_EXEC_AND_THROW_ON_ERROR

#define FLOW_ERROR_EXEC_AND_THROW_ON_ERROR (   ARG_ret_type,
  ARG_function_name,
  ... 
)
Value:
( \
/* We need both the result of the operation (if applicable) and whether it actually ran. */ \
/* So we must introduce this local variable (note it's within a { block } so should minimally interfere with */ \
/* the invoker's code). We can't use a sentinel value to combine the two, since the operation's result may */ \
/* require ARG_ret_type's entire range. */ \
ARG_ret_type result; \
/* We provide the function: f(Error_code*), where f(e_c) == ARG_function_name(..., e_c, ...). */ \
/* Also supply context info of this macro's invocation spot. */ \
/* Note that, if f() is executed, it may throw Runtime_error which is the point of its existence. */ \
([&](::flow::Error_code* _1) -> ARG_ret_type \
{ return ARG_function_name(__VA_ARGS__); }, \
&result, err_code, FLOW_UTIL_WHERE_AM_I_LITERAL(ARG_function_name))) \
{ \
/* Aforementioned f() WAS executed; did NOT throw (no error); and return value was placed into `result`. */ \
return result; \
} \
/* else: */ \
/* f() did not run, because err_code is non-null. So now macro invoker should do its thing assuming that fact. */ \
/* Recall that the idea is that f() is just recursively calling the method invoking this macro with the same */ \
/* arguments except for the Error_code* arg, where they supply specifically `_1` by our contract. */ \
)
bool exec_and_throw_on_error(const Func &func, Ret *ret, Error_code *err_code, util::String_view context)
Helper for FLOW_ERROR_EXEC_AND_THROW_ON_ERROR() macro that does everything in the latter not needing ...
Definition: error.hpp:128
#define FLOW_UTIL_WHERE_AM_I_LITERAL(ARG_function)
Helper macro: like FLOW_UTIL_WHERE_AM_I(), with a major relative strength – its replacement is a stri...
Definition: util.hpp:169

Narrow-use macro that implements the error code/exception semantics expected of most public-facing Flow (and Flow-like) class method APIs.

The semantics it helps implement are explained in flow::Error_code doc header. More formally, here is how to use it:

First, please read flow::Error_code doc header. Next read on:

Suppose you have an API f() in some class C that returns type T and promises, in its doc header, to implement the error reporting semantics listed in the aforementioned flow::Error_code doc header. That is, if user passes in null err_code, error would cause Run_time error(e_c) to be thrown; if non-null, then *err_code = e_c would be set sans exception – e_c being the error code explaining what went wrong, such as flow::net_flow::error::Code::S_WAIT_INTERRUPTED. Then here's how to use the macro:

// Example API. In this one, there's a 4th argument that happens to follow the standard Error_code* one.
// arg2 is a (const) reference, as opposed to a pointer or scalar, and is most efficiently handled by adding
// cref() to avoid copying it.
T f(AT1 arg1, const AT2& arg2, Error_code* err_code = 0, AT3 arg3 = 0)
{
FLOW_ERROR_EXEC_AND_THROW_ON_ERROR(T, // Provide the return type of the API.
// Forward all the args into the macro, but replace `err_code` => `_1`.
arg1, arg2, _1, arg3);
// ^-- Call ourselves and return if err_code is null. If got to present line, err_code is not null.
// ...Bulk of f() goes here! You can now set *err_code to anything without fear....
}
#define FLOW_ERROR_EXEC_AND_THROW_ON_ERROR(ARG_ret_type, ARG_function_name,...)
Narrow-use macro that implements the error code/exception semantics expected of most public-facing Fl...
Definition: error.hpp:363
See also
flow::Error_code for typical error reporting semantics this macro helps implement.
exec_void_and_throw_on_error() which you can use directly when ARG_ret_type would be void. The present macro does not work in that case; but at that point using the function directly is concise enough.
exec_and_throw_on_error() which you can use directly when T is a reference type. The present macro does not work in that case.
Parameters
ARG_ret_typeThe return type of the invoking function/method. It cannot be a reference type. In practice this would be, for example, size_t when wrapping a receive() (which returns # of bytes received or 0).
ARG_function_nameSuppose you wanted to, via infinite recursion, call the function – from where you use this macro – and would therefore write a statement of the form return F(A1, A2, ..., err_code, ...);. ARG_function_name shall be the F part of such a hypothetical statement. Tip: Even in non-static member functions (methods), just the method name – without the class name :: part – is almost always fine. Tip: However template args typically do have to be forwarded (e.g., in template<typename T> X::f() {} you'd supply f<T> as ARG_function_name), unless the compiler can infer them. Example: in a bool X::listen(int x, Error_code* err_code, float y) {} you'd have { return listen(x, err_code, y); } and thus ARG_function_name shall be just listen. Tip: But, if there are 2+ template args, and the compiler cannot infer them, you need to surround the x<a, b, ...> with parentheses: like: FLOW_ERROR_EXEC_AND_THROW_ON_ERROR(int, (x<a, b>), ...).
...First see the premise in the doc header for ARG_function_name just above. Then the ... arg list shall be as follows: A1, A2, ..., _1, .... In other words it shall be the arg list for the invoking function/method as-if recursively calling it, but with the err_code arg replaced by the special identifier _1. Example: in a bool X::listen(int x, Error_code* err_code, float y) {} you'd have { return listen(x, err_code, y); } and thus ... arg list shall be: x, _1, y.

Definition at line 363 of file error.hpp.

◆ FLOW_ERROR_LOG_ERROR

#define FLOW_ERROR_LOG_ERROR (   ARG_val)
Value:
( \
::flow::Error_code FLOW_ERROR_LOG_ERR_val(ARG_val); \
FLOW_LOG_WARNING("Error occurred: [" << FLOW_ERROR_LOG_ERR_val << "] " \
"[" << FLOW_ERROR_LOG_ERR_val.message() << "]."); \
)

Logs a warning about the given error code using FLOW_LOG_WARNING().

Parameters
ARG_valSee FLOW_ERROR_EMIT_ERROR().

Definition at line 233 of file error.hpp.

◆ FLOW_ERROR_SYS_ERROR_LOG_FATAL

#define FLOW_ERROR_SYS_ERROR_LOG_FATAL ( )     FLOW_LOG_FATAL("System error occurred: [" << sys_err_code << "] [" << sys_err_code.message() << "].")

Logs a log::Sev::S_FATAL message about the (often errno-based or from a library) error code in sys_err_code, usually just before aborting the process or otherwise entering undefined-behavior land such as via assert(false).

sys_err_code must be an object of type flow::Error_code in the context of the macro's invocation.

This is identical to FLOW_ERROR_SYS_ERROR_LOG_WARNING(), except the message logged has FATAL severity instead of a mere WARNING. Notes in that macro's doc header generally apply. However the use case is different.

The recommended (but in no way enforced or mandatory) pattern is something like:

Error_code sys_err_code;
// ...
// sys_err_code has been set to truthy value that is completely unexpected or so unpalatable as to make
// any attempt at recovery not worth the effort. Decision has therefore been made to abort and/or
// enter undefined-behavior land.
FLOW_LOG_FATAL("(...Explain what went wrong, and why it is very shocking; output values of interest; but not "
"`sys_err_code` since....) Details follow.");
// Enter undefined-behavior land.
// Different orgs/projects do different things; but a decent approach might be:
assert(false && "(...Re-explain what went wrong, so it shows up in the assert-trip message on some stderr.");
// Possibly really abort program, even if assert()s are disabled via NDEBUG.
std::abort();
#define FLOW_ERROR_SYS_ERROR_LOG_FATAL()
Logs a log::Sev::S_FATAL message about the (often errno-based or from a library) error code in sys_er...
Definition: error.hpp:302
#define FLOW_LOG_FATAL(ARG_stream_fragment)
Logs a FATAL message into flow::log::Logger *get_logger() with flow::log::Component get_log_component...
Definition: log.hpp:167

Definition at line 302 of file error.hpp.

◆ FLOW_ERROR_SYS_ERROR_LOG_WARNING

#define FLOW_ERROR_SYS_ERROR_LOG_WARNING ( )     FLOW_LOG_WARNING("System error occurred: [" << sys_err_code << "] [" << sys_err_code.message() << "].")

Logs a warning about the (often errno-based or from a library) error code in sys_err_code.

sys_err_code must be an object of type flow::Error_code in the context of the macro's invocation. See also FLOW_ERROR_SYS_ERROR_LOG_FATAL().

Note this implies a convention wherein system (especially errno-based or from a libary) error codes are to be saved into a stack variable or parameter flow::Error_code sys_err_code. Of course if you don't like this convention and/or this error message, it is trivial to log something manually.

It's a functional macro despite taking no arguments to convey that it mimics a void free function.

The recommended (but in no way enforced or mandatory) pattern is something like:

Error_code sys_err_code;
// ...
// sys_err_code has been set to truthy value. Decision has therefore been made to log about it but otherwise
// recover and continue algorithm.
FLOW_LOG_WARNING("(...Explain what went wrong; output values of interest; but not `sys_err_code` since....) "
"Details follow.");
// Continue operating. No assert(false); no std::abort()....
#define FLOW_ERROR_SYS_ERROR_LOG_WARNING()
Logs a warning about the (often errno-based or from a library) error code in sys_err_code.
Definition: error.hpp:269
#define FLOW_LOG_WARNING(ARG_stream_fragment)
Logs a WARNING message into flow::log::Logger *get_logger() with flow::log::Component get_log_compone...
Definition: log.hpp:152

Definition at line 269 of file error.hpp.