assert.hpp 16 KB

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