Support: quest -f cjk_ngram
[xapian.git] / xapian-core / common / omassert.h
blobe5895b1ec292371868718502400e58efeb3f6a8e
1 /** @file omassert.h
2 * @brief Various assertion macros.
3 */
4 /* Copyright (C) 2007,2008,2009,2012,2013,2015 Olly Betts
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.
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.
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
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.
26 #ifndef XAPIAN_INCLUDED_OMASSERT_H
27 #define XAPIAN_INCLUDED_OMASSERT_H
29 #ifndef XAPIAN_ASSERTIONS
30 // The configure script should always define XAPIAN_ASSERTIONS if it defines
31 // XAPIAN_ASSERTIONS_PARANOID.
32 # ifdef XAPIAN_ASSERTIONS_PARANOID
33 # error XAPIAN_ASSERTIONS_PARANOID defined without XAPIAN_ASSERTIONS
34 # endif
35 #else
37 #include <xapian/error.h>
39 #include "str.h"
41 #define XAPIAN_ASSERT_LOCATION__(LINE,MSG) __FILE__":"#LINE": "#MSG
42 #define XAPIAN_ASSERT_LOCATION_(LINE,MSG) XAPIAN_ASSERT_LOCATION__(LINE,MSG)
43 #define XAPIAN_ASSERT_LOCATION(MSG) XAPIAN_ASSERT_LOCATION_(__LINE__,MSG)
45 // Expensive (or potentially expensive) assertions can be marked as "Paranoid"
46 // - these can be disabled separately from other assertions to allow a build
47 // with assertions which still has good performance.
48 #ifdef XAPIAN_ASSERTIONS_PARANOID
49 # define AssertParanoid(COND) Assert(COND)
50 # define AssertRelParanoid(A,REL,B) AssertRel(A,REL,B)
51 # define AssertEqParanoid(A,B) AssertEq(A,B)
52 # define AssertEqDoubleParanoid(A,B) AssertEqDouble(A,B)
53 #endif
55 /** Assert that condition COND is non-zero.
57 * If this assertion fails, Xapian::AssertionError() will be thrown.
59 #define Assert(COND) \
60 do {\
61 if (rare(!(COND)))\
62 throw Xapian::AssertionError(XAPIAN_ASSERT_LOCATION(COND));\
63 } while (0)
65 /** Assert that A REL B is non-zero.
67 * The intended usage is that REL is ==, !=, <=, <, >=, or >.
69 * If this assertion fails, Xapian::AssertionError() will be thrown, and the
70 * exception message will include the values of A and B.
72 #define AssertRel(A,REL,B) \
73 do {\
74 if (rare(!((A) REL (B)))) {\
75 std::string xapian_assertion_msg(XAPIAN_ASSERT_LOCATION(A REL B));\
76 xapian_assertion_msg += " : values were ";\
77 xapian_assertion_msg += str(A);\
78 xapian_assertion_msg += " and ";\
79 xapian_assertion_msg += str(B);\
80 throw Xapian::AssertionError(xapian_assertion_msg);\
82 } while (0)
84 /** Assert that A == B.
86 * This is just a wrapper for AssertRel(A,==,B) and is provided partly for
87 * historical reasons (we've have AssertEq() for ages) and partly because
88 * it's convenient to have a shorthand for the most common relation which
89 * we want to assert.
91 #define AssertEq(A,B) AssertRel(A,==,B)
93 /** Helper function to check if two values are within DBL_EPSILON. */
94 namespace Xapian {
95 namespace Internal {
96 bool within_DBL_EPSILON(double a, double b);
100 /// Assert two values differ by DBL_EPSILON or more.
101 #define AssertEqDouble(A,B) \
102 do {\
103 using Xapian::Internal::within_DBL_EPSILON;\
104 if (rare(!within_DBL_EPSILON(A,B))) {\
105 std::string xapian_assertion_msg(XAPIAN_ASSERT_LOCATION(within_DBL_EPSILON(A,B)));\
106 xapian_assertion_msg += " : values were ";\
107 xapian_assertion_msg += str(A);\
108 xapian_assertion_msg += " and ";\
109 xapian_assertion_msg += str(B);\
110 throw Xapian::AssertionError(xapian_assertion_msg);\
112 } while (0)
114 #endif
116 // If assertions are disabled, set the macros to expand to (void)0 so that
117 // we get a compiler error in this case for assertions missing a trailing
118 // semicolon. This avoids one source of compile errors in debug builds
119 // which don't manifest in non-debug builds.
121 #ifndef Assert
122 # define Assert(COND) (void)0
123 # define AssertRel(A,REL,B) (void)0
124 # define AssertEq(A,B) (void)0
125 # define AssertEqDouble(A,B) (void)0
126 #endif
128 #ifndef AssertParanoid
129 # define AssertParanoid(COND) (void)0
130 # define AssertRelParanoid(A,REL,B) (void)0
131 # define AssertEqParanoid(A,B) (void)0
132 # define AssertEqDoubleParanoid(A,B) (void)0
133 #endif
135 /** Assert at compile-time that type TYPE is unsigned. */
136 #define STATIC_ASSERT_UNSIGNED_TYPE(TYPE) \
137 static_assert(static_cast<TYPE>(-1) > 0, "Type " #TYPE " not unsigned")
139 /** Assert at compile-time that integer type T1 can hold any value which
140 * integer type T2 can.
142 * NB Doesn't currently work reliably for type bool (which is typically
143 * incorrectly treated as equivalent to unsigned char or unsigned int).
145 * If T1 is unsigned, T2 must be unsigned and have no more bits.
147 * If T1 is signed, then T2 must have no more bits (if also signed) or
148 * fewer bits (if unsigned).
150 #define STATIC_ASSERT_TYPE_DOMINATES(T1, T2) \
151 static_assert(static_cast<T1>(-1) > 0 ? \
152 (static_cast<T2>(-1) > 0 && sizeof(T1) >= sizeof(T2)) : \
153 (sizeof(T1) >= sizeof(T2) + (static_cast<T2>(-1) > 0)), \
154 "Type " #T1 " doesn't dominate type " #T2)
156 #endif // XAPIAN_INCLUDED_OMASSERT_H