• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*!
2 @file
3 Defines macros to perform different kinds of assertions.
4 
5 @copyright Louis Dionne 2013-2017
6 Distributed under the Boost Software License, Version 1.0.
7 (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
8  */
9 
10 #ifndef BOOST_HANA_ASSERT_HPP
11 #define BOOST_HANA_ASSERT_HPP
12 
13 #include <boost/hana/concept/constant.hpp>
14 #include <boost/hana/config.hpp>
15 #include <boost/hana/detail/preprocessor.hpp>
16 #include <boost/hana/if.hpp>
17 #include <boost/hana/value.hpp>
18 
19 #include <cstdio>
20 #include <cstdlib>
21 
22 
23 #if defined(BOOST_HANA_DOXYGEN_INVOKED)
24     //! @ingroup group-assertions
25     //! Expands to a runtime assertion.
26     //!
27     //! Given a condition known at runtime, this macro expands to a runtime
28     //! assertion similar to the `assert` macro. The provided condition must
29     //! be explicitly convertible to a `bool`, and it must not be a model of
30     //! the `Constant` concept. If the condition is a `Constant`, a static
31     //! assertion will be triggered, asking you to use the
32     //! `BOOST_HANA_CONSTANT_ASSERT` macro instead.
33     //!
34     //! @note
35     //! This macro may only be used at function scope.
36 #   define BOOST_HANA_RUNTIME_ASSERT(condition) unspecified
37 
38     //! @ingroup group-assertions
39     //! Equivalent to `BOOST_HANA_RUNTIME_ASSERT`, but allows providing a
40     //! custom failure message.
41     //!
42     //! @warning
43     //! Conditions that contain multiple comma-separated elements should be
44     //! parenthesized.
45 #   define BOOST_HANA_RUNTIME_ASSERT_MSG(condition, message) unspecified
46 
47     //! @ingroup group-assertions
48     //! Compile-time assertion for `Constant`s.
49     //!
50     //! Given a condition known at compile-time in the form of a `Constant`,
51     //! this macro expands to a compile-time assertion similar to a `static_assert`.
52     //! The provided condition must be a model of the `Constant` concept, in
53     //! which case its value is retrieved using `hana::value` and then converted
54     //! to a `bool`. If the condition is not a `Constant`, a static assertion
55     //! will be triggered, asking you to use the `BOOST_HANA_RUNTIME_ASSERT`
56     //! macro instead.
57     //!
58     //! This macro may be used at global/namespace scope and function scope
59     //! only; it may not be used at class scope. Note that the condition may
60     //! never be evaluated at runtime. Hence, any side effect may not take
61     //! place (but you shouldn't rely on side effects inside assertions anyway).
62 #   define BOOST_HANA_CONSTANT_ASSERT(condition) unspecified
63 
64     //! @ingroup group-assertions
65     //! Equivalent to `BOOST_HANA_CONSTANT_ASSERT`, but allows providing a
66     //! custom failure message.
67     //!
68     //! @warning
69     //! Conditions that contain multiple comma-separated elements should be
70     //! parenthesized.
71 #   define BOOST_HANA_CONSTANT_ASSERT_MSG(condition, message) unspecified
72 
73     //! @ingroup group-assertions
74     //! Expands to the strongest form of assertion possible for the given
75     //! condition.
76     //!
77     //! Given a condition, `BOOST_HANA_ASSERT` expands either to a compile-time
78     //! or to a runtime assertion, depending on whether the value of the
79     //! condition is known at compile-time or at runtime. Compile-time
80     //! assertions are always preferred over runtime assertions. If the
81     //! condition is a model of the `Constant` concept, its value (retrievable
82     //! with `hana::value`) is assumed to be explicitly convertible to `bool`,
83     //! and a compile-time assertion is performed on it. Otherwise, the
84     //! condition itself is assumed to be explicitly convertible to `bool`,
85     //! and a runtime assertion is performed on it.
86     //!
87     //! If the assertion can be carried out at compile-time, the condition
88     //! is not guaranteed to be evaluated at runtime at all (but it may).
89     //! Hence, in general, you shouldn't rely on side effects that take place
90     //! inside an assertion.
91     //!
92     //! @note
93     //! This macro may only be used at function scope.
94 #   define BOOST_HANA_ASSERT(condition) unspecified
95 
96     //! @ingroup group-assertions
97     //! Equivalent to `BOOST_HANA_ASSERT`, but allows providing a custom
98     //! failure message.
99     //!
100     //! @warning
101     //! Conditions that contain multiple comma-separated elements should be
102     //! parenthesized.
103 #   define BOOST_HANA_ASSERT_MSG(condition, message) unspecified
104 
105     //! @ingroup group-assertions
106     //! Expands to a static assertion or a runtime assertion, depending on
107     //! whether `constexpr` lambdas are supported.
108     //!
109     //! This macro is used to assert on a condition that would be a constant
110     //! expression if constexpr lambdas were supported. Right now, constexpr
111     //! lambdas are not supported, and this is always a runtime assertion.
112     //! Specifically, this is equivalent to `BOOST_HANA_RUNTIME_ASSERT`.
113 #   define BOOST_HANA_CONSTEXPR_ASSERT(condition) unspecified
114 
115     //! @ingroup group-assertions
116     //! Equivalent to `BOOST_HANA_CONSTEXPR_ASSERT`, but allows providing a
117     //! custom failure message.
118 #   define BOOST_HANA_CONSTEXPR_ASSERT_MSG(condition, message) unspecified
119 
120 #elif defined(BOOST_HANA_CONFIG_DISABLE_ASSERTIONS)
121 
122 #   define BOOST_HANA_CONSTANT_ASSERT(...)                      /* nothing */
123 #   define BOOST_HANA_CONSTANT_ASSERT_MSG(condition, message)   /* nothing */
124 
125 #   define BOOST_HANA_RUNTIME_ASSERT(...)                       /* nothing */
126 #   define BOOST_HANA_RUNTIME_ASSERT_MSG(condition, message)    /* nothing */
127 
128 #   define BOOST_HANA_ASSERT(...)                               /* nothing */
129 #   define BOOST_HANA_ASSERT_MSG(condition, message)            /* nothing */
130 
131 #   define BOOST_HANA_CONSTEXPR_ASSERT(...)                     /* nothing */
132 #   define BOOST_HANA_CONSTEXPR_ASSERT_MSG(condition, message)  /* nothing */
133 
134 #else
135 
136 //////////////////////////////////////////////////////////////////////////////
137 // BOOST_HANA_RUNTIME_ASSERT and BOOST_HANA_RUNTIME_ASSERT_MSG
138 //////////////////////////////////////////////////////////////////////////////
139 #   define BOOST_HANA_RUNTIME_ASSERT_MSG(condition, message)                \
140         BOOST_HANA_RUNTIME_CHECK_MSG(condition, message)                    \
141 /**/
142 
143 #   define BOOST_HANA_RUNTIME_ASSERT(...)                                   \
144         BOOST_HANA_RUNTIME_CHECK(__VA_ARGS__)                               \
145 /**/
146 
147 //////////////////////////////////////////////////////////////////////////////
148 // BOOST_HANA_CONSTANT_ASSERT and BOOST_HANA_CONSTANT_ASSERT_MSG
149 //////////////////////////////////////////////////////////////////////////////
150 #   define BOOST_HANA_CONSTANT_ASSERT_MSG(condition, message)               \
151     BOOST_HANA_CONSTANT_CHECK_MSG(condition, message)                       \
152 /**/
153 
154 #   define BOOST_HANA_CONSTANT_ASSERT(...)                                  \
155         BOOST_HANA_CONSTANT_CHECK(__VA_ARGS__)                              \
156 /**/
157 
158 //////////////////////////////////////////////////////////////////////////////
159 // BOOST_HANA_ASSERT and BOOST_HANA_ASSERT_MSG
160 //////////////////////////////////////////////////////////////////////////////
161 #   define BOOST_HANA_ASSERT_MSG(condition, message)                        \
162         BOOST_HANA_CHECK_MSG(condition, message)                            \
163 /**/
164 
165 #   define BOOST_HANA_ASSERT(...)                                           \
166         BOOST_HANA_CHECK(__VA_ARGS__)                                       \
167 /**/
168 
169 //////////////////////////////////////////////////////////////////////////////
170 // BOOST_HANA_CONSTEXPR_ASSERT and BOOST_HANA_CONSTEXPR_ASSERT_MSG
171 //////////////////////////////////////////////////////////////////////////////
172 #   define BOOST_HANA_CONSTEXPR_ASSERT_MSG(condition, message)              \
173         BOOST_HANA_CONSTEXPR_CHECK_MSG(condition, message)                  \
174 /**/
175 
176 #   define BOOST_HANA_CONSTEXPR_ASSERT(...)                                 \
177         BOOST_HANA_CONSTEXPR_CHECK(__VA_ARGS__)                             \
178 /**/
179 
180 #endif
181 
182 //////////////////////////////////////////////////////////////////////////////
183 // BOOST_HANA_RUNTIME_CHECK and BOOST_HANA_RUNTIME_CHECK_MSG
184 //////////////////////////////////////////////////////////////////////////////
185 
186 //! @ingroup group-assertions
187 //! Equivalent to `BOOST_HANA_RUNTIME_ASSERT_MSG`, but not influenced by the
188 //! `BOOST_HANA_CONFIG_DISABLE_ASSERTIONS` config macro. For internal use only.
189 #   define BOOST_HANA_RUNTIME_CHECK_MSG(condition, message)                 \
190     do {                                                                    \
191         auto __hana_tmp = condition;                                        \
192         static_assert(!::boost::hana::Constant<decltype(__hana_tmp)>::value,\
193         "the expression (" # condition ") yields a Constant; "              \
194         "use BOOST_HANA_CONSTANT_ASSERT instead");                          \
195                                                                             \
196         if (!static_cast<bool>(__hana_tmp)) {                               \
197             ::std::fprintf(stderr, "Assertion failed: "                     \
198                 "(%s), function %s, file %s, line %i.\n",                   \
199                 message, __func__, __FILE__, __LINE__);                     \
200             ::std::abort();                                                 \
201         }                                                                   \
202     } while (false);                                                        \
203     static_assert(true, "force trailing semicolon")                         \
204 /**/
205 
206 //! @ingroup group-assertions
207 //! Equivalent to `BOOST_HANA_RUNTIME_ASSERT`, but not influenced by the
208 //! `BOOST_HANA_CONFIG_DISABLE_ASSERTIONS` config macro. For internal use only.
209 #   define BOOST_HANA_RUNTIME_CHECK(...)                                    \
210         BOOST_HANA_RUNTIME_CHECK_MSG(                                       \
211             (__VA_ARGS__),                                                  \
212             BOOST_HANA_PP_STRINGIZE(__VA_ARGS__)                            \
213         )                                                                   \
214 /**/
215 
216 //////////////////////////////////////////////////////////////////////////////
217 // BOOST_HANA_CONSTANT_CHECK and BOOST_HANA_CONSTANT_CHECK_MSG
218 //////////////////////////////////////////////////////////////////////////////
219 
220 //! @ingroup group-assertions
221 //! Equivalent to `BOOST_HANA_CONSTANT_ASSERT_MSG`, but not influenced by the
222 //! `BOOST_HANA_CONFIG_DISABLE_ASSERTIONS` config macro. For internal use only.
223 #   define BOOST_HANA_CONSTANT_CHECK_MSG(condition, message)                \
224         auto BOOST_HANA_PP_CONCAT(__hana_tmp_, __LINE__) = condition;       \
225         static_assert(::boost::hana::Constant<                              \
226             decltype(BOOST_HANA_PP_CONCAT(__hana_tmp_, __LINE__))           \
227         >::value,                                                           \
228         "the expression " # condition " does not yield a Constant; "        \
229         "use BOOST_HANA_RUNTIME_ASSERT instead");                           \
230         static_assert(::boost::hana::value<                                 \
231             decltype(BOOST_HANA_PP_CONCAT(__hana_tmp_, __LINE__))           \
232         >(), message);                                                      \
233         static_assert(true, "force trailing semicolon")                     \
234 /**/
235 
236 //! @ingroup group-assertions
237 //! Equivalent to `BOOST_HANA_CONSTANT_ASSERT`, but not influenced by the
238 //! `BOOST_HANA_CONFIG_DISABLE_ASSERTIONS` config macro. For internal use only.
239 #   define BOOST_HANA_CONSTANT_CHECK(...)                                   \
240         BOOST_HANA_CONSTANT_CHECK_MSG(                                      \
241             (__VA_ARGS__),                                                  \
242             BOOST_HANA_PP_STRINGIZE(__VA_ARGS__)                            \
243         )                                                                   \
244 /**/
245 
246 //////////////////////////////////////////////////////////////////////////////
247 // BOOST_HANA_CHECK and BOOST_HANA_CHECK_MSG
248 //////////////////////////////////////////////////////////////////////////////
249 
250 //! @ingroup group-assertions
251 //! Equivalent to `BOOST_HANA_ASSERT_MSG`, but not influenced by the
252 //! `BOOST_HANA_CONFIG_DISABLE_ASSERTIONS` config macro. For internal use only.
253 #   define BOOST_HANA_CHECK_MSG(condition, message)                         \
254     do {                                                                    \
255         auto __hana_tmp = condition;                                        \
256         ::boost::hana::if_(::boost::hana::bool_c<                           \
257             ::boost::hana::Constant<decltype(__hana_tmp)>::value>,          \
258             [](auto expr) {                                                 \
259                 static_assert(::boost::hana::value<decltype(expr)>(),       \
260                 message);                                                   \
261             },                                                              \
262             [](auto expr) {                                                 \
263                 if (!static_cast<bool>(expr)) {                             \
264                     ::std::fprintf(stderr, "Assertion failed: "             \
265                         "(%s), function %s, file %s, line %i.\n",           \
266                         message, __func__, __FILE__, __LINE__);             \
267                     ::std::abort();                                         \
268                 }                                                           \
269             }                                                               \
270         )(__hana_tmp);                                                      \
271     } while (false);                                                        \
272     static_assert(true, "force trailing semicolon")                         \
273 /**/
274 
275 //! @ingroup group-assertions
276 //! Equivalent to `BOOST_HANA__ASSERT`, but not influenced by the
277 //! `BOOST_HANA_CONFIG_DISABLE_ASSERTIONS` config macro. For internal use only.
278 #   define BOOST_HANA_CHECK(...)                                            \
279         BOOST_HANA_CHECK_MSG(                                               \
280             (__VA_ARGS__),                                                  \
281             BOOST_HANA_PP_STRINGIZE(__VA_ARGS__)                            \
282         )                                                                   \
283 /**/
284 
285 //////////////////////////////////////////////////////////////////////////////
286 // BOOST_HANA_CONSTEXPR_CHECK and BOOST_HANA_CONSTEXPR_CHECK_MSG
287 //////////////////////////////////////////////////////////////////////////////
288 
289 #if defined(BOOST_HANA_DOXYGEN_INVOKED)
290     //! @ingroup group-assertions
291     //! Equivalent to `BOOST_HANA_CONSTEXPR_ASSERT_MSG`, but not influenced by
292     //! the `BOOST_HANA_CONFIG_DISABLE_ASSERTIONS` config macro.
293     //! For internal use only.
294 #   define BOOST_HANA_CONSTEXPR_CHECK_MSG(condition, message) implementation-defined
295 
296     //! @ingroup group-assertions
297     //! Equivalent to `BOOST_HANA_CONSTEXPR_ASSERT`, but not influenced by the
298     //! `BOOST_HANA_CONFIG_DISABLE_ASSERTIONS` config macro.
299     //! For internal use only.
300 #   define BOOST_HANA_CONSTEXPR_CHECK(...) implementation-defined
301 
302 #elif defined(BOOST_HANA_CONFIG_HAS_CONSTEXPR_LAMBDA)
303 
304 #   define BOOST_HANA_CONSTEXPR_CHECK_MSG(condition, message)               \
305         static_assert(condition, message)                                   \
306 /**/
307 
308 #   define BOOST_HANA_CONSTEXPR_CHECK(...)                                  \
309         static_assert((__VA_ARGS__), BOOST_HANA_PP_STRINGIZE(__VA_ARGS__))  \
310 /**/
311 
312 #else
313 
314 #   define BOOST_HANA_CONSTEXPR_CHECK_MSG(condition, message)               \
315         BOOST_HANA_RUNTIME_CHECK_MSG(condition, message)                    \
316 /**/
317 
318 #   define BOOST_HANA_CONSTEXPR_CHECK(...)                                  \
319         BOOST_HANA_CONSTEXPR_CHECK_MSG(                                     \
320             (__VA_ARGS__),                                                  \
321             BOOST_HANA_PP_STRINGIZE(__VA_ARGS__)                            \
322         )                                                                   \
323 /**/
324 
325 #endif
326 
327 #endif // !BOOST_HANA_ASSERT_HPP
328