Skip to content
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

Merged
merged 1 commit into from
Jan 17, 2018

Conversation

n8sh
Copy link
Member

@n8sh n8sh commented Jan 15, 2018

Current function in std.experimental.allocator.package:

private void fillWithMemcpy(T)(void[] array, auto ref T filler) nothrow
{
    import core.stdc.string : memcpy;
    import std.algorithm.comparison : min;
    if (!array.length) return;
    memcpy(array.ptr, &filler, T.sizeof);
    // Fill the array from the initialized portion of itself exponentially.
    for (size_t offset = T.sizeof; offset < array.length; )
    {
        size_t extent = min(offset, array.length - offset);
        memcpy(array.ptr + offset, array.ptr, extent);
        offset += extent;
    }
}

When T.sizeof==1 we could use memset instead.

@dlang-bot
Copy link
Contributor

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:

  • smaller, focused PRs are easier to review than big ones

  • try not to mix up refactoring or style changes with bug fixes or feature enhancements

  • provide helpful commit messages explaining the rationale behind each change

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

Auto-close Bugzilla Description
18239 std.experimental.allocator fillWithMemcpy could use memset when T.sizeof==1

import core.stdc.string : memset;
import std.traits : CopyConstness;
if (!array.length) return;
memset(array.ptr, *cast(CopyConstness!(T*, ubyte*)) &filler, array.length);
Copy link
Member

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.

http://www.cplusplus.com/reference/cstring/memset/

Copy link
Member Author

@n8sh n8sh Jan 16, 2018

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

Copy link
Member

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);

Copy link
Member Author

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.

Copy link
Member

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.

Copy link
Member

@quickfur quickfur left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Member

@wilzbach wilzbach left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot!

@wilzbach wilzbach merged commit f760414 into dlang:master Jan 17, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants