cbase 1.50.0
C/C++ Static Template
Loading...
Searching...
No Matches
base_macros.h
Go to the documentation of this file.
1
34
35#ifndef BASE_MACROS_H
36#define BASE_MACROS_H
37
38#if defined(_WIN32)
39# ifndef WIN32_LEAN_AND_MEAN
41# define WIN32_LEAN_AND_MEAN
42# endif
43// Note: We don't include <windows.h> here to prevent namespace pollution.
44// Include it manually in the specific .c files that need it.
45#elif defined(__linux__) || (defined(__APPLE__) && defined(__MACH__))
47# include <unistd.h>
48#endif
49
50#if defined(__clang__)
52# define COMPILER_CLANG 1
54# define COMPILER_NAME "Clang"
55#elif defined(__GNUC__)
57# define COMPILER_GCC 1
59# define COMPILER_NAME "GCC"
60#elif defined(_MSC_VER)
62# define COMPILER_MSVC 1
64# define COMPILER_NAME "MSVC"
65#else
66# error "Compiler not supported"
67#endif
68
69#if defined(_WIN32)
71# define OS_WINDOWS 1
73# define OS_NAME "Windows"
74#elif defined(__linux__)
76# define OS_LINUX 1
78# define OS_NAME "Linux"
79#elif defined(__APPLE__) && defined(__MACH__)
81# define OS_MAC 1
83# define OS_NAME "macOS"
84#else
85# error "Operating system not supported"
86#endif
87
88#if defined(_M_X64) || defined(__x86_64__)
90# define ARCH_X64 1
92# define ARCH_NAME "x86_64"
93#elif defined(_M_IX86) || defined(__i386__)
95# define ARCH_X86 1
97# define ARCH_NAME "x86"
98#elif defined(_M_ARM64) || defined(__aarch64__)
100# define ARCH_ARM64 1
102# define ARCH_NAME "ARM64"
103#elif defined(_M_ARM) || defined(__arm__)
105# define ARCH_ARM 1
107# define ARCH_NAME "ARM"
108#else
109# error "Architecture not supported"
110#endif
111
112#if defined(NDEBUG)
114# define BUILD_RELEASE 1
116# define BUILD_NAME "Release"
117#else
119# define BUILD_DEBUG 1
121# define BUILD_NAME "Debug"
122#endif
123
124#if (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || defined(_M_IX86) || \
125 defined(_M_X64) || defined(__i386__) || defined(__x86_64__) || defined(_M_ARM) || \
126 defined(_M_ARM64)
128# define ENDIAN_LITTLE 1
130# define ENDIAN_NAME "Little Endian"
131#elif (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) || defined(__BIG_ENDIAN__)
133# define ENDIAN_BIG 1
135# define ENDIAN_NAME "Big Endian"
136#else
137# error "Could not determine endianness"
138#endif
139
140#if defined(__STDC_VERSION__)
141# if __STDC_VERSION__ >= 202311L
143# define C_STANDARD 23
145# define C_STANDARD_NAME "C23"
146# elif __STDC_VERSION__ >= 201710L
147# define C_STANDARD 17
148# define C_STANDARD_NAME "C17"
149# elif __STDC_VERSION__ >= 201112L
150# define C_STANDARD 11
151# define C_STANDARD_NAME "C11"
152# elif __STDC_VERSION__ >= 199901L
153# define C_STANDARD 99
154# define C_STANDARD_NAME "C99"
155# else
156# define C_STANDARD 89
157# define C_STANDARD_NAME "C89"
158# endif
159#else
161# define C_STANDARD 89
163# define C_STANDARD_NAME "C89/Default"
164#endif
165
166#include <stddef.h>
167#include <stdint.h>
168#include <stdio.h>
169#include <string.h>
170
176
178#define function static
179
181#define global static
182
184#define local_persist static
185
187#define external extern
188
190#if defined(COMPILER_MSVC)
191# define thread_local __declspec(thread)
192#elif defined(COMPILER_CLANG) || defined(COMPILER_GCC)
193# define thread_local __thread
194#elif C_STANDARD >= 11
195# define thread_local _Thread_local
196#else
197# error "Thread local storage not supported on this compiler!"
198#endif
199
200#if defined(COMPILER_GCC) || defined(COMPILER_CLANG)
202# define API_EXPORT __attribute__((visibility("default")))
204# define API_LOCAL __attribute__((visibility("hidden")))
205#elif defined(COMPILER_MSVC)
207# define API_EXPORT __declspec(dllexport)
209# define API_LOCAL
210#else
212# define API_EXPORT
214# define API_LOCAL
215#endif
216
217#ifdef __cplusplus
219# define C_LINKAGE_BEGIN extern "C" {
221# define C_LINKAGE_END }
222#else
224# define C_LINKAGE_BEGIN
226# define C_LINKAGE_END
227#endif
229
235
237#define STRINGIFY_DETAIL(x) #x
253#define STRINGIFY(x) STRINGIFY_DETAIL(x)
254
256#define GLUE_DETAIL(x, y) x##y
271#define GLUE(x, y) GLUE_DETAIL(x, y)
272
286#define INT_FROM_PTR(ptr) ((uintptr_t)(ptr))
287
301#define PTR_FROM_INT(type, val) ((type *)(uintptr_t)(val))
302
318#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
319
320#if defined(__GNUC__) || defined(__clang__) || \
321 (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L)
322
323# if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L
324# define _TYPEOF(x) typeof(x)
325# else
326# define _TYPEOF(x) __typeof__(x)
327# endif
328
332# define MIN(a, b) \
333 ({ \
334 _TYPEOF(a) _a = (a); \
335 _TYPEOF(b) _b = (b); \
336 _a < _b ? _a : _b; \
337 })
338
342# define MAX(a, b) \
343 ({ \
344 _TYPEOF(a) _a = (a); \
345 _TYPEOF(b) _b = (b); \
346 _a > _b ? _a : _b; \
347 })
348
352# define CLAMP(val, min, max) \
353 ({ \
354 _TYPEOF(val) _v = (val); \
355 _TYPEOF(min) _mn = (min); \
356 _TYPEOF(max) _mx = (max); \
357 (_v < _mn) ? _mn : ((_v > _mx) ? _mx : _v); \
358 })
359
360#else
361// Fallbacks for standard C89/C11 (MSVC)
363# define MIN(a, b) (((a) < (b)) ? (a) : (b))
365# define MAX(a, b) (((a) > (b)) ? (a) : (b))
367# define CLAMP(val, min, max) (((val) < (min)) ? (min) : ((val) > (max)) ? (max) : (val))
368#endif
369
387#define SWAP(type, a, b) \
388 do { \
389 type _tmp = (a); \
390 (a) = (b); \
391 (b) = _tmp; \
392 } while (0)
393
409#define Boolify(x) ((x) != 0)
410
431#define AsciiID4(a, b, c, d) \
432 (((u32)(u8)(d) << 24) | ((u32)(u8)(c) << 16) | ((u32)(u8)(b) << 8) | (u32)(u8)(a))
433
445#define ExpandAsciiID(x) (int)(sizeof(x)), (char *)(&(x))
447
453
468#define ALIGN_UP_POW2(x, p) (((x) + (p) - 1) & ~((p) - 1))
469
483#define ALIGN_DOWN_POW2(x, p) ((x) & ~((p) - 1))
484
499#define IS_POW2_OR_ZERO(x) (((x) & ((x) - 1)) == 0)
500
518#define IS_POW2(x) ((x) != 0 && (((x) & ((x) - 1)) == 0))
519
526#define SHIFT8(T, x, s) ((T)(x) << (s))
527
536#define PACK_U32_LE(a, b, c, d) \
537 (SHIFT8(U32, a, 0) | SHIFT8(U32, b, 8) | SHIFT8(U32, c, 16) | SHIFT8(U32, d, 24))
538
539
545
547#define MEM_ZERO(ptr, size) memset((ptr), 0, (size))
548
560#define MEM_ZERO_STRUCT(ptr) MEM_ZERO((ptr), sizeof(*(ptr)))
561
573#define MEM_ZERO_ARRAY(arr) MEM_ZERO((arr), sizeof(arr))
574
576#define MEM_COPY(dst, src, size) memmove((dst), (src), (size))
577
594#define MEM_COPY_STRUCT(dst, src) MEM_COPY((dst), (src), MIN(sizeof(*(dst)), sizeof(*(src))))
595
609#define MEM_COPY_ARRAY(dst, src) MEM_COPY((dst), (src), MIN(sizeof(dst), sizeof(src)))
611
624
633#define DLL_PUSH_BACK_NP(f, l, n, next, prev) \
634 ((f) == 0 ? ((f) = (l) = (n), (n)->next = (n)->prev = 0) \
635 : ((n)->prev = (l), (l)->next = (n), (l) = (n), (n)->next = 0))
636
656#define DLL_PUSH_BACK(f, l, n) DLL_PUSH_BACK_NP(f, l, n, next, prev)
657
667#define DLL_PUSH_FRONT(f, l, n) DLL_PUSH_BACK_NP(l, f, n, prev, next)
668
677#define DLL_REMOVE_NP(f, l, n, next, prev) \
678 ((f) == (n) ? ((f) == (l) ? ((f) = (l) = (0)) : ((f) = (f)->next, (f)->prev = 0)) \
679 : (l) == (n) ? ((l) = (l)->prev, (l)->next = 0) \
680 : ((n)->next->prev = (n)->prev, (n)->prev->next = (n)->next))
681
692#define DLL_REMOVE(f, l, n) DLL_REMOVE_NP(f, l, n, next, prev)
693
701#define SLL_QUEUE_PUSH_N(f, l, n, next) \
702 (((f) == 0 ? (f) = (l) = (n) : ((l)->next = (n), (l) = (n))), (n)->next = 0)
703
713#define SLL_QUEUE_PUSH(f, l, n) SLL_QUEUE_PUSH_N(f, l, n, next)
714
721#define SLL_STACK_PUSH_N(f, n, next) ((n)->next = (f), (f) = (n))
722
731#define SLL_STACK_PUSH(f, n) SLL_STACK_PUSH_N(f, n, next)
732
738#define SLL_STACK_POP_N(f, next) ((f) == 0 ? 0 : ((f) = (f)->next))
739
748#define SLL_STACK_POP(f) SLL_STACK_POP_N(f, next)
750
756
757#if defined(COMPILER_MSVC)
759# define debug_break() __debugbreak()
760#elif defined(COMPILER_GCC) || defined(COMPILER_CLANG)
762# define debug_break() __builtin_trap()
763#else
765# define debug_break() (*(volatile int *)0 = 0)
766#endif
767
768#if BUILD_DEBUG
773# define ASSERT(expr) \
774 do { \
775 if (!(expr)) { \
776 fputs("Assertion failed: " #expr "\n", stderr); \
777 fputs("File: " __FILE__ "\n", stderr); \
778 fputs("Line: " STRINGIFY(__LINE__) "\n", stderr); \
779 debug_break(); \
780 } \
781 } while (0)
782
787# define ASSERT_NOT_NULL(ptr) \
788 do { \
789 if ((ptr) == NULL) { \
790 fputs("Assertion failed: " #ptr " is NULL\n", stderr); \
791 fputs("File: " __FILE__ "\n", stderr); \
792 fputs("Line: " STRINGIFY(__LINE__) "\n", stderr); \
793 debug_break(); \
794 } \
795 } while (0)
796#else
797// Compile assertions out completely in Release builds for zero overhead
798# define ASSERT(expr) ((void)0)
799# define ASSERT_NOT_NULL(ptr) ((void)0)
800#endif
802
803#endif // BASE_MACROS_H