include/SDL_assert.h
author Sam Lantinga <slouken@libsdl.org>
Wed, 13 Jan 2010 07:52:53 +0000
changeset 3653 1cd9f7117b98
parent 3652 dbd6a29e4b77
child 3654 336f3df1578d
permissions -rw-r--r--
Automatically figure out the appropriate assertion level
slouken@3647
     1
/*
slouken@3647
     2
    SDL - Simple DirectMedia Layer
slouken@3647
     3
    Copyright (C) 1997-2009 Sam Lantinga
slouken@3647
     4
slouken@3647
     5
    This library is free software; you can redistribute it and/or
slouken@3647
     6
    modify it under the terms of the GNU Lesser General Public
slouken@3647
     7
    License as published by the Free Software Foundation; either
slouken@3647
     8
    version 2.1 of the License, or (at your option) any later version.
slouken@3647
     9
slouken@3647
    10
    This library is distributed in the hope that it will be useful,
slouken@3647
    11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
slouken@3647
    12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
slouken@3647
    13
    Lesser General Public License for more details.
slouken@3647
    14
slouken@3647
    15
    You should have received a copy of the GNU Lesser General Public
slouken@3647
    16
    License along with this library; if not, write to the Free Software
slouken@3647
    17
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
slouken@3647
    18
slouken@3647
    19
    Sam Lantinga
slouken@3647
    20
    slouken@libsdl.org
slouken@3647
    21
*/
slouken@3647
    22
#include "SDL_config.h"
slouken@3647
    23
slouken@3647
    24
#ifndef _SDL_assert_h
slouken@3647
    25
#define _SDL_assert_h
slouken@3647
    26
slouken@3647
    27
#ifndef SDL_ASSERT_LEVEL
slouken@3653
    28
#if defined(_DEBUG) || defined(DEBUG) || \
slouken@3653
    29
    (defined(__GNUC__) && !defined(__OPTIMIZE__))
slouken@3653
    30
#define SDL_ASSERT_LEVEL 2
slouken@3653
    31
#else
slouken@3653
    32
#define SDL_ASSERT_LEVEL 1
slouken@3647
    33
#endif
slouken@3653
    34
#endif /* SDL_ASSERT_LEVEL */
slouken@3647
    35
slouken@3647
    36
/*
slouken@3647
    37
sizeof (x) makes the compiler still parse the expression even without
slouken@3647
    38
assertions enabled, so the code is always checked at compile time, but
slouken@3647
    39
doesn't actually generate code for it, so there are no side effects or
slouken@3647
    40
expensive checks at run time, just the constant size of what x WOULD be,
slouken@3647
    41
which presumably gets optimized out as unused.
slouken@3647
    42
This also solves the problem of...
slouken@3647
    43
slouken@3647
    44
    int somevalue = blah();
slouken@3647
    45
    SDL_assert(somevalue == 1);
slouken@3647
    46
slouken@3647
    47
...which would cause compiles to complain that somevalue is unused if we
slouken@3647
    48
disable assertions.
slouken@3647
    49
*/
slouken@3647
    50
slouken@3647
    51
#define SDL_disabled_assert(condition) \
slouken@3647
    52
    do { (void) sizeof ((condition)); } while (0)
slouken@3647
    53
slouken@3647
    54
#if (SDL_ASSERT_LEVEL > 0)
slouken@3647
    55
slouken@3647
    56
/*
slouken@3647
    57
These are macros and not first class functions so that the debugger breaks
slouken@3647
    58
on the assertion line and not in some random guts of SDL, and so each
slouken@3647
    59
macro can have unique static variables associated with it.
slouken@3647
    60
*/
slouken@3647
    61
slouken@3647
    62
#if (defined(_MSC_VER) && ((_M_IX86) || (_M_X64)))
slouken@3647
    63
    #define SDL_TriggerBreakpoint() __asm { int 3 }
slouken@3647
    64
#elif (defined(__GNUC__) && ((__i386__) || (__x86_64__)))
slouken@3647
    65
    #define SDL_TriggerBreakpoint() __asm__ __volatile__ ( "int $3\n\t" )
slouken@3650
    66
#elif defined(HAVE_SIGNAL_H)
slouken@3647
    67
    #include <signal.h>
slouken@3647
    68
    #define SDL_TriggerBreakpoint() raise(SIGTRAP)
slouken@3647
    69
#else
slouken@3647
    70
    #error Please define your platform or set SDL_ASSERT_LEVEL to 0.
slouken@3647
    71
#endif
slouken@3647
    72
slouken@3647
    73
#if (__STDC_VERSION__ >= 199901L) /* C99 supports __func__ as a standard. */
slouken@3647
    74
#   define SDL_FUNCTION __func__
slouken@3647
    75
#elif ((__GNUC__ >= 2) || defined(_MSC_VER))
slouken@3647
    76
#   define SDL_FUNCTION __FUNCTION__
slouken@3647
    77
#else
slouken@3647
    78
#   define SDL_FUNCTION "???"
slouken@3647
    79
#endif
slouken@3647
    80
slouken@3647
    81
typedef enum
slouken@3647
    82
{
slouken@3647
    83
    SDL_ASSERTION_RETRY,  /**< Retry the assert immediately. */
slouken@3647
    84
    SDL_ASSERTION_BREAK,  /**< Make the debugger trigger a breakpoint. */
slouken@3647
    85
    SDL_ASSERTION_ABORT,  /**< Terminate the program. */
slouken@3647
    86
    SDL_ASSERTION_IGNORE,  /**< Ignore the assert. */
slouken@3647
    87
    SDL_ASSERTION_ALWAYS_IGNORE,  /**< Ignore the assert from now on. */
slouken@3647
    88
} SDL_assert_state;
slouken@3647
    89
slouken@3647
    90
typedef struct SDL_assert_data
slouken@3647
    91
{
slouken@3647
    92
    int always_ignore;
slouken@3647
    93
    unsigned int trigger_count;
slouken@3647
    94
    const char *condition;
slouken@3647
    95
    const char *filename;
slouken@3647
    96
    int linenum;
slouken@3647
    97
    const char *function;
slouken@3647
    98
    struct SDL_assert_data *next;
slouken@3647
    99
} SDL_assert_data;
slouken@3647
   100
slouken@3647
   101
SDL_assert_state SDL_ReportAssertion(SDL_assert_data *, const char *, int);
slouken@3647
   102
slouken@3647
   103
/* the do {} while(0) avoids dangling else problems:
slouken@3647
   104
    if (x) SDL_assert(y); else blah();
slouken@3647
   105
       ... without the do/while, the "else" could attach to this macro's "if".
slouken@3647
   106
   We try to handle just the minimum we need here in a macro...the loop,
slouken@3647
   107
   the static vars, and break points. The heavy lifting is handled in
slouken@3647
   108
   SDL_ReportAssertion(), in SDL_assert.c.
slouken@3647
   109
*/
slouken@3647
   110
#define SDL_enabled_assert(condition) \
slouken@3647
   111
    do { \
slouken@3647
   112
        while ( !(condition) ) { \
slouken@3649
   113
            static struct SDL_assert_data assert_data = { \
slouken@3647
   114
                0, 0, #condition, __FILE__, 0, 0, 0 \
slouken@3647
   115
            }; \
slouken@3649
   116
            const SDL_assert_state state = SDL_ReportAssertion(&assert_data, \
slouken@3647
   117
                                                               SDL_FUNCTION, \
slouken@3649
   118
                                                               __LINE__); \
slouken@3647
   119
            if (state == SDL_ASSERTION_RETRY) { \
slouken@3647
   120
                continue; /* go again. */ \
slouken@3647
   121
            } else if (state == SDL_ASSERTION_BREAK) { \
slouken@3647
   122
                SDL_TriggerBreakpoint(); \
slouken@3647
   123
            } \
slouken@3647
   124
            break; /* not retrying. */ \
slouken@3647
   125
        } \
slouken@3647
   126
    } while (0)
slouken@3647
   127
slouken@3647
   128
#endif  /* enabled assertions support code */
slouken@3647
   129
slouken@3647
   130
/* Enable various levels of assertions. */
slouken@3647
   131
#if SDL_ASSERT_LEVEL == 0   /* assertions disabled */
slouken@3647
   132
#   define SDL_assert(condition) SDL_disabled_assert(condition)
slouken@3647
   133
#   define SDL_assert_release(condition) SDL_disabled_assert(condition)
slouken@3647
   134
#   define SDL_assert_paranoid(condition) SDL_disabled_assert(condition)
slouken@3647
   135
#elif SDL_ASSERT_LEVEL == 1  /* release settings. */
slouken@3652
   136
#   define SDL_assert(condition) SDL_disabled_assert(condition)
slouken@3647
   137
#   define SDL_assert_release(condition) SDL_enabled_assert(condition)
slouken@3652
   138
#   define SDL_assert_paranoid(condition) SDL_disabled_assert(condition)
slouken@3647
   139
#elif SDL_ASSERT_LEVEL == 2  /* normal settings. */
slouken@3647
   140
#   define SDL_assert(condition) SDL_enabled_assert(condition)
slouken@3647
   141
#   define SDL_assert_release(condition) SDL_enabled_assert(condition)
slouken@3647
   142
#   define SDL_assert_paranoid(condition) SDL_disabled_assert(condition)
slouken@3647
   143
#elif SDL_ASSERT_LEVEL == 3  /* paranoid settings. */
slouken@3647
   144
#   define SDL_assert(condition) SDL_enabled_assert(condition)
slouken@3647
   145
#   define SDL_assert_release(condition) SDL_enabled_assert(condition)
slouken@3647
   146
#   define SDL_assert_paranoid(condition) SDL_enabled_assert(condition)
slouken@3647
   147
#else
slouken@3647
   148
#   error Unknown assertion level. Please fix your SDL_config.h.
slouken@3647
   149
#endif
slouken@3647
   150
slouken@3647
   151
#endif /* _SDL_assert_h */
slouken@3647
   152
slouken@3647
   153
/* vi: set ts=4 sw=4 expandtab: */