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