blob: 0e72c2b064c757470dd353324f84b72b9de7db26 [file] [log] [blame]
#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