2 The `.dup` and `.idup` properties for Associative Arrays and Dynamic Arrays
4 Copyright: Copyright Digital Mars 2000 - 2022.
5 License: Distributed under the $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0).
6 (See accompanying file LICENSE)
7 Source: $(DRUNTIMESRC core/internal/_array/_duplication.d)
9 module core.internal.array.duplication;
11 private extern (C) void[] _d_newarrayU(const scope TypeInfo ti, size_t length) pure nothrow;
13 U[] _dup(T, U)(scope T[] a) pure nothrow @trusted if (__traits(isPOD, T))
16 return _dupCtfe!(T, U)(a);
20 return _dupCtfe!(T, U)(a);
24 import core.stdc.string : memcpy;
25 auto arr = _d_newarrayU(typeid(T[]), a.length);
26 memcpy(arr.ptr, cast(const(void)*) a.ptr, T.sizeof * a.length);
27 return *cast(U[]*) &arr;
31 U[] _dupCtfe(T, U)(scope T[] a)
33 static if (is(T : void))
34 assert(0, "Cannot dup a void[] array at compile time.");
44 U[] _dup(T, U)(T[] a) if (!__traits(isPOD, T))
46 // note: copyEmplace is `@system` inside a `@trusted` block, so the __ctfe branch
47 // has the extra duty to infer _dup `@system` when the copy-constructor is `@system`.
49 return _dupCtfe!(T, U)(a);
53 return _dupCtfe!(T, U)(a);
57 import core.lifetime: copyEmplace;
58 U[] res = () @trusted {
59 auto arr = cast(U*) _d_newarrayU(typeid(T[]), a.length);
63 import core.internal.lifetime: emplaceInitializer;
64 // Initialize all remaining elements to not destruct garbage
65 foreach (j; i .. a.length)
66 emplaceInitializer(cast() arr[j]);
68 for (; i < a.length; i++)
70 copyEmplace(a.ptr[i], arr[i]);
72 return cast(U[])(arr[0..a.length]);
79 // https://issues.dlang.org/show_bug.cgi?id=22107
88 void fun(scope S[] values...) @safe
96 static struct S1 { int* p; }
97 static struct S2 { @disable this(); }
98 static struct S3 { @disable this(this); }
100 int dg1() pure nothrow @safe
115 static assert(!is(typeof(m.idup)));
116 static assert(!is(typeof(i.dup)));
121 static assert(!is(typeof(m.dup)));
122 static assert(!is(typeof(i.idup)));
127 static assert(!is(typeof(m.idup)));
130 int[] a = (inout(int)) { inout(const(int))[] a; return a.dup; }(0);
135 int dg2() pure nothrow @safe
138 S2[] m = [S2.init, S2.init];
139 immutable(S2)[] i = [S2.init, S2.init];
156 static struct Sunpure { this(this) @safe nothrow {} }
157 static struct Sthrow { this(this) @safe pure {} }
158 static struct Sunsafe { this(this) @system pure nothrow {} }
159 static struct Snocopy { @disable this(this); }
163 cast(void) [].dup!Sunsafe;
164 static assert(!__traits(compiles, () pure { [].dup!Sunpure; }));
165 static assert(!__traits(compiles, () nothrow { [].dup!Sthrow; }));
166 static assert(!__traits(compiles, () @safe { [].dup!Sunsafe; }));
167 static assert(!__traits(compiles, () { [].dup!Snocopy; }));
172 static assert(!__traits(compiles, () pure { [].idup!Sunpure; }));
173 static assert(!__traits(compiles, () nothrow { [].idup!Sthrow; }));
174 static assert(!__traits(compiles, () @safe { [].idup!Sunsafe; }));
175 static assert(!__traits(compiles, () { [].idup!Snocopy; }));
180 // test that the copy-constructor is called with .dup
181 static struct ArrElem
188 this(ref const ArrElem)
192 this(ref ArrElem) immutable
198 auto arr = [ArrElem(1), ArrElem(1)];
200 ArrElem[] b = arr.dup;
201 assert(b[0].a == 2 && b[1].a == 2);
203 immutable ArrElem[] c = arr.idup;
204 assert(c[0].a == 3 && c[1].a == 3);
209 static struct Sunpure { this(ref const typeof(this)) @safe nothrow {} }
210 static struct Sthrow { this(ref const typeof(this)) @safe pure {} }
211 static struct Sunsafe { this(ref const typeof(this)) @system pure nothrow {} }
214 cast(void) [].dup!Sunsafe;
215 static assert(!__traits(compiles, () pure { [].dup!Sunpure; }));
216 static assert(!__traits(compiles, () nothrow { [].dup!Sthrow; }));
217 static assert(!__traits(compiles, () @safe { [].dup!Sunsafe; }));
219 // for idup to work on structs that have copy constructors, it is necessary
220 // that the struct defines a copy constructor that creates immutable objects
221 static struct ISunpure { this(ref const typeof(this)) immutable @safe nothrow {} }
222 static struct ISthrow { this(ref const typeof(this)) immutable @safe pure {} }
223 static struct ISunsafe { this(ref const typeof(this)) immutable @system pure nothrow {} }
227 static assert(!__traits(compiles, () pure { [].idup!ISunpure; }));
228 static assert(!__traits(compiles, () nothrow { [].idup!ISthrow; }));
229 static assert(!__traits(compiles, () @safe { [].idup!ISunsafe; }));
234 static int*[] pureFoo() pure { return null; }
235 { char[] s; immutable x = s.dup; }
236 { immutable x = (cast(int*[])null).dup; }
237 { immutable x = pureFoo(); }
238 { immutable x = pureFoo().dup; }
245 debug(SENTINEL) {} else
246 assert(b.capacity >= 3);
253 shared(void)[] s = [cast(shared)1];
254 immutable(void)[] i = [cast(immutable)2];
257 static assert(is(typeof(s.dup) == shared(void)[]));
265 static assert(!__traits(compiles, m = s.dup));
288 // postblit and hence .dup could escape
289 this(this) { gp = p; }
293 scope S[1] arr = [S(&p)];
294 auto a = arr.dup; // dup does escape
297 // https://issues.dlang.org/show_bug.cgi?id=21983
298 // dup/idup destroys partially constructed arrays on failure
301 static struct SImpl(bool postblit)
311 throw new Exception("");
316 this(scope ref const SImpl other)
319 throw new Exception("");
321 this.num = other.num;
330 import core.stdc.stdio;
331 printf("Unexpected value: %lld\n", l);
338 alias Postblit = SImpl!true;
339 alias Copy = SImpl!false;
343 S[4] arr = [ S(1), S(2), S(3), S(4) ];
355 static assert(test!Postblit());
356 assert(test!Postblit());
358 static assert(test!Copy());