solidc
Robust collection of general-purpose cross-platform C libraries and data structures designed for rapid and safe development in C
Loading...
Searching...
No Matches
macros.h
Go to the documentation of this file.
1
6#ifndef __SOLIDC_MACROS__
7#define __SOLIDC_MACROS__
8
9#include <stdint.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13
14// =============================================================================
15// ASSERTION MACROS
16// =============================================================================
17
18#define ASSERT(cond) \
19 do { \
20 if (!(cond)) { \
21 printf("%s:%d [%s]: Assertion '%s' failed.\n", __FILE__, __LINE__, __func__, #cond); \
22 exit(1); \
23 } \
24 } while (0)
25
26#define ASSERT_EQ(a, b) \
27 do { \
28 typeof(a) _a = (a); \
29 typeof(b) _b = (b); \
30 if (_a != _b) { \
31 printf("%s:%d [%s]: Assertion '%s == %s' failed (%ld != %ld).\n", __FILE__, __LINE__, __func__, #a, #b, \
32 (intptr_t)_a, (intptr_t)_b); \
33 exit(1); \
34 } \
35 } while (0)
36
37#define ASSERT_NE(a, b) \
38 do { \
39 typeof(a) _a = (a); \
40 typeof(b) _b = (b); \
41 if (_a == _b) { \
42 printf("%s:%d [%s]: Assertion '%s != %s' failed (both are %ld).\n", __FILE__, __LINE__, __func__, #a, #b, \
43 (intptr_t)_a); \
44 exit(1); \
45 } \
46 } while (0)
47
48#define ASSERT_TRUE(cond) \
49 do { \
50 if (!(cond)) { \
51 printf("%s:%d [%s]: Assertion '%s' is not true.\n", __FILE__, __LINE__, __func__, #cond); \
52 exit(1); \
53 } \
54 } while (0)
55
56#define ASSERT_STR_EQ(a, b) \
57 do { \
58 const char* _a = (a); \
59 const char* _b = (b); \
60 if (_a == NULL || _b == NULL) { \
61 if (_a != _b) { \
62 printf("%s:%d [%s]: Assertion '%s == %s' failed (one is NULL).\n", __FILE__, __LINE__, __func__, #a, \
63 #b); \
64 exit(1); \
65 } \
66 } else if (strcmp(_a, _b) != 0) { \
67 printf("%s:%d [%s]: Assertion '%s == %s' failed (\"%s\" != \"%s\").\n", __FILE__, __LINE__, __func__, #a, \
68 #b, _a, _b); \
69 exit(1); \
70 } \
71 } while (0)
72
73#define ASSERT_NULL(ptr) \
74 do { \
75 if ((ptr) != NULL) { \
76 printf("%s:%d [%s]: Expected '%s' to be NULL.\n", __FILE__, __LINE__, __func__, #ptr); \
77 exit(1); \
78 } \
79 } while (0)
80
81#define ASSERT_NOT_NULL(ptr) \
82 do { \
83 if ((ptr) == NULL) { \
84 printf("%s:%d [%s]: Expected '%s' to not be NULL.\n", __FILE__, __LINE__, __func__, #ptr); \
85 exit(1); \
86 } \
87 } while (0)
88
89#define ASSERT_RANGE(val, min, max) \
90 do { \
91 typeof(val) _val = (val); \
92 typeof(min) _min = (min); \
93 typeof(max) _max = (max); \
94 if (_val < _min || _val > _max) { \
95 printf("%s:%d [%s]: Value %ld is not in range [%ld, %ld].\n", __FILE__, __LINE__, __func__, (long)_val, \
96 (long)_min, (long)_max); \
97 exit(1); \
98 } \
99 } while (0)
100
101#define ASSERT_FLOAT_EQ(a, b, epsilon) \
102 do { \
103 double _a = (double)(a); \
104 double _b = (double)(b); \
105 double _eps = (double)(epsilon); \
106 if ((_a - _b) > _eps || (_b - _a) > _eps) { \
107 printf("%s:%d [%s]: Float assertion '%s == %s' failed (%.6f != %.6f, epsilon=%.6f).\n", __FILE__, \
108 __LINE__, __func__, #a, #b, _a, _b, _eps); \
109 exit(1); \
110 } \
111 } while (0)
112
113// =============================================================================
114// STATIC ASSERTIONS
115// =============================================================================
116
117#if defined(__cplusplus)
118#define STATIC_ASSERT(cond, msg) static_assert(cond, msg)
119#else
120#define STATIC_ASSERT(cond, msg) _Static_assert(cond, msg)
121#endif
122
123#ifndef PRINTF_FORMAT
124#if defined(__GNUC__) || defined(__clang__)
125#define PRINTF_FORMAT(fmt, va) __attribute__((format(printf, fmt, va)))
126#else
127#define PRINTF_FORMAT(fmt, va)
128#endif
129#endif
130
131#if defined(__GNUC__) || defined(__clang__)
132#define WARN_UNUSED_RESULT __attribute__((warn_unused_result))
133#elif defined(_MSC_VER)
134#define WARN_UNUSED_RESULT _Check_return_
135#else
136#define WARN_UNUSED_RESULT
137#endif
138
139#define IS_POWER_OF_2(n) ((n) > 0 && ((n) & ((n) - 1)) == 0)
140#define STATIC_CHECK_POWER_OF_2(n) STATIC_ASSERT(IS_POWER_OF_2(n), #n " is not a power of 2")
141
142// =============================================================================
143// MEMORY AND ARRAY UTILITIES
144// =============================================================================
145
146#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
147#define ZERO_MEMORY(ptr, size) memset(ptr, 0, size)
148#define ZERO_STRUCT(s) memset(&(s), 0, sizeof(s))
149#define ZERO_ARRAY(arr) memset(arr, 0, sizeof(arr))
150
151// =============================================================================
152// MATHEMATICAL UTILITIES
153// =============================================================================
154
155#define MIN(a, b) ((a) < (b) ? (a) : (b))
156#define MAX(a, b) ((a) > (b) ? (a) : (b))
157#define ABS(x) ((x) < 0 ? -(x) : (x))
158#define CLAMP(x, min, max) (MIN(MAX(x, min), max))
159#define SWAP(a, b) \
160 do { \
161 typeof(a) _tmp = a; \
162 a = b; \
163 b = _tmp; \
164 } while (0)
165
166// Bit manipulation
167#define SET_BIT(num, pos) ((num) |= (1ULL << (pos)))
168#define CLEAR_BIT(num, pos) ((num) &= ~(1ULL << (pos)))
169#define TOGGLE_BIT(num, pos) ((num) ^= (1ULL << (pos)))
170#define CHECK_BIT(num, pos) (((num) >> (pos)) & 1)
171
172// Alignment macros
173#define ALIGN_UP(x, align) (((x) + (align) - 1) & ~((align) - 1))
174#define ALIGN_DOWN(x, align) ((x) & ~((align) - 1))
175#define IS_ALIGNED(x, align) (((x) & ((align) - 1)) == 0)
176
177// Round to nearest power of 2
178#define ROUND_UP_POW2(x) \
179 ({ \
180 typeof(x) _x = (x); \
181 _x--; \
182 _x |= _x >> 1; \
183 _x |= _x >> 2; \
184 _x |= _x >> 4; \
185 _x |= _x >> 8; \
186 _x |= _x >> 16; \
187 if (sizeof(_x) > 4) _x |= _x >> 32; \
188 _x++; \
189 })
190
191// =============================================================================
192// STRING UTILITIES
193// =============================================================================
194
195#define STREQ(a, b) (strcmp(a, b) == 0)
196#define STRNEQ(a, b, n) (strncmp(a, b, n) == 0)
197#define STR_EMPTY(s) ((s) == NULL || (s)[0] == '\0')
198#define STR_NOT_EMPTY(s) ((s) != NULL && (s)[0] != '\0')
199
200// =============================================================================
201// DEBUGGING AND LOGGING
202// =============================================================================
203
204#ifdef NDEBUG
205#define DEBUG_PRINT(fmt, ...) (void)fmt;
206#define DEBUG_VAR(var) (void)var;
207#define DEBUG_STR(str) (void)str;
208#else
209#define DEBUG_PRINT(fmt, ...) printf("[DEBUG] %s:%d: " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__)
210#define DEBUG_VAR(var) printf("[DEBUG] %s:%d: %s = %ld\n", __FILE__, __LINE__, #var, (long)(var))
211#define DEBUG_STR(str) printf("[DEBUG] %s:%d: %s = \"%s\"\n", __FILE__, __LINE__, #str, (str) ? (str) : "NULL")
212#endif
213
214#define LOG_ERROR(fmt, ...) \
215 fprintf(stderr, "[ERROR] %s:%d [%s]: " fmt "\n", __FILE__, __LINE__, __func__, ##__VA_ARGS__)
216
217#define LOG_WARN(fmt, ...) fprintf(stderr, "[WARN] %s:%d [%s]: " fmt "\n", __FILE__, __LINE__, __func__, ##__VA_ARGS__)
218
219#define LOG_INFO(fmt, ...) printf("[INFO] %s:%d [%s]: " fmt "\n", __FILE__, __LINE__, __func__, ##__VA_ARGS__)
220
221// =============================================================================
222// CONTAINER ITERATION
223// =============================================================================
224
225#define FOR_EACH_ARRAY(item, array) \
226 for (typeof((array)[0])*item = (array), *_end = (array) + ARRAY_SIZE(array); item < _end; ++item)
227
228#define FOR_EACH_RANGE(var, start, end) for (typeof(start) var = (start); var < (end); ++var)
229
230// =============================================================================
231// TIMING AND PERFORMANCE
232// =============================================================================
233
234#ifdef _WIN32
235#include <windows.h>
236
237#define TIME_DIFF(start, end, freq) ((double)((end).QuadPart - (start).QuadPart) / (double)(freq).QuadPart)
238
239#define TIME_DIFF_MS(start, end, freq) ((double)((end).QuadPart - (start).QuadPart) * 1000.0 / (double)(freq).QuadPart)
240
241#else
242#include <time.h>
243
244#define TIME_DIFF(start, end) \
245 ((double)((end).tv_sec - (start).tv_sec) + (double)((end).tv_nsec - (start).tv_nsec) / 1e9)
246
247// returns elapsed time in *milliseconds* as double
248#define TIME_DIFF_MS(start, end) \
249 ((double)((end).tv_sec - (start).tv_sec) * 1000.0 + (double)((end).tv_nsec - (start).tv_nsec) / 1.0e6)
250
251#endif
252
253#ifdef _WIN32
254#define TIME_BLOCK(name, block) \
255 do { \
256 LARGE_INTEGER _freq, _start, _end; \
257 QueryPerformanceFrequency(&_freq); \
258 QueryPerformanceCounter(&_start); \
259 block QueryPerformanceCounter(&_end); \
260 double _time = TIME_DIFF(_start, _end, _freq); \
261 printf("Time for %s: %.6f seconds\n", name, _time); \
262 } while (0)
263#else
264#define TIME_BLOCK(name, block) \
265 do { \
266 struct timespec _start, _end; \
267 clock_gettime(CLOCK_MONOTONIC, &_start); \
268 block clock_gettime(CLOCK_MONOTONIC, &_end); \
269 double _time = TIME_DIFF(_start, _end); \
270 printf("Time for %s: %.6f seconds\n", name, _time); \
271 } while (0)
272#endif
273
274#ifdef _WIN32
275#define TIME_BLOCK_MS(name, block) \
276 do { \
277 LARGE_INTEGER _freq, _start, _end; \
278 QueryPerformanceFrequency(&_freq); \
279 QueryPerformanceCounter(&_start); \
280 block QueryPerformanceCounter(&_end); \
281 double _ms = TIME_DIFF_MS(_start, _end, _freq); \
282 printf("Time for %s: %.3f ms\n", name, _ms); \
283 } while (0)
284#else
285#define TIME_BLOCK_MS(name, block) \
286 do { \
287 struct timespec _start, _end; \
288 clock_gettime(CLOCK_MONOTONIC, &_start); \
289 block clock_gettime(CLOCK_MONOTONIC, &_end); \
290 double _ms = TIME_DIFF_MS(_start, _end); \
291 printf("Time for %s: %.3f ms\n", name, _ms); \
292 } while (0)
293#endif
294
295// Get current time in nano-seconds.
296static inline uint64_t get_time_ns(void) {
297#if defined(_WIN32)
298 LARGE_INTEGER freq, counter;
299 QueryPerformanceFrequency(&freq);
300 QueryPerformanceCounter(&counter);
301
302 // We calculate seconds and remainder separately to prevent overflow
303 // (counter * 1e9) could overflow 64-bit int if the system uptime is long.
304 uint64_t seconds = counter.QuadPart / freq.QuadPart;
305 uint64_t remainder = counter.QuadPart % freq.QuadPart;
306 return (seconds * 1000000000ULL) + ((remainder * 1000000000ULL) / freq.QuadPart);
307#else
308 struct timespec ts;
309 // macOS (since 10.12) and Linux support this
310 clock_gettime(CLOCK_MONOTONIC, &ts);
311 return (uint64_t)ts.tv_sec * 1000000000ULL + (uint64_t)ts.tv_nsec;
312#endif
313}
314
315#endif // __SOLIDC_MACROS__