Radium Engine  1.5.20
Loading...
Searching...
No Matches
CoreMacros.hpp
1/* ========================================================================= *
2 * CoreMacros.hpp *
3 * core helper functions and macros for C and C++ *
4 * Valentin Roussellet *
5 * ========================================================================= */
6
7// This file contains a host of helper functions and macros that should behave
8// similarly on all platforms. They may be generally useful or helping to
9// abstract compiler / architecture / platform specificities to write portable
10// code when possible.
11
12// A good reference : http://sourceforge.net/p/predef/
13// clang-format off
14#pragma once
15
16#include <cassert>
17#include <cstdio>
18#include <iostream>
19#include <sstream>
20
21// ----------------------------------------------------------------------------
22// Compiler identification
23// ----------------------------------------------------------------------------
24#if defined(__clang__)
25#define COMPILER_CLANG
26#elif defined(__GNUC__)
27#define COMPILER_GCC
28#elif defined (_MSC_VER)
29#define COMPILER_MSVC
30#define _USE_MATH_DEFINES
31#else
32#error unsupported compiler
33#endif
34
35// ----------------------------------------------------------------------------
36// OS and architecture identification
37// ----------------------------------------------------------------------------
38
39#if defined(_WIN32) || defined(_WIN64) // ------------------------------ Windows
40#define OS_WINDOWS
41# if defined(_M_X64)
42# define ARCH_X64
43# elif defined(_M_IX86)
44# define ARCH_X86
45# else
46# error unsupported arch
47# endif
48#elif defined(__APPLE__) || defined(__MACH__) // ------------------------ Mac OS
49# define OS_MACOS
50#elif defined(__linux__) || defined (__CYGWIN__) // ---------------------- Linux
51# define OS_LINUX
52#else
53 #error unsupported OS
54#endif
55
56// Check arch for macos and linux
57#if defined (OS_MACOS) || defined(OS_LINUX)
58# if defined(__i386__)
59# define ARCH_X86
60# elif defined(__x86_64__) || defined (__x86_64)
61# define ARCH_X64
62# elif defined(__arm__) || defined (__arm)
63# define ARCH_ARM32
64# elif defined(__aarch64__) || defined(__aarch64)
65# define ARCH_ARM64
66# else
67# error unsupported arch
68# endif
69#endif
70
71// Todo : endianness, pointer sixe
72
73// ----------------------------------------------------------------------------
74// Build configuration
75// ----------------------------------------------------------------------------
76
77// This tells apart between debug and release builds :
78// DEBUG is defined in debug builds and RELEASE in release builds.
79// Additionally REL_DEB is defined on release build with debug info
80// Also the macro ON_DEBUG() can be used to execute an expression only on debug.
81// By default, debug has assert macros enabled. In release builds
82// asserts are disabled except if explicitly required by
83// defining CORE_USE_ASSERT
84
85
86// Make sure all "debug" macros are defined
87#if defined (DEBUG) || defined(_DEBUG) || defined (CORE_DEBUG) // ------- Debug
88# undef CORE_DEBUG
89# define CORE_DEBUG
90
91# undef _DEBUG
92# define _DEBUG
93
94# undef DEBUG
95# define DEBUG
96
97# undef NDEBUG
98# undef RELEASE
99
100# define ON_DEBUG(CODE) CODE
101#else // --------------------------------------------------------------- Release
102
103# define RELEASE
104
105#ifndef NO_DEBUG_INFO
106# define REL_DEB
107#endif
108
109# undef CORE_DEBUG
110# undef DEBUG
111# undef _DEBUG
112
113# if !defined (NDEBUG)
114# define NDEBUG
115# endif
116
117# define ON_DEBUG(CODE) /* Nothing */
118#endif
119
120// ----------------------------------------------------------------------------
121// Multithreading
122// ----------------------------------------------------------------------------
123#ifndef RA_MAX_THREAD
124# include <thread>
125# define RA_MAX_THREAD std::thread::hardware_concurrency() - 1
126#endif
127
128// ----------------------------------------------------------------------------
129// Preprocessor magic
130// ----------------------------------------------------------------------------
131
132// Wrapper for multiline macros
133// In debug we use the standard do..while(0) which is 'nice' to read and debug
134// in a debugger such as gdb.
135// In release we use the if(1) else; which compilers can optimize better
136#ifdef CORE_DEBUG
137# define MACRO_START do {
138# define MACRO_END } while (0)
139#else
140# define MACRO_START if(1) {
141# define MACRO_END } else {}
142#endif
143
144// Macro to avoid the "unused variable" warning with no side-effects.
145#define CORE_UNUSED(X) \
146 MACRO_START \
147 (void) sizeof((X));\
148 MACRO_END
149
150// Token concatenation
151// Preprocessor concatenation can be tricky if arguments are macros unless
152// "recursively" calling concatenation through chained macros which forces
153// the preprocessor to run another pass.
154#define CONCATENATE(XX,YY) CONCATENATE2(XX,YY)
155#define CONCATENATE2(XX,YY) CONCATENATE3(XX,YY)
156#define CONCATENATE3(XX,YY) XX##YY
157
158// Stringification has a similar problem.
159#ifdef __STRING
160# define STRINGIFY(X) __STRING(X)
161#else
162# define STRINGIFY(X) STRINGIFY2(X)
163# define STRINGIFY2(X) #X
164#endif
165
166// ----------------------------------------------------------------------------
167// Platform abstracted macros
168// ----------------------------------------------------------------------------
169
170// Breakpoints
171// This macro will trigger a breakpoint where it is placed. With MSVC a dialog
172// will ask you if you want to launch the debugger.
173#if defined (COMPILER_GCC) || defined (COMPILER_CLANG)
174#define BREAKPOINT(ARG) __builtin_trap();
175//asm volatile ("int $3")
176#elif defined (COMPILER_MSVC)
177 #define BREAKPOINT(ARG) __debugbreak()
178#else
179 #error unsupported platform
180#endif
181
182// Platform-independent macros
183// Note : there is support of deprecated and alignof in C++ 11
184
185// Alignment
186// ALIGN_OF : returns the alignment of a variable or field
187// ALIGNED : declare an aligned variable
188
189// Branch prediction hints (GCC & Clang only)
190// UNLIKELY tells the compiler to expect the condition to be false
191// LIKELY tells the compiler to expect the condition to be true
192
193// Inlining commands
194// ALWAYS_INLINE is the strongest. On GCC it will actually inline even
195// when building without optimization (which is a bad idea most of the time).
196// STRONG_INLINE is stronger than just "inline" where supported.
197// NO_INLINE tells the compiler to never inline the function.
198
199// STDCALL, CDECL, FASTCALL : keyword for the corresponding calling convention.
200
201#if defined (COMPILER_MSVC) // ----------------------------------- Visual Studio
202
203# define ALIGN_OF(X) __alignof(X)
204# define ALIGNED(DECL,ALIGN) __declspec(align(ALIGN)) DECL
205
206// Unfortunately visual studio does not have a branch prediction primitive.
207# define UNLIKELY(IFEXPR) IFEXPR
208# define LIKELY(IFEXPR) IFEXPR
209
210# define ALWAYS_INLINE __forceinline
211# define STRONG_INLINE __forceinline
212# define NO_INLINE __declspec(noinline)
213
214# define DLL_EXPORT __declspec(dllexport)
215# define DLL_IMPORT __declspec(dllimport)
216
217# define STDCALL __stdcall
218# ifndef CDECL
219# define CDECL __cdecl
220# endif
221# define FASTCALL __fastcall
222#elif defined(COMPILER_GCC) || defined (COMPILER_CLANG) // ------- GCC and CLang
223
224# define ALIGN_OF(X) __alignof__(X)
225# define ALIGNED(DECL,ALIGN) DECL __attribute__((aligned(ALIGN)))
226
227# define UNLIKELY(IFEXPR) __builtin_expect(bool(IFEXPR),0)
228# define LIKELY(IFEXPR) __builtin_expect(bool(IFEXPR),1)
229
230# define ALWAYS_INLINE __attribute((always_inline))
231# define STRONG_INLINE inline
232# define NO_INLINE __attribute__((noinline))
233
234# define DLL_EXPORT
235# define DLL_IMPORT
236
237# define STDCALL __attribute__((stdcall))
238# define CDECL /* default */
239# define FASTCALL __attribute__((fastcall))
240#else
241# error unsupported platform
242#endif
243
244
245// ----------------------------------------------------------------------------
246// Useful aliases
247// ----------------------------------------------------------------------------
248
249using uchar = unsigned char;
250using ushort = unsigned short;
251using uint = unsigned int;
252using ulong = unsigned long;
253
254// Use this to use double precision for all maths
255// #define CORE_USE_DOUBLE
256#ifndef CORE_USE_DOUBLE
257using Scalar = float;
258#else
259using Scalar = double;
260#endif
261
270constexpr Scalar operator"" _ra ( long double n )
271{
272 return Scalar( n );
273}
274
283constexpr Scalar operator"" _ra ( unsigned long long n )
284{
285 return Scalar( n );
286}
287
288// ----------------------------------------------------------------------------
289// Debug tools
290// ----------------------------------------------------------------------------
291
292namespace compile_time_utils
293{
294template<int x> struct size;
295}
296// This macro will print the size of a type in a compiler error
297// Note : there is a way to print it as a warning instead on StackOverflow
298#define STATIC_SIZEOF(TYPE) compile_time_utils::size<sizeof(TYPE)> static_sizeof
299
300// This macro controls if asserts are triggered or not.
301#if defined CORE_DEBUG || defined CORE_USE_ASSERT
302# define CORE_ENABLE_ASSERT
303# define ON_ASSERT( CODE ) CODE
304#else
305# undef CORE_ENABLE_ASSERT
306# define ON_ASSERT( CODE ) /* nothing */
307#endif
308
309
310
311// Common code to report a failure
312// expects the expression which triggered the report,
313// the description of the error, and a format string.
314// (arguments to printf are, in order :
315// filename (%s), line (%i), expr(%s), desc (%s)
316#define REPORT_FAIL( EXP, DESC, FMT ) \
317 MACRO_START \
318 std::stringstream stream; \
319 stream << DESC; \
320 fprintf(stderr, \
321 FMT,__FILE__,__LINE__, \
322 #EXP, stream.str().c_str() ); \
323MACRO_END
324
325
326
327// Custom assert, warn and error macros.
328// Standard assert has two main drawbacks : on some OSes it aborts the program,
329// and the debugger will break in assert.c or and not where the calling code
330// uses assert(). CORE_ASSERT guarantees a breakpoint when in a debugger,
331// and always prints a useful message.
332// CORE_WARN_IF has the same effect but it will only print a message.
333#ifdef CORE_ENABLE_ASSERT
334#define CORE_ASSERT( EXP, DESC ) \
335 MACRO_START \
336 if (UNLIKELY(!(EXP))) { \
337 REPORT_FAIL(EXP, DESC, "%s:%i: Assertion `%s` failed : %s\n");\
338 BREAKPOINT(0); \
339 } else {} \
340 MACRO_END
341
342#define CORE_WARN_IF( EXP, DESC ) \
343 MACRO_START \
344 if (UNLIKELY((EXP))) { \
345 REPORT_FAIL(EXP, DESC, "%s:%i: WARNING `%s` : %s\n");\
346 } else{} \
347 MACRO_END
348#else
349#define CORE_ASSERT( EXP, DESC ) // nothing
350#define CORE_WARN_IF( EXP, DESC ) // nothing
351#endif
352
353// Print an error and break, even in release.
354#define CORE_ERROR( DESC ) \
355 MACRO_START \
356 REPORT_FAIL(ERROR, DESC, "%s:%i %s: %s\n");\
357 BREAKPOINT(0); \
358 exit(EXIT_FAILURE); \
359 MACRO_END
360
361// Print an error and break if condition is not met, even in release
362#define CORE_ERROR_IF( EXP, DESC ) \
363 MACRO_START \
364 if( UNLIKELY(!(EXP))) { \
365 REPORT_FAIL(EXP, DESC, "%s:%i ERROR `%s`: %s\n");\
366 BREAKPOINT(0); \
367 exit(EXIT_FAILURE); \
368 }else{} \
369 MACRO_END
370
371
372
373// ----------------------------------------------------------------------------
374// Explicit compiler warning disables.
375// ----------------------------------------------------------------------------
376
377// With the most sensitive warning settings, using this file can trigger lots
378// of unwanted warnings, so we explicitly disable them. Add more at your
379// own risk...
380
381#if defined(COMPILER_GCC)
382// Triggered by the alias in static assert.
383 #pragma GCC diagnostic ignored "-Wunused-local-typedefs"
384#endif
385#if defined(COMPILER_MSVC)
386 #pragma warning(disable: 4244) // Conversion from double to float loses data.
387 #pragma warning(disable: 4251) // stl dllexports
388 #pragma warning(disable: 4267) // conversion from size_t to uint
389 #pragma warning(disable: 4275) // non - DLL-interface class 'class_1' used as base for DLL-interface class 'class_2'
390 #pragma warning(disable: 4577) // noexcept used with no exception handling mode
391 #pragma warning(disable: 4838) // conversion from enum to uint.
392 #pragma warning(disable: 4996) // sprintf unsafe
393 #pragma warning(disable: 4503) // Truncated decorated name
394 #ifndef NOMINMAX
395 #define NOMINMAX
396 #endif
397 #include <windows.h>
398#endif
399
400#ifndef eigen_assert
401#define eigen_assert(XXX) CORE_ASSERT(XXX, "Eigen Assert");
402#endif
403// clang-format on