Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #ifndef SGL_EXCEPTION_H_
- #define SGL_EXCEPTION_H_
- ////////////////////////////////////////////////////////////
- // Headers
- ////////////////////////////////////////////////////////////
- #include <iso646.h>
- #include <setjmp.h>
- #include <stdbool.h>
- #include <stdnoreturn.h>
- ////////////////////////////////////////////////////////////
- // Exceptions
- /**
- * @brief Basic exception type.
- *
- * The exceptions must be integers to satisfy the longjmp
- * function. The names used here are those of the exceptions
- * defined in the C++ <stdexcept> header and some other ones
- * from the C++ standard library. The mechanism cannot be
- * extended with user-defined types.
- *
- * The default sgl_exception is not meant to be thrown nor printed.
- * It only exists so that it can be used to catch any exception in
- * a catch block.
- */
- typedef enum
- {
- sgl_exception = -1,
- sgl_logic_error,
- sgl_domain_error,
- sgl_invalid_argument,
- sgl_length_error,
- sgl_out_of_range,
- sgl_runtime_error,
- sgl_range_error,
- sgl_overflow_error,
- sgl_underflow_error,
- sgl_bad_alloc,
- sgl_detail_exceptions_number
- } sgl_exception_t;
- #ifndef SGL_MAX_EXCEPTIONS
- /**
- * @def SGL_MAX_EXCEPTIONS
- *
- * Maximum number of nested exception blocks allowed in SGL.
- * It can be set to N with the compiler option
- * -DSGL_MAX_EXCEPTIONS=N
- */
- #define SGL_MAX_EXCEPTIONS 32
- #endif
- ////////////////////////////////////////////////////////////
- // Global implementation variables
- // Global array of jmp_buf
- extern jmp_buf sgl_detail_buf_array[SGL_MAX_EXCEPTIONS];
- // Whether we are in an exception catch bloc
- extern bool sgl_detail_in_catch_bloc[SGL_MAX_EXCEPTIONS];
- // Current exception index
- extern int sgl_detail_exceptions_index;
- // Current exception
- extern sgl_exception_t sgl_detail_current_exception;
- ////////////////////////////////////////////////////////////
- // Exception handling functions
- /**
- * Throws the given exception.
- */
- noreturn void sgl_throw(sgl_exception_t exception);
- /**
- * Rethrows the current exception.
- */
- noreturn void sgl_rethrow();
- /**
- * Returns whether an exception "inherits" from another
- * exception so that it is possible to catch several
- * related exceptions in a single catch block.
- */
- bool sgl_exception_inherits_from(sgl_exception_t exception,
- sgl_exception_t from);
- /**
- * Returns the error message associated to the given
- * exception.
- */
- const char* sgl_what(sgl_exception_t exception);
- ////////////////////////////////////////////////////////////
- // Exception handling macros
- /**
- * @def sgl_try
- *
- * Beginning of an exception try bloc.
- */
- #define sgl_try
- do {
- ++sgl_detail_exceptions_index;
- sgl_detail_in_catch_bloc[sgl_detail_exceptions_index] = false;
- if (not setjmp(sgl_detail_buf_array[sgl_detail_exceptions_index]))
- {
- /**
- * @def sgl_catch(exception)
- *
- * Catches an exception and execute the following bloc
- * of code if it corresponds to the thrown exceptions
- */
- #define sgl_catch(exception)
- }
- else if (sgl_exception_inherits_from(sgl_detail_current_exception, exception))
- {
- sgl_detail_in_catch_bloc[sgl_detail_exceptions_index] = true;
- --sgl_detail_exceptions_index;
- /**
- * @def sgl_endtry
- *
- * If something was thrown but nothing caught, throws it again.
- * Prints the current exception and aborts with -1 if we are not
- * into a catch block.
- */
- #define sgl_endtry
- }
- else
- {
- if (sgl_detail_exceptions_index > 0)
- {
- --sgl_detail_exceptions_index;
- sgl_rethrow();
- }
- else
- {
- sgl_terminate();
- }
- }
- --sgl_detail_exceptions_index;
- } while (0);
- ////////////////////////////////////////////////////////////
- // Program termination utilities
- /**
- * Type of the function called by sgl_terminate. While it does
- * not appear in the typedef, termination handlers should be
- * noreturn functions.
- */
- typedef void (*sgl_terminate_handler)();
- /**
- * @return the current termination handler.
- */
- sgl_terminate_handler sgl_get_terminate();
- /**
- * Sets a new termination handler. If a new_handler is NULL,
- * this functions sets back the default termination handler.
- *
- * @param new_handler New termination handler.
- * @return the old termination handler.
- */
- sgl_terminate_handler sgl_set_terminate(sgl_terminate_handler new_handler);
- /**
- * Calls the current termination handler. The default one
- * calls abort. This function is called when an exception
- * is thrown and not caught.
- */
- noreturn void sgl_terminate();
- #endif // SGL_EXCEPTION_H_
- #include <assert.h>
- #include <stdint.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <sgl/exception.h>
- ////////////////////////////////////////////////////////////
- // Global implementation variables
- jmp_buf sgl_detail_buf_array[SGL_MAX_EXCEPTIONS];
- bool sgl_detail_in_catch_bloc[SGL_MAX_EXCEPTIONS];
- int sgl_detail_exceptions_index = -1;
- sgl_exception_t sgl_detail_current_exception;
- ////////////////////////////////////////////////////////////
- // Throwing functions
- void sgl_throw(sgl_exception_t exception)
- {
- assert(exception != sgl_exception);
- sgl_detail_current_exception = exception;
- // Handle exceptions out of a try block
- if (sgl_detail_exceptions_index == -1)
- {
- sgl_terminate();
- }
- if (sgl_detail_in_catch_bloc[sgl_detail_exceptions_index])
- {
- --sgl_detail_exceptions_index;
- }
- longjmp(sgl_detail_buf_array[sgl_detail_exceptions_index], true);
- }
- noreturn void sgl_rethrow()
- {
- sgl_throw(sgl_detail_current_exception);
- }
- ////////////////////////////////////////////////////////////
- // Exceptions inheritance emulation
- bool sgl_exception_inherits_from(sgl_exception_t exception,
- sgl_exception_t from)
- {
- static uint_fast16_t inheritance[] = {
- 1 << sgl_logic_error,
- 1 << sgl_domain_error | 1 << sgl_logic_error,
- 1 << sgl_invalid_argument | 1 << sgl_logic_error,
- 1 << sgl_length_error | 1 << sgl_logic_error,
- 1 << sgl_out_of_range | 1 << sgl_logic_error,
- 1 << sgl_runtime_error,
- 1 << sgl_range_error | 1 << sgl_runtime_error,
- 1 << sgl_overflow_error | 1 << sgl_runtime_error,
- 1 << sgl_underflow_error | 1 << sgl_runtime_error,
- 1 << sgl_bad_alloc
- };
- if (from == sgl_exception)
- {
- // Everything inherits from exception
- return true;
- }
- return inheritance[exception] & (1 << from);
- }
- ////////////////////////////////////////////////////////////
- // Exception message function
- const char* sgl_what(sgl_exception_t exception)
- {
- static const char* const messages[] = {
- "logic error",
- "domain error",
- "invalid argument",
- "length error",
- "out of range error",
- "runtime error",
- "range error",
- "overflow error",
- "underflow error",
- "bad allocation"
- };
- if (exception < 0 || exception >= sgl_detail_exceptions_number)
- {
- return "unknown error";
- }
- return messages[exception];
- }
- ////////////////////////////////////////////////////////////
- // Program termination utilities
- // Default termination function
- static noreturn void default_terminate()
- {
- printf("Terminate called after throwing an exception.n");
- printf(" what(): %sn", sgl_what(sgl_detail_current_exception));
- abort();
- }
- // Current termination function
- static sgl_terminate_handler current_terminate = default_terminate;
- sgl_terminate_handler sgl_get_terminate()
- {
- return current_terminate;
- }
- sgl_terminate_handler sgl_set_terminate(sgl_terminate_handler new_handler)
- {
- sgl_terminate_handler old_handler = sgl_get_terminate();
- if (new_handler == NULL)
- {
- new_handler = default_terminate;
- }
- current_terminate = new_handler;
- return old_handler;
- }
- noreturn void sgl_terminate()
- {
- current_terminate();
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement