Best interface for memcpy() (and the string.h family of functions)
Jonathan Marler
johnnymarler at gmail.com
Wed May 29 15:41:42 UTC 2019
On Wednesday, 29 May 2019 at 11:46:28 UTC, Stefanos Baziotis
wrote:
> I'm a GSoC student (I'll post this week an update) in
> the project "Independency of D from the C Standard Library".
> Part of this project is a D implementation of the family of
> functions
> memcpy(), memset() etc.
>
> What do you think is the best interface for say memcpy()?
>
> My initial pick was void memcpyD(T)(T* dst, const T* src), but
> it was proposed
> that `ref` instead of pointers might be better.
>
> Thanks,
> Stefanos
The default memcpy signature is still pretty useful in many
cases. The original signature should still be implemented and
available as a non-template function:
void memcpy(void* dst, void* src, size_t length);
For D, you should also create a template so developer's don't
have to cast to `void*` all the time, but it just forwards all
calls to the real memcpy function like this:
void memcpy(T,U)(T* dst, U* src, size_t length)
{
pragma(inline, true);
memcpy(cast(void*)dst, cast(void*)src, length);
}
And there's no need to have a different name like `memcpyD`. The
function behaves the same as libc's memcpy, and when you have
libc available, you should use that implementation instead so you
can leverages other people's work when you can.
However, we also want to get type-safety and bounds-checking when
when can. So we should also provide a set of templates that
accept D arrays, verifies type-safety and bounds checking, then
forwards the call to memcpy.
/**
acopy - Array Copy
*/
void acopy(T,U)(T dst, U src) @trusted
if (isArrayLike!T && isArrayLike!U && dst[0].sizeof ==
src[0].sizeof)
in { assert(dst.length >= src.length, "copyFrom source length
larger than destination"); } do
{
pragma(inline, true);
static assert (!__traits(isStaticArray, T), "acopy doest not
accept static arrays since they are passed by value");
import whereever_memcpy_is: memcpy;
memcpy(dst.ptr, src.ptr, src.length * ElementSizeForCopy!dst);
}
/// ditto
void acopy(T,U)(T dst, U src) @system
if (isArrayLike!T && isPointerLike!U && dst[0].sizeof ==
src[0].sizeof)
{
pragma(inline, true);
static assert (!__traits(isStaticArray, T), "acopy doest not
accept static arrays since they are passed by value");
import whereever_memcpy_is: memcpy;
memcpy(dst.ptr, src, dst.length * ElementSizeForCopy!dst);
}
/// ditto
void acopy(T,U)(T dst, U src) @system
if (isPointerLike!T && isArrayLike!U && dst[0].sizeof ==
src[0].sizeof)
{
pragma(inline, true);
import whereever_memcpy_is: memcpy;
memcpy(dst, src.ptr, src.length * ElementSizeForCopy!dst);
}
/// ditto
void acopy(T,U)(T dst, U src, size_t size) @system
if (isPointerLike!T && isPointerLike!U && dst[0].sizeof ==
src[0].sizeof)
{
pragma(inline, true);
import whereever_memcpy_is: memcpy;
memcpy(dst, src, size * ElementSizeForCopy!dst);
}
Note that the isArrayLike and isPointerLike and
ElementSizeForCopy would probably look something like:
template isArrayLike(T)
{
enum isArrayLike =
is(typeof(T.init.length))
&& is(typeof(T.init.ptr))
&& is(typeof(T.init[0]));
}
template isPointerLike(T)
{
enum isPointerLike =
T.sizeof == (void*).sizeof
&& is(typeof(T.init[0]));
}
// The size of each array element. If the actual size is 0, then
it
// is assumed to be 1.
template ElementSizeForCopy(alias Array)
{
static if (Array[0].sizeof == 0)
enum ElementSizeForCopy = 1;
else
enum ElementSizeForCopy = Array[0].sizeof;
}
Note that everything here is an inline-template, so everything
gets reduced to a single memcpy call and some bounds checks.
More information about the Digitalmars-d
mailing list