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
7
8#if defined(SC_COMPILER_ENABLE_STD_CPP)
9#error \
10 "SC_COMPILER_ENABLE_STD_CPP has been replaced. Standard C/C++ headers and C++ runtime linkage are enabled by default; define SC_INCLUDE_STD_CPP=0 and SC_PROVIDE_CPP_RUNTIME_SHIMS=1 to request the old no-stdlib mode."
11#endif
12
13#if !defined(SC_INCLUDE_STD_CPP)
14#define SC_INCLUDE_STD_CPP 1
15#elif SC_INCLUDE_STD_CPP != 0 && SC_INCLUDE_STD_CPP != 1
16#error "SC_INCLUDE_STD_CPP must be 0 or 1."
17#endif
18
19#if !defined(SC_PROVIDE_CPP_RUNTIME_SHIMS)
20#define SC_PROVIDE_CPP_RUNTIME_SHIMS 0
21#elif SC_PROVIDE_CPP_RUNTIME_SHIMS != 0 && SC_PROVIDE_CPP_RUNTIME_SHIMS != 1
22#error "SC_PROVIDE_CPP_RUNTIME_SHIMS must be 0 or 1."
23#endif
24
29
32
33#if __clang__
34#define SC_COMPILER_CLANG 1
35#define SC_COMPILER_GCC 0
36#define SC_COMPILER_MSVC 0
37
38#if _MSC_VER
39#define SC_COMPILER_CLANG_CL 1
40#else
41#define SC_COMPILER_CLANG_CL 0
42#endif
43
44#elif _MSC_VER
45#define SC_COMPILER_CLANG 0
46#define SC_COMPILER_GCC 0
47#define SC_COMPILER_MSVC 1
48#define SC_COMPILER_CLANG_CL 0
49
50#else
51#define SC_COMPILER_CLANG 0
52#define SC_COMPILER_GCC 1
53#define SC_COMPILER_MSVC 0
54#define SC_COMPILER_CLANG_CL 0
55#endif
56
57#if defined(__FILC__)
58#define SC_COMPILER_FILC 1
59#else
60#define SC_COMPILER_FILC 0
61#endif
62
63#if SC_COMPILER_MSVC
64
65#define SC_COMPILER_FORCE_INLINE __forceinline
66#define SC_COMPILER_DEBUG_BREAK __debugbreak()
67
68#else
69
70#define SC_COMPILER_FORCE_INLINE __attribute__((always_inline)) inline
71#if defined(__has_builtin)
72#if __has_builtin(__builtin_debugtrap)
73#define SC_COMPILER_DEBUG_BREAK __builtin_debugtrap()
74#elif __has_builtin(__builtin_trap)
75#define SC_COMPILER_DEBUG_BREAK __builtin_trap()
76#else
77#error "No __builtin_trap or __builtin_debugtrap"
78#endif
79#else
80#error "No __has_builtin"
81#endif
82
83#endif
84
86#if SC_COMPILER_MSVC || SC_COMPILER_CLANG_CL
87#define SC_COMPILER_SYMBOL_IMPORT __declspec(dllimport)
88#define SC_COMPILER_SYMBOL_EXPORT __declspec(dllexport)
89#define SC_COMPILER_SYMBOL_HIDDEN
90#else
91#define SC_COMPILER_SYMBOL_IMPORT
92#define SC_COMPILER_SYMBOL_EXPORT __attribute__((visibility("default")))
93#define SC_COMPILER_SYMBOL_HIDDEN __attribute__((visibility("hidden")))
94#endif
95
96#if defined(SC_PLUGIN_LIBRARY)
97#define SC_COMPILER_EXTERN extern
98#else
99#define SC_COMPILER_EXTERN
100#endif
101
102#if defined(SC_PLUGIN_LIBRARY)
103#define SC_COMPILER_LIBRARY_EXPORT_0 SC_COMPILER_SYMBOL_IMPORT
104#define SC_COMPILER_LIBRARY_EXPORT_1 SC_COMPILER_SYMBOL_IMPORT
105#else
106#define SC_COMPILER_LIBRARY_EXPORT_0 SC_COMPILER_SYMBOL_HIDDEN
107#define SC_COMPILER_LIBRARY_EXPORT_1 SC_COMPILER_SYMBOL_EXPORT
108#endif
109#define SC_COMPILER_LIBRARY_EXPORT(value) SC_COMPILER_LIBRARY_EXPORT_IMPL(value)
110#define SC_COMPILER_LIBRARY_EXPORT_IMPL(value) SC_COMPILER_LIBRARY_EXPORT_##value
111
112#ifndef SC_EXPORT_LIBRARY_FOUNDATION
113#define SC_EXPORT_LIBRARY_FOUNDATION 0
114#endif
115#define SC_FOUNDATION_EXPORT SC_COMPILER_LIBRARY_EXPORT(SC_EXPORT_LIBRARY_FOUNDATION)
116
117#define SC_COMPILER_MACRO_ESCAPE(x) #x
118#define SC_COMPILER_MACRO_TO_LITERAL(x) SC_COMPILER_MACRO_ESCAPE(x)
119
120#if defined(SC_LIBRARY_ROOT)
121#define SC_COMPILER_LIBRARY_PATH SC_COMPILER_MACRO_TO_LITERAL(SC_LIBRARY_ROOT)
122#else
123#define SC_COMPILER_LIBRARY_PATH ""
124#endif
125
126#define WIDEN2(x) L##x
127#define WIDEN(x) WIDEN2(x)
128
129#if defined(__SANITIZE_ADDRESS__)
130#define SC_COMPILER_ASAN 1
131#else
132#define SC_COMPILER_ASAN 0
133#endif
134
136#if defined(__clang__)
137#define SC_COMPILER_WARNING_POP _Pragma("clang diagnostic pop")
138#elif defined(__GNUC__)
139#define SC_COMPILER_WARNING_POP _Pragma("GCC diagnostic pop")
140#else
141#define SC_COMPILER_WARNING_POP _Pragma("warning(pop)")
142#endif
143
145#define SC_COMPILER_OFFSETOF(Class, Field) __builtin_offsetof(Class, Field)
146
147// clang-format off
148namespace SC
149{
150template <int offset, typename T, typename R> T& fieldOffset(R& object) { return *reinterpret_cast<T*>(reinterpret_cast<char*>(&object) - offset); }
151} // namespace SC
152#define SC_COMPILER_FIELD_OFFSET(Class, Field, Value) SC::fieldOffset<SC_COMPILER_OFFSETOF(Class, Field), Class, decltype(Class::Field)>(Value);
153// clang-format on
154
156#if SC_COMPILER_CLANG
157#define SC_COMPILER_WARNING_PUSH_OFFSETOF \
158 _Pragma("clang diagnostic push"); \
159 _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"");
160#elif SC_COMPILER_GCC
161#define SC_COMPILER_WARNING_PUSH_OFFSETOF \
162 _Pragma("GCC diagnostic push"); \
163 _Pragma("GCC diagnostic ignored \"-Winvalid-offsetof\"");
164#else
165#define SC_COMPILER_WARNING_PUSH_OFFSETOF _Pragma("warning(push)")
166#endif
167
169#define SC_COMPILER_UNUSED(param) ((void)param)
170
172#if SC_COMPILER_CLANG
173#define SC_COMPILER_WARNING_PUSH_UNUSED_RESULT \
174 _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wunused-result\"") \
175 _Pragma("clang diagnostic ignored \"-Wunused-value\"")
176#elif SC_COMPILER_GCC
177#define SC_COMPILER_WARNING_PUSH_UNUSED_RESULT \
178 _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wunused-result\"") \
179 _Pragma("GCC diagnostic ignored \"-Wunused-value\"")
180#else
181#define SC_COMPILER_WARNING_PUSH_UNUSED_RESULT _Pragma("warning(push)") _Pragma("warning(disable : 4834 6031)")
182#endif
183
185#if defined(SC_LANGUAGE_FORCE_STANDARD_CPP)
186#if SC_LANGUAGE_FORCE_STANDARD_CPP == 14
187#define SC_LANGUAGE_CPP_VERSION 201402L
188#elif SC_LANGUAGE_FORCE_STANDARD_CPP == 17
189#define SC_LANGUAGE_CPP_VERSION 201703L
190#elif SC_LANGUAGE_FORCE_STANDARD_CPP == 20
191#define SC_LANGUAGE_CPP_VERSION 202002L
192#else
193#error "SC_LANGUAGE_FORCE_STANDARD_CPP has invalid value"
194#endif
195#else
196
198#if SC_COMPILER_MSVC
199#define SC_LANGUAGE_CPP_VERSION _MSVC_LANG
200#else
201#define SC_LANGUAGE_CPP_VERSION __cplusplus
202#endif
203
204#endif
205
206#if SC_LANGUAGE_CPP_VERSION >= 202002L
207
208#define SC_LANGUAGE_CPP_AT_LEAST_20 1
209#define SC_LANGUAGE_CPP_AT_LEAST_17 1
210#define SC_LANGUAGE_CPP_AT_LEAST_14 1
211
212#elif SC_LANGUAGE_CPP_VERSION >= 201703L
213
214#define SC_LANGUAGE_CPP_AT_LEAST_20 0
215#define SC_LANGUAGE_CPP_AT_LEAST_17 1
216#define SC_LANGUAGE_CPP_AT_LEAST_14 1
217
218#elif SC_LANGUAGE_CPP_VERSION >= 201402L
219
220#define SC_LANGUAGE_CPP_AT_LEAST_20 0
221#define SC_LANGUAGE_CPP_AT_LEAST_17 0
222#define SC_LANGUAGE_CPP_AT_LEAST_14 1
223
224#else
225
226#define SC_LANGUAGE_CPP_AT_LEAST_20 0
227#define SC_LANGUAGE_CPP_AT_LEAST_17 0
228#define SC_LANGUAGE_CPP_AT_LEAST_14 0
229
230#endif
231
232#undef SC_LANGUAGE_CPP_VERSION
233
234#if SC_LANGUAGE_CPP_AT_LEAST_20
235#define SC_LANGUAGE_LIKELY [[likely]]
236#define SC_LANGUAGE_UNLIKELY [[unlikely]]
237#else
238#define SC_LANGUAGE_LIKELY
239#define SC_LANGUAGE_UNLIKELY
240#endif
241
242#if SC_LANGUAGE_CPP_AT_LEAST_17
243#define SC_LANGUAGE_IF_CONSTEXPR constexpr
244#else
245#define SC_LANGUAGE_IF_CONSTEXPR
246#endif
247
248#if __cpp_exceptions == 199711 || _EXCEPTIONS
249#define SC_LANGUAGE_EXCEPTIONS 1
250#else
251#define SC_LANGUAGE_EXCEPTIONS 0
252#endif
253
254#ifndef __has_cpp_attribute
255#define SC_LANGUAGE_LIFETIME_BOUND
256#elif __has_cpp_attribute(msvc::lifetimebound)
257#define SC_LANGUAGE_LIFETIME_BOUND [[msvc::lifetimebound]]
258#elif __has_cpp_attribute(clang::lifetimebound)
259#define SC_LANGUAGE_LIFETIME_BOUND [[clang::lifetimebound]]
260#elif __has_cpp_attribute(lifetimebound)
261#define SC_LANGUAGE_LIFETIME_BOUND [[lifetimebound]]
262#else
263#define SC_LANGUAGE_LIFETIME_BOUND
264#endif
265
267// clang-format off
268namespace SC
269{
270namespace TypeTraits
271{
274
276template <class T> struct RemoveReference { using type = T; };
277template <class T> struct RemoveReference<T&> { using type = T; };
278template <class T> struct RemoveReference<T&&> { using type = T; };
280template <class T> struct IsLValueReference { static constexpr bool value = false; };
281template <class T> struct IsLValueReference<T&> { static constexpr bool value = true; };
283template <class T> struct IsRValueReference { static constexpr bool value = false; };
284template <class T> struct IsRValueReference<T&&>{ static constexpr bool value = true; };
286
287}
292
295
297template <typename T> constexpr T&& move(T& value) { return static_cast<T&&>(value); }
298
300template <typename T> constexpr T&& forward(typename TypeTraits::RemoveReference<T>::type& value) { return static_cast<T&&>(value); }
301
303template <typename T> constexpr T&& forward(typename TypeTraits::RemoveReference<T>::type&& value)
304{
305 static_assert(!TypeTraits::IsLValueReference<T>::value, "Forward an rvalue as an lvalue is not allowed");
306 return static_cast<T&&>(value);
307}
308
310template <typename T> constexpr inline void swap(T& t1, T& t2) { T temp = move(t1); t1 = move(t2); t2 = move(temp); }
312
313#ifdef max
314#undef max
315#endif
316#ifdef min
317#undef min
318#endif
321
323template <typename T> constexpr const T& min(const T& t1, const T& t2) { return t1 < t2 ? t1 : t2; }
325template <typename T> constexpr const T& max(const T& t1, const T& t2) { return t1 > t2 ? t1 : t2; }
326
328
329} // namespace SC
330// clang-format on
constexpr const T & min(const T &t1, const T &t2)
Finds the minimum of two values.
Definition Compiler.h:323
constexpr const T & max(const T &t1, const T &t2)
Finds the maximum of two values.
Definition Compiler.h:325
constexpr T && move(T &value)
Converts an lvalue to an rvalue reference.
Definition Compiler.h:297
constexpr T && forward(typename TypeTraits::RemoveReference< T >::type &value)
Forwards an lvalue or an rvalue as an rvalue reference.
Definition Compiler.h:300
constexpr void swap(T &t1, T &t2)
Swaps the values of two objects.
Definition Compiler.h:310
Determines if a type is an lvalue reference.
Definition Compiler.h:280
Determines if a type is an rvalue reference.
Definition Compiler.h:283
Removes reference from a type T.
Definition Compiler.h:276