util.h (11313B)
1 /* See LICENSE for license details. */ 2 #ifndef _UTIL_H_ 3 #define _UTIL_H_ 4 5 #include "compiler.h" 6 7 /* NOTE: glibc devs are actually buffoons who never write any real code 8 * the following headers include a bunch of other headers which need this crap defined first */ 9 #if OS_LINUX 10 #ifndef _GNU_SOURCE 11 #define _GNU_SOURCE 12 #endif 13 #endif 14 15 #include <stddef.h> 16 #include <stdint.h> 17 18 #ifndef asm 19 #define asm __asm__ 20 #endif 21 22 #ifndef typeof 23 #define typeof __typeof__ 24 #endif 25 26 #if OS_WINDOWS 27 #define EXPORT __declspec(dllexport) 28 #else 29 #define EXPORT 30 #endif 31 32 #ifdef _DEBUG 33 #define DEBUG_EXPORT EXPORT 34 #if OS_WINDOWS 35 #ifdef _BEAMFORMER_DLL 36 #define DEBUG_IMPORT __declspec(dllimport) 37 #else 38 #define DEBUG_IMPORT __declspec(dllexport) 39 #endif 40 #else 41 #ifdef _BEAMFORMER_DLL 42 #define DEBUG_IMPORT extern 43 #else 44 #define DEBUG_IMPORT 45 #endif 46 #endif 47 #define DEBUG_DECL(a) a 48 #define assert(c) do { if (!(c)) debugbreak(); } while (0) 49 #else 50 #define DEBUG_IMPORT global 51 #define DEBUG_EXPORT function 52 #define DEBUG_DECL(a) 53 #define assert(c) (void)(c) 54 #endif 55 #define ASSERT assert 56 57 #if ASAN_ACTIVE 58 void __asan_poison_memory_region(void *, ptrdiff_t); 59 void __asan_unpoison_memory_region(void *, ptrdiff_t); 60 #define asan_poison_region(region, size) __asan_poison_memory_region((region), (size)) 61 #define asan_unpoison_region(region, size) __asan_unpoison_memory_region((region), (size)) 62 #else 63 #define asan_poison_region(...) 64 #define asan_unpoison_region(...) 65 #endif 66 67 #define InvalidCodePath assert(0) 68 #define InvalidDefaultCase default: assert(0); break 69 70 #define arg_list(type, ...) (type []){__VA_ARGS__}, sizeof((type []){__VA_ARGS__}) / sizeof(type) 71 72 #define function static 73 #define global static 74 #define local_persist static 75 76 #if COMPILER_MSVC 77 #define thread_static __declspec(thread) 78 #elif COMPILER_CLANG || COMPILER_GCC 79 #define thread_static __thread 80 #else 81 #error thread_static not defined for this compiler 82 #endif 83 84 #define alignof _Alignof 85 #define static_assert _Static_assert 86 87 /* NOTE: garbage to get the prepocessor to properly stringize the value of a macro */ 88 #define str_(...) #__VA_ARGS__ 89 #define str(...) str_(__VA_ARGS__) 90 91 #define countof(a) (iz)(sizeof(a) / sizeof(*a)) 92 #define ARRAY_COUNT(a) (sizeof(a) / sizeof(*a)) 93 #define ABS(x) ((x) < 0 ? (-x) : (x)) 94 #define BETWEEN(x, a, b) ((x) >= (a) && (x) <= (b)) 95 #define CLAMP(x, a, b) ((x) < (a) ? (a) : (x) > (b) ? (b) : (x)) 96 #define CLAMP01(x) CLAMP(x, 0, 1) 97 #define ISPOWEROF2(a) (((a) & ((a) - 1)) == 0) 98 #define MIN(a, b) ((a) < (b) ? (a) : (b)) 99 #define MAX(a, b) ((a) > (b) ? (a) : (b)) 100 #define ORONE(x) ((x)? (x) : 1) 101 #define SIGN(x) ((x) < 0? -1 : 1) 102 #define swap(a, b) do {typeof(a) __tmp = (a); (a) = (b); (b) = __tmp;} while(0) 103 104 #define ISDIGIT(c) (BETWEEN((c), '0', '9')) 105 #define ISUPPER(c) (((c) & 0x20u) == 0) 106 #define TOLOWER(c) (((c) | 0x20u)) 107 #define TOUPPER(c) (((c) & ~(0x20u))) 108 109 #define f32_cmp(x, y) (ABS((x) - (y)) <= F32_EPSILON * MAX(1.0f, MAX(ABS(x), ABS(y)))) 110 111 #define DeferLoop(begin, end) for (i32 _i_ = ((begin), 0); !_i_; _i_ += 1, (end)) 112 #define DeferLoopTag(begin, end, tag) for (i32 __##tag = ((begin), 0); !__##tag ; __##tag += 1, (end)) 113 114 #define EachBit(a, it) (u64 it = ctz_u64(a); it != 64; a &= ~(1u << (it)), it = ctz_u64(a)) 115 #define EachElement(array, it) (u64 it = 0; it < countof(array); it += 1) 116 #define EachEnumValue(type, it) (type it = (type)0; it < type##_Count; it = (type)(it + 1)) 117 #define EachNonZeroEnumValue(type, it) (type it = (type)1; it < type##_Count; it = (type)(it + 1)) 118 119 #define spin_wait(c) while ((c)) cpu_yield() 120 121 #define DA_STRUCT(kind, name) typedef struct { \ 122 kind *data; \ 123 iz count; \ 124 iz capacity; \ 125 } name ##List; 126 127 /* NOTE(rnp): no guarantees about actually getting an element */ 128 #define SLLPop(list) list; list = list ? list->next : 0 129 #define SLLPush(v, list) do { \ 130 (v)->next = (list); \ 131 (list) = v; \ 132 } while (0) 133 134 #define SLLPopFreelist(list) list; do { \ 135 asan_unpoison_region((list), sizeof(*(list))); \ 136 (void)SLLPop((list)); \ 137 } while(0) 138 139 #define SLLPushFreelist(v, list) do { \ 140 SLLPush((v), (list)); \ 141 asan_poison_region((v), sizeof(*(v))); \ 142 } while(0) 143 144 #define DLLPushDown(v, list) do { \ 145 (v)->next = (list); \ 146 if ((v)->next) (v)->next->prev = (v); \ 147 (list) = (v); \ 148 } while (0) 149 150 #define DLLRemove(v) do { \ 151 if ((v)->next) (v)->next->prev = (v)->prev; \ 152 if ((v)->prev) (v)->prev->next = (v)->next; \ 153 } while (0) 154 155 #define KB(a) ((u64)(a) << 10ULL) 156 #define MB(a) ((u64)(a) << 20ULL) 157 #define GB(a) ((u64)(a) << 30ULL) 158 159 #define I32_MAX (0x7FFFFFFFL) 160 #define U16_MAX (0x0000FFFFUL) 161 #define U32_MAX (0xFFFFFFFFUL) 162 #define U64_MAX (0xFFFFFFFFFFFFFFFFULL) 163 #define F32_INFINITY (1e+300*1e+300) 164 #define F32_EPSILON (1e-6f) 165 #ifndef PI 166 #define PI (3.14159265358979323846f) 167 #endif 168 169 typedef char c8; 170 typedef uint8_t u8; 171 typedef int16_t i16; 172 typedef uint16_t u16; 173 typedef uint16_t b16; 174 typedef int32_t i32; 175 typedef uint32_t u32; 176 typedef int64_t i64; 177 typedef uint64_t u64; 178 typedef uint32_t b32; 179 typedef float f32; 180 typedef double f64; 181 typedef ptrdiff_t iz; 182 typedef size_t uz; 183 typedef ptrdiff_t iptr; 184 typedef size_t uptr; 185 186 #include "intrinsics.c" 187 188 typedef alignas(16) union { 189 u8 U8[16]; 190 u16 U16[8]; 191 u32 U32[4]; 192 u64 U64[2]; 193 u32x4 U32x4; 194 } u128; 195 196 typedef struct { u8 *beg, *end; } Arena; 197 typedef struct { Arena *arena; u8 *old_beg; } TempArena; 198 199 typedef struct { iz len; u8 *data; } s8; 200 #define s8(s) (s8){.len = countof(s) - 1, .data = (u8 *)s} 201 #define s8_comp(s) {sizeof(s) - 1, (u8 *)s} 202 203 typedef struct { iz len; u16 *data; } s16; 204 205 typedef struct { u32 cp, consumed; } UnicodeDecode; 206 207 typedef enum { 208 IntegerConversionResult_Invalid, 209 IntegerConversionResult_OutOfRange, 210 IntegerConversionResult_Success, 211 } IntegerConversionResult; 212 213 typedef struct { 214 IntegerConversionResult result; 215 union { 216 u64 U64; 217 i64 S64; 218 }; 219 s8 unparsed; 220 } IntegerConversion; 221 222 typedef struct { u64 start, stop; } RangeU64; 223 224 typedef union { 225 struct { i32 x, y; }; 226 struct { i32 w, h; }; 227 i32 E[2]; 228 } iv2; 229 230 typedef union { 231 struct { i32 x, y, z; }; 232 struct { i32 w, h, d; }; 233 iv2 xy; 234 i32 E[3]; 235 } iv3; 236 237 typedef union { 238 struct { i32 x, y, z, w; }; 239 struct { iv3 xyz; i32 _w; }; 240 i32 E[4]; 241 } iv4; 242 243 typedef union { 244 struct { u32 x, y; }; 245 struct { u32 w, h; }; 246 u32 E[2]; 247 } uv2; 248 249 typedef union { 250 struct { u32 x, y, z; }; 251 struct { u32 w, h, d; }; 252 uv2 xy; 253 u32 E[3]; 254 } uv3; 255 256 typedef union { 257 struct { u32 x, y, z, w; }; 258 struct { uv3 xyz; u32 _w; }; 259 u32 E[4]; 260 } uv4; 261 262 typedef union { 263 struct { f32 x, y; }; 264 struct { f32 w, h; }; 265 f32 E[2]; 266 } v2; 267 268 typedef union { 269 struct { f32 x, y, z; }; 270 struct { f32 w, h, d; }; 271 f32 E[3]; 272 } v3; 273 274 typedef union { 275 struct { f32 x, y, z, w; }; 276 struct { f32 r, g, b, a; }; 277 struct { v3 xyz; f32 _1; }; 278 struct { f32 _2; v3 yzw; }; 279 struct { v2 xy, zw; }; 280 f32 E[4]; 281 } v4; 282 283 #define XZ(v) (v2){.x = v.x, .y = v.z} 284 #define YZ(v) (v2){.x = v.y, .y = v.z} 285 #define XY(v) (v2){.x = v.x, .y = v.y} 286 287 typedef union { 288 struct { v4 x, y, z, w; }; 289 v4 c[4]; 290 f32 E[16]; 291 } m4; 292 293 /* TODO(rnp): delete raylib */ 294 typedef struct { 295 v3 origin; 296 v3 direction; 297 } ray; 298 299 typedef struct { v2 pos, size; } Rect; 300 #define INVERTED_INFINITY_RECT (Rect){.pos = {.x = -F32_INFINITY, .y = -F32_INFINITY}, \ 301 .size = {.x = -F32_INFINITY, .y = -F32_INFINITY}} 302 303 typedef struct { 304 u8 *data; 305 i32 widx; 306 i32 cap; 307 b32 errors; 308 } Stream; 309 310 #define INVALID_FILE (-1) 311 312 typedef struct OS OS; 313 314 typedef struct { 315 Arena arena; 316 iptr handle; 317 iptr window_handle; 318 iptr gl_context; 319 iptr user_context; 320 i32 sync_variable; 321 b32 asleep; 322 } GLWorkerThreadContext; 323 324 #define FILE_WATCH_CALLBACK_FN(name) b32 name(s8 path, iptr user_data, Arena arena) 325 typedef FILE_WATCH_CALLBACK_FN(file_watch_callback); 326 327 typedef struct { 328 iptr user_data; 329 u64 hash; 330 file_watch_callback *callback; 331 } FileWatch; 332 333 typedef struct { 334 u64 hash; 335 iptr handle; 336 s8 name; 337 338 FileWatch *data; 339 iz count; 340 iz capacity; 341 Arena buffer; 342 } FileWatchDirectory; 343 DA_STRUCT(FileWatchDirectory, FileWatchDirectory); 344 345 typedef struct { 346 void *region; 347 iptr os_context; 348 } SharedMemoryRegion; 349 350 typedef struct { u64 value[1]; } Barrier; 351 352 typedef struct { 353 u64 index; 354 u64 count; 355 Barrier barrier; 356 u64 *broadcast_memory; 357 } LaneContext; 358 359 typedef struct { 360 u8 name[16]; 361 u64 name_length; 362 363 LaneContext lane_context; 364 } ThreadContext; 365 366 #define OS_ALLOC_ARENA_FN(name) Arena name(iz capacity) 367 typedef OS_ALLOC_ARENA_FN(os_alloc_arena_fn); 368 369 #define OS_ADD_FILE_WATCH_FN(name) void name(FileWatchDirectoryList *fwctx, Arena *a, s8 path, \ 370 file_watch_callback *callback, iptr user_data) 371 typedef OS_ADD_FILE_WATCH_FN(os_add_file_watch_fn); 372 373 #define OS_WAKE_WORKER_FN(name) void name(GLWorkerThreadContext *ctx) 374 typedef OS_WAKE_WORKER_FN(os_wake_worker_fn); 375 376 #define OS_READ_WHOLE_FILE_FN(name) s8 name(Arena *arena, char *file) 377 typedef OS_READ_WHOLE_FILE_FN(os_read_whole_file_fn); 378 379 #define OS_WAIT_ON_VALUE_FN(name) b32 name(i32 *value, i32 current, u32 timeout_ms) 380 typedef OS_WAIT_ON_VALUE_FN(os_wait_on_value_fn); 381 382 #define OS_WAKE_WAITERS_FN(name) void name(i32 *sync) 383 typedef OS_WAKE_WAITERS_FN(os_wake_waiters_fn); 384 385 #define OS_WRITE_NEW_FILE_FN(name) b32 name(char *fname, s8 raw) 386 typedef OS_WRITE_NEW_FILE_FN(os_write_new_file_fn); 387 388 #define OS_WRITE_FILE_FN(name) b32 name(iptr file, s8 raw) 389 typedef OS_WRITE_FILE_FN(os_write_file_fn); 390 391 #define OS_THREAD_ENTRY_POINT_FN(name) iptr name(iptr _ctx) 392 typedef OS_THREAD_ENTRY_POINT_FN(os_thread_entry_point_fn); 393 394 #define OS_SHARED_MEMORY_LOCK_REGION_FN(name) b32 name(SharedMemoryRegion *sm, i32 *locks, i32 lock_index, u32 timeout_ms) 395 typedef OS_SHARED_MEMORY_LOCK_REGION_FN(os_shared_memory_region_lock_fn); 396 397 #define OS_SHARED_MEMORY_UNLOCK_REGION_FN(name) void name(SharedMemoryRegion *sm, i32 *locks, i32 lock_index) 398 typedef OS_SHARED_MEMORY_UNLOCK_REGION_FN(os_shared_memory_region_unlock_fn); 399 400 #define RENDERDOC_GET_API_FN(name) b32 name(u32 version, void **out_api) 401 typedef RENDERDOC_GET_API_FN(renderdoc_get_api_fn); 402 403 #define RENDERDOC_START_FRAME_CAPTURE_FN(name) void name(iptr gl_context, iptr window_handle) 404 typedef RENDERDOC_START_FRAME_CAPTURE_FN(renderdoc_start_frame_capture_fn); 405 406 #define RENDERDOC_END_FRAME_CAPTURE_FN(name) b32 name(iptr gl_context, iptr window_handle) 407 typedef RENDERDOC_END_FRAME_CAPTURE_FN(renderdoc_end_frame_capture_fn); 408 409 typedef alignas(16) u8 RenderDocAPI[216]; 410 #define RENDERDOC_API_FN_ADDR(a, offset) (*(iptr *)((*a) + offset)) 411 #define RENDERDOC_START_FRAME_CAPTURE(a) (renderdoc_start_frame_capture_fn *)RENDERDOC_API_FN_ADDR(a, 152) 412 #define RENDERDOC_END_FRAME_CAPTURE(a) (renderdoc_end_frame_capture_fn *) RENDERDOC_API_FN_ADDR(a, 168) 413 414 typedef struct { 415 u32 logical_processor_count; 416 u32 page_size; 417 } OS_SystemInfo; 418 419 #define LABEL_GL_OBJECT(type, id, s) {s8 _s = (s); glObjectLabel(type, id, (i32)_s.len, (c8 *)_s.data);} 420 421 #include "util.c" 422 #include "math.c" 423 424 #endif /* _UTIL_H_ */