21#ifndef SOLIDC_MACROS_H
22#define SOLIDC_MACROS_H
31#if defined(__cplusplus)
43#elif defined(__clang__)
47#elif defined(__GNUC__)
62#if SOLIDC_GCC || SOLIDC_CLANG
63#define LIKELY(x) __builtin_expect(!!(x), 1)
64#define UNLIKELY(x) __builtin_expect(!!(x), 0)
67#define UNLIKELY(x) (x)
74#if SOLIDC_GCC || SOLIDC_CLANG
75#define WARN_UNUSED_RESULT __attribute__((warn_unused_result))
77#define WARN_UNUSED_RESULT _Check_return_
79#define WARN_UNUSED_RESULT
87#if SOLIDC_GCC || SOLIDC_CLANG
88#define PRINTF_FORMAT(fmt, va) __attribute__((format(printf, fmt, va)))
90#define PRINTF_FORMAT(fmt, va)
94#if SOLIDC_GCC || SOLIDC_CLANG
95#define NORETURN __attribute__((noreturn))
97#define NORETURN __declspec(noreturn)
103#define UNUSED(x) ((void)(x))
106#define THREAD_LOCAL __declspec(thread)
107#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
108#define THREAD_LOCAL _Thread_local
111#define THREAD_LOCAL __thread
119#if defined(__cplusplus)
120#define STATIC_ASSERT(cond, msg) static_assert(cond, msg)
121#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
122#define STATIC_ASSERT(cond, msg) _Static_assert(cond, msg)
125#define STATIC_ASSERT(cond, msg) typedef char _static_assert_##__LINE__[(cond) ? 1 : -1]
138#define ASSERT(cond) \
140 if (UNLIKELY(!(cond))) { \
141 fprintf(stderr, "%s:%d [%s]: Assertion '%s' failed.\n", __FILE__, __LINE__, __func__, #cond); \
147#define ASSERT_TRUE(cond) ASSERT(cond)
150#define ASSERT_NULL(ptr) \
152 if (UNLIKELY((ptr) != NULL)) { \
153 fprintf(stderr, "%s:%d [%s]: Expected '%s' to be NULL.\n", __FILE__, __LINE__, __func__, #ptr); \
159#define ASSERT_NOT_NULL(ptr) \
161 if (UNLIKELY((ptr) == NULL)) { \
162 fprintf(stderr, "%s:%d [%s]: Expected '%s' to not be NULL.\n", __FILE__, __LINE__, __func__, #ptr); \
171#define ASSERT_STR_EQ(a, b) \
173 const char* _ase_a = (a); \
174 const char* _ase_b = (b); \
175 if (_ase_a == NULL || _ase_b == NULL) { \
176 if (_ase_a != _ase_b) { \
177 fprintf(stderr, "%s:%d [%s]: '%s == %s' failed (one is NULL).\n", __FILE__, __LINE__, __func__, #a, \
181 } else if (strcmp(_ase_a, _ase_b) != 0) { \
182 fprintf(stderr, "%s:%d [%s]: '%s == %s' failed (\"%s\" != \"%s\").\n", __FILE__, __LINE__, __func__, #a, \
183 #b, _ase_a, _ase_b); \
192#define ASSERT_FLOAT_EQ(a, b, epsilon) \
194 double _afe_a = (double)(a); \
195 double _afe_b = (double)(b); \
196 double _afe_eps = (double)(epsilon); \
197 double _afe_d = _afe_a - _afe_b; \
199 if ((_afe_d > _afe_eps) || (-_afe_d > _afe_eps)) { \
201 "%s:%d [%s]: Float '%s == %s' failed" \
202 " (%.6f != %.6f, eps=%.6f).\n", \
203 __FILE__, __LINE__, __func__, #a, #b, _afe_a, _afe_b, _afe_eps); \
217#if SOLIDC_GCC || SOLIDC_CLANG
220#define ASSERT_EQ(a, b) \
222 __typeof__(a) _aeq_a = (a); \
223 __typeof__(b) _aeq_b = (b); \
224 if (UNLIKELY(_aeq_a != _aeq_b)) { \
226 "%s:%d [%s]: '%s == %s' failed" \
227 " (%td != %td).\n", \
228 __FILE__, __LINE__, __func__, #a, #b, (ptrdiff_t)_aeq_a, (ptrdiff_t)_aeq_b); \
234#define ASSERT_NE(a, b) \
236 __typeof__(a) _ane_a = (a); \
237 __typeof__(b) _ane_b = (b); \
238 if (UNLIKELY(_ane_a == _ane_b)) { \
240 "%s:%d [%s]: '%s != %s' failed" \
242 __FILE__, __LINE__, __func__, #a, #b, (ptrdiff_t)_ane_a); \
248#define ASSERT_RANGE(val, min, max) \
250 __typeof__(val) _ar_v = (val); \
251 __typeof__(min) _ar_min = (min); \
252 __typeof__(max) _ar_max = (max); \
253 if (UNLIKELY(_ar_v < _ar_min || _ar_v > _ar_max)) { \
254 fprintf(stderr, "%s:%d [%s]: %s=%td not in [%td, %td].\n", __FILE__, __LINE__, __func__, #val, \
255 (ptrdiff_t)_ar_v, (ptrdiff_t)_ar_min, (ptrdiff_t)_ar_max); \
262#define ASSERT_EQ(a, b) \
264 intptr_t _aeq_a = (intptr_t)(a); \
265 intptr_t _aeq_b = (intptr_t)(b); \
266 if (UNLIKELY(_aeq_a != _aeq_b)) { \
268 "%s:%d [%s]: '%s == %s' failed" \
269 " (%td != %td).\n", \
270 __FILE__, __LINE__, __func__, #a, #b, _aeq_a, _aeq_b); \
275#define ASSERT_NE(a, b) \
277 intptr_t _ane_a = (intptr_t)(a); \
278 intptr_t _ane_b = (intptr_t)(b); \
279 if (UNLIKELY(_ane_a == _ane_b)) { \
281 "%s:%d [%s]: '%s != %s' failed" \
283 __FILE__, __LINE__, __func__, #a, #b, _ane_a); \
288#define ASSERT_RANGE(val, min, max) \
290 intptr_t _ar_v = (intptr_t)(val); \
291 intptr_t _ar_min = (intptr_t)(min); \
292 intptr_t _ar_max = (intptr_t)(max); \
293 if (UNLIKELY(_ar_v < _ar_min || _ar_v > _ar_max)) { \
294 fprintf(stderr, "%s:%d [%s]: %s=%td not in [%td, %td].\n", __FILE__, __LINE__, __func__, #val, _ar_v, \
304#define ASSERT(cond) UNUSED(cond)
305#define ASSERT_TRUE(cond) UNUSED(cond)
306#define ASSERT_NULL(ptr) UNUSED(ptr)
307#define ASSERT_NOT_NULL(ptr) UNUSED(ptr)
308#define ASSERT_STR_EQ(a, b) (UNUSED(a), UNUSED(b))
309#define ASSERT_FLOAT_EQ(a, b, e) (UNUSED(a), UNUSED(b), UNUSED(e))
310#define ASSERT_EQ(a, b) (UNUSED(a), UNUSED(b))
311#define ASSERT_NE(a, b) (UNUSED(a), UNUSED(b))
312#define ASSERT_RANGE(v, lo, hi) (UNUSED(v), UNUSED(lo), UNUSED(hi))
321#define IS_POWER_OF_2(n) ((n) > 0 && (((n) & ((n) - 1)) == 0))
324#define STATIC_CHECK_POWER_OF_2(n) STATIC_ASSERT(IS_POWER_OF_2(n), #n " must be a power of 2")
333static inline uint64_t round_up_pow2_u64(uint64_t x) {
334 if (x == 0)
return 1;
350static inline uint32_t round_up_pow2_u32(uint32_t x) {
351 if (x == 0)
return 1;
366#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
369#define ZERO_MEMORY(ptr, size) memset((ptr), 0, (size))
372#define ZERO_STRUCT(s) memset(&(s), 0, sizeof(s))
375#define ZERO_ARRAY(arr) memset((arr), 0, sizeof(arr))
382#define MIN(a, b) ((a) < (b) ? (a) : (b))
385#define MAX(a, b) ((a) > (b) ? (a) : (b))
388#define ABS(x) ((x) < 0 ? -(x) : (x))
391#define CLAMP(x, lo, hi) (MIN(MAX((x), (lo)), (hi)))
398#define SET_BIT(v, pos) ((v) |= (1ULL << (pos)))
401#define CLEAR_BIT(v, pos) ((v) &= ~(1ULL << (pos)))
404#define TOGGLE_BIT(v, pos) ((v) ^= (1ULL << (pos)))
407#define CHECK_BIT(v, pos) (((v) >> (pos)) & 1U)
416#define ALIGN_UP(x, align) (((x) + (align) - 1) & ~((align) - 1))
419#define ALIGN_DOWN(x, align) ((x) & ~((align) - 1))
422#define IS_ALIGNED(x, align) (((x) & ((align) - 1)) == 0)
429#define STREQ(a, b) (strcmp((a), (b)) == 0)
432#define STRNEQ(a, b, n) (strncmp((a), (b), (n)) == 0)
435#define STR_EMPTY(s) ((s) == NULL || (s)[0] == '\0')
438#define STR_NOT_EMPTY(s) ((s) != NULL && (s)[0] != '\0')
450#define DEBUG_PRINT(fmt, ...) printf("[DEBUG] %s:%d: " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__)
453#define DEBUG_VAR(var) printf("[DEBUG] %s:%d: %s = %td\n", __FILE__, __LINE__, #var, (ptrdiff_t)(var))
456#define DEBUG_STR(str) printf("[DEBUG] %s:%d: %s = \"%s\"\n", __FILE__, __LINE__, #str, (str) ? (str) : "(null)")
460#define DEBUG_PRINT(fmt, ...) ((void)0)
461#define DEBUG_VAR(var) UNUSED(var)
462#define DEBUG_STR(str) UNUSED(str)
467#define LOG_ERROR(fmt, ...) \
468 fprintf(stderr, "[ERROR] %s:%d [%s]: " fmt "\n", __FILE__, __LINE__, __func__, ##__VA_ARGS__)
471#define LOG_WARN(fmt, ...) fprintf(stderr, "[WARN] %s:%d [%s]: " fmt "\n", __FILE__, __LINE__, __func__, ##__VA_ARGS__)
474#define LOG_INFO(fmt, ...) printf("[INFO] %s:%d [%s]: " fmt "\n", __FILE__, __LINE__, __func__, ##__VA_ARGS__)
484#if SOLIDC_GCC || SOLIDC_CLANG
494#define FOR_EACH_ARRAY(item, array) \
495 for (__typeof__(&(array)[0]) item = (array), _fea_end = (array) + ARRAY_SIZE(array); item < _fea_end; ++item)
503#define FOR_EACH_RANGE(var, start, end) for (__typeof__(start) var = (start); var < (end); ++var)
516#define FOR_EACH_ARRAY(item, array) \
517 for (void *item = (void*)(array), *_fea_end = (void*)((char*)(array) + sizeof(array)); item < _fea_end; \
518 item = (char*)item + (sizeof((array)[0])))
520#define FOR_EACH_RANGE(var, start, end) for (ptrdiff_t var = (ptrdiff_t)(start); var < (ptrdiff_t)(end); ++var)
550#define TIME_DIFF(start, end, freq) ((double)((end).QuadPart - (start).QuadPart) / (double)(freq).QuadPart)
556#define TIME_DIFF_MS(start, end, freq) ((double)((end).QuadPart - (start).QuadPart) * 1000.0 / (double)(freq).QuadPart)
558#define TIME_BLOCK(name, block) \
560 LARGE_INTEGER _freq, _t0, _t1; \
561 QueryPerformanceFrequency(&_freq); \
562 QueryPerformanceCounter(&_t0); \
563 block QueryPerformanceCounter(&_t1); \
564 printf("Time[%s]: %.6f s\n", (name), TIME_DIFF(_t0, _t1, _freq)); \
567#define TIME_BLOCK_MS(name, block) \
569 LARGE_INTEGER _freq, _t0, _t1; \
570 QueryPerformanceFrequency(&_freq); \
571 QueryPerformanceCounter(&_t0); \
572 block QueryPerformanceCounter(&_t1); \
573 printf("Time[%s]: %.3f ms\n", (name), TIME_DIFF_MS(_t0, _t1, _freq)); \
581#define TIME_DIFF(start, end) \
582 ((double)((end).tv_sec - (start).tv_sec) + (double)((end).tv_nsec - (start).tv_nsec) / 1.0e9)
588#define TIME_DIFF_MS(start, end) \
589 ((double)((end).tv_sec - (start).tv_sec) * 1000.0 + (double)((end).tv_nsec - (start).tv_nsec) / 1.0e6)
591#define TIME_BLOCK(name, block) \
593 struct timespec _t0, _t1; \
594 clock_gettime(CLOCK_MONOTONIC, &_t0); \
595 block clock_gettime(CLOCK_MONOTONIC, &_t1); \
596 printf("Time[%s]: %.6f s\n", (name), TIME_DIFF(_t0, _t1)); \
599#define TIME_BLOCK_MS(name, block) \
601 struct timespec _t0, _t1; \
602 clock_gettime(CLOCK_MONOTONIC, &_t0); \
603 block clock_gettime(CLOCK_MONOTONIC, &_t1); \
604 printf("Time[%s]: %.3f ms\n", (name), TIME_DIFF_MS(_t0, _t1)); \
618static inline uint64_t get_time_ns(
void) {
620 LARGE_INTEGER freq, counter;
621 QueryPerformanceFrequency(&freq);
622 QueryPerformanceCounter(&counter);
624 uint64_t seconds = (uint64_t)counter.QuadPart / (uint64_t)freq.QuadPart;
625 uint64_t remainder = (uint64_t)counter.QuadPart % (uint64_t)freq.QuadPart;
626 return seconds * UINT64_C(1000000000) + (remainder * UINT64_C(1000000000)) / (uint64_t)freq.QuadPart;
629 clock_gettime(CLOCK_MONOTONIC, &ts);
630 return (uint64_t)ts.tv_sec * UINT64_C(1000000000) + (uint64_t)ts.tv_nsec;
645#define strtok_r(str, delim, saveptr) strtok_s((str), (delim), (saveptr))
653static inline struct tm* gmtime_r(
const time_t* timep,
struct tm* result) {
654 return gmtime_s(result, timep) == 0 ? result : NULL;
663static inline struct tm* localtime_r(
const time_t* timep,
struct tm* result) {
664 return localtime_s(result, timep) == 0 ? result : NULL;
669#if defined(__cplusplus)