Sane C++ Libraries
C++ Platform Abstraction Libraries
Loading...
Searching...
No Matches
Compiler.h
1// Copyright (c) Stefano Cristiano
2// SPDX-License-Identifier: MIT
3#pragma once
4#if defined(SC_COMPILER_ENABLE_CONFIG)
5#include "SCConfig.h"
6#endif
11
14
15#if __clang__
16#define SC_COMPILER_CLANG 1
17#define SC_COMPILER_GCC 0
18#define SC_COMPILER_MSVC 0
19
20#if _MSC_VER
21#define SC_COMPILER_CLANG_CL 1
22#else
23#define SC_COMPILER_CLANG_CL 0
24#endif
25
26#elif _MSC_VER
27#define SC_COMPILER_CLANG 0
28#define SC_COMPILER_GCC 0
29#define SC_COMPILER_MSVC 1
30#define SC_COMPILER_CLANG_CL 0
31
32#else
33#define SC_COMPILER_CLANG 0
34#define SC_COMPILER_GCC 1
35#define SC_COMPILER_MSVC 0
36#define SC_COMPILER_CLANG_CL 0
37#endif
38
39#if defined(__FILC__)
40#define SC_COMPILER_FILC 1
41#else
42#define SC_COMPILER_FILC 0
43#endif
44
45#if SC_COMPILER_MSVC
46
47#define SC_COMPILER_FORCE_INLINE __forceinline
48#define SC_COMPILER_DEBUG_BREAK __debugbreak()
49
50#else
51
52#define SC_COMPILER_FORCE_INLINE __attribute__((always_inline)) inline
53#if defined(__has_builtin)
54#if __has_builtin(__builtin_debugtrap)
55#define SC_COMPILER_DEBUG_BREAK __builtin_debugtrap()
56#elif __has_builtin(__builtin_trap)
57#define SC_COMPILER_DEBUG_BREAK __builtin_trap()
58#else
59#error "No __builtin_trap or __builtin_debugtrap"
60#endif
61#else
62#error "No __has_builtin"
63#endif
64
65#endif
66
68#if SC_COMPILER_MSVC || SC_COMPILER_CLANG_CL
69#define SC_COMPILER_SYMBOL_IMPORT __declspec(dllimport)
70#define SC_COMPILER_SYMBOL_EXPORT __declspec(dllexport)
71#define SC_COMPILER_SYMBOL_HIDDEN
72#else
73#define SC_COMPILER_SYMBOL_IMPORT
74#define SC_COMPILER_SYMBOL_EXPORT __attribute__((visibility("default")))
75#define SC_COMPILER_SYMBOL_HIDDEN __attribute__((visibility("hidden")))
76#endif
77
78#if defined(SC_PLUGIN_LIBRARY)
79#define SC_COMPILER_EXTERN extern
80#else
81#define SC_COMPILER_EXTERN
82#endif
83
84#if defined(SC_PLUGIN_LIBRARY)
85#define SC_COMPILER_LIBRARY_EXPORT_0 SC_COMPILER_SYMBOL_IMPORT
86#define SC_COMPILER_LIBRARY_EXPORT_1 SC_COMPILER_SYMBOL_IMPORT
87#else
88#define SC_COMPILER_LIBRARY_EXPORT_0 SC_COMPILER_SYMBOL_HIDDEN
89#define SC_COMPILER_LIBRARY_EXPORT_1 SC_COMPILER_SYMBOL_EXPORT
90#endif
91#define SC_COMPILER_LIBRARY_EXPORT(value) SC_COMPILER_LIBRARY_EXPORT_IMPL(value)
92#define SC_COMPILER_LIBRARY_EXPORT_IMPL(value) SC_COMPILER_LIBRARY_EXPORT_##value
93
94#ifndef SC_EXPORT_LIBRARY_FOUNDATION
95#define SC_EXPORT_LIBRARY_FOUNDATION 0
96#endif
97#define SC_FOUNDATION_EXPORT SC_COMPILER_LIBRARY_EXPORT(SC_EXPORT_LIBRARY_FOUNDATION)
98
99#define SC_COMPILER_MACRO_ESCAPE(x) #x
100#define SC_COMPILER_MACRO_TO_LITERAL(x) SC_COMPILER_MACRO_ESCAPE(x)
101
102#if defined(SC_LIBRARY_ROOT)
103#define SC_COMPILER_LIBRARY_PATH SC_COMPILER_MACRO_TO_LITERAL(SC_LIBRARY_ROOT)
104#else
105#define SC_COMPILER_LIBRARY_PATH ""
106#endif
107
108#define WIDEN2(x) L##x
109#define WIDEN(x) WIDEN2(x)
110
111#if defined(__SANITIZE_ADDRESS__)
112#define SC_COMPILER_ASAN 1
113#else
114#define SC_COMPILER_ASAN 0
115#endif
116
118#if defined(__clang__)
119#define SC_COMPILER_WARNING_POP _Pragma("clang diagnostic pop")
120#elif defined(__GNUC__)
121#define SC_COMPILER_WARNING_POP _Pragma("GCC diagnostic pop")
122#else
123#define SC_COMPILER_WARNING_POP _Pragma("warning(pop)")
124#endif
125
127#define SC_COMPILER_OFFSETOF(Class, Field) __builtin_offsetof(Class, Field)
128
129// clang-format off
130namespace SC
131{
132template <int offset, typename T, typename R> T& fieldOffset(R& object) { return *reinterpret_cast<T*>(reinterpret_cast<char*>(&object) - offset); }
133} // namespace SC
134#define SC_COMPILER_FIELD_OFFSET(Class, Field, Value) SC::fieldOffset<SC_COMPILER_OFFSETOF(Class, Field), Class, decltype(Class::Field)>(Value);
135// clang-format on
136
138#if SC_COMPILER_CLANG
139#define SC_COMPILER_WARNING_PUSH_OFFSETOF \
140 _Pragma("clang diagnostic push"); \
141 _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"");
142#elif SC_COMPILER_GCC
143#define SC_COMPILER_WARNING_PUSH_OFFSETOF \
144 _Pragma("GCC diagnostic push"); \
145 _Pragma("GCC diagnostic ignored \"-Winvalid-offsetof\"");
146#else
147#define SC_COMPILER_WARNING_PUSH_OFFSETOF _Pragma("warning(push)")
148#endif
149
151#define SC_COMPILER_UNUSED(param) ((void)param)
152
154#if SC_COMPILER_CLANG
155#define SC_COMPILER_WARNING_PUSH_UNUSED_RESULT \
156 _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wunused-result\"") \
157 _Pragma("clang diagnostic ignored \"-Wunused-value\"")
158#elif SC_COMPILER_GCC
159#define SC_COMPILER_WARNING_PUSH_UNUSED_RESULT \
160 _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wunused-result\"") \
161 _Pragma("GCC diagnostic ignored \"-Wunused-value\"")
162#else
163#define SC_COMPILER_WARNING_PUSH_UNUSED_RESULT _Pragma("warning(push)") _Pragma("warning(disable : 4834 6031)")
164#endif
165
167#if defined(SC_LANGUAGE_FORCE_STANDARD_CPP)
168#if SC_LANGUAGE_FORCE_STANDARD_CPP == 14
169#define SC_LANGUAGE_CPP_VERSION 201402L
170#elif SC_LANGUAGE_FORCE_STANDARD_CPP == 17
171#define SC_LANGUAGE_CPP_VERSION 201703L
172#elif SC_LANGUAGE_FORCE_STANDARD_CPP == 20
173#define SC_LANGUAGE_CPP_VERSION 202002L
174#else
175#error "SC_LANGUAGE_FORCE_STANDARD_CPP has invalid value"
176#endif
177#else
178
180#if SC_COMPILER_MSVC
181#define SC_LANGUAGE_CPP_VERSION _MSVC_LANG
182#else
183#define SC_LANGUAGE_CPP_VERSION __cplusplus
184#endif
185
186#endif
187
188#if SC_LANGUAGE_CPP_VERSION >= 202002L
189
190#define SC_LANGUAGE_CPP_AT_LEAST_20 1
191#define SC_LANGUAGE_CPP_AT_LEAST_17 1
192#define SC_LANGUAGE_CPP_AT_LEAST_14 1
193
194#elif SC_LANGUAGE_CPP_VERSION >= 201703L
195
196#define SC_LANGUAGE_CPP_AT_LEAST_20 0
197#define SC_LANGUAGE_CPP_AT_LEAST_17 1
198#define SC_LANGUAGE_CPP_AT_LEAST_14 1
199
200#elif SC_LANGUAGE_CPP_VERSION >= 201402L
201
202#define SC_LANGUAGE_CPP_AT_LEAST_20 0
203#define SC_LANGUAGE_CPP_AT_LEAST_17 0
204#define SC_LANGUAGE_CPP_AT_LEAST_14 1
205
206#else
207
208#define SC_LANGUAGE_CPP_AT_LEAST_20 0
209#define SC_LANGUAGE_CPP_AT_LEAST_17 0
210#define SC_LANGUAGE_CPP_AT_LEAST_14 0
211
212#endif
213
214#undef SC_LANGUAGE_CPP_VERSION
215
216#if SC_LANGUAGE_CPP_AT_LEAST_20
217#define SC_LANGUAGE_LIKELY [[likely]]
218#define SC_LANGUAGE_UNLIKELY [[unlikely]]
219#else
220#define SC_LANGUAGE_LIKELY
221#define SC_LANGUAGE_UNLIKELY
222#endif
223
224#if SC_LANGUAGE_CPP_AT_LEAST_17
225#define SC_LANGUAGE_IF_CONSTEXPR constexpr
226#else
227#define SC_LANGUAGE_IF_CONSTEXPR
228#endif
229
230#if __cpp_exceptions == 199711 || _EXCEPTIONS
231#define SC_LANGUAGE_EXCEPTIONS 1
232#else
233#define SC_LANGUAGE_EXCEPTIONS 0
234#endif
235
236#ifndef __has_cpp_attribute
237#define SC_LANGUAGE_LIFETIME_BOUND
238#elif __has_cpp_attribute(msvc::lifetimebound)
239#define SC_LANGUAGE_LIFETIME_BOUND [[msvc::lifetimebound]]
240#elif __has_cpp_attribute(clang::lifetimebound)
241#define SC_LANGUAGE_LIFETIME_BOUND [[clang::lifetimebound]]
242#elif __has_cpp_attribute(lifetimebound)
243#define SC_LANGUAGE_LIFETIME_BOUND [[lifetimebound]]
244#else
245#define SC_LANGUAGE_LIFETIME_BOUND
246#endif
247
249// clang-format off
250namespace SC
251{
252namespace TypeTraits
253{
256
258template <class T> struct RemoveReference { using type = T; };
259template <class T> struct RemoveReference<T&> { using type = T; };
260template <class T> struct RemoveReference<T&&> { using type = T; };
262template <class T> struct IsLValueReference { static constexpr bool value = false; };
263template <class T> struct IsLValueReference<T&> { static constexpr bool value = true; };
265template <class T> struct IsRValueReference { static constexpr bool value = false; };
266template <class T> struct IsRValueReference<T&&>{ static constexpr bool value = true; };
268
269}
274
277
279template <typename T> constexpr T&& move(T& value) { return static_cast<T&&>(value); }
280
282template <typename T> constexpr T&& forward(typename TypeTraits::RemoveReference<T>::type& value) { return static_cast<T&&>(value); }
283
285template <typename T> constexpr T&& forward(typename TypeTraits::RemoveReference<T>::type&& value)
286{
287 static_assert(!TypeTraits::IsLValueReference<T>::value, "Forward an rvalue as an lvalue is not allowed");
288 return static_cast<T&&>(value);
289}
290
292template <typename T> constexpr inline void swap(T& t1, T& t2) { T temp = move(t1); t1 = move(t2); t2 = move(temp); }
294
295#ifdef max
296#undef max
297#endif
298#ifdef min
299#undef min
300#endif
303
305template <typename T> constexpr const T& min(const T& t1, const T& t2) { return t1 < t2 ? t1 : t2; }
307template <typename T> constexpr const T& max(const T& t1, const T& t2) { return t1 > t2 ? t1 : t2; }
308
310
311} // namespace SC
312// clang-format on
constexpr const T & min(const T &t1, const T &t2)
Finds the minimum of two values.
Definition Compiler.h:305
constexpr const T & max(const T &t1, const T &t2)
Finds the maximum of two values.
Definition Compiler.h:307
constexpr T && move(T &value)
Converts an lvalue to an rvalue reference.
Definition Compiler.h:279
constexpr T && forward(typename TypeTraits::RemoveReference< T >::type &value)
Forwards an lvalue or an rvalue as an rvalue reference.
Definition Compiler.h:282
constexpr void swap(T &t1, T &t2)
Swaps the values of two objects.
Definition Compiler.h:292
Determines if a type is an lvalue reference.
Definition Compiler.h:262
Determines if a type is an rvalue reference.
Definition Compiler.h:265
Removes reference from a type T.
Definition Compiler.h:258