Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
Assertions.h
Go to the documentation of this file.
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#ifndef _Stroika_Foundation_Debug_Assertions_h_
5#define _Stroika_Foundation_Debug_Assertions_h_ 1
6
7#include "Stroika/Foundation/StroikaPreComp.h"
8
9#include "Stroika/Foundation/Common/Common.h"
11
12/**
13 * \file
14 *
15 * \quote
16 * "Truth emerges more readily from error than from confusion."
17 * - Francis Bacon
18 *
19 * \note MACRO NAMES
20 * We use easily conflicted names, like Assert, Ensure, etc, for the macros, but elsewhere in Stroika,
21 * (since v3) - we switched to more decorated macro names, to avoid conflicts with other libraries.
22 *
23 * We chose NOT to do this with Ensure/Assert etc because
24 * > they are used so much it would be awkward
25 * > they will go away before too long, due to C++26 contracts (I hope)
26 */
27
28namespace Stroika::Foundation::Debug {
29
30/**
31 * \brief The qStroika_Foundation_Debug_AssertionsChecked flag determines if assertions are checked and validated (else used as hints for [[assume]])
32 *
33 * \brief alias qStroika_Foundation_Debug_AssertionsChecked was called qDebug before Stroika v3.0d11
34 * \brief this mechanism will be replaced in future versions of Stroika with 'contracts' (when we support c++26 - so two major releases from now)
35 *
36 * Defaults to value determined by other common bug defines (_DEBUG,NDEBUG), or 1.
37 *
38 * Assure other common defines for this concept: (_DEBUG,NDEBUG) are set consistently (even if its not explicitly checked).
39 */
40#if !defined(qStroika_Foundation_Debug_AssertionsChecked)
41#if defined(_DEBUG)
42#define qStroika_Foundation_Debug_AssertionsChecked 1
43#elif defined(NDEBUG)
44#define qStroika_Foundation_Debug_AssertionsChecked 0
45#else
46 // The <cassert> convention is that if NDEBUG is defined, we turn off debugging, but if nothing like it is defined, we
47 // turn on assertions by default. The caller can simply specify qStroika_Foundation_Debug_AssertionsChecked to prevent this defaulting if desired.
48#define qStroika_Foundation_Debug_AssertionsChecked 1
49#endif
50#endif
51
52// Check for consistent defines
53#if qStroika_Foundation_Debug_AssertionsChecked
54#if defined(NDEBUG)
55 // NB #warning is a non-standard extension - maybe we shouldnt use?
56 static_assert (false, "INCONSISTENT DEFINES (NDEBUG and qStroika_Foundation_Debug_AssertionsChecked=1)");
57#endif
58#else
59#if defined(_DEBUG)
60 // NB #warning is a non-standard extension - maybe we shouldnt use?
61 static_assert (false, "INCONSISTENT DEFINES (_DEBUG and qStroika_Foundation_Debug_AssertionsChecked=0)");
62#endif
63#endif
64
65 /**
66 * \brief Stroika_Foundation_Debug_Widen is used mostly internally to expand macros like Stroika_Foundation_Debug_Widen ( __FILE__) into UNICODE SAFE strings (so debug messages work properly if run on locale with charset other than matching filesystem)
67 * Idea from https://stackoverflow.com/questions/3291047/how-do-i-print-the-string-which-file-expands-to-correctly
68 */
69#define Stroika_Foundation_Debug_Widen2_(x) L##x
70#define Stroika_Foundation_Debug_Widen(x) Stroika_Foundation_Debug_Widen2_ (x)
71
72#if qStroika_Foundation_Debug_AssertionsChecked || defined(__Doxygen__)
73 /**
74 * Note: Some any parameters may be null, if no suitable value is available.
75 *
76 * \note AssertionHandlers shall NOT throw an exception (but I don't think we can declare typedef as noexcept)
77 * The reason for this is so that assertions can be used safely in circumstances that don't expect
78 * exceptions.
79 *
80 * Assertion handlers typically just print a debug message, and then exit the program. They are fatal, and must not return/throw.
81 */
82 using AssertionHandlerType = void (*) (const wchar_t* assertCategory, const wchar_t* assertionText, const wchar_t* fileName,
83 int lineNum, const wchar_t* functionName) noexcept;
84
85 /**
86 * Stroika makes very heavy use of assertions (to some extent inspired and
87 * patterned after Bertrand Meyers Eiffel assertion mechanism). Assertions are logical
88 * statements about function parameters, results, object states, etc, which are guaranteed
89 * (required) to be held true. These logical assertions serve two important functions:
90 * they <em>document</em> the requirements on input parameters for a function,
91 * and the promises made on function return. And they perform this documentation task <em>
92 * in such a way that the compiler can generate special code (conditionally) to verify that
93 * the assertions hold true</em>.
94 *
95 * This latter point about conditional compilation is important. If the macro
96 * preprocessor symbol <code>qStroika_Foundation_Debug_AssertionsChecked</code> is true (non-zero), then this assertion checking is
97 * enabled. If the symbol is false (zero), then the checking is disabled. <b>Of course the
98 * promises must always hold true!</b> But since the checking can significantly slow the code,
99 * it is best to only build with assertions on in certain circumstances (like while developing,
100 * and for much of QA/testing); but for released products it should be disabled so the editor
101 * operates at maximum speed.
102 *
103 * Stroika's assertion mechanism is not only present to help debug Stroika itself.
104 * After all, that would have little value to a user of the Stroika class library. It is also
105 * very helpful to a programmer using the class library. This is because nearly all the
106 * parameters passed to Stroika functions are immediately checked for validity, so mistakes
107 * are trapped as early as possible. If you pass bad values to a Stroika function, you will
108 * very likely get a debugger trap at almost exactly the point in your calling code where
109 * the error occurred. This can make debugging code written using Stroika much easier.
110 *
111 * Stroika provides four families of 'assertion' macro functions. The are named
112 * <code><em>Assert</em></code>,
113 * <code><em>Require</em></code>,
114 * <code><em>Ensure</em></code>, and
115 * <code><em>Verify</em></code>.
116 *
117 * The family you will most often be interested in is <code><em>Require</em></code>s.
118 * This is because these are used to check parameters validity on entry to a function. So
119 * typically when you see a <em>Require</em> fail, you will find that it is the calling
120 * function which is passing invalid arguments to the function which triggered the requirement
121 * failure. The other reason <em>Requires</em> will be of particular interest to programmers
122 * using Stroika is because checking the <em>Require</em> declarations at the beginning of a
123 * function is often very telling about the details of what sort of parameters the function
124 * expects.
125 *
126 * Probably the next most common sort of assertion you will see is <em>Ensures</em>.
127 * These state <em>promises</em> about the return values of a function. These should very rarely
128 * be triggered (if they are , they almost always indicate a bug in the function that triggered
129 * the Ensure failure). But the reason they are still of interest to programmers using Stroika
130 * is because they document what can be assumed about return values from a particular function.
131 *
132 * Plain <em>Assertions</em> are for assertions which don't fall into any of the above
133 * categories, but are still useful checks to be performed. When an assertion is triggered,
134 * it is almost always diagnostic of a bug in the code which triggered the assertion (or
135 * corrupted data structures). (aside: Assertions logically mean the same thing as Ensures,
136 * except that Ensures only check return values).</p>
137 *
138 * <em>Verify</em>s are inspired by the MFC VERIFY() macro, and the particular
139 * idiosyncrasies of the Win32 SDK, though they can be used cross-platform. Many of the Win32 SDK
140 * routines return non-zero on success, and zero on failure. Most sample Win32 code you look at
141 * simply ignores these results. For paranoia sake (which was very helpful in the old moldy win32s
142 * days) I wrap most Win32 SDK calls in a <em><code>Verify</code></em> wrapper. This - when
143 * debugging is enabled - checks the return value, and asserts if there is a problem.
144 * <b>Very Important: Unlike the other flavors of Assertions, Verify always evaluates its
145 * argument!</b>.
146 *
147 * This last point is worth repeating, as it is the only source of bugs I've ever seen
148 * introduced from the use of assertions (and I've seen the mistake more than once). <b>All
149 * flavors of assertions (except Verify) do NOT evaluate their arguments if <code>qStroika_Foundation_Debug_AssertionsChecked</code>
150 * is off</b>. This means you <b>cannot</b> count on the arguments to assertions having any
151 * side-effects. Use <em>Verify</em> instead of the other assertion flavors if you want to
152 * only check for compliance if <em><code>qStroika_Foundation_Debug_AssertionsChecked</code></em> is true, but want the side-effect
153 * to happen regardless.
154 *
155 * Now when assertions are triggered, just what happens? Here I think there is only one
156 * sensible answer. And that is that the program drops into the debugger. And what happens
157 * after that is undefined. This is Stroika's default behavior.
158 *
159 * But there are others who hold the view that triggered assertions should generate
160 * exceptions. This isn't an appropriate forum for explanations of why this is generally
161 * a bad idea. Instead, I simply provide the flexibility to allow those who want todo this
162 * that ability. There are <code>SetAssertionHandler</code> and <code>GetAssertionHandler</code>
163 * functions which allow the programmer to specify an alternate assertion handling scheme. The
164 * only assumption Stroika makes about this scheme is that the assertion handling function not
165 * return (so it must either exit the program, or longjump/throw). Led makes no guarantee that
166 * attempts to throw out past an assertion will succeed.
167 *
168 * GetAssertionHandler() never returns nullptr - it always returns some handler.
169 */
171
172 /**
173 */
174 AssertionHandlerType GetDefaultAssertionHandler ();
175
176 /**
177 * See @'GetAssertionHandler'. If SetAssertionHandler() is called with nullptr,
178 * then this merely selects the default assertion handler.
179 */
180 void SetAssertionHandler (AssertionHandlerType assertionHandler);
181
182 /**
183 */
184 AssertionHandlerType GetWeakAssertionHandler ();
185
186 /**
187 */
188 AssertionHandlerType GetDefaultWeakAssertionHandler ();
189
190 /**
191 * See @'GetAssertionHandler'. If SetAssertionHandler() is called with nullptr,
192 * then this merely selects the default assertion handler.
193 */
194 void SetWeakAssertionHandler (AssertionHandlerType assertionHandler);
195
196 namespace Private_ {
197 // don't call directly - implementation detail...
198 // NOTE - take strings as wchar_t so no lose UNICODE, but functionName as char* since I cannot figure out so far how to get UNICODE filename
199 [[noreturn]] void Assertion_Failure_Handler_ (const wchar_t* assertCategory, const wchar_t* assertionText, const wchar_t* fileName,
200 int lineNum, const char* functionName) noexcept;
201 // don't call directly - implementation detail...
202 // NOTE - take strings as wchar_t so no lose UNICODE, but functionName as char* since I cannot figure out so far how to get UNICODE filename
203 void Weak_Assertion_Failure_Handler_ (const wchar_t* assertCategory, const wchar_t* assertionText, const wchar_t* fileName,
204 int lineNum, const char* functionName) noexcept;
205
206 /**
207 * Private implementation utility macro
208 * \note these are ASCII - not wchar_t for now, since not clear how to get UNICODE here? --LGP 2024-04-01
209 */
210#if !defined(__Doxygen__)
211#if qCompilerAndStdLib_Support__PRETTY_FUNCTION__
212#define ASSERT_PRIVATE_ENCLOSING_FUNCTION_NAME_ __PRETTY_FUNCTION__
213#elif qCompilerAndStdLib_Support__func__
214#define ASSERT_PRIVATE_ENCLOSING_FUNCTION_NAME_ __func__
215#elif qCompilerAndStdLib_Support__FUNCTION__
216#define ASSERT_PRIVATE_ENCLOSING_FUNCTION_NAME_ __FUNCTION__
217#else
218#define ASSERT_PRIVATE_ENCLOSING_FUNCTION_NAME_ L""
219#endif
220#endif
221 }
222
223#endif
224
225 /**
226 * \def AssertExpression(c)
227 *
228 * Like Assert(), but without [[assume]] support, and in the form of an expression (since https://en.cppreference.com/w/cpp/language/attributes/assume - can only be applied to a statement)
229 *
230 * result is EXPRESSION;
231 */
232#if qStroika_Foundation_Debug_AssertionsChecked
233#define AssertExpression(c) \
234 (!!(c) || (Stroika::Foundation::Debug::Private_::Assertion_Failure_Handler_ (L"Assert", Stroika_Foundation_Debug_Widen (#c), \
235 Stroika_Foundation_Debug_Widen (__FILE__), __LINE__, \
236 ASSERT_PRIVATE_ENCLOSING_FUNCTION_NAME_), \
237 false))
238#else
239#define AssertExpression(c) ((void)0)
240#endif
241
242 /**
243 * \def Assert(c)
244 *
245 * \note logically
246 * if (!(c)) {
247 * GetAssertionHandler () (...)
248 * }
249 *
250 * \note As of C++23, Stroika uses the [[assume(X)]] attribute in the case of qStroika_Foundation_Debug_AssertionsChecked false. This means that - though the arguments will not be evaluated in a release
251 * build, they must be syntactic (new requirement in Stroika v3.0).
252 *
253 * @see GetAssertionHandler
254 */
255#if qStroika_Foundation_Debug_AssertionsChecked
256#define Assert(c) AssertExpression (c)
257#else
258#define Assert(c) _ASSUME_ATTRIBUTE_ (c)
259#endif
260
261 /**
262 * Like Require(), but without [[assume]] support, and in the form of an expression (since https://en.cppreference.com/w/cpp/language/attributes/assume - can only be applied to a statement)
263 *
264 * result is EXPRESSION;
265 */
266#if qStroika_Foundation_Debug_AssertionsChecked
267#define RequireExpression(c) \
268 (!!(c) || (Stroika::Foundation::Debug::Private_::Assertion_Failure_Handler_ (L"Require", Stroika_Foundation_Debug_Widen (#c), \
269 Stroika_Foundation_Debug_Widen (__FILE__), __LINE__, \
270 ASSERT_PRIVATE_ENCLOSING_FUNCTION_NAME_), \
271 false))
272#else
273#define RequireExpression(c) ((void)0)
274#endif
275
276 /**
277 * \def Require(c) - alias for Assert(), but with a different message upon failure, and used to declare an assertion about the incoming contract - arguments to a function.
278 */
279#if qStroika_Foundation_Debug_AssertionsChecked
280#define Require(c) RequireExpression (c)
281#else
282#define Require(c) _ASSUME_ATTRIBUTE_ (c)
283#endif
284
285 /**
286 * \def EnsureExpression(c) - alias for AssertExpression(), but with a different message, and used to declare an assertion promised about the state at the end of a function.
287 */
288#if qStroika_Foundation_Debug_AssertionsChecked
289#define EnsureExpression(c) \
290 (!!(c) || (Stroika::Foundation::Debug::Private_::Assertion_Failure_Handler_ (L"Ensure", Stroika_Foundation_Debug_Widen (#c), \
291 Stroika_Foundation_Debug_Widen (__FILE__), __LINE__, \
292 ASSERT_PRIVATE_ENCLOSING_FUNCTION_NAME_), \
293 false))
294#else
295#define EnsureExpression(c) ((void)0)
296#endif
297
298 /**
299 * \def Ensure(c) - alias for Assert(), but with a different message upon failure, and used to declare an assertion promised about the state at the end of a function.
300 */
301#if qStroika_Foundation_Debug_AssertionsChecked
302#define Ensure(c) EnsureExpression (c)
303#else
304#define Ensure(c) _ASSUME_ATTRIBUTE_ (c)
305#endif
306
307 /**
308 * \def AssertMember(p,c)
309 *
310 * Simple wrapper on Assert () - checking p is a member of class c (with dynamic_cast)
311 */
312#define AssertMember(p, c) Assert (dynamic_cast<const c*> (p) != nullptr)
313
314 /**
315 * \def EnsureMember(p,c)
316 *
317 * Simple wrapper on Ensure () - checking p is a member of class c (with dynamic_cast)
318 */
319#define EnsureMember(p, c) Ensure (dynamic_cast<const c*> (p) != nullptr)
320
321 /**
322 * \def RequireMember(p,c)
323 *
324 * Simple wrapper on Require () - checking p is a member of class c (with dynamic_cast)
325 */
326#define RequireMember(p, c) Require (dynamic_cast<const c*> (p) != nullptr)
327
328 /**
329 * \def AssertNotNull(p)
330 *
331 * Simple wrapper on Assert () - checking p != nullptr
332 */
333#define AssertNotNull(p) Assert (p != nullptr)
334
335 /**
336 * \def EnsureNotNull(p)
337 *
338 * Simple wrapper on Ensure () - checking p != nullptr
339 */
340#define EnsureNotNull(p) Ensure (p != nullptr)
341
342 /**
343 * \def RequireNotNull(p)
344 *
345 * Simple wrapper on Require () - checking p != nullptr
346 */
347#define RequireNotNull(p) Require (p != nullptr)
348
349 /**
350 * \def AssertNotReached(p)
351 *
352 * A program bug within the procedure called from, if this code is ever reached. In release builds, this calls unreachable, so can be optimized/assumed never reached.
353 */
354#if qStroika_Foundation_Debug_AssertionsChecked
355#define AssertNotReached() \
356 Stroika::Foundation::Debug::Private_::Assertion_Failure_Handler_ (L"Assert", L"Not Reached", Stroika_Foundation_Debug_Widen (__FILE__), \
357 __LINE__, ASSERT_PRIVATE_ENCLOSING_FUNCTION_NAME_)
358#elif __cpp_lib_unreachable < 202202
359#define AssertNotReached()
360#else
361#define AssertNotReached() unreachable ()
362#endif
363
364 /**
365 * \def EnsureNotReached(p)
366 *
367 * A program bug within the procedure called from, if this code is ever reached. In release builds, this calls unreachable, so can be optimized/assumed never reached.
368 */
369#if qStroika_Foundation_Debug_AssertionsChecked
370#define EnsureNotReached() \
371 Stroika::Foundation::Debug::Private_::Assertion_Failure_Handler_ (L"Ensure", L"Not Reached", Stroika_Foundation_Debug_Widen (__FILE__), \
372 __LINE__, ASSERT_PRIVATE_ENCLOSING_FUNCTION_NAME_)
373#elif __cpp_lib_unreachable < 202202
374#define EnsureNotReached()
375#else
376#define EnsureNotReached() unreachable ()
377#endif
378
379 /**
380 * \def RequireNotReached(p)
381 *
382 * A program bug within the caller, if this code is ever reached. In release builds, this calls unreachable, so can be optimized/assumed on argument condition.
383 */
384#if qStroika_Foundation_Debug_AssertionsChecked
385#define RequireNotReached() \
386 Stroika::Foundation::Debug::Private_::Assertion_Failure_Handler_ (L"Require", L"Not Reached", Stroika_Foundation_Debug_Widen (__FILE__), \
387 __LINE__, ASSERT_PRIVATE_ENCLOSING_FUNCTION_NAME_)
388#elif __cpp_lib_unreachable < 202202
389#define RequireNotReached()
390#else
391#define RequireNotReached() unreachable ()
392#endif
393
394 /**
395 * \def AssertNotImplemented()
396 *
397 * Use this to mark code that is not yet implemented. Using this name for sections of code which fail because of not being implemented
398 * makes it easier to search for such code, and when something breaks (esp during porting) - its easier to see why
399 */
400#if qStroika_Foundation_Debug_AssertionsChecked
401#define AssertNotImplemented() \
402 Stroika::Foundation::Debug::Private_::Assertion_Failure_Handler_ (L"Assert", L"Not Implemented", Stroika_Foundation_Debug_Widen (__FILE__), \
403 __LINE__, ASSERT_PRIVATE_ENCLOSING_FUNCTION_NAME_)
404#else
405#define AssertNotImplemented()
406#endif
407
408 /**
409 * \def Verify(c)
410 *
411 * Verify () is an 'assertion' like Assert, except its argument is ALWAYS
412 * EVALUATED, even if debug is OFF. This is useful for cases where you just want
413 * todo an assertion about the result of a function, but don't want to keep the
414 * result in a temporary just to look at it for this one assertion test...
415 *
416 * @see GetAssertionHandler
417 */
418#if qStroika_Foundation_Debug_AssertionsChecked
419#define Verify(c) Assert (c)
420#else
421#define Verify(c) ((void)(c))
422#endif
423
424 /**
425 * \brief A WeakAssert() is for things that aren't guaranteed to be true, but are overwhelmingly likely to be true. Use this so you see debug logs of rare events you way want to dig into, but don't want to fail/crash the program just because it fails.
426 *
427 * \def WeakAssert(c)
428 *
429 * \note logically
430 * if (!(c)) {
431 * Stroika::Foundation::Debug::Private_::Weak_Assertion_Failure_Handler_ (L"Assert", Stroika_Foundation_Debug_Widen (#c), Stroika_Foundation_Debug_Widen ( __FILE__), __LINE__, ASSERT_PRIVATE_ENCLOSING_FUNCTION_NAME_); }
432 * }
433 * But using funny !! and || syntax to allow use in expressions
434 *
435 * @see GetWeakAssertionHandler
436 */
437#if qStroika_Foundation_Debug_AssertionsChecked
438#define WeakAssert(c) \
439 (!!(c) || (Stroika::Foundation::Debug::Private_::Weak_Assertion_Failure_Handler_ (L"WeakAssert", Stroika_Foundation_Debug_Widen (#c), \
440 Stroika_Foundation_Debug_Widen (__FILE__), __LINE__, \
441 ASSERT_PRIVATE_ENCLOSING_FUNCTION_NAME_), \
442 false))
443#else
444#define WeakAssert(c) ((void)0)
445#endif
446
447 /**
448 * \def WeakAssertMember(p,c)
449 *
450 * @see AssertMember
451 */
452#define WeakAssertMember(p, c) WeakAssert (dynamic_cast<const c*> (p) != nullptr)
453
454 /**
455 * \def WeakAssertNotNull(p)
456 *
457 * @see WeakAssert
458 */
459#define WeakAssertNotNull(p) WeakAssert (p != nullptr)
460
461 /**
462 * \def WeakAssertNotReached(p)
463 *
464 * @see WeakAssert
465 */
466#if qStroika_Foundation_Debug_AssertionsChecked
467#define WeakAssertNotReached() \
468 Stroika::Foundation::Debug::Private_::Weak_Assertion_Failure_Handler_ ( \
469 L"WeakAssert", L"Not Reached", Stroika_Foundation_Debug_Widen (__FILE__), __LINE__, ASSERT_PRIVATE_ENCLOSING_FUNCTION_NAME_)
470#else
471#define WeakAssertNotReached()
472#endif
473
474 /**
475 * \def WeakAssertNotImplemented()
476 *
477 * Use this to mark code that is not yet implemented. Using this name for sections of code which fail because of not being implemented
478 * makes it easier to search for such code, and when something breaks (esp during porting) - its easier to see why
479 *
480 * @see WeakAssert
481 */
482#if qStroika_Foundation_Debug_AssertionsChecked
483#define WeakAssertNotImplemented() \
484 Stroika::Foundation::Debug::Private_::Weak_Assertion_Failure_Handler_ ( \
485 L"WeakAssert", L"Not Implemented", Stroika_Foundation_Debug_Widen (__FILE__), __LINE__, ASSERT_PRIVATE_ENCLOSING_FUNCTION_NAME_)
486#else
487#define WeakAssertNotImplemented()
488#endif
489
490 /**
491 * \def WeakVerify(c)
492 *
493 * Verify () is an assertion like Assert, except its argument is ALWAYS
494 * EVALUATED, even if debug is OFF. This is useful for cases where you just want
495 * todo an assertion about the result of a function, but don't want to keep the
496 * result in a temporary just to look at it for this one assertion test...
497 *
498 * @see Verify
499 * @see WeakAssert
500 */
501#if qStroika_Foundation_Debug_AssertionsChecked
502#define WeakVerify(c) WeakAssert (c)
503#else
504#define WeakVerify(c) ((void)(c))
505#endif
506
507 /// --------------------- DEPRECATED CODE ------------------------
508 [[deprecated ("Since Stroika v3.0d6 - use the wchar_t overload")]] void
509 SetWeakAssertionHandler (void (*legacyHandler) (const char* assertCategory, const char* assertionText, const char* fileName,
510 int lineNum, const char* functionName) noexcept);
511 [[deprecated ("Since Stroika v3.0d6 - use the wchar_t overload")]] void
512 SetAssertionHandler (void (*legacyHandler) (const char* assertCategory, const char* assertionText, const char* fileName, int lineNum,
513 const char* functionName) noexcept);
514
515// DEPRECATED NAME (to be removed in Stroika v3.0a1 - deprecated since Stroika v3.0d11)
516#define qDebug qStroika_Foundation_Debug_AssertionsChecked
517}
518
519/*
520 ********************************************************************************
521 ***************************** Implementation Details ***************************
522 ********************************************************************************
523 */
525
526#endif /*_Stroika_Foundation_Debug_Assertions_h_*/
void SetWeakAssertionHandler(AssertionHandlerType assertionHandler)
void SetAssertionHandler(AssertionHandlerType assertionHandler)
AssertionHandlerType GetAssertionHandler()
#define qStroika_Foundation_Debug_AssertionsChecked
The qStroika_Foundation_Debug_AssertionsChecked flag determines if assertions are checked and validat...
Definition Assertions.h:48
void(*)(const wchar_t *assertCategory, const wchar_t *assertionText, const wchar_t *fileName, int lineNum, const wchar_t *functionName) noexcept AssertionHandlerType
Definition Assertions.h:83
#define CompileTimeFlagChecker_HEADER(NS_PREFIX, NAME, VALUE)
CompileTimeFlagChecker_HEADER () will generate a LINK ERROR if you ever compile a header with one val...