qxLib
assert.h
Go to the documentation of this file.
1 /**
2 
3  @file assert.h
4  @author Khrapov
5  @date 29.10.2020
6  @copyright © Nick Khrapov, 2021. All right reserved.
7 
8 **/
9 #pragma once
10 
11 #include <qx/algo/predicates.h>
12 #include <qx/category.h>
13 #include <qx/logger/logger.h>
14 
15 #include <exception>
16 
17 #if QX_MSVC
18  #define _QX_DEBUG_BREAK __debugbreak()
19 #elif QX_CLANG
20  #define _QX_DEBUG_BREAK __builtin_debugtrap()
21 #elif QX_GNU
22  #include <signal.h>
23  #define _QX_DEBUG_BREAK raise(SIGTRAP)
24 #else
25  #define _QX_DEBUG_BREAK QX_EMPTY_MACRO
26 #endif
27 
28 namespace qx::details
29 {
30 
31 template<verbosity eVerbosity>
32 void resolve_assert_proceeding(
33  // macro args
34  const category& fileCategory,
35  string_view svFunction,
36  string_view svFile,
37  int nLine,
38  string_view svCondition)
39 {
40  QX_LOGGER_INSTANCE.log(eVerbosity, QX_TEXT("[{}] "), fileCategory, svFile, svFunction, nLine, svCondition);
41  QX_LOGGER_INSTANCE.flush();
42 }
43 
44 template<verbosity eVerbosity>
45 void resolve_assert_proceeding(
46  // macro args
47  const category& fileCategory,
48  string_view svFunction,
49  string_view svFile,
50  int nLine,
51  string_view svCondition,
52  // ... args
53  const category& category)
54 {
55  string sMessage;
56  sMessage.append_format(QX_TEXT("[{}] "), svCondition);
57  QX_LOGGER_INSTANCE.log(eVerbosity, sMessage, category, svFile, svFunction, nLine);
58  QX_LOGGER_INSTANCE.flush();
59 }
60 
61 template<verbosity eVerbosity, class... args_t>
62  requires log_acceptable_args_c<args_t...>
63 void resolve_assert_proceeding(
64  // macro args
65  const category& fileCategory,
66  string_view svFunction,
67  string_view svFile,
68  int nLine,
69  string_view svCondition,
70  // ... args
71  format_string_strong_checks<args_t...> sFormat,
72  args_t&&... args)
73 {
74  string sMessage;
75  sMessage.append_format(QX_TEXT("[{}] "), svCondition);
76  sMessage.append_format(sFormat, std::forward<args_t>(args)...);
77  QX_LOGGER_INSTANCE.log(eVerbosity, sMessage, fileCategory, svFile, svFunction, nLine);
78  QX_LOGGER_INSTANCE.flush();
79 }
80 
81 template<verbosity eVerbosity>
82 void resolve_assert_proceeding(
83  // macro args
84  const category& fileCategory,
85  string_view svFunction,
86  string_view svFile,
87  int nLine,
88  string_view svCondition,
89  // ... args
90  string_view svMessage)
91 {
92  string sMessage;
93  sMessage.append_format(QX_TEXT("[{}] {}"), svCondition, svMessage);
94  QX_LOGGER_INSTANCE.log(eVerbosity, sMessage, fileCategory, svFile, svFunction, nLine);
95  QX_LOGGER_INSTANCE.flush();
96 }
97 
98 template<verbosity eVerbosity, class... args_t>
99  requires log_acceptable_args_c<args_t...>
100 void resolve_assert_proceeding(
101  // macro args
102  const category& fileCategory,
103  string_view svFunction,
104  string_view svFile,
105  int nLine,
106  string_view svCondition,
107  // ... args
108  const category& category,
109  format_string_strong_checks<args_t...> sFormat,
110  args_t&&... args)
111 {
112  string sMessage;
113  sMessage.append_format(QX_TEXT("[{}] "), svCondition);
114  sMessage.append_format(sFormat, std::forward<args_t>(args)...);
115  QX_LOGGER_INSTANCE.log(eVerbosity, sMessage, category, svFile, svFunction, nLine);
116  QX_LOGGER_INSTANCE.flush();
117 }
118 
119 template<verbosity eVerbosity>
120 void resolve_assert_proceeding(
121  // macro args
122  const category& fileCategory,
123  string_view svFunction,
124  string_view svFile,
125  int nLine,
126  string_view svCondition,
127  // ... args
128  const category& category,
129  string_view svMessage)
130 {
131  string sMessage;
132  sMessage.append_format(QX_TEXT("[{}] {}"), svCondition, svMessage);
133  QX_LOGGER_INSTANCE.log(eVerbosity, sMessage, category, svFile, svFunction, nLine);
134  QX_LOGGER_INSTANCE.flush();
135 }
136 
137 } // namespace qx::details
138 
139 // ----------------------------------- setup -----------------------------------
140 
141 #ifndef QX_DEBUG_BREAK
142  #define QX_DEBUG_BREAK _QX_DEBUG_BREAK
143 #endif
144 
145 #ifndef QX_EXPECT_BEFORE_DEBUG_BREAK
146  #define QX_EXPECT_BEFORE_DEBUG_BREAK(condition, ...) \
147  qx::details::resolve_assert_proceeding<qx::verbosity::error>( \
148  QX_FILE_CATEGORY(), \
149  qx::to_string(__FUNCTION__), \
150  QX_SHORT_FILE, \
151  QX_LINE, \
152  QX_TEXT(#condition), \
153  ##__VA_ARGS__)
154 #endif
155 
156 #ifndef QX_EXPECT_DEBUG_BREAK
157  #if QX_WITH_DEBUG_INFO
158  #define QX_EXPECT_DEBUG_BREAK QX_DEBUG_BREAK
159  #else
160  #define QX_EXPECT_DEBUG_BREAK true
161  #endif
162 #endif
163 
164 #ifndef QX_EXPECT_AFTER_DEBUG_BREAK
165  #define QX_EXPECT_AFTER_DEBUG_BREAK(condition, ...) true
166 #endif
167 
168 #ifndef QX_ASSERT_BEFORE_DEBUG_BREAK
169  #define QX_ASSERT_BEFORE_DEBUG_BREAK(condition, ...) \
170  qx::details::resolve_assert_proceeding<qx::verbosity::critical>( \
171  QX_FILE_CATEGORY(), \
172  qx::to_string(__FUNCTION__), \
173  QX_SHORT_FILE, \
174  QX_LINE, \
175  QX_TEXT(#condition), \
176  ##__VA_ARGS__)
177 #endif
178 
179 #ifndef QX_ASSERT_DEBUG_BREAK
180  #if QX_WITH_DEBUG_INFO
181  #define QX_ASSERT_DEBUG_BREAK QX_DEBUG_BREAK
182  #else
183  #define QX_ASSERT_DEBUG_BREAK true
184  #endif
185 #endif
186 
187 #ifndef QX_ASSERT_AFTER_DEBUG_BREAK
188  #define QX_ASSERT_AFTER_DEBUG_BREAK(condition, ...) std::terminate()
189 #endif
190 
191 // ------------------------------- common macros -------------------------------
192 
193 #define _QX_ASSERT(before_debug_break, debug_break, after_debug_break, condition, ...) \
194  (qx::predicates::is_valid(condition) \
195  || (before_debug_break(condition, ##__VA_ARGS__), \
196  debug_break, \
197  after_debug_break(condition, ##__VA_ARGS__), \
198  false))
199 
200 #define _QX_ASSERT_CONTINUE(before_debug_break, debug_break, after_debug_break, condition, ...) \
201  if (!_QX_ASSERT(before_debug_break, debug_break, after_debug_break, condition, ##__VA_ARGS__)) [[unlikely]] \
202  continue; \
203  else \
204  QX_EMPTY_MACRO
205 
206 #define _QX_ASSERT_BREAK(before_debug_break, debug_break, after_debug_break, condition, ...) \
207  if (!_QX_ASSERT(before_debug_break, debug_break, after_debug_break, condition, ##__VA_ARGS__)) [[unlikely]] \
208  break; \
209  else \
210  QX_EMPTY_MACRO
211 
212 #define _QX_ASSERT_RETURN( \
213  before_debug_break, \
214  debug_break, \
215  after_debug_break, \
216  return_keyword, \
217  condition, \
218  return_value, \
219  ...) \
220  if (!_QX_ASSERT(before_debug_break, debug_break, after_debug_break, condition, ##__VA_ARGS__)) [[unlikely]] \
221  return_keyword return_value; \
222  else \
223  QX_EMPTY_MACRO
224 
225 // -------------------------------- user macros --------------------------------
226 
227 /**
228  @brief Verifies that condition is true
229  @details ASSERT macros generate fatal failures and abort the program execution
230  @param condition - condition to check. if false, assert fails
231  @param ... - "category + format string + format arguments"
232  or "category + format string"
233  or "format string + format arguments"
234  or "format string"
235  or "category"
236 **/
237 #define QX_ASSERT(condition, ...) \
238  _QX_ASSERT( \
239  QX_ASSERT_BEFORE_DEBUG_BREAK, \
240  QX_ASSERT_DEBUG_BREAK, \
241  QX_ASSERT_AFTER_DEBUG_BREAK, \
242  condition, \
243  ##__VA_ARGS__)
244 
245 /**
246  @brief Verifies that condition is true
247  @details EXPECT macros generate nonfatal failures and allow to continue running
248  @param condition - condition to check. if false, assert fails
249  @param ... - "category + format string + format arguments"
250  or "category + format string"
251  or "format string + format arguments"
252  or "format string"
253  or "category"
254 **/
255 #define QX_EXPECT(condition, ...) \
256  _QX_ASSERT( \
257  QX_EXPECT_BEFORE_DEBUG_BREAK, \
258  QX_EXPECT_DEBUG_BREAK, \
259  QX_EXPECT_AFTER_DEBUG_BREAK, \
260  condition, \
261  ##__VA_ARGS__)
262 
263 /**
264  @brief Verifies that condition is true and continues loop if false
265  @details EXPECT macros generate nonfatal failures and allow to continue running
266  @param condition - condition to check. if false, assert fails
267  @param ... - "category + format string + format arguments"
268  or "category + format string"
269  or "format string + format arguments"
270  or "format string"
271  or "category"
272 **/
273 #define QX_EXPECT_CONTINUE(condition, ...) \
274  _QX_ASSERT_CONTINUE( \
275  QX_EXPECT_BEFORE_DEBUG_BREAK, \
276  QX_EXPECT_DEBUG_BREAK, \
277  QX_EXPECT_AFTER_DEBUG_BREAK, \
278  condition, \
279  ##__VA_ARGS__)
280 
281 /**
282  @brief Verifies that condition is true and break loop if false
283  @details EXPECT macros generate nonfatal failures and allow to continue running
284  @param condition - condition to check. if false, assert fails
285  @param ... - "category + format string + format arguments"
286  or "category + format string"
287  or "format string + format arguments"
288  or "format string"
289  or "category"
290 **/
291 #define QX_EXPECT_BREAK(condition, ...) \
292  _QX_ASSERT_BREAK( \
293  QX_EXPECT_BEFORE_DEBUG_BREAK, \
294  QX_EXPECT_DEBUG_BREAK, \
295  QX_EXPECT_AFTER_DEBUG_BREAK, \
296  condition, \
297  ##__VA_ARGS__)
298 
299 /**
300  @brief Verifies that condition is true and "return return_value;" if false
301  @details EXPECT macros generate nonfatal failures and allow to continue running
302  @param condition - condition to check. if false, assert fails
303  @param return_value - return value. use empty argument, if return type is void
304  @param ... - "category + format string + format arguments"
305  or "category + format string"
306  or "format string + format arguments"
307  or "format string"
308  or "category"
309 **/
310 #define QX_EXPECT_RETURN(condition, return_value, ...) \
311  _QX_ASSERT_RETURN( \
312  QX_EXPECT_BEFORE_DEBUG_BREAK, \
313  QX_EXPECT_DEBUG_BREAK, \
314  QX_EXPECT_AFTER_DEBUG_BREAK, \
315  return, \
316  condition, \
317  return_value, \
318  ##__VA_ARGS__)
319 
320 /**
321  @brief Verifies that condition is true and "return;" if false
322  @details EXPECT macros generate nonfatal failures and allow to continue running
323  @param condition - condition to check. if false, assert fails
324  @param ... - "category + format string + format arguments"
325  or "category + format string"
326  or "format string + format arguments"
327  or "format string"
328  or "category"
329 **/
330 #define QX_EXPECT_RETURN_VOID(condition, ...) \
331  _QX_ASSERT_RETURN( \
332  QX_EXPECT_BEFORE_DEBUG_BREAK, \
333  QX_EXPECT_DEBUG_BREAK, \
334  QX_EXPECT_AFTER_DEBUG_BREAK, \
335  return, \
336  condition, \
337  , \
338  ##__VA_ARGS__)
339 
340 /**
341  @brief Verifies that condition is true and "co_return return_value;" if false
342  @details EXPECT macros generate nonfatal failures and allow to continue running
343  @param condition - condition to check. if false, assert fails
344  @param return_value - return value. use empty argument, if return type is void
345  @param ... - "category + format string + format arguments"
346  or "category + format string"
347  or "format string + format arguments"
348  or "format string"
349  or "category"
350 **/
351 #define QX_EXPECT_CO_RETURN(condition, return_value, ...) \
352  _QX_ASSERT_RETURN( \
353  QX_EXPECT_BEFORE_DEBUG_BREAK, \
354  QX_EXPECT_DEBUG_BREAK, \
355  QX_EXPECT_AFTER_DEBUG_BREAK, \
356  co_return, \
357  condition, \
358  return_value, \
359  ##__VA_ARGS__)
360 
361 /**
362  @brief Verifies that condition is true and "co_return;" if false
363  @details EXPECT macros generate nonfatal failures and allow to continue running
364  @param condition - condition to check. if false, assert fails
365  @param ... - "category + format string + format arguments"
366  or "category + format string"
367  or "format string + format arguments"
368  or "format string"
369  or "category"
370 **/
371 #define QX_EXPECT_CO_RETURN_VOID(condition, ...) \
372  _QX_ASSERT_RETURN( \
373  QX_EXPECT_BEFORE_DEBUG_BREAK, \
374  QX_EXPECT_DEBUG_BREAK, \
375  QX_EXPECT_AFTER_DEBUG_BREAK, \
376  co_return, \
377  condition, \
378  , \
379  ##__VA_ARGS__)
380 
381 /**
382  @brief Use this as a condition in any macro above to indicate that this part of your code must never be executed
383 **/
384 #define QX_NO_ENTRY !QX_TEXT("No entry")
385 
386 /**
387  @brief Use this as a condition in any macro above to indicate that this part of your code is not ready yet
388 **/
389 #define QX_NOT_IMPLEMENTED !QX_TEXT("Not implemented")
390 
391 namespace qx::details
392 {
393 
394 inline bool hit_once(bool& bHit)
395 {
396  const bool bReturn = bHit;
397  bHit = true;
398  return bReturn;
399 }
400 
401 } // namespace qx::details
402 
403 /**
404  @def QX_PREDICATE_HIT_ONCE
405  @brief Predicate to add to a condition in any EXPECT macro. When added, a macro will only hit once.
406  @note It must be after the actual condition.
407  @code
408  QX_EXPECT((a > b || b == 0) || QX_PREDICATE_HIT_ONCE());
409  @endcode
410 **/
411 #define QX_PREDICATE_HIT_ONCE() \
412  []() \
413  { \
414  static bool h = false; \
415  return qx::details::hit_once(h); \
416  }()
requires(same_variadic_args_v< args_t... >) const expr auto coalesce(args_t &&... args)
Coalesce function, C# a ?? b analogue.
Definition: coalesce.inl:57