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 
123 bool 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 
132 void 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
200 template <typename T>
SwrSizeofWorkaround(T)201 static 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