2021-04-18 07:35:25 +04:00
/*
Simple DirectMedia Layer
2022-07-15 06:00:50 +04:00
Copyright ( C ) 1997 - 2022 Sam Lantinga < slouken @ libsdl . org >
2021-04-18 07:35:25 +04:00
This software is provided ' as - is ' , without any express or implied
warranty . In no event will the authors be held liable for any damages
arising from the use of this software .
Permission is granted to anyone to use this software for any purpose ,
including commercial applications , and to alter it and redistribute it
freely , subject to the following restrictions :
1. The origin of this software must not be misrepresented ; you must not
claim that you wrote the original software . If you use this software
in a product , an acknowledgment in the product documentation would be
appreciated but is not required .
2. Altered source versions must be plainly marked as such , and must not be
misrepresented as being the original software .
3. This notice may not be removed or altered from any source distribution .
*/
# ifndef SDL_assert_h_
# define SDL_assert_h_
2022-07-19 07:48:31 +04:00
# include "SDL_config.h"
2021-04-18 07:35:25 +04:00
# include "begin_code.h"
/* Set up for C function definitions, even when using C++ */
# ifdef __cplusplus
extern " C " {
# endif
# ifndef SDL_ASSERT_LEVEL
# ifdef SDL_DEFAULT_ASSERT_LEVEL
# define SDL_ASSERT_LEVEL SDL_DEFAULT_ASSERT_LEVEL
# elif defined(_DEBUG) || defined(DEBUG) || \
( defined ( __GNUC__ ) & & ! defined ( __OPTIMIZE__ ) )
# define SDL_ASSERT_LEVEL 2
# else
# define SDL_ASSERT_LEVEL 1
# endif
# endif /* SDL_ASSERT_LEVEL */
/*
These are macros and not first class functions so that the debugger breaks
on the assertion line and not in some random guts of SDL , and so each
assert can have unique static variables associated with it .
*/
# if defined(_MSC_VER)
/* Don't include intrin.h here because it contains C++ code */
extern void __cdecl __debugbreak ( void ) ;
# define SDL_TriggerBreakpoint() __debugbreak()
# elif ( (!defined(__NACL__)) && ((defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__))) )
# define SDL_TriggerBreakpoint() __asm__ __volatile__ ( "int $3\n\t" )
2021-05-09 13:30:38 +04:00
# elif ( defined(__APPLE__) && (defined(__arm64__) || defined(__aarch64__)) ) /* this might work on other ARM targets, but this is a known quantity... */
2021-04-20 23:40:33 +04:00
# define SDL_TriggerBreakpoint() __asm__ __volatile__ ( "brk #22\n\t" )
2021-05-09 13:30:38 +04:00
# elif defined(__APPLE__) && defined(__arm__)
# define SDL_TriggerBreakpoint() __asm__ __volatile__ ( "bkpt #22\n\t" )
2021-04-18 07:35:25 +04:00
# elif defined(__386__) && defined(__WATCOMC__)
# define SDL_TriggerBreakpoint() { _asm { int 0x03 } }
# elif defined(HAVE_SIGNAL_H) && !defined(__WATCOMC__)
# include <signal.h>
# define SDL_TriggerBreakpoint() raise(SIGTRAP)
# else
/* How do we trigger breakpoints on this platform? */
# define SDL_TriggerBreakpoint()
# endif
# if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 supports __func__ as a standard. */
# define SDL_FUNCTION __func__
# elif ((__GNUC__ >= 2) || defined(_MSC_VER) || defined (__WATCOMC__))
# define SDL_FUNCTION __FUNCTION__
# else
# define SDL_FUNCTION "???"
# endif
# define SDL_FILE __FILE__
# define SDL_LINE __LINE__
/*
sizeof ( x ) makes the compiler still parse the expression even without
assertions enabled , so the code is always checked at compile time , but
doesn ' t actually generate code for it , so there are no side effects or
expensive checks at run time , just the constant size of what x WOULD be ,
which presumably gets optimized out as unused .
This also solves the problem of . . .
int somevalue = blah ( ) ;
SDL_assert ( somevalue = = 1 ) ;
. . . which would cause compiles to complain that somevalue is unused if we
disable assertions .
*/
/* "while (0,0)" fools Microsoft's compiler's /W4 warning level into thinking
this condition isn ' t constant . And looks like an owl ' s face ! */
# ifdef _MSC_VER /* stupid /W4 warnings. */
# define SDL_NULL_WHILE_LOOP_CONDITION (0,0)
# else
# define SDL_NULL_WHILE_LOOP_CONDITION (0)
# endif
# define SDL_disabled_assert(condition) \
do { ( void ) sizeof ( ( condition ) ) ; } while ( SDL_NULL_WHILE_LOOP_CONDITION )
typedef enum
{
SDL_ASSERTION_RETRY , /**< Retry the assert immediately. */
SDL_ASSERTION_BREAK , /**< Make the debugger trigger a breakpoint. */
SDL_ASSERTION_ABORT , /**< Terminate the program. */
SDL_ASSERTION_IGNORE , /**< Ignore the assert. */
SDL_ASSERTION_ALWAYS_IGNORE /**< Ignore the assert from now on. */
} SDL_AssertState ;
typedef struct SDL_AssertData
{
int always_ignore ;
unsigned int trigger_count ;
const char * condition ;
const char * filename ;
int linenum ;
const char * function ;
const struct SDL_AssertData * next ;
} SDL_AssertData ;
# if (SDL_ASSERT_LEVEL > 0)
/* Never call this directly. Use the SDL_assert* macros. */
extern DECLSPEC SDL_AssertState SDLCALL SDL_ReportAssertion ( SDL_AssertData * ,
const char * ,
const char * , int )
# if defined(__clang__)
# if __has_feature(attribute_analyzer_noreturn)
/* this tells Clang's static analysis that we're a custom assert function,
and that the analyzer should assume the condition was always true past this
SDL_assert test . */
__attribute__ ( ( analyzer_noreturn ) )
# endif
# endif
;
/* the do {} while(0) avoids dangling else problems:
if ( x ) SDL_assert ( y ) ; else blah ( ) ;
. . . without the do / while , the " else " could attach to this macro ' s " if " .
We try to handle just the minimum we need here in a macro . . . the loop ,
the static vars , and break points . The heavy lifting is handled in
SDL_ReportAssertion ( ) , in SDL_assert . c .
*/
# define SDL_enabled_assert(condition) \
do { \
while ( ! ( condition ) ) { \
static struct SDL_AssertData sdl_assert_data = { \
0 , 0 , # condition , 0 , 0 , 0 , 0 \
} ; \
const SDL_AssertState sdl_assert_state = SDL_ReportAssertion ( & sdl_assert_data , SDL_FUNCTION , SDL_FILE , SDL_LINE ) ; \
if ( sdl_assert_state = = SDL_ASSERTION_RETRY ) { \
continue ; /* go again. */ \
} else if ( sdl_assert_state = = SDL_ASSERTION_BREAK ) { \
SDL_TriggerBreakpoint ( ) ; \
} \
break ; /* not retrying. */ \
} \
} while ( SDL_NULL_WHILE_LOOP_CONDITION )
# endif /* enabled assertions support code */
/* Enable various levels of assertions. */
# if SDL_ASSERT_LEVEL == 0 /* assertions disabled */
# define SDL_assert(condition) SDL_disabled_assert(condition)
# define SDL_assert_release(condition) SDL_disabled_assert(condition)
# define SDL_assert_paranoid(condition) SDL_disabled_assert(condition)
# elif SDL_ASSERT_LEVEL == 1 /* release settings. */
# define SDL_assert(condition) SDL_disabled_assert(condition)
# define SDL_assert_release(condition) SDL_enabled_assert(condition)
# define SDL_assert_paranoid(condition) SDL_disabled_assert(condition)
# elif SDL_ASSERT_LEVEL == 2 /* normal settings. */
# define SDL_assert(condition) SDL_enabled_assert(condition)
# define SDL_assert_release(condition) SDL_enabled_assert(condition)
# define SDL_assert_paranoid(condition) SDL_disabled_assert(condition)
# elif SDL_ASSERT_LEVEL == 3 /* paranoid settings. */
# define SDL_assert(condition) SDL_enabled_assert(condition)
# define SDL_assert_release(condition) SDL_enabled_assert(condition)
# define SDL_assert_paranoid(condition) SDL_enabled_assert(condition)
# else
# error Unknown assertion level.
# endif
/* this assertion is never disabled at any level. */
# define SDL_assert_always(condition) SDL_enabled_assert(condition)
2021-05-09 13:30:38 +04:00
/**
* A callback that fires when an SDL assertion fails .
*
* \ param data a pointer to the SDL_AssertData structure corresponding to the
* current assertion
* \ param userdata what was passed as ` userdata ` to SDL_SetAssertionHandler ( )
* \ returns an SDL_AssertState value indicating how to handle the failure .
*/
2021-04-18 07:35:25 +04:00
typedef SDL_AssertState ( SDLCALL * SDL_AssertionHandler ) (
const SDL_AssertData * data , void * userdata ) ;
/**
2021-05-09 13:30:38 +04:00
* Set an application - defined assertion handler .
2021-04-18 07:35:25 +04:00
*
2021-05-09 13:30:38 +04:00
* This function allows an application to show its own assertion UI and / or
* force the response to an assertion failure . If the application doesn ' t
* provide this , SDL will try to do the right thing , popping up a
* system - specific GUI dialog , and probably minimizing any fullscreen windows .
2021-04-18 07:35:25 +04:00
*
2021-05-09 13:30:38 +04:00
* This callback may fire from any thread , but it runs wrapped in a mutex , so
* it will only fire from one thread at a time .
2021-04-18 07:35:25 +04:00
*
2021-05-09 13:30:38 +04:00
* This callback is NOT reset to SDL ' s internal handler upon SDL_Quit ( ) !
2021-04-18 07:35:25 +04:00
*
2021-05-09 13:30:38 +04:00
* \ param handler the SDL_AssertionHandler function to call when an assertion
* fails or NULL for the default handler
* \ param userdata a pointer that is passed to ` handler `
2021-04-18 07:35:25 +04:00
*
2021-12-07 05:20:09 +04:00
* \ since This function is available since SDL 2.0 .0 .
*
2021-05-09 13:30:38 +04:00
* \ sa SDL_GetAssertionHandler
2021-04-18 07:35:25 +04:00
*/
extern DECLSPEC void SDLCALL SDL_SetAssertionHandler (
SDL_AssertionHandler handler ,
void * userdata ) ;
/**
2021-05-09 13:30:38 +04:00
* Get the default assertion handler .
*
* This returns the function pointer that is called by default when an
* assertion is triggered . This is an internal function provided by SDL , that
* is used for assertions when SDL_SetAssertionHandler ( ) hasn ' t been used to
* provide a different function .
2021-04-18 07:35:25 +04:00
*
2021-05-09 13:30:38 +04:00
* \ returns the default SDL_AssertionHandler that is called when an assert
* triggers .
2021-04-18 07:35:25 +04:00
*
2021-05-09 13:30:38 +04:00
* \ since This function is available since SDL 2.0 .2 .
*
* \ sa SDL_GetAssertionHandler
2021-04-18 07:35:25 +04:00
*/
extern DECLSPEC SDL_AssertionHandler SDLCALL SDL_GetDefaultAssertionHandler ( void ) ;
/**
2021-05-09 13:30:38 +04:00
* Get the current assertion handler .
*
* This returns the function pointer that is called when an assertion is
* triggered . This is either the value last passed to
* SDL_SetAssertionHandler ( ) , or if no application - specified function is set ,
* is equivalent to calling SDL_GetDefaultAssertionHandler ( ) .
*
* The parameter ` puserdata ` is a pointer to a void * , which will store the
* " userdata " pointer that was passed to SDL_SetAssertionHandler ( ) . This value
* will always be NULL for the default handler . If you don ' t care about this
* data , it is safe to pass a NULL pointer to this function to ignore it .
2021-04-18 07:35:25 +04:00
*
2021-05-09 13:30:38 +04:00
* \ param puserdata pointer which is filled with the " userdata " pointer that
* was passed to SDL_SetAssertionHandler ( )
* \ returns the SDL_AssertionHandler that is called when an assert triggers .
2021-04-18 07:35:25 +04:00
*
2021-05-09 13:30:38 +04:00
* \ since This function is available since SDL 2.0 .2 .
*
* \ sa SDL_SetAssertionHandler
2021-04-18 07:35:25 +04:00
*/
extern DECLSPEC SDL_AssertionHandler SDLCALL SDL_GetAssertionHandler ( void * * puserdata ) ;
/**
2021-05-09 13:30:38 +04:00
* Get a list of all assertion failures .
*
* This function gets all assertions triggered since the last call to
* SDL_ResetAssertionReport ( ) , or the start of the program .
2021-04-18 07:35:25 +04:00
*
2021-05-09 13:30:38 +04:00
* The proper way to examine this data looks something like this :
2021-04-18 07:35:25 +04:00
*
2021-05-09 13:30:38 +04:00
* ` ` ` c
* const SDL_AssertData * item = SDL_GetAssertionReport ( ) ;
* while ( item ) {
* printf ( " '%s', %s (%s:%d), triggered %u times, always ignore: %s. \\ n " ,
* item - > condition , item - > function , item - > filename ,
* item - > linenum , item - > trigger_count ,
* item - > always_ignore ? " yes " : " no " ) ;
* item = item - > next ;
* }
* ` ` `
2021-04-18 07:35:25 +04:00
*
2021-05-09 13:30:38 +04:00
* \ returns a list of all failed assertions or NULL if the list is empty . This
* memory should not be modified or freed by the application .
2021-04-18 07:35:25 +04:00
*
2021-12-07 05:20:09 +04:00
* \ since This function is available since SDL 2.0 .0 .
*
2021-05-09 13:30:38 +04:00
* \ sa SDL_ResetAssertionReport
2021-04-18 07:35:25 +04:00
*/
extern DECLSPEC const SDL_AssertData * SDLCALL SDL_GetAssertionReport ( void ) ;
/**
2021-05-09 13:30:38 +04:00
* Clear the list of all assertion failures .
2021-04-18 07:35:25 +04:00
*
2021-05-09 13:30:38 +04:00
* This function will clear the list of all assertions triggered up to that
* point . Immediately following this call , SDL_GetAssertionReport will return
* no items . In addition , any previously - triggered assertions will be reset to
* a trigger_count of zero , and their always_ignore state will be false .
2021-04-18 07:35:25 +04:00
*
2021-12-07 05:20:09 +04:00
* \ since This function is available since SDL 2.0 .0 .
*
2021-05-09 13:30:38 +04:00
* \ sa SDL_GetAssertionReport
2021-04-18 07:35:25 +04:00
*/
extern DECLSPEC void SDLCALL SDL_ResetAssertionReport ( void ) ;
/* these had wrong naming conventions until 2.0.4. Please update your app! */
# define SDL_assert_state SDL_AssertState
# define SDL_assert_data SDL_AssertData
/* Ends C function definitions when using C++ */
# ifdef __cplusplus
}
# endif
# include "close_code.h"
# endif /* SDL_assert_h_ */
/* vi: set ts=4 sw=4 expandtab: */