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 SC_COMPILER_MSVC
40
41#define SC_COMPILER_FORCE_INLINE __forceinline
42#define SC_COMPILER_DEBUG_BREAK __debugbreak()
43
44#else
45
46#define SC_COMPILER_FORCE_INLINE __attribute__((always_inline)) inline
47#if defined(__has_builtin)
48#if __has_builtin(__builtin_debugtrap)
49#define SC_COMPILER_DEBUG_BREAK __builtin_debugtrap()
50#elif __has_builtin(__builtin_trap)
51#define SC_COMPILER_DEBUG_BREAK __builtin_trap()
52#else
53#error "No __builtin_trap or __builtin_debugtrap"
54#endif
55#else
56#error "No __has_builtin"
57#endif
58
59#endif
60
62#if SC_COMPILER_MSVC || SC_COMPILER_CLANG_CL
63#define SC_COMPILER_SYMBOL_IMPORT __declspec(dllimport)
64#define SC_COMPILER_SYMBOL_EXPORT __declspec(dllexport)
65#define SC_COMPILER_SYMBOL_HIDDEN
66#else
67#define SC_COMPILER_SYMBOL_IMPORT
68#define SC_COMPILER_SYMBOL_EXPORT __attribute__((visibility("default")))
69#define SC_COMPILER_SYMBOL_HIDDEN __attribute__((visibility("hidden")))
70#endif
71
72#if defined(SC_PLUGIN_LIBRARY)
73#define SC_COMPILER_EXTERN extern
74#else
75#define SC_COMPILER_EXTERN
76#endif
77
78#if defined(SC_PLUGIN_LIBRARY)
79#define SC_COMPILER_LIBRARY_EXPORT_0 SC_COMPILER_SYMBOL_IMPORT
80#define SC_COMPILER_LIBRARY_EXPORT_1 SC_COMPILER_SYMBOL_IMPORT
81#else
82#define SC_COMPILER_LIBRARY_EXPORT_0 SC_COMPILER_SYMBOL_HIDDEN
83#define SC_COMPILER_LIBRARY_EXPORT_1 SC_COMPILER_SYMBOL_EXPORT
84#endif
85#define SC_COMPILER_LIBRARY_EXPORT(value) SC_COMPILER_LIBRARY_EXPORT_IMPL(value)
86#define SC_COMPILER_LIBRARY_EXPORT_IMPL(value) SC_COMPILER_LIBRARY_EXPORT_##value
87
88#ifndef SC_EXPORT_LIBRARY_FOUNDATION
89#define SC_EXPORT_LIBRARY_FOUNDATION 0
90#endif
91#define SC_FOUNDATION_EXPORT SC_COMPILER_LIBRARY_EXPORT(SC_EXPORT_LIBRARY_FOUNDATION)
92
93#define SC_COMPILER_MACRO_ESCAPE(x) #x
94#define SC_COMPILER_MACRO_TO_LITERAL(x) SC_COMPILER_MACRO_ESCAPE(x)
95
96#if defined(SC_LIBRARY_ROOT)
97#define SC_COMPILER_LIBRARY_PATH SC_COMPILER_MACRO_TO_LITERAL(SC_LIBRARY_ROOT)
98#else
99#define SC_COMPILER_LIBRARY_PATH ""
100#endif
101
102#define WIDEN2(x) L##x
103#define WIDEN(x) WIDEN2(x)
104
105#if defined(__SANITIZE_ADDRESS__)
106#define SC_COMPILER_ASAN 1
107#else
108#define SC_COMPILER_ASAN 0
109#endif
110
112#if defined(__clang__)
113#define SC_COMPILER_WARNING_POP _Pragma("clang diagnostic pop")
114#elif defined(__GNUC__)
115#define SC_COMPILER_WARNING_POP _Pragma("GCC diagnostic pop")
116#else
117#define SC_COMPILER_WARNING_POP _Pragma("warning(pop)")
118#endif
119
121#define SC_COMPILER_OFFSETOF(Class, Field) __builtin_offsetof(Class, Field)
122
123// clang-format off
124namespace SC
125{
126template <int offset, typename T, typename R> T& fieldOffset(R& object) { return *reinterpret_cast<T*>(reinterpret_cast<char*>(&object) - offset); }
127} // namespace SC
128#define SC_COMPILER_FIELD_OFFSET(Class, Field, Value) SC::fieldOffset<SC_COMPILER_OFFSETOF(Class, Field), Class, decltype(Class::Field)>(Value);
129// clang-format on
130
132#if SC_COMPILER_CLANG
133#define SC_COMPILER_WARNING_PUSH_OFFSETOF \
134 _Pragma("clang diagnostic push"); \
135 _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"");
136#elif SC_COMPILER_GCC
137#define SC_COMPILER_WARNING_PUSH_OFFSETOF \
138 _Pragma("GCC diagnostic push"); \
139 _Pragma("GCC diagnostic ignored \"-Winvalid-offsetof\"");
140#else
141#define SC_COMPILER_WARNING_PUSH_OFFSETOF _Pragma("warning(push)")
142#endif
143
145#define SC_COMPILER_UNUSED(param) ((void)param)
146
148#if SC_COMPILER_CLANG
149#define SC_COMPILER_WARNING_PUSH_UNUSED_RESULT \
150 _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wunused-result\"") \
151 _Pragma("clang diagnostic ignored \"-Wunused-value\"")
152#elif SC_COMPILER_GCC
153#define SC_COMPILER_WARNING_PUSH_UNUSED_RESULT \
154 _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wunused-result\"") \
155 _Pragma("GCC diagnostic ignored \"-Wunused-value\"")
156#else
157#define SC_COMPILER_WARNING_PUSH_UNUSED_RESULT _Pragma("warning(push)") _Pragma("warning(disable : 4834 6031)")
158#endif
159
161#if defined(SC_LANGUAGE_FORCE_STANDARD_CPP)
162#if SC_LANGUAGE_FORCE_STANDARD_CPP == 14
163#define SC_LANGUAGE_CPP_VERSION 201402L
164#elif SC_LANGUAGE_FORCE_STANDARD_CPP == 17
165#define SC_LANGUAGE_CPP_VERSION 201703L
166#elif SC_LANGUAGE_FORCE_STANDARD_CPP == 20
167#define SC_LANGUAGE_CPP_VERSION 202002L
168#else
169#error "SC_LANGUAGE_FORCE_STANDARD_CPP has invalid value"
170#endif
171#else
172
174#if SC_COMPILER_MSVC
175#define SC_LANGUAGE_CPP_VERSION _MSVC_LANG
176#else
177#define SC_LANGUAGE_CPP_VERSION __cplusplus
178#endif
179
180#endif
181
182#if SC_LANGUAGE_CPP_VERSION >= 202002L
183
184#define SC_LANGUAGE_CPP_AT_LEAST_20 1
185#define SC_LANGUAGE_CPP_AT_LEAST_17 1
186#define SC_LANGUAGE_CPP_AT_LEAST_14 1
187
188#elif SC_LANGUAGE_CPP_VERSION >= 201703L
189
190#define SC_LANGUAGE_CPP_AT_LEAST_20 0
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 >= 201402L
195
196#define SC_LANGUAGE_CPP_AT_LEAST_20 0
197#define SC_LANGUAGE_CPP_AT_LEAST_17 0
198#define SC_LANGUAGE_CPP_AT_LEAST_14 1
199
200#else
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 0
205
206#endif
207
208#undef SC_LANGUAGE_CPP_VERSION
209
210#if SC_LANGUAGE_CPP_AT_LEAST_20
211#define SC_LANGUAGE_LIKELY [[likely]]
212#define SC_LANGUAGE_UNLIKELY [[unlikely]]
213#else
214#define SC_LANGUAGE_LIKELY
215#define SC_LANGUAGE_UNLIKELY
216#endif
217
218#if SC_LANGUAGE_CPP_AT_LEAST_17
219#define SC_LANGUAGE_IF_CONSTEXPR constexpr
220#else
221#define SC_LANGUAGE_IF_CONSTEXPR
222#endif
223
224#if __cpp_exceptions == 199711 || _EXCEPTIONS
225#define SC_LANGUAGE_EXCEPTIONS 1
226#else
227#define SC_LANGUAGE_EXCEPTIONS 0
228#endif
229
230#ifndef __has_cpp_attribute
231#define SC_LANGUAGE_LIFETIME_BOUND
232#elif __has_cpp_attribute(msvc::lifetimebound)
233#define SC_LANGUAGE_LIFETIME_BOUND [[msvc::lifetimebound]]
234#elif __has_cpp_attribute(clang::lifetimebound)
235#define SC_LANGUAGE_LIFETIME_BOUND [[clang::lifetimebound]]
236#elif __has_cpp_attribute(lifetimebound)
237#define SC_LANGUAGE_LIFETIME_BOUND [[lifetimebound]]
238#else
239#define SC_LANGUAGE_LIFETIME_BOUND
240#endif
241
243// clang-format off
244namespace SC
245{
246namespace TypeTraits
247{
250
252template <class T> struct RemoveReference { using type = T; };
253template <class T> struct RemoveReference<T&> { using type = T; };
254template <class T> struct RemoveReference<T&&> { using type = T; };
256template <class T> struct IsLValueReference { static constexpr bool value = false; };
257template <class T> struct IsLValueReference<T&> { static constexpr bool value = true; };
259template <class T> struct IsRValueReference { static constexpr bool value = false; };
260template <class T> struct IsRValueReference<T&&>{ static constexpr bool value = true; };
262
263}
268
271
273template <typename T> constexpr T&& move(T& value) { return static_cast<T&&>(value); }
274
276template <typename T> constexpr T&& forward(typename TypeTraits::RemoveReference<T>::type& value) { return static_cast<T&&>(value); }
277
279template <typename T> constexpr T&& forward(typename TypeTraits::RemoveReference<T>::type&& value)
280{
281 static_assert(!TypeTraits::IsLValueReference<T>::value, "Forward an rvalue as an lvalue is not allowed");
282 return static_cast<T&&>(value);
283}
284
286template <typename T> constexpr inline void swap(T& t1, T& t2) { T temp = move(t1); t1 = move(t2); t2 = move(temp); }
288
289#ifdef max
290#undef max
291#endif
292#ifdef min
293#undef min
294#endif
297
299template <typename T> constexpr const T& min(const T& t1, const T& t2) { return t1 < t2 ? t1 : t2; }
301template <typename T> constexpr const T& max(const T& t1, const T& t2) { return t1 > t2 ? t1 : t2; }
302
304
305} // namespace SC
306// clang-format on
constexpr const T & min(const T &t1, const T &t2)
Finds the minimum of two values.
Definition Compiler.h:299
constexpr const T & max(const T &t1, const T &t2)
Finds the maximum of two values.
Definition Compiler.h:301
constexpr T && move(T &value)
Converts an lvalue to an rvalue reference.
Definition Compiler.h:273
constexpr T && forward(typename TypeTraits::RemoveReference< T >::type &value)
Forwards an lvalue or an rvalue as an rvalue reference.
Definition Compiler.h:276
constexpr void swap(T &t1, T &t2)
Swaps the values of two objects.
Definition Compiler.h:286
Determines if a type is an lvalue reference.
Definition Compiler.h:256
Determines if a type is an rvalue reference.
Definition Compiler.h:259
Removes reference from a type T.
Definition Compiler.h:252