// ::String8::Impl::Start::

static void 
StrConcat(c8 *str, c8 *append)
{
	u32 len = StrLen(str);
	u32 i = 0;
	for (; append[i] != '\0'; i += 1)
	{
		str[i] = append[i];
	}

	str[i] = '\0';
}

static b32 
StrEqL(const char *l, const char *r, u64 len)
{
	for (u64 i = 0; *l == *r && *l && i < len; l++, r++, i++);
	return *l == *r;
}

static b32 
StrEq(const char *l, const char *r) 
{
	for (; *l == *r && *l; l++, r++);
	return *l == '\0' && *r == '\0';
}

static u32
StrLen(const char *str) 
{
	const char *start;
	
	for (start = str; *str != '\0'; ++str)
		/* Iterate only */;

	return (u32)(str - start);
}

static String8 
MakeString8(c8 *str, u64 len)
{
	return (String8){ .value = str, .len = len };
}

static String8 
String8Concat(Arena *arena, String8 string, String8 append)
{
	u64 str_len = string.len + append.len;
	String8 str = {
		.value = MakeArray(arena, c8, str_len + 1),
		.len = str_len,
	};

	MemCpy(str.value, string.value, string.len);
	MemCpy(str.value+string.len, append.value, append.len);

	str.value[str_len] = '\0';

	return str;
}

static void 
String8TrimSuffix(String8 *str, c8 delimiter)
{
	if (!str || str->len == 0) return;

	for (i64 i = i64(str->len)-1; i > 0; i -= 1)
	{
		if (str->value[i] == delimiter)
		{
			str->value[i] = '\0';
			str->len = i == 0 ? 0 : u64(i - 1);
			break;
		}
	}
}

static i64 
String8FindLast(String8 str, c8 delimiter)
{
	if (str.len == 0) return -1;

	i64 result = 1;

	for (i64 i = i64(str.len)-1; i >= 0; i -= 1)
	{
		if (str.value[i] == delimiter)
		{
			result = i;
			break;
		}
	}

	return result;
}

static b32 
String8Eq(String8 l, String8 r)
{
	return StrEqL(l.value, r.value, l.len);
}

static b32
String8StartsWith(String8 string, String8 cmp)
{
	return StrEqL(string.value, cmp.value, cmp.len);
}

static String8 
PreSplitString8(String8 string, String8 delimiter)
{
	if (string.len == 0 || delimiter.len == 0) return string;

	u32 new_len = 0;
	u32 matched_chars = 0;

	for (u32 i = 0; i < string.len; i++)
	{

		if (string.value[i] == delimiter.value[matched_chars])
			matched_chars += 1;
		else
			matched_chars = 0;

		if (matched_chars == delimiter.len || delimiter.value[matched_chars+1] == '\0') 
		{
			new_len = i;
			break;
		}
	}

	return (String8){ .value = string.value, .len = new_len };
}

static String8 
PreSplitNewString8(Arena *arena, String8 string, String8 delimiter)
{
	String8 result = PreSplitString8(string, delimiter);
	
	if (result.len > 0)
	{
		result.value = MakeArray(arena, char, result.len+1);
		MemCpy(result.value, string.value, result.len);
		result.value[result.len] = '\0';
	}

	return result;
}

// ::String8::Impl::End::


// ::Memory::Impl::Start::

static void 
MemZero(void *ptr, isize size)
{
	if (!size || !ptr) return;

	isize iter_size = size > isizeof(u64) ? 8 : 1;
	iter_size *= 4;
	isize iter_len = size / iter_size;

	u64 *mem = (u64 *)ptr;

	if (iter_size > isizeof(u64))
	{
		while (iter_len > 0)
		{
			mem[0] = 0;
			mem[1] = 0;
			mem[2] = 0;
			mem[3] = 0;
			mem += 4;
			iter_len--;
		}
	}

	u8 *byte_mem = (u8 *)mem;
	isize rem_len = size % iter_size;
	while (rem_len > 0)
	{
		byte_mem[0] = 0;
		byte_mem++;
		rem_len--;
	}
}

static void 
MemCpy(rawptr dst, rawptr src, usize size)
{
	if (size == 0) return;

	isize iter_size = size > isizeof(u64) ? 8 : 1;
	iter_size *= 4;
	isize iter_len = size / iter_size;
	isize rem_len = 0;

	u64 *mem_dst = (u64 *)dst;
	u64 *mem_src = (u64 *)src;


	if (iter_size > isizeof(size))
	{
		while (iter_len > 0)
		{
			mem_dst[0] = mem_src[0];
			mem_dst[1] = mem_src[1];
			mem_dst[2] = mem_src[2];
			mem_dst[3] = mem_src[3];
			mem_dst += 4;
			mem_src += 4;
			iter_len--;
		}

		rem_len = size % iter_size;
	}
	else
		rem_len = size;


	u8 *byte_dst = (u8 *)mem_dst;
	u8 *byte_src = (u8 *)mem_src;
	while (rem_len > 0)
	{
		byte_dst[0] = byte_src[0];
		byte_dst++;
		byte_src++;
		rem_len--;
	}
}

// ::Memory::Impl::End::



// ::Convert::Impl::Start::

static inline void
U32ColToVec4(Vec4 *dst, u32 src)
{
	if (src == 0)
	{
		dst->r = dst->g = dst->b = 0.0; 
		dst->a = 1.0;
	}
	else
	{
		U32ToVec4(dst, src);
	}
}

static inline void 
U32ToVec4(Vec4 *dst, u32 src)
{
	dst->r = f32((src >> 0)  & 0xFF) / 255.0;
	dst->g = f32((src >> 8)  & 0xFF) / 255.0;
	dst->b = f32((src >> 16) & 0xFF) / 255.0;
	dst->a = f32((src >> 24) & 0xFF) / 255.0;
}

// ::Convert::Impl::End::



// ::Hashing::Impl::Start::

u64 static inline 
HashFromString(String8 string)
{
	return XXH3_64bits_withSeed(string.value, string.len, HASH_SEED);
}

// ::Hashing::Impl::End::


// ::Math::Impl::Start::

DefMathImpl(Min);
DefMathImpl(Max);

// ::Math::Impl::End::
