#pragma once

// ::Constants::

constexpr usize DEFAULT_ALIGNMENT = (2*sizeof(rawptr));
constexpr u64 HASH_SEED = 5995;

// ::Macros::

#define Assert(condition, message) do { assert((condition) && (message)); } while(0)

#define KB(n) n			* 1024LL
#define MB(n) KB(n) * 1024LL
#define GB(n) MB(n) * 1024LL
#define TB(n) GB(n) * 1024LL

#define BitEq(var, bits) (((var) & (bits)) == (bits))
#define AlignPow2(x, b)	(((x) + (b) - 1) & (~((b) - 1)))	
#define IsPow2(x)				((x) != 0 && ((x) &((x) - 1)) == 0)
#define PtrAdd(ptr, add) ((rawptr)(((uintptr)ptr) + ((uintptr)add)))

#define MakeArray(arena, type, count) (type *)(ArenaAlloc(arena, (isize)(sizeof(type)) * (isize)(count)))
#define Len(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))

#define i8(x) ((i8)(x))
#define i16(x) ((i16)(x))
#define i32(x) ((i32)(x))
#define i64(x) ((i64)(x))

#define u8(x) ((u8)(x))
#define u16(x) ((u16)(x))
#define u32(x) ((u32)(x))
#define u64(x) ((u64)(x))

#define c8(x) ((c8)(x))
#define c8ptr(x) ((c8 *)(x))
#define u8ptr(x) ((u8 *)(x))
#define i8ptr(x) ((i8 *)(x))

#define intptr(x) ((intptr)(x))
#define uintptr(x) ((uintptr)(x))

#define f32(x) ((f32)(x))
#define f64(x) ((f64)(x))

#define rawptr(x) ((rawptr)(x))

#define String8Array(v, c) MakeString8((c8 *)(v), sizeof(*(v))*(c)) 
#define String8Struct(v) MakeString8((c8 *)(v), sizeof(*(v)))
#define String8CStr(v) MakeString8((c8 *)v, StrLen(v))

#define DefIntegerImpl(def) \
	Def##def(i8); \
	Def##def(i16); \
	Def##def(i32); \
	Def##def(i64); \
	Def##def(u8); \
	Def##def(u16); \
	Def##def(u32); \
	Def##def(u64)

#define DefFloatImpl(def) \
	Def##def(f32); \
	Def##def(f64)

#define DefMathImpl(def) \
	DefIntegerImpl(def); \
	DefFloatImpl(def)

#define ArrayType(T) \
typedef struct T##Array \
{ \
	T 	*data; \
	u64 length; \
} T##Array

#define PtrArrayType(T) \
typedef struct T##PtrArray \
{ \
 	T 	**data; \
	u64 	length; \
} T##PtrArray

#define InitArrayType(arr, arena, T, len) \
arr.data = MakeArray(arena, T, len); \
arr.length = len

// ::String8::

static b32 String8Eq(String8 l, String8 r);
static u32 StrLen(const char *str);
static b32 StrEqL(const char *l, const char *r, u64 len);
static b32 StrEq(const char *l, const char *r);
static void StrConcat(c8 *str, c8 *append);
static String8 MakeString8(c8 *str, u64 len);
static String8 String8Concat(Arena *arena, String8 string, String8 append);
static void String8TrimSuffix(String8 *str, c8 delimiter);
static i64 String8FindLast(String8 str, c8 delimiter);
static String8 PreSplitString8(String8 string, String8 delimiter);
static String8 PreSplitNewString8(Arena *arena, String8 string, String8 delimiter);

// ::Memory::

static void MemZero(void *ptr, isize size);
static void MemCpy(rawptr dst, rawptr src, usize len);

// ::Convert::

static inline void U32ColToVec4(Vec4 *dst, u32 src);
static inline void U32ToVec4(Vec4 *dst, u32 src);

// ::Math::

#define DefMin(T) \
T Min##T(T l, T r) \
{ \
	return l < r ? l : r; \
}

#define DefMax(T) \
T Max##T(T l, T r) \
{ \
	return l > r ? l : r; \
}

#define DefClamp(T) \
T Clamp##T(T v, T min, T max) \
{ \
	return Min##T(max, Max##T(v, min)); \
}

#define DefAbs(T) \
T Abs##T(T v) \
{ \
	return v < (T)0 ? -v : v; \
}

// ::Hashing::

u64 static inline HashFromString(String8 string);
