Files
corelang/base.cpp
2023-04-02 12:13:11 +02:00

443 lines
13 KiB
C++

#define CORE_BASE
#if defined(__clang__)
#define COMPILER_CLANG 1
#if defined(_WIN32)
#define OS_WINDOWS 1
#elif defined(__linux__)
#define OS_LINUX 1
#else
#error Couldnt figure out the platform automatically
#endif
#elif defined(_MSC_VER)
#define COMPILER_MSVC 1
#define OS_WINDOWS 1
#elif defined(__GNUC__)
#define COMPILER_GCC 1
#if defined(__linux__)
#define OS_LINUX 1
#endif
#else
#error Couldnt figure out the compiler
#endif
#if defined(OS_MAC)
#define OS_UNIX 1
#endif
#if defined(OS_LINUX)
#define OS_UNIX 1
#endif
#if !defined(COMPILER_MSVC)
#define COMPILER_MSVC 0
#endif
#if !defined(COMPILER_GCC)
#define COMPILER_GCC 0
#endif
#if !defined(COMPILER_CLANG)
#define COMPILER_CLANG 0
#endif
#if !defined(OS_WINDOWS)
#define OS_WINDOWS 0
#endif
#if !defined(OS_LINUX)
#define OS_LINUX 0
#endif
#if !defined(OS_MAC)
#define OS_MAC 0
#endif
#if !defined(OS_UNIX)
#define OS_UNIX 0
#endif
#if OS_WINDOWS
#define OS_EXE ".exe"
#define OS_NAME "Win32"_s
#define OS_NAME_LOWER "win32"_s
#elif OS_LINUX
#define OS_EXE ".out"
#define OS_NAME "Linux"_s
#define OS_NAME_LOWER "linux"_s
#elif OS_MAC
#define OS_EXE ".out"
#define OS_NAME "Mac"_s
#define OS_NAME_LOWER "mac"_s
#else
#error Couldnt figure out the OS with C macros!
#endif
#if OS_WINDOWS
#define NOMINMAX
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <windows.h>
#define Breakpoint __debugbreak()
#define force_inline __forceinline
#else
#define Breakpoint (*(volatile int *)0 = 0)
#define force_inline inline
#endif
#include <stdlib.h>
#include <float.h>
#include <stdint.h>
typedef int8_t S8;
typedef int16_t S16;
typedef int32_t S32;
typedef int64_t S64;
typedef uint8_t U8;
typedef uint16_t U16;
typedef uint32_t U32;
typedef uint64_t U64;
typedef S8 B8;
typedef S16 B16;
typedef S32 B32;
typedef S64 B64;
typedef float F32;
typedef double F64;
#define U64MAX UINT64_MAX
#define U32MAX UINT32_MAX
#define U16MAX UINT16_MAX
#define U8MAX UINT8_MAX
#define U64MIN 0
#define U32MIN 0
#define U16MIN 0
#define U8MIN 0
#define S64MAX INT64_MAX
#define S64MIN INT64_MIN
#define S32MAX INT32_MAX
#define S32MIN INT32_MIN
#define S16MAX INT16_MAX
#define S16MIN INT16_MIN
#define S8MAX INT8_MAX
#define S8MIN INT8_MIN
#define F32MAX FLT_MAX
#define F32MIN FLT_MIN
#define F64MAX DBL_MAX
#define F64MIN DBL_MIN
#define api
#define CORE_Static static
#define global static
#define assert(x) \
do { \
if (!(x)) Breakpoint; \
} while (0)
#define assert_message(x, ...) assert(x)
#define invalid_codepath assert_message(0, "Invalid codepath")
#define invalid_return \
do { \
assert_message(0, "Invalid codepath"); \
return {}; \
} while (0)
#define invalid_default_case \
default: \
invalid_codepath
#define not_implemented assert_message(0, "Not implemented")
#define unused(x) ((void)x)
#define buff_cap(x) (sizeof(x) / sizeof((x)[0]))
#define is_flag_set(val, flag) ((val) & (flag))
#define set_flag(val, flag) ((val) |= (flag))
#define unset_flag(val, flag) ((val) &= (~(flag)))
#define bit_flag(x) (1ull << (x))
#define kib(x) ((x)*1024llu)
#define mib(x) (kib(x) * 1024llu)
#define gib(x) (mib(x) * 1024llu)
#define JOIN1(X, Y) X##Y
#define JOIN(X, Y) JOIN1(X, Y)
#define string_expand(x) (int)x.len, x.str
struct String {
U8 *str;
S64 len;
};
global String string_null = {(U8 *)"null", 4};
union Intern_String { // Basically just String
String s;
struct {
U8 *str;
S64 len;
};
};
struct Allocator {
typedef void *Allocate(Allocator *, size_t);
typedef void Deallocate(Allocator *, void *p);
Allocate *allocate;
Deallocate *deallocate;
};
CORE_Static void memory_zero(void *p, size_t size);
CORE_Static void deallocate_stub(Allocator *, void *) {}
#define allocate_array(a, T, size, ...) (T *)allocate_size(a, sizeof(T) * (size), ##__VA_ARGS__)
#define allocate_struct(a, T, ...) allocate_array(a, T, 1, ##__VA_ARGS__)
CORE_Static void *allocate_size(Allocator *allocator, size_t size, bool zero_memory = true) {
void *result = allocator->allocate(allocator, size);
if (zero_memory) {
memory_zero(result, size);
}
return result;
}
CORE_Static void deallocate(Allocator *allocator, void *p) {
assert(p);
allocator->deallocate(allocator, p);
}
//-----------------------------------------------------------------------------
// Utilities
//-----------------------------------------------------------------------------
CORE_Static size_t
get_align_offset(size_t size, size_t align) {
size_t mask = align - 1;
size_t val = size & mask;
if (val) {
val = align - val;
}
return val;
}
CORE_Static size_t
align_up(size_t size, size_t align) {
size_t result = size + get_align_offset(size, align);
return result;
}
CORE_Static size_t
align_down(size_t size, size_t align) {
size += 1; // Make sure 8 when align is 8 doesn't get rounded down to 0
size_t result = size - (align - get_align_offset(size, align));
return result;
}
CORE_Static void
memory_copy(void *dst, const void *src, size_t size) {
U8 *d = (U8 *)dst;
U8 *s = (U8 *)src;
for (size_t i = 0; i < size; i++) {
d[i] = s[i];
}
}
CORE_Static void
memory_zero(void *p, size_t size) {
U8 *pp = (U8 *)p;
for (size_t i = 0; i < size; i++)
pp[i] = 0;
}
template <class T>
void swap(T &a, T &b) {
T temp = a;
a = b;
b = temp;
}
template <class T>
T max(T a, T b) {
if (a > b) return a;
return b;
}
template <class T>
T min(T a, T b) {
if (a > b) return b;
return a;
}
template <class T>
T clamp_top(T val, T max) {
if (val > max) val = max;
return val;
}
template <class T>
T clamp_bot(T bot, T val) {
if (val < bot) val = bot;
return val;
}
template <class T>
T clamp(T min, T val, T max) {
if (val > max) val = max;
if (val < min) val = min;
return val;
}
CORE_Static U64
hash_string(String string) {
U64 hash = (U64)14695981039346656037ULL;
for (S64 i = 0; i < string.len; i++) {
hash = hash ^ (U64)(string.str[i]);
hash = hash * (U64)1099511628211ULL;
}
return hash;
}
CORE_Static U64
hash_u64(U64 x) {
x *= 0xff51afd7ed558ccd;
x ^= x >> 32;
return x;
}
CORE_Static U64
hash_ptr(const void *ptr) {
return hash_u64((uintptr_t)ptr);
}
CORE_Static U64
hash_mix(U64 x, U64 y) {
// @note: murmur hash 3 mixer but I add the 'y'
// which means it's probably bad, hopefully better
// then some random scribble I could do
x ^= (y >> 33);
x *= 0xff51afd7ed558ccd;
x ^= (x >> 33);
x *= 0xc4ceb9fe1a85ec53;
x ^= (y >> 33);
return x;
}
CORE_Static U64
is_pow2(U64 x) {
assert(x != 0);
B32 result = (x & (x - 1llu)) == 0;
return result;
}
CORE_Static U64
wrap_around_pow2(U64 x, U64 power_of_2) {
assert(is_pow2(power_of_2));
U64 r = (((x) & ((power_of_2)-1llu)));
return r;
}
force_inline String
operator""_s(const char *str, size_t size) {
return String{(U8 *)str, (S64)size};
}
force_inline B32
operator==(Intern_String a, Intern_String b) {
return a.str == b.str;
}
force_inline B32
operator!=(Intern_String a, Intern_String b) {
B32 result = a.str == b.str;
return !result;
}
//-----------------------------------------------------------------------------
// Very cool macros. Since these are macros it's recommended to wrap them
// in a function and not use directly
//----- -----------------------------------------------------------------------
#define SLL_QUEUE_ADD_MOD(f, l, n, next) \
do { \
if ((f) == 0) { \
(f) = (l) = (n); \
} \
else { \
(l) = (l)->next = (n); \
} \
} while (0)
#define SLL_QUEUE_ADD(f, l, n) SLL_QUEUE_ADD_MOD(f, l, n, next)
#define SLL_QUEUE_POP_FIRST_MOD(f, l, next) \
do { \
if ((f) == (l)) { \
(f) = (l) = 0; \
} \
else { \
(f) = (f)->next; \
} \
} while (0)
#define SLL_QUEUE_POP_FIRST(f, l) SLL_QUEUE_POP_FIRST_MOD(f, l, next)
#define SLL_STACK_ADD_MOD(stack_base, new_stack_base, next) \
do { \
(new_stack_base)->next = (stack_base); \
(stack_base) = (new_stack_base); \
} while (0)
#define SLL_STACK_ADD(stack_base, new_stack_base) SLL_STACK_ADD_MOD(stack_base, new_stack_base, next)
#define SLL_STACK_POP(stack_base) \
do { \
if (stack_base) { \
auto(N) = (stack_base); \
(stack_base) = (stack_base)->next; \
(N)->next = 0; \
} \
} while (0)
#define DLL_QUEUE_ADD_LAST_MOD(f, l, node, next, prev) \
do { \
if ((f) == 0) { \
(f) = (l) = (node); \
(node)->prev = 0; \
(node)->next = 0; \
} \
else { \
(l)->next = (node); \
(node)->prev = (l); \
(node)->next = 0; \
(l) = (node); \
} \
} while (0)
#define DLL_QUEUE_ADD_LAST(f, l, node) DLL_QUEUE_ADD_LAST_MOD(f, l, node, next, prev)
#define DLL_QUEUE_ADD(f, l, node) DLL_QUEUE_ADD_LAST(f, l, node)
#define DLL_QUEUE_REMOVE_MOD(first, last, node, next, prev) \
do { \
if ((first) == (last)) { \
assert_message((node) == (first), "Macro assert failed"); \
(first) = (last) = 0; \
} \
else if ((last) == (node)) { \
(last) = (last)->prev; \
(last)->next = 0; \
} \
else if ((first) == (node)) { \
(first) = (first)->next; \
(first)->prev = 0; \
} \
else { \
(node)->prev->next = (node)->next; \
(node)->next->prev = (node)->prev; \
} \
} while (0)
#define DLL_QUEUE_REMOVE(first, last, node) DLL_QUEUE_REMOVE_MOD(first, last, node, next, prev)
#define DLL_STACK_ADD_MOD(first, node, next, prev) \
do { \
(node)->next = (first); \
if ((first)) \
(first)->prev = (node); \
(first) = (node); \
(node)->prev = 0; \
} while (0)
#define DLL_STACK_ADD(first, node) DLL_STACK_ADD_MOD(first, node, next, prev)
#define DLL_STACK_REMOVE_MOD(first, node, next, prev) \
do { \
if ((node) == (first)) { \
(first) = (first)->next; \
if ((first)) \
(first)->prev = 0; \
} \
else { \
(node)->prev->next = (node)->next; \
if ((node)->next) \
(node)->next->prev = (node)->prev; \
} \
} while (0)
#define DLL_STACK_REMOVE(first, node) DLL_STACK_REMOVE_MOD(first, node, next, prev)
#define For_Linked_List_Named(a, it) for (auto *it = (a); it; it = it->next) // @todo: reference?
#define For_Linked_List(a) For_Linked_List_Named(a, it)