-
-
Notifications
You must be signed in to change notification settings - Fork 709
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix Issue 18239: fillWithMemcpy use memset when T.sizeof == 1 #6034
Conversation
Thanks for your pull request, @n8sh! We are looking forward to reviewing it, and you should be hearing from a maintainer soon. Some tips to help speed things up:
Bear in mind that large or tricky changes may require multiple rounds of review and revision. Please see CONTRIBUTING.md for more information. Bugzilla references
|
import core.stdc.string : memset; | ||
import std.traits : CopyConstness; | ||
if (!array.length) return; | ||
memset(array.ptr, *cast(CopyConstness!(T*, ubyte*)) &filler, array.length); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not cast(int) filler
as the API expects?
pure nothrow @nogc @system void* memset(return void* s, int c, size_t n);
https://dlang.org/phobos/core_stdc_string.html#.memset
For other reviewers are wondering too why int
is required by the C header:
The value is passed as an int, but the function fills the block of memory using the unsigned char conversion of this value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not
cast(int) filler
My rationale is that it's possible for to T override opCast so cast(int) filler
could return something whose low byte is not bitwise identical to T.init.
EDIT: And it might also not be legal to cast to int at all, e.g.
https://run.dlang.io/is/r1jeI2.
import std.stdio;
struct S
{
char c;
}
void main()
{
static assert(S.sizeof == 1);
// This will fail to compile.
writeln(cast(int) S.init);
}
as the API expects
ubyte will be promoted to int
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about using a union to make the intent clearer, instead of that line noise complicated cast?
union U { T t; ubyte asByte; }
U u;
u.t = filler;
memset(array.ptr, u.filler, array.length);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
u.t = filler;
I need to avoid opAssign
in order for this function to always have the same behavior as the existing fillWithMemcpy
which never calls opAssign
. I could do:
union U { Unqual!T t; ubyte asByte; }
U u = void;
memcpy(&u.t, &filler, 1);
memset(array.ptr, u.asByte, array.length);
if you think that would be clearer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm. If you wish to avoid opAssign, I suppose there's really no other way than to dereference a pointer cast to ubyte
. Fair enough.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot!
Current function in std.experimental.allocator.package:
When T.sizeof==1 we could use memset instead.