d: Merge upstream dmd, druntime b65767825f, phobos 92dc5a4e9.
[official-gcc.git] / libphobos / libdruntime / core / internal / array / duplication.d
blob9df84893bb9e0a08b738846f7cc8d9b7aba5a98e
1 /**
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)
8 */
9 module core.internal.array.duplication;
11 U[] _dup(T, U)(scope T[] a) pure nothrow @trusted if (__traits(isPOD, T))
13 if (__ctfe)
14 return _dupCtfe!(T, U)(a);
16 version (D_BetterC)
18 return _dupCtfe!(T, U)(a);
20 else
22 import core.stdc.string : memcpy;
23 import core.internal.array.construction: _d_newarrayUPureNothrow;
24 auto arr = _d_newarrayUPureNothrow!U(a.length, is(U == shared));
25 memcpy(cast(void*) arr.ptr, cast(const(void)*) a.ptr, T.sizeof * a.length);
26 return arr;
30 U[] _dupCtfe(T, U)(scope T[] a)
32 static if (is(T : void))
33 assert(0, "Cannot dup a void[] array at compile time.");
34 else
36 U[] res;
37 foreach (ref e; a)
38 res ~= e;
39 return res;
43 U[] _dup(T, U)(T[] a) if (!__traits(isPOD, T))
45 // note: copyEmplace is `@system` inside a `@trusted` block, so the __ctfe branch
46 // has the extra duty to infer _dup `@system` when the copy-constructor is `@system`.
47 if (__ctfe)
48 return _dupCtfe!(T, U)(a);
50 version (D_BetterC)
52 return _dupCtfe!(T, U)(a);
54 else
56 import core.lifetime: copyEmplace;
57 import core.internal.array.construction: _d_newarrayU;
58 U[] res = () @trusted {
59 auto arr = cast(U*) _d_newarrayU!T(a.length, is(T == shared));
60 size_t i;
61 scope (failure)
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]);
73 } ();
75 return res;
79 // https://issues.dlang.org/show_bug.cgi?id=22107
80 @safe unittest
82 static int i;
83 @safe struct S
85 this(this) { i++; }
88 void fun(scope S[] values...) @safe
90 values.dup;
94 @safe unittest
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
103 char[] m;
104 string i;
105 m = m.dup;
106 i = i.idup;
107 m = i.dup;
108 i = m.idup;
111 S1[] m;
112 immutable(S1)[] i;
113 m = m.dup;
114 i = i.idup;
115 static assert(!is(typeof(m.idup)));
116 static assert(!is(typeof(i.dup)));
119 S3[] m;
120 immutable(S3)[] i;
121 static assert(!is(typeof(m.dup)));
122 static assert(!is(typeof(i.idup)));
125 shared(S1)[] m;
126 m = m.dup;
127 static assert(!is(typeof(m.idup)));
130 int[] a = (inout(int)) { inout(const(int))[] a; return a.dup; }(0);
132 return 1;
135 int dg2() pure nothrow @safe
138 S2[] m = [S2.init, S2.init];
139 immutable(S2)[] i = [S2.init, S2.init];
140 m = m.dup;
141 m = i.dup;
142 i = m.idup;
143 i = i.idup;
145 return 2;
148 enum a = dg1();
149 enum b = dg2();
150 assert(dg1() == a);
151 assert(dg2() == b);
154 @system unittest
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); }
161 [].dup!Sunpure;
162 [].dup!Sthrow;
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; }));
169 [].idup!Sunpure;
170 [].idup!Sthrow;
171 [].idup!Sunsafe;
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; }));
178 @safe unittest
180 // test that the copy-constructor is called with .dup
181 static struct ArrElem
183 int a;
184 this(int a)
186 this.a = a;
188 this(ref const ArrElem)
190 a = 2;
192 this(ref ArrElem) immutable
194 a = 3;
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);
207 @system unittest
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 {} }
212 [].dup!Sunpure;
213 [].dup!Sthrow;
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 {} }
224 [].idup!ISunpure;
225 [].idup!ISthrow;
226 [].idup!ISunsafe;
227 static assert(!__traits(compiles, () pure { [].idup!ISunpure; }));
228 static assert(!__traits(compiles, () nothrow { [].idup!ISthrow; }));
229 static assert(!__traits(compiles, () @safe { [].idup!ISunsafe; }));
232 @safe unittest
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; }
241 @safe unittest
243 auto a = [1, 2, 3];
244 auto b = a.dup;
245 debug(SENTINEL) {} else
246 assert(b.capacity >= 3);
249 @system unittest
251 // Bugzilla 12580
252 void[] m = [0];
253 shared(void)[] s = [cast(shared)1];
254 immutable(void)[] i = [cast(immutable)2];
256 s = s.dup;
257 static assert(is(typeof(s.dup) == shared(void)[]));
259 m = i.dup;
260 i = m.dup;
261 i = i.idup;
262 i = m.idup;
263 i = s.idup;
264 i = s.dup;
265 static assert(!__traits(compiles, m = s.dup));
268 @safe unittest
270 // Bugzilla 13809
271 static struct S
273 this(this) {}
274 ~this() {}
277 S[] arr;
278 auto a = arr.dup;
281 @system unittest
283 // Bugzilla 16504
284 static struct S
286 __gshared int* gp;
287 int* p;
288 // postblit and hence .dup could escape
289 this(this) { gp = p; }
292 int 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
299 @safe unittest
301 static struct SImpl(bool postblit)
303 int num;
304 long l = 0xDEADBEEF;
306 static if (postblit)
308 this(this)
310 if (this.num == 3)
311 throw new Exception("");
314 else
316 this(scope ref const SImpl other)
318 if (other.num == 3)
319 throw new Exception("");
321 this.num = other.num;
322 this.l = other.l;
326 ~this() @trusted
328 if (l != 0xDEADBEEF)
330 import core.stdc.stdio;
331 printf("Unexpected value: %lld\n", l);
332 fflush(stdout);
333 assert(false);
338 alias Postblit = SImpl!true;
339 alias Copy = SImpl!false;
341 static int test(S)()
343 S[4] arr = [ S(1), S(2), S(3), S(4) ];
346 arr.dup();
347 assert(false);
349 catch (Exception)
351 return 1;
355 static assert(test!Postblit());
356 assert(test!Postblit());
358 static assert(test!Copy());
359 assert(test!Copy());
362 // https://issues.dlang.org/show_bug.cgi?id=24453
363 @safe unittest
365 static inout(char)[] foo(ref scope return inout(char)[] s)
367 auto bla = s.idup;
368 return s;