#pragma once

#include <assert.h>

typedef struct Arena_t Arena;

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

// ::Util::Size::Defines::

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

// ::Util::Memory::Defines::

#define DEFAULT_ALIGNMENT (2*sizeof(rawptr))

#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) (((char *)ptr) + add)

// ::Util::Array::Defines::

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

// ::Util::Compression::Defines::

#define HM_MAX_SYMBOLS 256

// ::Util::Strings::Defines::
#define Str8L(x) (Str8){ .len = Len(x), .value = (u8 *)x }
#define MakeString(x) #x

// ::Util::Hashing::Defines::
#define HASH_SEED 5995

typedef struct HMEnc_t
{
	u8 	length[256];
	u32 code[256];
} HMEnc;

typedef struct HMNode_t HMNode;
typedef struct HMNode_t 
{
	u32 		freq;
	u32 		sym;
	HMNode *l;
	HMNode *r;
} HMNode;

typedef struct BitWriter_t
{
	u32 bits;
	i32 pos;
	u8 *current;
	u8 *end;
} BitWriter;

typedef struct Str8_t
{
	u32 len;
	u8  *value;
} Str8;

// ::Util::Strings::Functions::Header::

u32 StrLen(const char *str);
b32 StrEq(const char *l, const char *r);
i32 SPrintf(char *buf, rawptr fmt, ...);
Str8 MakeStr8(u8 *str, u32 len);
Str8 PreSplitStr8(Str8 string, Str8 delimiter);
Str8 PreSplitNewStr8(Arena *arena, Str8 string, Str8 delimiter);

// ::Util::Memory::Functions::Header::

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

// ::Util::Math::Functions::Header::

u32 u32Min(u32 l, u32 r);
i32 i32Min(i32 l, i32 r);
u32 u32Max(u32 l, u32 r);
i32 i32Max(i32 l, i32 r);
i32 i32Clamp(i32 v, i32 min, i32 max);
u32 u32Clamp(u32 v, u32 min, u32 max);

// ::Util::Compression::Functions::Header::

b32 HMCompressData(u8 *data, u32 len, u8 *out);
u32 static inline ReadBit(BitWriter *bw);
void static inline RefillBits(BitWriter *bw);
void static inline FlushBits(BitWriter *bw);
void static inline WriteBit(BitWriter *bw, u32 v);
void static inline HMScan1(HMNode *nodes, u8 symbol);
void static inline HMScan2(HMNode *nodes, u8 symbol1, u8 symbol2);
void static inline HMScan3(HMNode *nodes, u8 symbol1, u8 symbol2, u8 symbol3);
void static inline HMScan4(HMNode *nodes, u8 symbol1, u8 symbol2, u8 symbol3, u8 symbol4);
void static inline HMBuildTable(HMNode *nodes);
void static inline HMQuicksort(HMNode *nodes, u32 low, u32 high);

// ::Util::Hashing::Functions::Header::

u64 static inline HashFromString(Str8 string);
