|
30 | 30 |
|
31 | 31 | #pragma once |
32 | 32 |
|
| 33 | +/** |
| 34 | + * Basic definitions and simple functions to be used everywhere. |
| 35 | + */ |
| 36 | + |
| 37 | +// IWYU pragma: always_keep |
| 38 | + |
| 39 | +// Ensure that C++ standard is at least C++17. |
| 40 | +// If on MSVC, also ensures that the `Zc:__cplusplus` flag is present. |
| 41 | +static_assert(__cplusplus >= 201703L, "Minimum of C++17 required."); |
| 42 | + |
| 43 | +// IWYU pragma: begin_exports |
| 44 | + |
33 | 45 | #include <cstddef> |
34 | 46 | #include <cstdint> |
| 47 | +#include <cstring> |
35 | 48 | #include <type_traits> |
36 | 49 | #include <utility> |
37 | 50 |
|
38 | 51 | #if __has_include(<godot_cpp/core/version.hpp>) |
39 | 52 | #include <godot_cpp/core/version.hpp> |
40 | 53 | #endif |
41 | 54 |
|
| 55 | +// IWYU pragma: end_exports |
| 56 | + |
42 | 57 | namespace godot { |
43 | 58 |
|
| 59 | +#if defined(__has_feature) |
| 60 | +#define GD_HAS_FEATURE(m_feature) __has_feature(m_feature) |
| 61 | +#else |
| 62 | +#define GD_HAS_FEATURE(m_feature) 0 |
| 63 | +#endif |
| 64 | + |
| 65 | +#if defined(__has_cpp_attribute) |
| 66 | +#define GD_HAS_CPP_ATTRIBUTE(m_feature) __has_cpp_attribute(m_feature) |
| 67 | +#else |
| 68 | +#define GD_HAS_CPP_ATTRIBUTE(m_feature) 0 |
| 69 | +#endif |
| 70 | + |
| 71 | +#if (GD_HAS_FEATURE(address_sanitizer) || defined(__SANITIZE_ADDRESS__)) && !defined(ASAN_ENABLED) |
| 72 | +#error Address sanitizer was enabled without defining `ASAN_ENABLED` |
| 73 | +#endif |
| 74 | + |
| 75 | +#if (GD_HAS_FEATURE(leak_sanitizer) || defined(__SANITIZE_LEAKS__)) && !defined(LSAN_ENABLED) |
| 76 | +#error Leak sanitizer was enabled without defining `LSAN_ENABLED` |
| 77 | +#endif |
| 78 | + |
| 79 | +#if (GD_HAS_FEATURE(memory_sanitizer) || defined(__SANITIZE_MEMORY__)) && !defined(MSAN_ENABLED) |
| 80 | +#error Memory sanitizer was enabled without defining `MSAN_ENABLED` |
| 81 | +#endif |
| 82 | + |
| 83 | +#if (GD_HAS_FEATURE(thread_sanitizer) || defined(__SANITIZE_THREAD__)) && !defined(TSAN_ENABLED) |
| 84 | +#error Thread sanitizer was enabled without defining `TSAN_ENABLED` |
| 85 | +#endif |
| 86 | + |
| 87 | +#if (GD_HAS_FEATURE(undefined_behavior_sanitizer) || defined(__UNDEFINED_SANITIZER__)) && !defined(UBSAN_ENABLED) |
| 88 | +#error Undefined behavior sanitizer was enabled without defining `UBSAN_ENABLED` |
| 89 | +#endif |
| 90 | + |
44 | 91 | #if !defined(GDE_EXPORT) |
45 | 92 | #if defined(_WIN32) |
46 | 93 | #define GDE_EXPORT __declspec(dllexport) |
@@ -96,6 +143,18 @@ namespace godot { |
96 | 143 | #define _ALLOW_DISCARD_ (void) |
97 | 144 | #endif |
98 | 145 |
|
| 146 | +#if GD_HAS_CPP_ATTRIBUTE(clang::lifetimebound) |
| 147 | +#define _LIFETIME_BOUND_ [[clang::lifetimebound]] |
| 148 | +#elif GD_HAS_CPP_ATTRIBUTE(gnu::lifetimebound) |
| 149 | +#define _LIFETIME_BOUND_ [[gnu::lifetimebound]] |
| 150 | +#elif GD_HAS_CPP_ATTRIBUTE(msvc::lifetimebound) |
| 151 | +#define _LIFETIME_BOUND_ [[msvc::lifetimebound]] |
| 152 | +#elif GD_HAS_CPP_ATTRIBUTE(lifetimebound) |
| 153 | +#define _LIFETIME_BOUND_ [[lifetimebound]] |
| 154 | +#else |
| 155 | +#define _LIFETIME_BOUND_ |
| 156 | +#endif |
| 157 | + |
99 | 158 | // Windows badly defines a lot of stuff we'll never use. Undefine it. |
100 | 159 | #ifdef _WIN32 |
101 | 160 | #undef min // override standard definition |
@@ -136,106 +195,17 @@ constexpr auto CLAMP(const T m_a, const T2 m_min, const T3 m_max) { |
136 | 195 | return m_a < m_min ? m_min : (m_a > m_max ? m_max : m_a); |
137 | 196 | } |
138 | 197 |
|
| 198 | +// Like std::size, but without requiring any additional includes. |
| 199 | +template <typename T, size_t SIZE> |
| 200 | +constexpr size_t std_size(const T (&)[SIZE]) { |
| 201 | + return SIZE; |
| 202 | +} |
| 203 | + |
139 | 204 | // Generic swap template. |
140 | 205 | #ifndef SWAP |
141 | 206 | #define SWAP(m_x, m_y) std::swap((m_x), (m_y)) |
142 | 207 | #endif // SWAP |
143 | 208 |
|
144 | | -/* Functions to handle powers of 2 and shifting. */ |
145 | | - |
146 | | -// Returns `true` if a positive integer is a power of 2, `false` otherwise. |
147 | | -template <typename T> |
148 | | -constexpr bool is_power_of_2(const T x) { |
149 | | - return x && ((x & (x - 1)) == 0); |
150 | | -} |
151 | | - |
152 | | -// Function to find the next power of 2 to an integer. |
153 | | -constexpr unsigned int next_power_of_2(unsigned int x) { |
154 | | - if (x == 0) { |
155 | | - return 0; |
156 | | - } |
157 | | - |
158 | | - --x; |
159 | | - x |= x >> 1; |
160 | | - x |= x >> 2; |
161 | | - x |= x >> 4; |
162 | | - x |= x >> 8; |
163 | | - x |= x >> 16; |
164 | | - |
165 | | - return ++x; |
166 | | -} |
167 | | - |
168 | | -// Function to find the previous power of 2 to an integer. |
169 | | -constexpr unsigned int previous_power_of_2(unsigned int x) { |
170 | | - x |= x >> 1; |
171 | | - x |= x >> 2; |
172 | | - x |= x >> 4; |
173 | | - x |= x >> 8; |
174 | | - x |= x >> 16; |
175 | | - return x - (x >> 1); |
176 | | -} |
177 | | - |
178 | | -// Function to find the closest power of 2 to an integer. |
179 | | -constexpr unsigned int closest_power_of_2(unsigned int x) { |
180 | | - unsigned int nx = next_power_of_2(x); |
181 | | - unsigned int px = previous_power_of_2(x); |
182 | | - return (nx - x) > (x - px) ? px : nx; |
183 | | -} |
184 | | - |
185 | | -// Get a shift value from a power of 2. |
186 | | -constexpr int get_shift_from_power_of_2(unsigned int p_bits) { |
187 | | - for (unsigned int i = 0; i < 32; i++) { |
188 | | - if (p_bits == (unsigned int)(1 << i)) { |
189 | | - return i; |
190 | | - } |
191 | | - } |
192 | | - |
193 | | - return -1; |
194 | | -} |
195 | | - |
196 | | -template <typename T> |
197 | | -constexpr T nearest_power_of_2_templated(T x) { |
198 | | - --x; |
199 | | - |
200 | | - // The number of operations on x is the base two logarithm |
201 | | - // of the number of bits in the type. Add three to account |
202 | | - // for sizeof(T) being in bytes. |
203 | | - constexpr size_t num = get_shift_from_power_of_2(sizeof(T)) + 3; |
204 | | - |
205 | | - // If the compiler is smart, it unrolls this loop. |
206 | | - // If it's dumb, this is a bit slow. |
207 | | - for (size_t i = 0; i < num; i++) { |
208 | | - x |= x >> (1 << i); |
209 | | - } |
210 | | - |
211 | | - return ++x; |
212 | | -} |
213 | | - |
214 | | -// Function to find the nearest (bigger) power of 2 to an integer. |
215 | | -constexpr unsigned int nearest_shift(unsigned int p_number) { |
216 | | - for (int i = 30; i >= 0; i--) { |
217 | | - if (p_number & (1 << i)) { |
218 | | - return i + 1; |
219 | | - } |
220 | | - } |
221 | | - |
222 | | - return 0; |
223 | | -} |
224 | | - |
225 | | -// constexpr function to find the floored log2 of a number |
226 | | -template <typename T> |
227 | | -constexpr T floor_log2(T x) { |
228 | | - return x < 2 ? x : 1 + floor_log2(x >> 1); |
229 | | -} |
230 | | - |
231 | | -// Get the number of bits needed to represent the number. |
232 | | -// IE, if you pass in 8, you will get 4. |
233 | | -// If you want to know how many bits are needed to store 8 values however, pass in (8 - 1). |
234 | | -template <typename T> |
235 | | -constexpr T get_num_bits(T x) { |
236 | | - return floor_log2(x); |
237 | | -} |
238 | | - |
239 | 209 | // Swap 16, 32 and 64 bits value for endianness. |
240 | 210 | #if defined(__GNUC__) |
241 | 211 | #define BSWAP16(x) __builtin_bswap16(x) |
@@ -313,10 +283,6 @@ struct BuildIndexSequence<0, Is...> : IndexSequence<Is...> {}; |
313 | 283 | // Limit the depth of recursive algorithms when dealing with Array/Dictionary |
314 | 284 | #define MAX_RECURSION 100 |
315 | 285 |
|
316 | | -#ifdef DEBUG_ENABLED |
317 | | -#define DEBUG_METHODS_ENABLED |
318 | | -#endif |
319 | | - |
320 | 286 | // Macro GD_IS_DEFINED() allows to check if a macro is defined. It needs to be defined to anything (say 1) to work. |
321 | 287 | #define __GDARG_PLACEHOLDER_1 false, |
322 | 288 | #define __gd_take_second_arg(__ignored, val, ...) val |
@@ -372,17 +338,58 @@ inline constexpr bool is_zero_constructible_v = is_zero_constructible<T>::value; |
372 | 338 | #endif |
373 | 339 |
|
374 | 340 | #if defined(_MSC_VER) && !defined(__clang__) |
375 | | -#define GODOT_MSVC_PRAGMA(m_content) __pragma(m_content) |
| 341 | +#define GODOT_MSVC_PRAGMA(m_command) __pragma(m_command) |
376 | 342 | #define GODOT_MSVC_WARNING_PUSH GODOT_MSVC_PRAGMA(warning(push)) |
377 | 343 | #define GODOT_MSVC_WARNING_IGNORE(m_warning) GODOT_MSVC_PRAGMA(warning(disable : m_warning)) |
378 | 344 | #define GODOT_MSVC_WARNING_POP GODOT_MSVC_PRAGMA(warning(pop)) |
379 | 345 | #define GODOT_MSVC_WARNING_PUSH_AND_IGNORE(m_warning) GODOT_MSVC_WARNING_PUSH GODOT_MSVC_WARNING_IGNORE(m_warning) |
380 | 346 | #else |
381 | | -#define GODOT_MSVC_PRAGMA(m_content) |
| 347 | +#define GODOT_MSVC_PRAGMA(m_command) |
382 | 348 | #define GODOT_MSVC_WARNING_PUSH |
383 | 349 | #define GODOT_MSVC_WARNING_IGNORE(m_warning) |
384 | 350 | #define GODOT_MSVC_WARNING_POP |
385 | 351 | #define GODOT_MSVC_WARNING_PUSH_AND_IGNORE(m_warning) |
386 | 352 | #endif |
387 | 353 |
|
| 354 | +// Deprecation warning suppression helper macros. |
| 355 | +#if defined(__clang__) |
| 356 | +#define GODOT_PUSH_IGNORE_DEPRECATION() GODOT_CLANG_WARNING_PUSH_AND_IGNORE("-Wdeprecated-declarations") |
| 357 | +#define GODOT_POP_IGNORE_DEPRECATION() GODOT_CLANG_WARNING_POP |
| 358 | +#endif |
| 359 | + |
| 360 | +#if defined(__GNUC__) && !defined(__clang__) |
| 361 | +#define GODOT_PUSH_IGNORE_DEPRECATION() GODOT_GCC_WARNING_PUSH_AND_IGNORE("-Wdeprecated-declarations") |
| 362 | +#define GODOT_POP_IGNORE_DEPRECATION() GODOT_GCC_WARNING_POP |
| 363 | +#endif |
| 364 | + |
| 365 | +#if defined(_MSC_VER) && !defined(__clang__) |
| 366 | +#define GODOT_PUSH_IGNORE_DEPRECATION() GODOT_MSVC_WARNING_PUSH_AND_IGNORE(4996) |
| 367 | +#define GODOT_POP_IGNORE_DEPRECATION() GODOT_MSVC_WARNING_POP |
| 368 | +#endif |
| 369 | + |
| 370 | +template <typename T, typename = void> |
| 371 | +struct is_fully_defined : std::false_type {}; |
| 372 | + |
| 373 | +template <typename T> |
| 374 | +struct is_fully_defined<T, std::void_t<decltype(sizeof(T))>> : std::true_type {}; |
| 375 | + |
| 376 | +template <typename T> |
| 377 | +constexpr bool is_fully_defined_v = is_fully_defined<T>::value; |
| 378 | + |
| 379 | +#ifndef SCU_BUILD_ENABLED |
| 380 | +/// Enforces the requirement that a class is not fully defined. |
| 381 | +/// This can be used to reduce include coupling and keep compile times low. |
| 382 | +/// The check must be made at the top of the corresponding .cpp file of a header. |
| 383 | +#define STATIC_ASSERT_INCOMPLETE_TYPE(m_keyword, m_type) \ |
| 384 | + m_keyword m_type; \ |
| 385 | + static_assert(!is_fully_defined_v<m_type>, #m_type " was unexpectedly fully defined. Please check the include hierarchy of '" __FILE__ "' and remove includes that resolve the " #m_keyword "."); |
| 386 | +#else |
| 387 | +#define STATIC_ASSERT_INCOMPLETE_TYPE(m_keyword, m_type) |
| 388 | +#endif |
| 389 | + |
| 390 | +#define _GD_VARNAME_CONCAT_B_(m_ignore, m_name) m_name |
| 391 | +#define _GD_VARNAME_CONCAT_A_(m_a, m_b, m_c) _GD_VARNAME_CONCAT_B_(hello there, m_a##m_b##m_c) |
| 392 | +#define _GD_VARNAME_CONCAT_(m_a, m_b, m_c) _GD_VARNAME_CONCAT_A_(m_a, m_b, m_c) |
| 393 | +#define GD_UNIQUE_NAME(m_name) _GD_VARNAME_CONCAT_(m_name, _, __COUNTER__) |
| 394 | + |
388 | 395 | } //namespace godot |
0 commit comments