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
64#if defined(SC_PLUGIN_LIBRARY)
65#define SC_COMPILER_EXPORT __declspec(dllimport)
66#define SC_COMPILER_EXTERN extern
67#else
68#define SC_COMPILER_EXPORT __declspec(dllexport)
69#define SC_COMPILER_EXTERN
70#endif
71
72#else
73
74#define SC_COMPILER_EXTERN
75#if defined(SC_PLUGIN_LIBRARY)
76#define SC_COMPILER_EXPORT
77#else
78#define SC_COMPILER_EXPORT __attribute__((visibility("default")))
79#endif
80
81#endif
82
83#define WIDEN2(x) L##x
84#define WIDEN(x) WIDEN2(x)
85
86#if !DOXYGEN && defined(SC_LIBRARY_PATH)
87#define SC_COMPILER_MACRO_ESCAPE(input) __SC_COMPILER_MACRO_ESCAPE_HELPER(input)
88#define __SC_COMPILER_MACRO_ESCAPE_HELPER(input) #input
89#define __SC_COMPILER_MACRO_TO_LITERAL(string) #string
90#define SC_COMPILER_MACRO_TO_LITERAL(string) __SC_COMPILER_MACRO_TO_LITERAL(string)
91#if _WIN32
92#define SC_COMPILER_LIBRARY_PATH WIDEN(SC_COMPILER_MACRO_TO_LITERAL(SC_COMPILER_MACRO_ESCAPE(SC_LIBRARY_PATH)))
93#else
94#define SC_COMPILER_LIBRARY_PATH SC_COMPILER_MACRO_TO_LITERAL(SC_COMPILER_MACRO_ESCAPE(SC_LIBRARY_PATH))
95#endif
96#endif
97
98#if defined(__SANITIZE_ADDRESS__)
99#define SC_COMPILER_ASAN 1
100#else
101#define SC_COMPILER_ASAN 0
102#endif
103
105#if defined(__clang__)
106#define SC_COMPILER_WARNING_POP _Pragma("clang diagnostic pop")
107#elif defined(__GNUC__)
108#define SC_COMPILER_WARNING_POP _Pragma("GCC diagnostic pop")
109#else
110#define SC_COMPILER_WARNING_POP _Pragma("warning(pop)")
111#endif
112
114#define SC_COMPILER_OFFSETOF(Class, Field) __builtin_offsetof(Class, Field)
115
116// clang-format off
117namespace SC
118{
119template <int offset, typename T, typename R> T& fieldOffset(R& object) { return *reinterpret_cast<T*>(reinterpret_cast<char*>(&object) - offset); }
120} // namespace SC
121#define SC_COMPILER_FIELD_OFFSET(Class, Field, Value) SC::fieldOffset<SC_COMPILER_OFFSETOF(Class, Field), Class, decltype(Class::Field)>(Value);
122// clang-format on
123
125#if SC_COMPILER_CLANG
126#define SC_COMPILER_WARNING_PUSH_OFFSETOF \
127 _Pragma("clang diagnostic push"); \
128 _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"");
129#elif SC_COMPILER_GCC
130#define SC_COMPILER_WARNING_PUSH_OFFSETOF \
131 _Pragma("GCC diagnostic push"); \
132 _Pragma("GCC diagnostic ignored \"-Winvalid-offsetof\"");
133#else
134#define SC_COMPILER_WARNING_PUSH_OFFSETOF _Pragma("warning(push)")
135#endif
136
138#define SC_COMPILER_UNUSED(param) ((void)param)
139
141#if SC_COMPILER_CLANG
142#define SC_COMPILER_WARNING_PUSH_UNUSED_RESULT \
143 _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wunused-result\"")
144#elif SC_COMPILER_GCC
145#define SC_COMPILER_WARNING_PUSH_UNUSED_RESULT \
146 _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wunused-result\"")
147#else
148#define SC_COMPILER_WARNING_PUSH_UNUSED_RESULT _Pragma("warning(push)") _Pragma("warning(disable : 4834 6031)")
149#endif
150
152#if defined(SC_LANGUAGE_FORCE_STANDARD_CPP)
153#if SC_LANGUAGE_FORCE_STANDARD_CPP == 14
154#define SC_LANGUAGE_CPP_VERSION 201402L
155#elif SC_LANGUAGE_FORCE_STANDARD_CPP == 17
156#define SC_LANGUAGE_CPP_VERSION 201703L
157#elif SC_LANGUAGE_FORCE_STANDARD_CPP == 20
158#define SC_LANGUAGE_CPP_VERSION 202002L
159#else
160#error "SC_LANGUAGE_FORCE_STANDARD_CPP has invalid value"
161#endif
162#else
163
165#if SC_COMPILER_MSVC
166#define SC_LANGUAGE_CPP_VERSION _MSVC_LANG
167#else
168#define SC_LANGUAGE_CPP_VERSION __cplusplus
169#endif
170
171#endif
172
173#if SC_LANGUAGE_CPP_VERSION >= 202002L
174
175#define SC_LANGUAGE_CPP_AT_LEAST_20 1
176#define SC_LANGUAGE_CPP_AT_LEAST_17 1
177#define SC_LANGUAGE_CPP_AT_LEAST_14 1
178
179#elif SC_LANGUAGE_CPP_VERSION >= 201703L
180
181#define SC_LANGUAGE_CPP_AT_LEAST_20 0
182#define SC_LANGUAGE_CPP_AT_LEAST_17 1
183#define SC_LANGUAGE_CPP_AT_LEAST_14 1
184
185#elif SC_LANGUAGE_CPP_VERSION >= 201402L
186
187#define SC_LANGUAGE_CPP_AT_LEAST_20 0
188#define SC_LANGUAGE_CPP_AT_LEAST_17 0
189#define SC_LANGUAGE_CPP_AT_LEAST_14 1
190
191#else
192
193#define SC_LANGUAGE_CPP_AT_LEAST_20 0
194#define SC_LANGUAGE_CPP_AT_LEAST_17 0
195#define SC_LANGUAGE_CPP_AT_LEAST_14 0
196
197#endif
198
199#undef SC_LANGUAGE_CPP_VERSION
200
201#if SC_LANGUAGE_CPP_AT_LEAST_20
202#define SC_LANGUAGE_LIKELY [[likely]]
203#define SC_LANGUAGE_UNLIKELY [[unlikely]]
204#else
205#define SC_LANGUAGE_LIKELY
206#define SC_LANGUAGE_UNLIKELY
207#endif
208
209#if SC_LANGUAGE_CPP_AT_LEAST_17
210#define SC_LANGUAGE_IF_CONSTEXPR constexpr
211#else
212#define SC_LANGUAGE_IF_CONSTEXPR
213#endif
214
215#if __cpp_exceptions == 199711 || _EXCEPTIONS
216#define SC_LANGUAGE_EXCEPTIONS 1
217#else
218#define SC_LANGUAGE_EXCEPTIONS 0
219#endif
220
221#ifndef __has_cpp_attribute
222#define SC_LANGUAGE_LIFETIME_BOUND
223#elif __has_cpp_attribute(msvc::lifetimebound)
224#define SC_LANGUAGE_LIFETIME_BOUND [[msvc::lifetimebound]]
225#elif __has_cpp_attribute(clang::lifetimebound)
226#define SC_LANGUAGE_LIFETIME_BOUND [[clang::lifetimebound]]
227#elif __has_cpp_attribute(lifetimebound)
228#define SC_LANGUAGE_LIFETIME_BOUND [[lifetimebound]]
229#else
230#define SC_LANGUAGE_LIFETIME_BOUND
231#endif
232
234// clang-format off
235namespace SC
236{
237namespace TypeTraits
238{
241
243template <class T> struct RemoveReference { using type = T; };
244template <class T> struct RemoveReference<T&> { using type = T; };
245template <class T> struct RemoveReference<T&&> { using type = T; };
247template <class T> struct IsLValueReference { static constexpr bool value = false; };
248template <class T> struct IsLValueReference<T&> { static constexpr bool value = true; };
250template <class T> struct IsRValueReference { static constexpr bool value = false; };
251template <class T> struct IsRValueReference<T&&>{ static constexpr bool value = true; };
253
254}
259
262
264template <typename T> constexpr T&& move(T& value) { return static_cast<T&&>(value); }
265
267template <typename T> constexpr T&& forward(typename TypeTraits::RemoveReference<T>::type& value) { return static_cast<T&&>(value); }
268
270template <typename T> constexpr T&& forward(typename TypeTraits::RemoveReference<T>::type&& value)
271{
272 static_assert(!TypeTraits::IsLValueReference<T>::value, "Forward an rvalue as an lvalue is not allowed");
273 return static_cast<T&&>(value);
274}
275
277template <typename T> constexpr inline void swap(T& t1, T& t2) { T temp = move(t1); t1 = move(t2); t2 = move(temp); }
279
280#ifdef max
281#undef max
282#endif
283#ifdef min
284#undef min
285#endif
288
290template <typename T> constexpr const T& min(const T& t1, const T& t2) { return t1 < t2 ? t1 : t2; }
292template <typename T> constexpr const T& max(const T& t1, const T& t2) { return t1 > t2 ? t1 : t2; }
293
295
296} // namespace SC
297// clang-format on
constexpr const T & min(const T &t1, const T &t2)
Finds the minimum of two values.
Definition Compiler.h:290
constexpr const T & max(const T &t1, const T &t2)
Finds the maximum of two values.
Definition Compiler.h:292
constexpr T && move(T &value)
Converts an lvalue to an rvalue reference.
Definition Compiler.h:264
constexpr T && forward(typename TypeTraits::RemoveReference< T >::type &value)
Forwards an lvalue or an rvalue as an rvalue reference.
Definition Compiler.h:267
constexpr void swap(T &t1, T &t2)
Swaps the values of two objects.
Definition Compiler.h:277
Determines if a type is an lvalue reference.
Definition Compiler.h:247
Determines if a type is an rvalue reference.
Definition Compiler.h:250
Removes reference from a type T.
Definition Compiler.h:243