mirror of
https://github.com/Zygo/bees.git
synced 2025-05-17 13:25:45 +02:00
Sometimes we need to check constraints on 4 variables at once. It would be nice if variadic macros in C++ were also polymorphic. Signed-off-by: Zygo Blaxell <bees@furryterror.org>
163 lines
5.3 KiB
C++
163 lines
5.3 KiB
C++
#ifndef CRUCIBLE_ERROR_H
|
|
#define CRUCIBLE_ERROR_H
|
|
|
|
// Common error-handling idioms for C library calls
|
|
|
|
#include <cerrno>
|
|
#include <cstring>
|
|
#include <functional>
|
|
#include <sstream>
|
|
#include <stdexcept>
|
|
#include <system_error>
|
|
|
|
#include <unistd.h>
|
|
|
|
namespace crucible {
|
|
using namespace std;
|
|
|
|
// Common error-handling idioms for C library calls
|
|
|
|
template <class T> T die_if_minus_errno(const char *expr, T rv)
|
|
{
|
|
if (rv < 0) {
|
|
throw system_error(error_code(-rv, system_category()), expr);
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
template <class T> T die_if_minus_one(const char *expr, T rv)
|
|
{
|
|
if (rv == -1) {
|
|
throw system_error(error_code(errno, system_category()), expr);
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
template <class T> T die_if_zero(const char *expr, T rv)
|
|
{
|
|
if (rv == 0) {
|
|
throw system_error(error_code(errno, system_category()), expr);
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
template <class T> T die_if_non_zero(const char *expr, T rv)
|
|
{
|
|
if (rv != 0) {
|
|
throw system_error(error_code(errno, system_category()), expr);
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
// Usage: catch_all([&]() { /* insert body here */ } );
|
|
// Executes body with exceptions caught and reported to cerr.
|
|
// Returns:
|
|
// 0 if f() returns
|
|
// non-zero if f() throws an exception
|
|
// -1 for unknown exception
|
|
// 1 for std::exception or class derived thereof
|
|
|
|
void set_catch_explainer(function<void(string s)> f);
|
|
void default_catch_explainer(string s);
|
|
int catch_all(const function<void()> &f, const function<void(string)> &explainer = default_catch_explainer);
|
|
|
|
// catch_and_explain traps the exception, calls the explainer, then rethrows the original exception
|
|
void catch_and_explain(const function<void()> &f, const function<void(string)> &explainer = default_catch_explainer);
|
|
};
|
|
|
|
// 0 on success, -errno on error.
|
|
// Covers most pthread functions.
|
|
#define DIE_IF_MINUS_ERRNO(expr) crucible::die_if_minus_errno(#expr, expr)
|
|
|
|
// -1 on error, all other values mean success.
|
|
#define DIE_IF_MINUS_ONE(expr) crucible::die_if_minus_one(#expr, expr)
|
|
|
|
// 0 (or NULL) on error, all other values mean success.
|
|
#define DIE_IF_ZERO(expr) crucible::die_if_zero(#expr, expr)
|
|
|
|
// 0 (or NULL) on success, all other values mean error.
|
|
#define DIE_IF_NON_ZERO(expr) crucible::die_if_non_zero(#expr, expr)
|
|
|
|
// macro for throwing an error
|
|
#define THROW_ERROR(type, expr) do { \
|
|
std::ostringstream _te_oss; \
|
|
_te_oss << expr << " at " << __FILE__ << ":" << __LINE__; \
|
|
throw type(_te_oss.str()); \
|
|
} while (0)
|
|
|
|
// macro for throwing a system_error with errno
|
|
#define THROW_ERRNO(expr) do { \
|
|
std::ostringstream _te_oss; \
|
|
_te_oss << expr << " at " << __FILE__ << ":" << __LINE__; \
|
|
throw std::system_error(std::error_code(errno, std::system_category()), _te_oss.str()); \
|
|
} while (0)
|
|
|
|
// macro for throwing a system_error with some other variable
|
|
#define THROW_ERRNO_VALUE(value, expr) do { \
|
|
std::ostringstream _te_oss; \
|
|
_te_oss << expr << " at " << __FILE__ << ":" << __LINE__; \
|
|
throw std::system_error(std::error_code((value), std::system_category()), _te_oss.str()); \
|
|
} while (0)
|
|
|
|
// macros for checking a constraint
|
|
#define THROW_CHECK0(type, expr) do { \
|
|
if (!(expr)) { \
|
|
THROW_ERROR(type, "failed constraint check (" << #expr << ")"); \
|
|
} \
|
|
} while(0)
|
|
|
|
#define THROW_CHECK1(type, value, expr) do { \
|
|
if (!(expr)) { \
|
|
THROW_ERROR(type, #value << " = " << (value) << " failed constraint check (" << #expr << ")"); \
|
|
} \
|
|
} while(0)
|
|
|
|
#define THROW_CHECK2(type, value1, value2, expr) do { \
|
|
if (!(expr)) { \
|
|
THROW_ERROR(type, #value1 << " = " << (value1) << ", " #value2 << " = " << (value2) \
|
|
<< " failed constraint check (" << #expr << ")"); \
|
|
} \
|
|
} while(0)
|
|
|
|
#define THROW_CHECK3(type, value1, value2, value3, expr) do { \
|
|
if (!(expr)) { \
|
|
THROW_ERROR(type, #value1 << " = " << (value1) << ", " #value2 << " = " << (value2) << ", " #value3 << " = " << (value3) \
|
|
<< " failed constraint check (" << #expr << ")"); \
|
|
} \
|
|
} while(0)
|
|
|
|
#define THROW_CHECK4(type, value1, value2, value3, value4, expr) do { \
|
|
if (!(expr)) { \
|
|
THROW_ERROR(type, #value1 << " = " << (value1) << ", " #value2 << " = " << (value2) << ", " #value3 << " = " << (value3) << ", " #value4 << " = " << (value4) \
|
|
<< " failed constraint check (" << #expr << ")"); \
|
|
} \
|
|
} while(0)
|
|
|
|
#define THROW_CHECK_BIN_OP(type, value1, op, value2) do { \
|
|
if (!((value1) op (value2))) { \
|
|
THROW_ERROR(type, "failed constraint check " << #value1 << " (" << (value1) << ") " << #op << " " << #value2 << " (" << (value2) << ")"); \
|
|
} \
|
|
} while(0)
|
|
|
|
#define THROW_CHECK_PREFIX_OP(type, op, value1) do { \
|
|
if (!(op (value1))) { \
|
|
THROW_ERROR(type, "failed constraint check " << #op << " " << #value1 << " (" << (value1) << ")"); \
|
|
} \
|
|
} while(0)
|
|
|
|
#define THROW_CHECK_RANGE(type, value_min, value_test, value_max) do { \
|
|
if ((value_test) < (value_min) || (value_max) < (value_test)) { \
|
|
THROW_ERROR(type, "failed constraint check " << #value_min << " (" << (value_min) << ") <= " #value_test << " (" << (value_test) \
|
|
<< ") <= " << #value_max << " (" << (value_max) << ")"); \
|
|
} \
|
|
} while(0)
|
|
|
|
#define THROW_CHECK_ARRAY_RANGE(type, value_min, value_test, value_max) do { \
|
|
if ((value_test) < (value_min) || !((value_test) < (value_max))) { \
|
|
THROW_ERROR(type, "failed constraint check " << #value_min << " (" << (value_min) << ") <= " #value_test << " (" << (value_test) \
|
|
<< ") < " << #value_max << " (" << (value_max) << ")"); \
|
|
} \
|
|
} while(0)
|
|
|
|
#endif // CRUCIBLE_ERROR_H
|