summaryrefslogtreecommitdiff
path: root/boost/hana/assert.hpp
blob: c5297704744335138b6f5e65f1fbf3296528098e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
/*!
@file
Defines macros to perform different kinds of assertions.

@copyright Louis Dionne 2013-2016
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
 */

#ifndef BOOST_HANA_ASSERT_HPP
#define BOOST_HANA_ASSERT_HPP

#include <boost/hana/concept/constant.hpp>
#include <boost/hana/config.hpp>
#include <boost/hana/detail/preprocessor.hpp>
#include <boost/hana/if.hpp>
#include <boost/hana/value.hpp>

#include <cstdio>
#include <cstdlib>


#if defined(BOOST_HANA_DOXYGEN_INVOKED)
    //! @ingroup group-assertions
    //! Expands to a runtime assertion.
    //!
    //! Given a condition known at runtime, this macro expands to a runtime
    //! assertion similar to the `assert` macro. The provided condition must
    //! be explicitly convertible to a `bool`, and it must not be a model of
    //! the `Constant` concept. If the condition is a `Constant`, a static
    //! assertion will be triggered, asking you to use the
    //! `BOOST_HANA_CONSTANT_ASSERT` macro instead.
    //!
    //! @note
    //! This macro may only be used at function scope.
#   define BOOST_HANA_RUNTIME_ASSERT(condition) unspecified

    //! @ingroup group-assertions
    //! Equivalent to `BOOST_HANA_RUNTIME_ASSERT`, but allows providing a
    //! custom failure message.
    //!
    //! @warning
    //! Conditions that contain multiple comma-separated elements should be
    //! parenthesized.
#   define BOOST_HANA_RUNTIME_ASSERT_MSG(condition, message) unspecified

    //! @ingroup group-assertions
    //! Compile-time assertion for `Constant`s.
    //!
    //! Given a condition known at compile-time in the form of a `Constant`,
    //! this macro expands to a compile-time assertion similar to a `static_assert`.
    //! The provided condition must be a model of the `Constant` concept, in
    //! which case its value is retrieved using `hana::value` and then converted
    //! to a `bool`. If the condition is not a `Constant`, a static assertion
    //! will be triggered, asking you to use the `BOOST_HANA_RUNTIME_ASSERT`
    //! macro instead.
    //!
    //! This macro may be used at global/namespace scope and function scope
    //! only; it may not be used at class scope. Note that the condition may
    //! never be evaluated at runtime. Hence, any side effect may not take
    //! place (but you shouldn't rely on side effects inside assertions anyway).
#   define BOOST_HANA_CONSTANT_ASSERT(condition) unspecified

    //! @ingroup group-assertions
    //! Equivalent to `BOOST_HANA_CONSTANT_ASSERT`, but allows providing a
    //! custom failure message.
    //!
    //! @warning
    //! Conditions that contain multiple comma-separated elements should be
    //! parenthesized.
#   define BOOST_HANA_CONSTANT_ASSERT_MSG(condition, message) unspecified

    //! @ingroup group-assertions
    //! Expands to the strongest form of assertion possible for the given
    //! condition.
    //!
    //! Given a condition, `BOOST_HANA_ASSERT` expands either to a compile-time
    //! or to a runtime assertion, depending on whether the value of the
    //! condition is known at compile-time or at runtime. Compile-time
    //! assertions are always preferred over runtime assertions. If the
    //! condition is a model of the `Constant` concept, its value (retrievable
    //! with `hana::value`) is assumed to be explicitly convertible to `bool`,
    //! and a compile-time assertion is performed on it. Otherwise, the
    //! condition itself is assumed to be explicitly convertible to `bool`,
    //! and a runtime assertion is performed on it.
    //!
    //! If the assertion can be carried out at compile-time, the condition
    //! is not guaranteed to be evaluated at runtime at all (but it may).
    //! Hence, in general, you shouldn't rely on side effects that take place
    //! inside an assertion.
    //!
    //! @note
    //! This macro may only be used at function scope.
#   define BOOST_HANA_ASSERT(condition) unspecified

    //! @ingroup group-assertions
    //! Equivalent to `BOOST_HANA_ASSERT`, but allows providing a custom
    //! failure message.
    //!
    //! @warning
    //! Conditions that contain multiple comma-separated elements should be
    //! parenthesized.
#   define BOOST_HANA_ASSERT_MSG(condition, message) unspecified

    //! @ingroup group-assertions
    //! Expands to a static assertion or a runtime assertion, depending on
    //! whether `constexpr` lambdas are supported.
    //!
    //! This macro is used to assert on a condition that would be a constant
    //! expression if constexpr lambdas were supported. Right now, constexpr
    //! lambdas are not supported, and this is always a runtime assertion.
    //! Specifically, this is equivalent to `BOOST_HANA_RUNTIME_ASSERT`.
#   define BOOST_HANA_CONSTEXPR_ASSERT(condition) unspecified

    //! @ingroup group-assertions
    //! Equivalent to `BOOST_HANA_CONSTEXPR_ASSERT`, but allows providing a
    //! custom failure message.
#   define BOOST_HANA_CONSTEXPR_ASSERT_MSG(condition, message) unspecified

#elif defined(BOOST_HANA_CONFIG_DISABLE_ASSERTIONS)

#   define BOOST_HANA_CONSTANT_ASSERT(...)                      /* nothing */
#   define BOOST_HANA_CONSTANT_ASSERT_MSG(condition, message)   /* nothing */

#   define BOOST_HANA_RUNTIME_ASSERT(...)                       /* nothing */
#   define BOOST_HANA_RUNTIME_ASSERT_MSG(condition, message)    /* nothing */

#   define BOOST_HANA_ASSERT(...)                               /* nothing */
#   define BOOST_HANA_ASSERT_MSG(condition, message)            /* nothing */

#   define BOOST_HANA_CONSTEXPR_ASSERT(...)                     /* nothing */
#   define BOOST_HANA_CONSTEXPR_ASSERT_MSG(condition, message)  /* nothing */

#else

//////////////////////////////////////////////////////////////////////////////
// BOOST_HANA_RUNTIME_ASSERT and BOOST_HANA_RUNTIME_ASSERT_MSG
//////////////////////////////////////////////////////////////////////////////
#   define BOOST_HANA_RUNTIME_ASSERT_MSG(condition, message)                \
        BOOST_HANA_RUNTIME_CHECK_MSG(condition, message)                    \
/**/

#   define BOOST_HANA_RUNTIME_ASSERT(...)                                   \
        BOOST_HANA_RUNTIME_CHECK(__VA_ARGS__)                               \
/**/

//////////////////////////////////////////////////////////////////////////////
// BOOST_HANA_CONSTANT_ASSERT and BOOST_HANA_CONSTANT_ASSERT_MSG
//////////////////////////////////////////////////////////////////////////////
#   define BOOST_HANA_CONSTANT_ASSERT_MSG(condition, message)               \
    BOOST_HANA_CONSTANT_CHECK_MSG(condition, message)                       \
/**/

#   define BOOST_HANA_CONSTANT_ASSERT(...)                                  \
        BOOST_HANA_CONSTANT_CHECK(__VA_ARGS__)                              \
/**/

//////////////////////////////////////////////////////////////////////////////
// BOOST_HANA_ASSERT and BOOST_HANA_ASSERT_MSG
//////////////////////////////////////////////////////////////////////////////
#   define BOOST_HANA_ASSERT_MSG(condition, message)                        \
        BOOST_HANA_CHECK_MSG(condition, message)                            \
/**/

#   define BOOST_HANA_ASSERT(...)                                           \
        BOOST_HANA_CHECK(__VA_ARGS__)                                       \
/**/

//////////////////////////////////////////////////////////////////////////////
// BOOST_HANA_CONSTEXPR_ASSERT and BOOST_HANA_CONSTEXPR_ASSERT_MSG
//////////////////////////////////////////////////////////////////////////////
#   define BOOST_HANA_CONSTEXPR_ASSERT_MSG(condition, message)              \
        BOOST_HANA_CONSTEXPR_CHECK_MSG(condition, message)                  \
/**/

#   define BOOST_HANA_CONSTEXPR_ASSERT(...)                                 \
        BOOST_HANA_CONSTEXPR_CHECK(__VA_ARGS__)                             \
/**/

#endif

//////////////////////////////////////////////////////////////////////////////
// BOOST_HANA_RUNTIME_CHECK and BOOST_HANA_RUNTIME_CHECK_MSG
//////////////////////////////////////////////////////////////////////////////

//! @ingroup group-assertions
//! Equivalent to `BOOST_HANA_RUNTIME_ASSERT_MSG`, but not influenced by the
//! `BOOST_HANA_CONFIG_DISABLE_ASSERTIONS` config macro. For internal use only.
#   define BOOST_HANA_RUNTIME_CHECK_MSG(condition, message)                 \
    do {                                                                    \
        auto __hana_tmp = condition;                                        \
        static_assert(!::boost::hana::Constant<decltype(__hana_tmp)>::value,\
        "the expression (" # condition ") yields a Constant; "              \
        "use BOOST_HANA_CONSTANT_ASSERT instead");                          \
                                                                            \
        if (!static_cast<bool>(__hana_tmp)) {                               \
            ::std::fprintf(stderr, "Assertion failed: "                     \
                "(%s), function %s, file %s, line %i.\n",                   \
                message, __func__, __FILE__, __LINE__);                     \
            ::std::abort();                                                 \
        }                                                                   \
    } while (false);                                                        \
    static_assert(true, "force trailing semicolon")                         \
/**/

//! @ingroup group-assertions
//! Equivalent to `BOOST_HANA_RUNTIME_ASSERT`, but not influenced by the
//! `BOOST_HANA_CONFIG_DISABLE_ASSERTIONS` config macro. For internal use only.
#   define BOOST_HANA_RUNTIME_CHECK(...)                                    \
        BOOST_HANA_RUNTIME_CHECK_MSG(                                       \
            (__VA_ARGS__),                                                  \
            BOOST_HANA_PP_STRINGIZE(__VA_ARGS__)                            \
        )                                                                   \
/**/

//////////////////////////////////////////////////////////////////////////////
// BOOST_HANA_CONSTANT_CHECK and BOOST_HANA_CONSTANT_CHECK_MSG
//////////////////////////////////////////////////////////////////////////////

//! @ingroup group-assertions
//! Equivalent to `BOOST_HANA_CONSTANT_ASSERT_MSG`, but not influenced by the
//! `BOOST_HANA_CONFIG_DISABLE_ASSERTIONS` config macro. For internal use only.
#   define BOOST_HANA_CONSTANT_CHECK_MSG(condition, message)                \
        auto BOOST_HANA_PP_CONCAT(__hana_tmp_, __LINE__) = condition;       \
        static_assert(::boost::hana::Constant<                              \
            decltype(BOOST_HANA_PP_CONCAT(__hana_tmp_, __LINE__))           \
        >::value,                                                           \
        "the expression " # condition " does not yield a Constant; "        \
        "use BOOST_HANA_RUNTIME_ASSERT instead");                           \
        static_assert(::boost::hana::value<                                 \
            decltype(BOOST_HANA_PP_CONCAT(__hana_tmp_, __LINE__))           \
        >(), message);                                                      \
        static_assert(true, "force trailing semicolon")                     \
/**/

//! @ingroup group-assertions
//! Equivalent to `BOOST_HANA_CONSTANT_ASSERT`, but not influenced by the
//! `BOOST_HANA_CONFIG_DISABLE_ASSERTIONS` config macro. For internal use only.
#   define BOOST_HANA_CONSTANT_CHECK(...)                                   \
        BOOST_HANA_CONSTANT_CHECK_MSG(                                      \
            (__VA_ARGS__),                                                  \
            BOOST_HANA_PP_STRINGIZE(__VA_ARGS__)                            \
        )                                                                   \
/**/

//////////////////////////////////////////////////////////////////////////////
// BOOST_HANA_CHECK and BOOST_HANA_CHECK_MSG
//////////////////////////////////////////////////////////////////////////////

//! @ingroup group-assertions
//! Equivalent to `BOOST_HANA_ASSERT_MSG`, but not influenced by the
//! `BOOST_HANA_CONFIG_DISABLE_ASSERTIONS` config macro. For internal use only.
#   define BOOST_HANA_CHECK_MSG(condition, message)                         \
    do {                                                                    \
        auto __hana_tmp = condition;                                        \
        ::boost::hana::if_(::boost::hana::bool_c<                           \
            ::boost::hana::Constant<decltype(__hana_tmp)>::value>,          \
            [](auto expr) {                                                 \
                static_assert(::boost::hana::value<decltype(expr)>(),       \
                message);                                                   \
            },                                                              \
            [](auto expr) {                                                 \
                if (!static_cast<bool>(expr)) {                             \
                    ::std::fprintf(stderr, "Assertion failed: "             \
                        "(%s), function %s, file %s, line %i.\n",           \
                        message, __func__, __FILE__, __LINE__);             \
                    ::std::abort();                                         \
                }                                                           \
            }                                                               \
        )(__hana_tmp);                                                      \
    } while (false);                                                        \
    static_assert(true, "force trailing semicolon")                         \
/**/

//! @ingroup group-assertions
//! Equivalent to `BOOST_HANA__ASSERT`, but not influenced by the
//! `BOOST_HANA_CONFIG_DISABLE_ASSERTIONS` config macro. For internal use only.
#   define BOOST_HANA_CHECK(...)                                            \
        BOOST_HANA_CHECK_MSG(                                               \
            (__VA_ARGS__),                                                  \
            BOOST_HANA_PP_STRINGIZE(__VA_ARGS__)                            \
        )                                                                   \
/**/

//////////////////////////////////////////////////////////////////////////////
// BOOST_HANA_CONSTEXPR_CHECK and BOOST_HANA_CONSTEXPR_CHECK_MSG
//////////////////////////////////////////////////////////////////////////////

//! @ingroup group-assertions
//! Equivalent to `BOOST_HANA_CONSTEXPR_ASSERT_MSG`, but not influenced by the
//! `BOOST_HANA_CONFIG_DISABLE_ASSERTIONS` config macro. For internal use only.
#   define BOOST_HANA_CONSTEXPR_CHECK_MSG(condition, message)               \
        BOOST_HANA_RUNTIME_CHECK_MSG(condition, message)                    \
/**/

//! @ingroup group-assertions
//! Equivalent to `BOOST_HANA_CONSTEXPR_ASSERT`, but not influenced by the
//! `BOOST_HANA_CONFIG_DISABLE_ASSERTIONS` config macro. For internal use only.
#   define BOOST_HANA_CONSTEXPR_CHECK(...)                                  \
        BOOST_HANA_CONSTEXPR_CHECK_MSG(                                     \
            (__VA_ARGS__),                                                  \
            BOOST_HANA_PP_STRINGIZE(__VA_ARGS__)                            \
        )                                                                   \
/**/

#endif // !BOOST_HANA_ASSERT_HPP