158 lines
4.1 KiB
C
158 lines
4.1 KiB
C
#ifndef _pre_h_
|
|
#define _pre_h_
|
|
/* Prelude file, containing some useful macros and types. */
|
|
|
|
#include <stdint.h>
|
|
#include <stddef.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <stdarg.h>
|
|
|
|
typedef int8_t i8;
|
|
typedef uint8_t u8;
|
|
typedef int16_t i16;
|
|
typedef uint16_t u16;
|
|
typedef int32_t i32;
|
|
typedef uint32_t u32;
|
|
typedef int64_t i64;
|
|
typedef uint64_t u64;
|
|
typedef float f32;
|
|
typedef double f64;
|
|
|
|
typedef uintptr_t uptr;
|
|
typedef ptrdiff_t isize;
|
|
typedef size_t usize;
|
|
typedef _Bool bool;
|
|
|
|
#define true ((bool)1)
|
|
#define false ((bool)0)
|
|
#define nil ((void *)0)
|
|
#define U64_MAX ((u64)-1)
|
|
|
|
#define Slice(T) \
|
|
struct { \
|
|
T *s; \
|
|
isize len; \
|
|
}
|
|
|
|
typedef Slice(u8) Str;
|
|
#define Optional(T) struct {T val; bool ok;}
|
|
#define Some(T, v) (T){v, true}
|
|
#define None(T) (T){.ok = false}
|
|
/* Meant for use with stb_ds */
|
|
#define Vec(T) T *
|
|
#define HashMap(K, V) struct { K key; V value; }
|
|
#define HashMapStr(V) struct { char *key; V value; }
|
|
|
|
/* Length of an array */
|
|
#define countof(arr) (isize)(sizeof(arr) / sizeof(*(arr)))
|
|
/* Length of string literal */
|
|
#define lengthof(s) (countof(s) - 1)
|
|
|
|
#define ViewMem(T, arr, lo, hi) ((Slice(T)){.s = arr+lo, .len = hi - lo})
|
|
#define View(sl, lo, hi) ((sl).s += lo, (sl).len = hi - lo, (sl))
|
|
#define foreach(val, arr) for(__typeof__(*(arr)) *__p = (arr), (val) = *__p; __p < (arr)+(arrlen((arr))); (val) = *(__p++))
|
|
#define foreach_getindex(val, arr) (&(val) - (arr))
|
|
|
|
/* Useful integer operations good to have. */
|
|
#define max(x, y) ((x) > (y) ? (x) : (y))
|
|
#define min(x, y) ((x) < (y) ? (x) : (y))
|
|
#define clamp(x, lo, hi) max(lo, min(x, hi))
|
|
|
|
#define BitPos(pos) (1 << (pos))
|
|
|
|
#if defined(__GNUC__) || defined(__clang__)
|
|
# define debugtrap() __builtin_trap()
|
|
# define unreachable() __builtin_unreachable()
|
|
#else /* not optimal... */
|
|
# define debugtrap() abort()
|
|
# define unreachable() abort()
|
|
#endif
|
|
|
|
#ifndef NDEBUG
|
|
# if defined (__GNUC__) || defined(__clang__)
|
|
# define Assert(pred) if (!(pred)) { __builtin_trap(); }
|
|
# else
|
|
# define Assert(pred) if (!(pred)) { *(volatile int *)0 = 0; }
|
|
# endif
|
|
# define trace(...) do { \
|
|
fprintf(stderr, "%s:%-5i", __FILE__, __LINE__); \
|
|
fprintf(stderr, __VA_ARGS__); \
|
|
} while (0)
|
|
#else
|
|
# define Assert(pred)
|
|
# define trace(...)
|
|
#endif
|
|
|
|
/* Creates a `Str` from a string literal */
|
|
#define Sl(s) ((Str){ (u8 *)s, (isize)lengthof(s) })
|
|
/* Creates a `Str` from a buffer of size `len` */
|
|
#define Sb(s, len) ((Str){ (u8 *)s, (isize)len })
|
|
/* Creates a `Str` from a C string. */
|
|
#define Str_from_c(s) ((Str){ (u8 *)s, (isize)(s != nil ? strlen(s) : 0) })
|
|
#define Str_empty(s) ((s).len == 0)
|
|
#define Str_default(s, sor) (!Str_empty(s) ? (s) : (sor))
|
|
|
|
int
|
|
vsnprintf(char *, unsigned long, const char *, va_list);
|
|
|
|
/* "Converts" a `Str` into a C string. Since `Str` are meant to be
|
|
* null-terminated already, no conversion is made, but ensures that the
|
|
* null terminator is present. */
|
|
static inline char *
|
|
Str_to_c(Str s)
|
|
{
|
|
if (s.len == 0 || s.s == nil)
|
|
return nil;
|
|
Assert(s.s[s.len - 1] == '\0');
|
|
return (char *)s.s;
|
|
}
|
|
|
|
/* Returns `true` if both strings are equal. */
|
|
static inline bool
|
|
Str_equal(Str s1, Str s2)
|
|
{
|
|
/* because passing nil to mem* is UB even if size == 0... */
|
|
return (s1.len == s2.len) && (s1.len == 0 || memcmp(s1.s, s2.s, s1.len) == 0);
|
|
}
|
|
|
|
/* Heaps allocates a new `Str` of size `len`, with contents from `data` if it is
|
|
* not `nil`.*/
|
|
static inline Str
|
|
Str_new(const u8 *data, isize len)
|
|
{
|
|
Assert(len >= 0);
|
|
Str s;
|
|
s.s = calloc(len + 1, sizeof(*s.s));
|
|
s.len = len;
|
|
if (data != nil) {
|
|
memcpy(s.s, data, len);
|
|
s.s[len + 1] = '\0'; /* ensure */
|
|
}
|
|
return s;
|
|
}
|
|
|
|
/* Returns a formatted string (heap allocated) of the exact required size. */
|
|
static inline Str
|
|
Strafmt(const char *fmt, ...)
|
|
{
|
|
Str s = {0};
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
|
/* Calculate buffer size required to hold the formatted string */
|
|
int reqs = vsnprintf(nil, 0, fmt, args);
|
|
va_end(args);
|
|
if (reqs < 0)
|
|
return s;
|
|
|
|
s = Str_new(nil, reqs);
|
|
va_start(args, fmt); /* `vsnprintf` touched the arg list, reinitialize it */
|
|
/* the nil terminator is guaranteed by `Str_new` */
|
|
vsnprintf((char *)s.s, s.len + 1, fmt, args);
|
|
va_end(args);
|
|
|
|
return s;
|
|
}
|
|
|
|
#endif
|