]> git.ipfire.org Git - people/ms/gcc.git/blob - libphobos/libdruntime/core/internal/array/duplication.d
d: Merge upstream dmd, druntime 4ca4140e58, phobos 454dff14d.
[people/ms/gcc.git] / libphobos / libdruntime / core / internal / array / duplication.d
1 /**
2 The `.dup` and `.idup` properties for Associative Arrays and Dynamic Arrays
3
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;
10
11 private extern (C) void[] _d_newarrayU(const scope TypeInfo ti, size_t length) pure nothrow;
12
13 U[] _dup(T, U)(scope T[] a) pure nothrow @trusted if (__traits(isPOD, T))
14 {
15 if (__ctfe)
16 return _dupCtfe!(T, U)(a);
17
18 version (D_BetterC)
19 {
20 return _dupCtfe!(T, U)(a);
21 }
22 else
23 {
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;
28 }
29 }
30
31 U[] _dupCtfe(T, U)(scope T[] a)
32 {
33 static if (is(T : void))
34 assert(0, "Cannot dup a void[] array at compile time.");
35 else
36 {
37 U[] res;
38 foreach (ref e; a)
39 res ~= e;
40 return res;
41 }
42 }
43
44 U[] _dup(T, U)(T[] a) if (!__traits(isPOD, T))
45 {
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`.
48 if (__ctfe)
49 return _dupCtfe!(T, U)(a);
50
51 version (D_BetterC)
52 {
53 return _dupCtfe!(T, U)(a);
54 }
55 else
56 {
57 import core.lifetime: copyEmplace;
58 U[] res = () @trusted {
59 auto arr = cast(U*) _d_newarrayU(typeid(T[]), a.length);
60 size_t i;
61 scope (failure)
62 {
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]);
67 }
68 for (; i < a.length; i++)
69 {
70 copyEmplace(a.ptr[i], arr[i]);
71 }
72 return cast(U[])(arr[0..a.length]);
73 } ();
74
75 return res;
76 }
77 }
78
79 // https://issues.dlang.org/show_bug.cgi?id=22107
80 @safe unittest
81 {
82 static int i;
83 @safe struct S
84 {
85 this(this) { i++; }
86 }
87
88 void fun(scope S[] values...) @safe
89 {
90 values.dup;
91 }
92 }
93
94 @safe unittest
95 {
96 static struct S1 { int* p; }
97 static struct S2 { @disable this(); }
98 static struct S3 { @disable this(this); }
99
100 int dg1() pure nothrow @safe
101 {
102 {
103 char[] m;
104 string i;
105 m = m.dup;
106 i = i.idup;
107 m = i.dup;
108 i = m.idup;
109 }
110 {
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)));
117 }
118 {
119 S3[] m;
120 immutable(S3)[] i;
121 static assert(!is(typeof(m.dup)));
122 static assert(!is(typeof(i.idup)));
123 }
124 {
125 shared(S1)[] m;
126 m = m.dup;
127 static assert(!is(typeof(m.idup)));
128 }
129 {
130 int[] a = (inout(int)) { inout(const(int))[] a; return a.dup; }(0);
131 }
132 return 1;
133 }
134
135 int dg2() pure nothrow @safe
136 {
137 {
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;
144 }
145 return 2;
146 }
147
148 enum a = dg1();
149 enum b = dg2();
150 assert(dg1() == a);
151 assert(dg2() == b);
152 }
153
154 @system unittest
155 {
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); }
160
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; }));
168
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; }));
176 }
177
178 @safe unittest
179 {
180 // test that the copy-constructor is called with .dup
181 static struct ArrElem
182 {
183 int a;
184 this(int a)
185 {
186 this.a = a;
187 }
188 this(ref const ArrElem)
189 {
190 a = 2;
191 }
192 this(ref ArrElem) immutable
193 {
194 a = 3;
195 }
196 }
197
198 auto arr = [ArrElem(1), ArrElem(1)];
199
200 ArrElem[] b = arr.dup;
201 assert(b[0].a == 2 && b[1].a == 2);
202
203 immutable ArrElem[] c = arr.idup;
204 assert(c[0].a == 3 && c[1].a == 3);
205 }
206
207 @system unittest
208 {
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; }));
218
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; }));
230 }
231
232 @safe unittest
233 {
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; }
239 }
240
241 @safe unittest
242 {
243 auto a = [1, 2, 3];
244 auto b = a.dup;
245 debug(SENTINEL) {} else
246 assert(b.capacity >= 3);
247 }
248
249 @system unittest
250 {
251 // Bugzilla 12580
252 void[] m = [0];
253 shared(void)[] s = [cast(shared)1];
254 immutable(void)[] i = [cast(immutable)2];
255
256 s = s.dup;
257 static assert(is(typeof(s.dup) == shared(void)[]));
258
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));
266 }
267
268 @safe unittest
269 {
270 // Bugzilla 13809
271 static struct S
272 {
273 this(this) {}
274 ~this() {}
275 }
276
277 S[] arr;
278 auto a = arr.dup;
279 }
280
281 @system unittest
282 {
283 // Bugzilla 16504
284 static struct S
285 {
286 __gshared int* gp;
287 int* p;
288 // postblit and hence .dup could escape
289 this(this) { gp = p; }
290 }
291
292 int p;
293 scope S[1] arr = [S(&p)];
294 auto a = arr.dup; // dup does escape
295 }
296
297 // https://issues.dlang.org/show_bug.cgi?id=21983
298 // dup/idup destroys partially constructed arrays on failure
299 @safe unittest
300 {
301 static struct SImpl(bool postblit)
302 {
303 int num;
304 long l = 0xDEADBEEF;
305
306 static if (postblit)
307 {
308 this(this)
309 {
310 if (this.num == 3)
311 throw new Exception("");
312 }
313 }
314 else
315 {
316 this(scope ref const SImpl other)
317 {
318 if (other.num == 3)
319 throw new Exception("");
320
321 this.num = other.num;
322 this.l = other.l;
323 }
324 }
325
326 ~this() @trusted
327 {
328 if (l != 0xDEADBEEF)
329 {
330 import core.stdc.stdio;
331 printf("Unexpected value: %lld\n", l);
332 fflush(stdout);
333 assert(false);
334 }
335 }
336 }
337
338 alias Postblit = SImpl!true;
339 alias Copy = SImpl!false;
340
341 static int test(S)()
342 {
343 S[4] arr = [ S(1), S(2), S(3), S(4) ];
344 try
345 {
346 arr.dup();
347 assert(false);
348 }
349 catch (Exception)
350 {
351 return 1;
352 }
353 }
354
355 static assert(test!Postblit());
356 assert(test!Postblit());
357
358 static assert(test!Copy());
359 assert(test!Copy());
360 }