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