1 #ifndef R_ASSERT_H 2 #define R_ASSERT_H 3 4 #include "r_log.h" 5 6 #define R_STATIC_ASSERT(x)\ 7 switch (0) {\ 8 case 0:\ 9 case (x):;\ 10 } 11 12 R_API void r_assert_log(RLogLevel level, const char *fmt, ...) R_PRINTF_CHECK(2, 3); 13 14 #if defined (__GNUC__) && defined (__cplusplus) 15 #define R_FUNCTION ((const char*) (__PRETTY_FUNCTION__)) 16 #elif defined(__STDC__) && defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L 17 #define R_FUNCTION ((const char*) (__func__)) 18 #elif defined (__GNUC__) || (defined(_MSC_VER) && (_MSC_VER > 1300)) 19 #define R_FUNCTION ((const char*) (__FUNCTION__)) 20 #else 21 #warning Do not know how to get function name in this setup 22 #define R_FUNCTION ((const char*) ("???")) 23 #endif 24 25 #define r_warn_if_reached() \ 26 do { \ 27 r_assert_log (R_LOGLVL_WARN, "(%s:%d):%s%s code should not be reached\n", \ 28 __FILE__, __LINE__, R_FUNCTION, R_FUNCTION[0] ? ":" : ""); \ 29 } while (0) 30 31 #define r_warn_if_fail(expr) \ 32 do { \ 33 if (!(expr)) { \ 34 r_assert_log (R_LOGLVL_WARN, "WARNING (%s:%d):%s%s runtime check failed: (%s)\n", \ 35 __FILE__, __LINE__, R_FUNCTION, R_FUNCTION[0] ? ":" : "", #expr); \ 36 } \ 37 } while (0) 38 39 /* 40 * R_CHECKS_LEVEL determines the behaviour of the r_return_* set of functions. 41 * 42 * 0: completely disable every function and make them like no-operation 43 * 1: silently enable checks. Check expressions and do return, but do not log anything 44 * 2: enable checks and logging (DEFAULT) 45 * 3: transform them into real assertion 46 */ 47 #ifndef R_CHECKS_LEVEL 48 #define R_CHECKS_LEVEL 2 49 #endif 50 51 #if R_CHECKS_LEVEL == 0 52 53 #define r_return_if_fail(expr) do { ; } while(0) 54 #define r_return_val_if_fail(expr, val) do { ; } while(0) 55 #define r_return_if_reached() do { ; } while(0) 56 #define r_return_val_if_reached(val) do { ; } while(0) 57 58 #elif R_CHECKS_LEVEL == 1 || R_CHECKS_LEVEL == 2 // R_CHECKS_LEVEL 59 60 #if R_CHECKS_LEVEL == 1 61 #define H_LOG_(loglevel, fmt, ...) 62 #else 63 #define H_LOG_(loglevel, fmt, ...) r_assert_log (loglevel, fmt, __VA_ARGS__) 64 #endif 65 66 /** 67 * r_return_if_fail: 68 * @expr: the expression to check 69 * 70 * Verifies that the expression @expr, usually representing a precondition, 71 * evaluates to `true`. If the function returns a value, use 72 * r_return_val_if_fail() instead. 73 * 74 * If @expr evaluates to %FALSE, the current function should be considered to 75 * have undefined behaviour (a programmer error). The only correct solution 76 * to such an error is to change the module that is calling the current 77 * function, so that it avoids this incorrect call. 78 * 79 * To make this undefined behaviour visible, if @expr evaluates to %FALSE, 80 * the result is usually that a critical message is logged and the current 81 * function returns. 82 * 83 */ 84 #define r_return_if_fail(expr) \ 85 do { \ 86 if (!(expr)) { \ 87 H_LOG_ (R_LOGLVL_WARN, "%s: assertion '%s' failed (line %d)\n", R_FUNCTION, #expr, __LINE__); \ 88 return; \ 89 } \ 90 } while (0) 91 92 #define r_return_val_if_fail(expr, val) \ 93 do { \ 94 if (!(expr)) { \ 95 H_LOG_ (R_LOGLVL_WARN, "%s: assertion '%s' failed (line %d)\n", R_FUNCTION, #expr, __LINE__); \ 96 return (val); \ 97 } \ 98 } while (0) 99 100 #define r_return_if_reached() \ 101 do { \ 102 H_LOG_ (R_LOGLVL_ERROR, "file %s: line %d (%s): should not be reached\n", __FILE__, __LINE__, R_FUNCTION); \ 103 return; \ 104 } while (0) 105 106 #define r_return_val_if_reached(val) \ 107 do { \ 108 H_LOG_ (R_LOGLVL_ERROR, "file %s: line %d (%s): should not be reached\n", __FILE__, __LINE__, R_FUNCTION); \ 109 return (val); \ 110 } while (0) 111 112 #else // R_CHECKS_LEVEL 113 114 #include <assert.h> 115 116 #define r_return_if_fail(expr) do { assert (expr); } while(0) 117 #define r_return_val_if_fail(expr, val) do { assert (expr); } while(0) 118 #define r_return_if_reached() do { assert (false); } while(0) 119 #define r_return_val_if_reached(val) do { assert (false); } while(0) 120 121 #endif // R_CHECKS_LEVEL 122 123 #endif 124