Wolfgang Thallergcc 15.1.0ada185d1 year agoHistory
466 lines · 9.7 KB · D
RawDownload
module core.internal.array.arrayassign; // Force `enforceRawArraysConformable` to remain `pure` `@nogc`private void enforceRawArraysConformable(const char[] action, const size_t elementSize,    const void[] a1, const void[] a2, const bool allowOverlap) @trusted @nogc pure nothrow{    import core.internal.util.array : enforceRawArraysConformable;     alias Type = void function(const char[] action, const size_t elementSize,        const void[] a1, const void[] a2, in bool allowOverlap = false) @nogc pure nothrow;    (cast(Type)&enforceRawArraysConformable)(action, elementSize, a1, a2, allowOverlap);} private template CopyElem(string CopyAction){    const char[] CopyElem = "{\n" ~ q{            memcpy(&tmp, cast(void*) &dst, elemSize);            } ~ CopyAction ~ q{            auto elem = cast(Unqual!T*) &tmp;            destroy(*elem);        } ~ "}\n";} private template CopyArray(bool CanOverlap, string CopyAction){    const char[] CopyArray = CanOverlap ? q{        if (vFrom.ptr < vTo.ptr && vTo.ptr < vFrom.ptr + elemSize * vFrom.length)            foreach_reverse (i, ref dst; to)            } ~ CopyElem!(CopyAction) ~ q{        else            foreach (i, ref dst; to)            } ~ CopyElem!(CopyAction)        : q{            foreach (i, ref dst; to)            } ~ CopyElem!(CopyAction);} private template ArrayAssign(string CopyLogic, string AllowOverLap){    const char[] ArrayAssign = q{        import core.internal.traits : hasElaborateCopyConstructor, Unqual;        import core.lifetime : copyEmplace;        import core.stdc.string : memcpy;         void[] vFrom = (cast(void*) from.ptr)[0 .. from.length];        void[] vTo = (cast(void*) to.ptr)[0 .. to.length];        enum elemSize = T.sizeof;         enforceRawArraysConformable("copy", elemSize, vFrom, vTo, } ~ AllowOverLap ~ q{);         void[elemSize] tmp = void;         } ~ CopyLogic ~ q{         return to;    };} /** * Does array assignment (not construction) from another array of the same * element type. Handles overlapping copies. Assumes the right hand side is an * lvalue, * * Used for static array assignment with non-POD element types: * --- * struct S * { *     ~this() {} // destructor, so not Plain Old Data * } * * void main() * { *   S[3] arr; *   S[3] lvalue; * *   arr = lvalue; *   // Generates: *   // _d_arrayassign_l(arr[], lvalue[]), arr; * } * --- * * Params: *     to = destination array *     from = source array * Returns: *     `to` */Tarr _d_arrayassign_l(Tarr : T[], T)(return scope Tarr to, scope Tarr from) @trusted{    mixin(ArrayAssign!(q{        static if (hasElaborateCopyConstructor!T)            } ~ CopyArray!(true, "copyEmplace(from[i], dst);") ~ q{        else            } ~ CopyArray!(true, "memcpy(cast(void*) &dst, cast(void*) &from[i], elemSize);"),        "true"));} @safe unittest{    int counter;    struct S    {        int val;        this(int val) { this.val = val; }        this(const scope ref S rhs)        {            val = rhs.val;            counter++;        }    }     S[4] arr1;    S[4] arr2 = [S(0), S(1), S(2), S(3)];    _d_arrayassign_l(arr1[], arr2[]);     assert(counter == 4);    assert(arr1 == arr2);} // copy constructor@safe unittest{    int counter;    struct S    {        int val;        this(int val) { this.val = val; }        this(const scope ref S rhs)        {            val = rhs.val;            counter++;        }    }     S[4] arr1;    S[4] arr2 = [S(0), S(1), S(2), S(3)];    _d_arrayassign_l(arr1[], arr2[]);     assert(counter == 4);    assert(arr1 == arr2);} @safe nothrow unittest{    // Test that throwing works    int counter;    bool didThrow;     struct Throw    {        int val;        this(this)        {            counter++;            if (counter == 2)                throw new Exception("");        }    }    try    {        Throw[4] a;        Throw[4] b = [Throw(1), Throw(2), Throw(3), Throw(4)];        _d_arrayassign_l(a[], b[]);    }    catch (Exception)    {        didThrow = true;    }    assert(didThrow);    assert(counter == 2);      // Test that `nothrow` works    didThrow = false;    counter = 0;    struct NoThrow    {        int val;        this(this)        {            counter++;        }    }    try    {        NoThrow[4] a;        NoThrow[4] b = [NoThrow(1), NoThrow(2), NoThrow(3), NoThrow(4)];        _d_arrayassign_l(a[], b[]);    }    catch (Exception)    {        didThrow = false;    }    assert(!didThrow);    assert(counter == 4);} /** * Does array assignment (not construction) from another array of the same * element type. Does not support overlapping copies. Assumes the right hand * side is an rvalue, * * Used for static array assignment with non-POD element types: * --- * struct S * { *     ~this() {} // destructor, so not Plain Old Data * } * * void main() * { *   S[3] arr; *   S[3] getRvalue() {return lvalue;} * *   arr = getRvalue(); *   // Generates: *   // (__appendtmp = getRvalue), _d_arrayassign_l(arr[], __appendtmp), arr; * } * --- * * Params: *     to = destination array *     from = source array * Returns: *     `to` */Tarr _d_arrayassign_r(Tarr : T[], T)(return scope Tarr to, scope Tarr from) @trusted{    mixin(ArrayAssign!(        CopyArray!(false, "memcpy(cast(void*) &dst, cast(void*) &from[i], elemSize);"),        "false"));} @safe unittest{    int counter;    struct S    {        int val;        this(int val) { this.val = val; }        this(const scope ref S rhs)        {            val = rhs.val;            counter++;        }    }     S[4] arr1;    S[4] arr2 = [S(0), S(1), S(2), S(3)];    _d_arrayassign_r(arr1[], arr2[]);     assert(counter == 0);    assert(arr1 == arr2);} // copy constructor@safe unittest{    int counter;    struct S    {        int val;        this(int val) { this.val = val; }        this(const scope ref S rhs)        {            val = rhs.val;            counter++;        }    }     S[4] arr1;    S[4] arr2 = [S(0), S(1), S(2), S(3)];    _d_arrayassign_r(arr1[], arr2[]);     assert(counter == 0);    assert(arr1 == arr2);} @safe nothrow unittest{    // Test that `nothrow` works    bool didThrow = false;    int counter = 0;    struct NoThrow    {        int val;        this(this)        {            counter++;        }    }    try    {        NoThrow[4] a;        NoThrow[4] b = [NoThrow(1), NoThrow(2), NoThrow(3), NoThrow(4)];        _d_arrayassign_r(a[], b[]);    }    catch (Exception)    {        didThrow = false;    }    assert(!didThrow);    assert(counter == 0);} /** * Sets all elements of an array to a single value. Takes into account postblits, * copy constructors and destructors. For Plain Old Data elements,`rt/memset.d` * is used. * * --- * struct S * { *     ~this() {} // destructor, so not Plain Old Data * } * * void main() * { *   S[3] arr; *   S value; * *   arr = value; *   // Generates: *   // _d_arraysetassign(arr[], value), arr; * } * --- * * Params: *     to = destination array *     value = the element to set * Returns: *     `to` */Tarr _d_arraysetassign(Tarr : T[], T)(return scope Tarr to, scope ref T value) @trusted{    import core.internal.traits : Unqual;    import core.lifetime : copyEmplace;    import core.stdc.string : memcpy;     enum elemSize = T.sizeof;    void[elemSize] tmp = void;     foreach (ref dst; to)    {        memcpy(&tmp, cast(void*) &dst, elemSize);        // Use `memcpy` if `T` has a `@disable`d postblit.        static if (__traits(isCopyable, T))            copyEmplace(value, dst);        else            memcpy(cast(void*) &dst, cast(void*) &value, elemSize);        auto elem = cast(Unqual!T*) &tmp;        destroy(*elem);    }     return to;} // postblit and destructor@safe unittest{    string ops;    struct S    {        int val;        this(this) { ops ~= "="; }        ~this() { ops ~= "~"; }    }     S[4] arr;    S s = S(1234);    _d_arraysetassign(arr[], s);    assert(ops == "=~=~=~=~");    assert(arr == [S(1234), S(1234), S(1234), S(1234)]);} // copy constructor@safe unittest{    string ops;    struct S    {        int val;        this(const scope ref S rhs)        {            val = rhs.val;            ops ~= "=";        }        ~this() { ops ~= "~"; }    }     S[4] arr;    S s = S(1234);    _d_arraysetassign(arr[], s);    assert(ops == "=~=~=~=~");    assert(arr == [S(1234), S(1234), S(1234), S(1234)]);} // disabled copy constructor@safe unittest{    static struct S    {        int val;        @disable this(ref S);    }    S[1] arr;    S s = S(1234);    _d_arraysetassign(arr[], s);    assert(arr[0].val == 1234);} // throwing and `nothrow`@safe nothrow unittest{    // Test that throwing works    bool didThrow;    int counter;    struct Throw    {        int val;        this(this)        {            counter++;            if (counter == 2)                throw new Exception("Oh no.");        }    }     try    {        Throw[4] a;        Throw b = Throw(1);        _d_arraysetassign(a[], b);    }    catch (Exception)    {        didThrow = true;    }    assert(didThrow);    assert(counter == 2);     // Test that `nothrow` works    didThrow = false;    counter = 0;    struct NoThrow    {        int val;        this(this) { counter++; }    }     try    {        NoThrow[4] a;        NoThrow b = NoThrow(1);        _d_arraysetassign(a[], b);        foreach (ref e; a)            assert(e == NoThrow(1));    }    catch (Exception)    {        didThrow = true;    }    assert(!didThrow);    // The array `a` is destroyed when the `try` block ends.    assert(counter == 4);}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t