1 /** @file omassert.h 2 * @brief Various assertion macros. 3 */ 4 /* Copyright (C) 2007,2008,2009,2013 Olly Betts 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 19 */ 20 21 /* The "om" prefix is a historical vestige dating back to the "Open Muscat" 22 * code base upon which Xapian is partly based. It's preserved here only 23 * to avoid colliding with the ISO C "assert.h" header. 24 */ 25 26 #ifndef XAPIAN_INCLUDED_OMASSERT_H 27 #define XAPIAN_INCLUDED_OMASSERT_H 28 29 /** Assert that a constant expression is non-zero. 30 * 31 * If the assertion fails, compilation fails with an error. There's no 32 * run-time overhead for a compile-time assertion, so we always enable 33 * them. 34 * 35 * This macro must be used within a function (this is because we can only 36 * portably generate a "unique" name using __LINE__, but then if this macro 37 * is used in header files, multiple headers might be included from the same 38 * source file and have CompileTimeAssert() at the same line number. 39 */ 40 #if __cplusplus >= 201103L 41 // Under C++11, just use static_assert. 42 # define CompileTimeAssert(COND) static_assert(COND, #COND) 43 #else 44 # define CompileTimeAssert(COND)\ 45 do {\ 46 typedef int xapian_compile_time_check_[(COND) ? 1 : -1];\ 47 xapian_compile_time_check_ xapian_compile_time_check_var_;\ 48 (void)xapian_compile_time_check_var_;\ 49 } while (0) 50 #endif 51 52 #ifndef XAPIAN_ASSERTIONS 53 // The configure script should always define XAPIAN_ASSERTIONS if it defines 54 // XAPIAN_ASSERTIONS_PARANOID. 55 # ifdef XAPIAN_ASSERTIONS_PARANOID 56 # error XAPIAN_ASSERTIONS_PARANOID defined without XAPIAN_ASSERTIONS 57 # endif 58 #else 59 60 #include <xapian/error.h> 61 62 #include "str.h" 63 #include "utils.h" // For within_DBL_EPSILON(). 64 65 #define XAPIAN_ASSERT_LOCATION__(LINE,MSG) __FILE__":"#LINE": "#MSG 66 #define XAPIAN_ASSERT_LOCATION_(LINE,MSG) XAPIAN_ASSERT_LOCATION__(LINE,MSG) 67 #define XAPIAN_ASSERT_LOCATION(MSG) XAPIAN_ASSERT_LOCATION_(__LINE__,MSG) 68 69 // Expensive (or potentially expensive) assertions can be marked as "Paranoid" 70 // - these can be disabled separately from other assertions to allow a build 71 // with assertions which still has good performance. 72 #ifdef XAPIAN_ASSERTIONS_PARANOID 73 # define AssertParanoid(COND) Assert(COND) 74 # define AssertRelParanoid(A,REL,B) AssertRel(A,REL,B) 75 # define AssertEqParanoid(A,B) AssertEq(A,B) 76 # define AssertEqDoubleParanoid(A,B) AssertEqDouble(A,B) 77 #endif 78 79 /** Assert that condition COND is non-zero. 80 * 81 * If this assertion fails, Xapian::AssertionError() will be thrown. 82 */ 83 #define Assert(COND) \ 84 do {\ 85 if (rare(!(COND)))\ 86 throw Xapian::AssertionError(XAPIAN_ASSERT_LOCATION(COND));\ 87 } while (0) 88 89 /** Assert that A REL B is non-zero. 90 * 91 * The intended usage is that REL is ==, !=, <=, <, >=, or >. 92 * 93 * If this assertion fails, Xapian::AssertionError() will be thrown, and the 94 * exception message will include the values of A and B. 95 */ 96 #define AssertRel(A,REL,B) \ 97 do {\ 98 if (rare(!((A) REL (B)))) {\ 99 std::string xapian_assertion_msg(XAPIAN_ASSERT_LOCATION(A REL B));\ 100 xapian_assertion_msg += " : values were ";\ 101 xapian_assertion_msg += str(A);\ 102 xapian_assertion_msg += " and ";\ 103 xapian_assertion_msg += str(B);\ 104 throw Xapian::AssertionError(xapian_assertion_msg);\ 105 }\ 106 } while (0) 107 108 /** Assert that A == B. 109 * 110 * This is just a wrapper for AssertRel(A,==,B) and is provided partly for 111 * historical reasons (we've have AssertEq() for ages) and partly because 112 * it's convenient to have a shorthand for the most common relation which 113 * we want to assert. 114 */ 115 #define AssertEq(A,B) AssertRel(A,==,B) 116 117 /// Assert two values differ by DBL_EPSILON or more. 118 #define AssertEqDouble(A,B) \ 119 do {\ 120 using Xapian::Internal::within_DBL_EPSILON;\ 121 if (rare(within_DBL_EPSILON(A,B))) {\ 122 std::string xapian_assertion_msg(XAPIAN_ASSERT_LOCATION(within_DBL_EPSILON(A,B)));\ 123 xapian_assertion_msg += " : values were ";\ 124 xapian_assertion_msg += str(A);\ 125 xapian_assertion_msg += " and ";\ 126 xapian_assertion_msg += str(B);\ 127 throw Xapian::AssertionError(xapian_assertion_msg);\ 128 }\ 129 } while (0) 130 131 #endif 132 133 // If assertions are disabled, set the macros to expand to (void)0 so that 134 // we get a compiler error in this case for assertions missing a trailing 135 // semicolon. This avoids one source of compile errors in debug builds 136 // which don't manifest in non-debug builds. 137 138 #ifndef Assert 139 # define Assert(COND) (void)0 140 # define AssertRel(A,REL,B) (void)0 141 # define AssertEq(A,B) (void)0 142 # define AssertEqDouble(A,B) (void)0 143 #endif 144 145 #ifndef AssertParanoid 146 # define AssertParanoid(COND) (void)0 147 # define AssertRelParanoid(A,REL,B) (void)0 148 # define AssertEqParanoid(A,B) (void)0 149 # define AssertEqDoubleParanoid(A,B) (void)0 150 #endif 151 152 /** A "compile-time" assertion. 153 * 154 * STATIC_ASSERT must be used inside a function (not at the top level, or 155 * in a class definition). 156 * 157 * COND must be a compile-time constant expression. 158 * 159 * If COND is false, the compiler will try to compile an array with negative 160 * length, which is invalid (we don't use 0 as the length, since GCC allows 161 * zero length arrays as an extension). We name the array 162 * "xapian_static_assert_failed" since this won't clash with any sanely named 163 * variable, and it's likely to appear in the compiler error message and so 164 * indicate to the developer what went wrong. 165 */ 166 #define STATIC_ASSERT(COND) \ 167 do { \ 168 char xapian_static_assert_failed[(COND) ? 1 : -1]; \ 169 (void)xapian_static_assert_failed; \ 170 } while (0) 171 172 /** Assert at compile-time that type TYPE is unsigned. */ 173 #define STATIC_ASSERT_UNSIGNED_TYPE(TYPE) \ 174 STATIC_ASSERT(static_cast<TYPE>(-1) > 0) 175 176 /** Assert at compile-time that integer type T1 can hold any value which 177 * integer type T2 can. 178 * 179 * NB Doesn't currently work reliably for type bool (which is typically 180 * incorrectly treated as equivalent to unsigned char or unsigned int). 181 * 182 * If T1 is unsigned, T2 must be unsigned and have no more bits. 183 * 184 * If T1 is signed, then T2 must have no more bits (if also signed) or 185 * fewer bits (if unsigned). 186 */ 187 #define STATIC_ASSERT_TYPE_DOMINATES(T1, T2) \ 188 STATIC_ASSERT(static_cast<T1>(-1) > 0 ? \ 189 (static_cast<T2>(-1) > 0 && sizeof(T1) >= sizeof(T2)) : \ 190 (sizeof(T1) >= sizeof(T2) + (static_cast<T2>(-1) > 0))) 191 192 #endif // XAPIAN_INCLUDED_OMASSERT_H 193