1/****************************************************************************
2 * Copyright (C) 2014-2015 Intel Corporation.   All Rights Reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 ****************************************************************************/
23
24#ifndef __SWR_ASSERT_H__
25#define __SWR_ASSERT_H__
26
27#if !defined(__SWR_OS_H__)
28#error swr_assert.h should not be included directly, please include "common/os.h" instead.
29#endif
30
31//=============================================================================
32//
33// MACROS defined in this file:
34//
35// - SWR_ASSUME(expression, ...):   Tell compiler that the expression is true.
36//                                  Helps with static code analysis as well.
37//                                  DO NOT USE if code after this dynamically
38//                                  checks for errors and handles them.  The
39//                                  compiler may optimize out the error check.
40//
41// - SWR_ASSERT(expression, ...):   Inform the user is expression is false.
42//                                  This check is only conditionally made,
43//                                  usually only in debug mode.
44//
45// - SWR_REL_ASSERT(expression, ...): Unconditionally enabled version of SWR_ASSERT
46//
47// - SWR_ASSUME_ASSERT(expression, ...): Conditionally enabled SWR_ASSERT.  Uses
48//                                       SWR_ASSUME if SWR_ASSERT is disabled.
49//                                       DO NOT USE in combination with actual
50//                                       error checking (see SWR_ASSUME)
51//
52// - SWR_REL_ASSUME_ASSERT(expression, ...): Same as SWR_REL_ASSERT.
53//
54//=============================================================================
55
56// Stupid preprocessor tricks to avoid -Wall / -W4 warnings
57#if defined(_MSC_VER)
58#define _SWR_WARN_DISABLE __pragma(warning(push)) __pragma(warning(disable : 4127))
59#define _SWR_WARN_RESTORE __pragma(warning(pop))
60#else // ! MSVC compiler
61#define _SWR_WARN_DISABLE
62#define _SWR_WARN_RESTORE
63#endif
64
65#define _SWR_MACRO_START \
66    do                   \
67    {
68#define _SWR_MACRO_END \
69    _SWR_WARN_DISABLE  \
70    }                  \
71    while (0)          \
72    _SWR_WARN_RESTORE
73
74#if defined(_MSC_VER)
75#define SWR_ASSUME(e, ...)        \
76    _SWR_MACRO_START __assume(e); \
77    _SWR_MACRO_END
78#elif defined(__clang__)
79#define SWR_ASSUME(e, ...)                \
80    _SWR_MACRO_START __builtin_assume(e); \
81    _SWR_MACRO_END
82#elif defined(__GNUC__)
83#define SWR_ASSUME(e, ...)                                       \
84    _SWR_MACRO_START((e) ? ((void)0) : __builtin_unreachable()); \
85    _SWR_MACRO_END
86#else
87#define SWR_ASSUME(e, ...)      \
88    _SWR_MACRO_START ASSUME(e); \
89    _SWR_MACRO_END
90#endif
91
92#if !defined(SWR_ENABLE_ASSERTS)
93
94#if !defined(NDEBUG)
95#define SWR_ENABLE_ASSERTS 1
96#else
97#define SWR_ENABLE_ASSERTS 0
98#endif // _DEBUG
99
100#endif // SWR_ENABLE_ASSERTS
101
102#if !defined(SWR_ENABLE_REL_ASSERTS)
103#define SWR_ENABLE_REL_ASSERTS 1
104#endif
105
106#if SWR_ENABLE_ASSERTS || SWR_ENABLE_REL_ASSERTS
107#include "assert.h"
108
109#if !defined(__cplusplus)
110
111#pragma message("C++ is required for SWR Asserts, falling back to assert.h")
112
113#if SWR_ENABLE_ASSERTS
114#define SWR_ASSERT(e, ...) assert(e)
115#endif
116
117#if SWR_ENABLE_REL_ASSERTS
118#define SWR_REL_ASSERT(e, ...) assert(e)
119#endif
120
121#else
122
123bool SwrAssert(bool        chkDebugger,
124               bool&       enabled,
125               const char* pExpression,
126               const char* pFileName,
127               uint32_t    lineNum,
128               const char* function,
129               const char* pFmtString = nullptr,
130               ...);
131
132void SwrTrace(
133    const char* pFileName, uint32_t lineNum, const char* function, const char* pFmtString, ...);
134
135#define _SWR_ASSERT(chkDebugger, e, ...)                                                                            \
136    _SWR_MACRO_START                                                                                                \
137    bool expFailed = !(e);                                                                                          \
138    if (expFailed)                                                                                                  \
139    {                                                                                                               \
140        static bool swrAssertEnabled = true;                                                                        \
141        expFailed                    = SwrAssert(                                                                   \
142            chkDebugger, swrAssertEnabled, #e, __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
143        if (expFailed)                                                                                              \
144        {                                                                                                           \
145            DEBUGBREAK;                                                                                             \
146        }                                                                                                           \
147    }                                                                                                               \
148    _SWR_MACRO_END
149
150#define _SWR_INVALID(chkDebugger, ...)                                                                     \
151    _SWR_MACRO_START                                                                                       \
152    static bool swrAssertEnabled = true;                                                                   \
153    bool        expFailed        = SwrAssert(                                                              \
154        chkDebugger, swrAssertEnabled, "", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
155    if (expFailed)                                                                                         \
156    {                                                                                                      \
157        DEBUGBREAK;                                                                                        \
158    }                                                                                                      \
159    _SWR_MACRO_END
160
161#define _SWR_TRACE(_fmtstr, ...) SwrTrace(__FILE__, __LINE__, __FUNCTION__, _fmtstr, ##__VA_ARGS__);
162
163#if SWR_ENABLE_ASSERTS
164#define SWR_ASSERT(e, ...) _SWR_ASSERT(true, e, ##__VA_ARGS__)
165#define SWR_ASSUME_ASSERT(e, ...) SWR_ASSERT(e, ##__VA_ARGS__)
166#define SWR_TRACE(_fmtstr, ...) _SWR_TRACE(_fmtstr, ##__VA_ARGS__)
167#endif // SWR_ENABLE_ASSERTS
168
169#if SWR_ENABLE_REL_ASSERTS
170#define SWR_REL_ASSERT(e, ...) _SWR_ASSERT(false, e, ##__VA_ARGS__)
171#define SWR_REL_ASSUME_ASSERT(e, ...) SWR_REL_ASSERT(e, ##__VA_ARGS__)
172#define SWR_REL_TRACE(_fmtstr, ...) _SWR_TRACE(_fmtstr, ##__VA_ARGS__)
173
174// SWR_INVALID is always enabled
175// Funky handling to allow 0 arguments with g++/gcc
176// This is needed because you can't "swallow commas" with ##_VA_ARGS__ unless
177// there is a first argument to the macro.  So having a macro that can optionally
178// accept 0 arguments is tricky.
179#define _SWR_INVALID_0() _SWR_INVALID(false)
180#define _SWR_INVALID_1(...) _SWR_INVALID(false, ##__VA_ARGS__)
181#define _SWR_INVALID_VARGS_(_10, _9, _8, _7, _6, _5, _4, _3, _2, _1, N, ...) N
182#define _SWR_INVALID_VARGS(...) _SWR_INVALID_VARGS_(__VA_ARGS__, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1)
183#define _SWR_INVALID_VARGS_0() 1, 2, 3, 4, 5, 6, 7, 9, 9, 10
184#define _SWR_INVALID_CONCAT_(a, b) a##b
185#define _SWR_INVALID_CONCAT(a, b) _SWR_INVALID_CONCAT_(a, b)
186#define SWR_INVALID(...)                                                                       \
187    _SWR_INVALID_CONCAT(_SWR_INVALID_, _SWR_INVALID_VARGS(_SWR_INVALID_VARGS_0 __VA_ARGS__())) \
188    (__VA_ARGS__)
189
190#define SWR_STATIC_ASSERT(expression, ...) \
191    static_assert((expression), "Failed:\n    " #expression "\n    " __VA_ARGS__);
192
193#endif // SWR_ENABLE_REL_ASSERTS
194
195#endif // C++
196
197#endif // SWR_ENABLE_ASSERTS || SWR_ENABLE_REL_ASSERTS
198
199// Needed to allow passing bitfield members to sizeof() in disabled asserts
200template <typename T>
201static bool SwrSizeofWorkaround(T)
202{
203    return false;
204}
205
206#if !SWR_ENABLE_ASSERTS
207#define SWR_ASSERT(e, ...)                                 \
208    _SWR_MACRO_START(void) sizeof(SwrSizeofWorkaround(e)); \
209    _SWR_MACRO_END
210#define SWR_ASSUME_ASSERT(e, ...) SWR_ASSUME(e, ##__VA_ARGS__)
211#define SWR_TRACE(_fmtstr, ...) \
212    _SWR_MACRO_START(void)(0);  \
213    _SWR_MACRO_END
214#endif
215
216#if !SWR_ENABLE_REL_ASSERTS
217#define SWR_REL_ASSERT(e, ...)                             \
218    _SWR_MACRO_START(void) sizeof(SwrSizeofWorkaround(e)); \
219    _SWR_MACRO_END
220#define SWR_INVALID(...)       \
221    _SWR_MACRO_START(void)(0); \
222    _SWR_MACRO_END
223#define SWR_REL_ASSUME_ASSERT(e, ...) SWR_ASSUME(e, ##__VA_ARGS__)
224#define SWR_REL_TRACE(_fmtstr, ...) \
225    _SWR_MACRO_START(void)(0);      \
226    _SWR_MACRO_END
227#define SWR_STATIC_ASSERT(e, ...)                           \
228    _SWR_MACRO_START(void)  sizeof(SwrSizeofWorkaround(e)); \
229    _SWR_MACRO_END
230#endif
231
232#if defined(_MSC_VER)
233#define SWR_FUNCTION_DECL __FUNCSIG__
234#elif (defined(__GNUC__) || defined(__clang__))
235#define SWR_FUNCTION_DECL __PRETTY_FUNCTION__
236#else
237#define SWR_FUNCTION_DECL __FUNCTION__
238#endif
239
240#define SWR_NOT_IMPL SWR_INVALID("%s not implemented", SWR_FUNCTION_DECL)
241
242#endif //__SWR_ASSERT_H__
243