| |
| #include <isl/ctx.h> |
| #include <isl/options.h> |
| |
| #include <functional> |
| #include <memory> |
| #include <stdexcept> |
| #include <string> |
| |
| /* ISL_USE_EXCEPTIONS should be defined to 1 if exceptions are available. |
| * gcc and clang define __cpp_exceptions; MSVC and xlC define _CPPUNWIND. |
| * If exceptions are not available, any error condition will result |
| * in an abort. |
| */ |
| #ifndef ISL_USE_EXCEPTIONS |
| #if defined(__cpp_exceptions) || defined(_CPPUNWIND) |
| #define ISL_USE_EXCEPTIONS 1 |
| #else |
| #define ISL_USE_EXCEPTIONS 0 |
| #endif |
| #endif |
| |
| namespace isl { |
| |
| class ctx { |
| isl_ctx *ptr; |
| public: |
| /* implicit */ ctx(isl_ctx *ctx) : ptr(ctx) {} |
| isl_ctx *release() { |
| auto tmp = ptr; |
| ptr = nullptr; |
| return tmp; |
| } |
| isl_ctx *get() { |
| return ptr; |
| } |
| }; |
| |
| /* Macros hiding try/catch. |
| * If exceptions are not available, then no exceptions will be thrown and |
| * there is nothing to catch. |
| */ |
| #if ISL_USE_EXCEPTIONS |
| #define ISL_CPP_TRY try |
| #define ISL_CPP_CATCH_ALL catch (...) |
| #else |
| #define ISL_CPP_TRY if (1) |
| #define ISL_CPP_CATCH_ALL if (0) |
| #endif |
| |
| #if ISL_USE_EXCEPTIONS |
| |
| /* Class capturing isl errors. |
| * |
| * The what() return value is stored in a reference counted string |
| * to ensure that the copy constructor and the assignment operator |
| * do not throw any exceptions. |
| */ |
| class exception : public std::exception { |
| std::shared_ptr<std::string> what_str; |
| |
| protected: |
| inline exception(const char *what_arg, const char *msg, |
| const char *file, int line); |
| public: |
| exception() {} |
| exception(const char *what_arg) { |
| what_str = std::make_shared<std::string>(what_arg); |
| } |
| static inline exception create(enum isl_error error, const char *msg, |
| const char *file, int line); |
| static inline exception create_from_last_error(ctx ctx); |
| virtual const char *what() const noexcept { |
| return what_str->c_str(); |
| } |
| |
| /* Default behavior on error conditions that occur inside isl calls |
| * performed from inside the bindings. |
| * In the case exceptions are available, isl should continue |
| * without printing a warning since the warning message |
| * will be included in the exception thrown from inside the bindings. |
| */ |
| static constexpr auto on_error = ISL_ON_ERROR_CONTINUE; |
| /* Wrapper for throwing an exception on NULL input. |
| */ |
| static void throw_NULL_input(const char *file, int line) { |
| throw create(isl_error_invalid, "NULL input", file, line); |
| } |
| /* Wrapper for throwing an exception corresponding to the last |
| * error on "ctx". |
| */ |
| static void throw_last_error(ctx ctx) { |
| throw create_from_last_error(ctx); |
| } |
| }; |
| |
| /* Create an exception of a type described by "what_arg", with |
| * error message "msg" in line "line" of file "file". |
| * |
| * Create a string holding the what() return value that |
| * corresponds to what isl would have printed. |
| * If no error message or no error file was set, then use "what_arg" instead. |
| */ |
| exception::exception(const char *what_arg, const char *msg, const char *file, |
| int line) |
| { |
| if (!msg || !file) |
| what_str = std::make_shared<std::string>(what_arg); |
| else |
| what_str = std::make_shared<std::string>(std::string(file) + |
| ":" + std::to_string(line) + ": " + msg); |
| } |
| |
| class exception_abort : public exception { |
| friend exception; |
| exception_abort(const char *msg, const char *file, int line) : |
| exception("execution aborted", msg, file, line) {} |
| }; |
| |
| class exception_alloc : public exception { |
| friend exception; |
| exception_alloc(const char *msg, const char *file, int line) : |
| exception("memory allocation failure", msg, file, line) {} |
| }; |
| |
| class exception_unknown : public exception { |
| friend exception; |
| exception_unknown(const char *msg, const char *file, int line) : |
| exception("unknown failure", msg, file, line) {} |
| }; |
| |
| class exception_internal : public exception { |
| friend exception; |
| exception_internal(const char *msg, const char *file, int line) : |
| exception("internal error", msg, file, line) {} |
| }; |
| |
| class exception_invalid : public exception { |
| friend exception; |
| exception_invalid(const char *msg, const char *file, int line) : |
| exception("invalid argument", msg, file, line) {} |
| }; |
| |
| class exception_quota : public exception { |
| friend exception; |
| exception_quota(const char *msg, const char *file, int line) : |
| exception("quota exceeded", msg, file, line) {} |
| }; |
| |
| class exception_unsupported : public exception { |
| friend exception; |
| exception_unsupported(const char *msg, const char *file, int line) : |
| exception("unsupported operation", msg, file, line) {} |
| }; |
| |
| /* Create an exception of the class that corresponds to "error", with |
| * error message "msg" in line "line" of file "file". |
| * |
| * isl_error_none is treated as an invalid error type. |
| */ |
| exception exception::create(enum isl_error error, const char *msg, |
| const char *file, int line) |
| { |
| switch (error) { |
| case isl_error_none: |
| break; |
| case isl_error_abort: return exception_abort(msg, file, line); |
| case isl_error_alloc: return exception_alloc(msg, file, line); |
| case isl_error_unknown: return exception_unknown(msg, file, line); |
| case isl_error_internal: return exception_internal(msg, file, line); |
| case isl_error_invalid: return exception_invalid(msg, file, line); |
| case isl_error_quota: return exception_quota(msg, file, line); |
| case isl_error_unsupported: |
| return exception_unsupported(msg, file, line); |
| } |
| |
| throw exception_invalid("invalid error type", file, line); |
| } |
| |
| /* Create an exception from the last error that occurred on "ctx" and |
| * reset the error. |
| * |
| * If "ctx" is NULL or if it is not in an error state at the start, |
| * then an invalid argument exception is thrown. |
| */ |
| exception exception::create_from_last_error(ctx ctx) |
| { |
| enum isl_error error; |
| const char *msg, *file; |
| int line; |
| |
| error = isl_ctx_last_error(ctx.get()); |
| msg = isl_ctx_last_error_msg(ctx.get()); |
| file = isl_ctx_last_error_file(ctx.get()); |
| line = isl_ctx_last_error_line(ctx.get()); |
| isl_ctx_reset_error(ctx.get()); |
| |
| return create(error, msg, file, line); |
| } |
| |
| #else |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| |
| class exception { |
| public: |
| /* Default behavior on error conditions that occur inside isl calls |
| * performed from inside the bindings. |
| * In the case exceptions are not available, isl should abort. |
| */ |
| static constexpr auto on_error = ISL_ON_ERROR_ABORT; |
| /* Wrapper for throwing an exception on NULL input. |
| * In the case exceptions are not available, print an error and abort. |
| */ |
| static void throw_NULL_input(const char *file, int line) { |
| fprintf(stderr, "%s:%d: NULL input\n", file, line); |
| abort(); |
| } |
| /* Wrapper for throwing an exception corresponding to the last |
| * error on "ctx". |
| * isl should already abort when an error condition occurs, |
| * so this function should never be called. |
| */ |
| static void throw_last_error(ctx ctx) { |
| abort(); |
| } |
| }; |
| |
| #endif |
| |
| /* Helper class for setting the on_error and resetting the option |
| * to the original value when leaving the scope. |
| */ |
| class options_scoped_set_on_error { |
| isl_ctx *ctx; |
| int saved_on_error; |
| public: |
| options_scoped_set_on_error(class ctx ctx, int on_error) { |
| this->ctx = ctx.get(); |
| saved_on_error = isl_options_get_on_error(this->ctx); |
| isl_options_set_on_error(this->ctx, on_error); |
| } |
| ~options_scoped_set_on_error() { |
| isl_options_set_on_error(ctx, saved_on_error); |
| } |
| }; |
| |
| } // namespace isl |