rutile/compiler/pre.h
2025-01-12 18:20:42 -03:00

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