Wolfgang Thallergcc16 merge934c3885 months agoHistory
389 lines · 9.8 KB · D
RawDownload
/**The `.dup` and `.idup` properties for Associative Arrays and Dynamic Arrays Copyright: Copyright Digital Mars 2000 - 2022.License: Distributed under the $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0).    (See accompanying file LICENSE)Source: $(DRUNTIMESRC core/internal/_array/_duplication.d)*/module core.internal.array.duplication; U[] _dup(T, U)(scope T[] a) pure nothrow @trusted if (__traits(isPOD, T)){    if (__ctfe)        return _dupCtfe!(T, U)(a);     version (D_BetterC)    {        return _dupCtfe!(T, U)(a);    }    else    {        import core.stdc.string : memcpy;        import core.internal.array.construction: _d_newarrayUPureNothrow;        auto arr = _d_newarrayUPureNothrow!U(a.length, is(U == shared));        memcpy(cast(void*) arr.ptr, cast(const(void)*) a.ptr, T.sizeof * a.length);        return arr;    }} U[] _dupCtfe(T, U)(scope T[] a){    import core.internal.traits : Unqual;     static if (is(T : void))        assert(0, "Cannot dup a void[] array at compile time.");    else    {        U[] res;        static if (is(T == shared SharedPayload, SharedPayload))        {            // CTFE still needs a low-level element copy path for shared POD            // arrays because `.dup` models the runtime bitcopy before any            // synchronization policy is applied to the duplicated slice.            Unqual!U[] tmp;            foreach (i; 0 .. a.length)                // This cast is only to make the CTFE path express the same raw                // element copy that the runtime POD implementation performs                // with memcpy; it is not meant as a synchronized access pattern                // for published shared data.                tmp ~= (cast(Unqual!T[]) a)[i];            res = cast(typeof(res)) tmp;        }        else        {            foreach (ref e; a)                res ~= e;        }        return res;    }} U[] _dup(T, U)(T[] a) if (!__traits(isPOD, T)){    // note: copyEmplace is `@system` inside a `@trusted` block, so the __ctfe branch    // has the extra duty to infer _dup `@system` when the copy-constructor is `@system`.    if (__ctfe)        return _dupCtfe!(T, U)(a);     version (D_BetterC)    {        return _dupCtfe!(T, U)(a);    }    else    {        import core.lifetime: copyEmplace;        import core.internal.array.construction: _d_newarrayU;        U[] res = () @trusted {            auto arr = cast(U*) _d_newarrayU!T(a.length, is(T == shared));            size_t i;            scope (failure)            {                import core.internal.lifetime: emplaceInitializer;                // Initialize all remaining elements to not destruct garbage                foreach (j; i .. a.length)                    emplaceInitializer(cast() arr[j]);            }            for (; i < a.length; i++)            {                copyEmplace(a.ptr[i], arr[i]);            }            return cast(U[])(arr[0..a.length]);        } ();         return res;    }} // https://issues.dlang.org/show_bug.cgi?id=22107@safe unittest{    static int i;    @safe struct S    {        this(this) { i++; }    }     void fun(scope S[] values...) @safe    {        values.dup;    }} @safe unittest{    static struct S1 { int* p; }    static struct S2 { @disable this(); }    static struct S3 { @disable this(this); }     int dg1() pure nothrow @safe    {        {           char[] m;           string i;           m = m.dup;           i = i.idup;           m = i.dup;           i = m.idup;        }        {           S1[] m;           immutable(S1)[] i;           m = m.dup;           i = i.idup;           static assert(!is(typeof(m.idup)));           static assert(!is(typeof(i.dup)));        }        {            S3[] m;            immutable(S3)[] i;            static assert(!is(typeof(m.dup)));            static assert(!is(typeof(i.idup)));        }        {            shared(S1)[] m;            m = m.dup;            static assert(!is(typeof(m.idup)));        }        {            int[] a = (inout(int)) { inout(const(int))[] a; return a.dup; }(0);        }        return 1;    }     int dg2() pure nothrow @safe    {        {           S2[] m = [S2.init, S2.init];           immutable(S2)[] i = [S2.init, S2.init];           m = m.dup;           m = i.dup;           i = m.idup;           i = i.idup;        }        return 2;    }     enum a = dg1();    enum b = dg2();    assert(dg1() == a);    assert(dg2() == b);} @system unittest{    static struct Sunpure { this(this) @safe nothrow {} }    static struct Sthrow { this(this) @safe pure {} }    static struct Sunsafe { this(this) @system pure nothrow {} }    static struct Snocopy { @disable this(this); }     [].dup!Sunpure;    [].dup!Sthrow;    cast(void) [].dup!Sunsafe;    static assert(!__traits(compiles, () pure    { [].dup!Sunpure; }));    static assert(!__traits(compiles, () nothrow { [].dup!Sthrow; }));    static assert(!__traits(compiles, () @safe   { [].dup!Sunsafe; }));    static assert(!__traits(compiles, ()         { [].dup!Snocopy; }));     [].idup!Sunpure;    [].idup!Sthrow;    [].idup!Sunsafe;    static assert(!__traits(compiles, () pure    { [].idup!Sunpure; }));    static assert(!__traits(compiles, () nothrow { [].idup!Sthrow; }));    static assert(!__traits(compiles, () @safe   { [].idup!Sunsafe; }));    static assert(!__traits(compiles, ()         { [].idup!Snocopy; }));} @safe unittest{    // test that the copy-constructor is called with .dup    static struct ArrElem    {        int a;        this(int a)        {            this.a = a;        }        this(ref const ArrElem)        {            a = 2;        }        this(ref ArrElem) immutable        {            a = 3;        }    }     auto arr = [ArrElem(1), ArrElem(1)];     ArrElem[] b = arr.dup;    assert(b[0].a == 2 && b[1].a == 2);     immutable ArrElem[] c = arr.idup;    assert(c[0].a == 3 && c[1].a == 3);} @system unittest{    static struct Sunpure { this(ref const typeof(this)) @safe nothrow {} }    static struct Sthrow { this(ref const typeof(this)) @safe pure {} }    static struct Sunsafe { this(ref const typeof(this)) @system pure nothrow {} }    [].dup!Sunpure;    [].dup!Sthrow;    cast(void) [].dup!Sunsafe;    static assert(!__traits(compiles, () pure    { [].dup!Sunpure; }));    static assert(!__traits(compiles, () nothrow { [].dup!Sthrow; }));    static assert(!__traits(compiles, () @safe   { [].dup!Sunsafe; }));     // for idup to work on structs that have copy constructors, it is necessary    // that the struct defines a copy constructor that creates immutable objects    static struct ISunpure { this(ref const typeof(this)) immutable @safe nothrow {} }    static struct ISthrow { this(ref const typeof(this)) immutable @safe pure {} }    static struct ISunsafe { this(ref const typeof(this)) immutable @system pure nothrow {} }    [].idup!ISunpure;    [].idup!ISthrow;    [].idup!ISunsafe;    static assert(!__traits(compiles, () pure    { [].idup!ISunpure; }));    static assert(!__traits(compiles, () nothrow { [].idup!ISthrow; }));    static assert(!__traits(compiles, () @safe   { [].idup!ISunsafe; }));} @safe unittest{    static int*[] pureFoo() pure { return null; }    { char[] s; immutable x = s.dup; }    { immutable x = (cast(int*[])null).dup; }    { immutable x = pureFoo(); }    { immutable x = pureFoo().dup; }} @safe unittest{    auto a = [1, 2, 3];    auto b = a.dup;    debug(SENTINEL) {} else        assert(b.capacity >= 3);} @system unittest{    // Bugzilla 12580    void[] m = [0];    shared(void)[] s = [cast(shared)1];    immutable(void)[] i = [cast(immutable)2];     s = s.dup;    static assert(is(typeof(s.dup) == shared(void)[]));     m = i.dup;    i = m.dup;    i = i.idup;    i = m.idup;    i = s.idup;    i = s.dup;    static assert(!__traits(compiles, m = s.dup));} @safe unittest{    // Bugzilla 13809    static struct S    {        this(this) {}        ~this() {}    }     S[] arr;    auto a = arr.dup;} @system unittest{    // Bugzilla 16504    static struct S    {        __gshared int* gp;        int* p;        // postblit and hence .dup could escape        this(this) { gp = p; }    }     int p;    scope S[1] arr = [S(&p)];    auto a = arr.dup; // dup does escape} // https://issues.dlang.org/show_bug.cgi?id=21983// dup/idup destroys partially constructed arrays on failure@safe unittest{    static struct SImpl(bool postblit)    {        int num;        long l = 0xDEADBEEF;         static if (postblit)        {            this(this)            {                if (this.num == 3)                    throw new Exception("");            }        }        else        {            this(scope ref const SImpl other)            {                if (other.num == 3)                    throw new Exception("");                 this.num = other.num;                this.l = other.l;            }        }         ~this() @trusted        {            if (l != 0xDEADBEEF)            {                import core.stdc.stdio : fflush, printf;                printf("Unexpected value: %lld\n", l);                fflush(null);                assert(false);            }        }    }     alias Postblit = SImpl!true;    alias Copy = SImpl!false;     static int test(S)()    {        S[4] arr = [ S(1), S(2), S(3), S(4) ];        try        {            arr.dup();            assert(false);        }        catch (Exception)        {            return 1;        }    }     static assert(test!Postblit());    assert(test!Postblit());     static assert(test!Copy());    assert(test!Copy());} // https://issues.dlang.org/show_bug.cgi?id=24453@safe unittest{    static inout(char)[] foo(return ref scope inout(char)[] s)    {        auto bla = s.idup;        return s;    }}

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