module core.stdc.string;

pragma(LDC_intrinsic, "llvm.memcpy.p0.p0.i#")
void llvm_memcpy(T)(void* dst, const(void)* src, T length, bool volatile_ = false) pure @nogc nothrow @trusted
if(__traits(isIntegral, T));

extern(C) void*
memcpy(scope return void* dst, scope const(void*) src, ulong length) pure @nogc nothrow @trusted
{
	llvm_memcpy!(long)(dst, src, cast(long)length);
	return dst;
}

pragma(LDC_intrinsic, "llvm.memset.p0.i#")
void llvm_memset(T)(void* dst, ubyte value, T length, bool volatile_ = false) pure @nogc nothrow @trusted
if(__traits(isIntegral, T));

extern(C) void*
memset(scope return void* s, int c, ulong n) pure nothrow @nogc
{
	ubyte value = cast(ubyte)(c & 0xFF);
	llvm_memset!(long)(s, value, cast(long)n);
	return s;
}

extern(C) int memcmp(const(void)* s1, const(void)* s2, size_t n) pure @nogc nothrow @trusted
{
	auto b = cast(ubyte*) s1;
	auto b2 = cast(ubyte*) s2;
	foreach(i; 0 .. n) {
		if(auto diff = *b -  *b2)
			return diff;
		b++;
		b2++;
	}
	return 0;
}

extern(C) ulong strlen(scope const(char)* s) pure nothrow @nogc
{
	const(char)* a = s;
	size_t*      w;

	size_t Ones()            => (cast(size_t)-1/ubyte.max);
	size_t Highs()           => (Ones() * (ubyte.max/2+1));
	size_t HasZero(size_t x) => ((x)-Ones() & ~(x) & Highs());

	for(; cast(size_t)s % size_t.sizeof; s += 1) 
	{
		if(!*s)
		{
			return s-a;
		}
	}

	for(w = cast(size_t*)s; !HasZero(*w); w += 1) {}

	for(s = cast(char*)w; *s; s += 1) {}

	return s-a;
}
