d: Merge upstream dmd, druntime 4ca4140e58, phobos 454dff14d.
[official-gcc.git] / libphobos / libdruntime / core / internal / array / appending.d
blobb609167eefe2f02122daef1a2c08f888fd7272de
1 /**
2 This module contains support for controlling dynamic arrays' appending
4 Copyright: Copyright Digital Mars 2000 - 2019.
5 License: Distributed under the
6 $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0).
7 (See accompanying file LICENSE)
8 Source: $(DRUNTIMESRC core/_internal/_array/_appending.d)
9 */
10 module core.internal.array.appending;
12 /// See $(REF _d_arrayappendcTX, rt,lifetime,_d_arrayappendcTX)
13 private extern (C) byte[] _d_arrayappendcTX(const TypeInfo ti, ref return scope byte[] px, size_t n) @trusted pure nothrow;
15 private enum isCopyingNothrow(T) = __traits(compiles, (ref T rhs) nothrow { T lhs = rhs; });
17 /// Implementation of `_d_arrayappendcTX` and `_d_arrayappendcTXTrace`
18 template _d_arrayappendcTXImpl(Tarr : T[], T)
20 private enum errorMessage = "Cannot append to array if compiling without support for runtime type information!";
22 /**
23 * Extend an array `px` by `n` elements.
24 * Caller must initialize those elements.
25 * Params:
26 * px = the array that will be extended, taken as a reference
27 * n = how many new elements to extend it with
28 * Returns:
29 * The new value of `px`
30 * Bugs:
31 * This function template was ported from a much older runtime hook that bypassed safety,
32 * purity, and throwabilty checks. To prevent breaking existing code, this function template
33 * is temporarily declared `@trusted pure` until the implementation can be brought up to modern D expectations.
35 ref Tarr _d_arrayappendcTX(return ref scope Tarr px, size_t n) @trusted pure nothrow
37 // needed for CTFE: https://github.com/dlang/druntime/pull/3870#issuecomment-1178800718
38 pragma(inline, false);
39 version (D_TypeInfo)
41 auto ti = typeid(Tarr);
43 // _d_arrayappendcTX takes the `px` as a ref byte[], but its length
44 // should still be the original length
45 auto pxx = (cast(byte*)px.ptr)[0 .. px.length];
46 ._d_arrayappendcTX(ti, pxx, n);
47 px = (cast(T*)pxx.ptr)[0 .. pxx.length];
49 return px;
51 else
52 assert(0, errorMessage);
55 version (D_ProfileGC)
57 import core.internal.array.utils : _d_HookTraceImpl;
59 /**
60 * TraceGC wrapper around $(REF _d_arrayappendcTX, rt,array,appending,_d_arrayappendcTXImpl).
61 * Bugs:
62 * This function template was ported from a much older runtime hook that bypassed safety,
63 * purity, and throwabilty checks. To prevent breaking existing code, this function template
64 * is temporarily declared `@trusted pure` until the implementation can be brought up to modern D expectations.
66 alias _d_arrayappendcTXTrace = _d_HookTraceImpl!(Tarr, _d_arrayappendcTX, errorMessage);
70 /// Implementation of `_d_arrayappendT`
71 ref Tarr _d_arrayappendT(Tarr : T[], T)(return ref scope Tarr x, scope Tarr y) @trusted
73 pragma(inline, false);
75 import core.stdc.string : memcpy;
76 import core.internal.traits : hasElaborateCopyConstructor, Unqual;
78 enum hasPostblit = __traits(hasPostblit, T);
79 auto length = x.length;
81 _d_arrayappendcTXImpl!Tarr._d_arrayappendcTX(x, y.length);
83 // Only call `copyEmplace` if `T` has a copy ctor and no postblit.
84 static if (hasElaborateCopyConstructor!T && !hasPostblit)
86 import core.lifetime : copyEmplace;
88 foreach (i, ref elem; y)
89 copyEmplace(elem, x[length + i]);
91 else
93 if (y.length)
95 // blit all elements at once
96 auto xptr = cast(Unqual!T *)&x[length];
97 immutable size = T.sizeof;
99 memcpy(xptr, cast(Unqual!T *)&y[0], y.length * size);
101 // call postblits if they exist
102 static if (hasPostblit)
104 auto eptr = xptr + y.length;
105 for (auto ptr = xptr; ptr < eptr; ptr++)
106 ptr.__xpostblit();
111 return x;
114 version (D_ProfileGC)
117 * TraceGC wrapper around $(REF _d_arrayappendT, core,internal,array,appending).
119 ref Tarr _d_arrayappendTTrace(Tarr : T[], T)(string file, int line, string funcname, return ref scope Tarr x, scope Tarr y) @trusted
121 version (D_TypeInfo)
123 import core.internal.array.utils: TraceHook, gcStatsPure, accumulatePure;
124 mixin(TraceHook!(Tarr.stringof, "_d_arrayappendT"));
126 return _d_arrayappendT(x, y);
128 else
129 assert(0, "Cannot append to array if compiling without support for runtime type information!");
133 @safe unittest
135 double[] arr1;
136 foreach (i; 0 .. 4)
137 _d_arrayappendT(arr1, [cast(double)i]);
138 assert(arr1 == [0.0, 1.0, 2.0, 3.0]);
141 @safe unittest
143 int blitted;
144 struct Item
146 this(this)
148 blitted++;
152 Item[] arr1 = [Item(), Item()];
153 Item[] arr2 = [Item(), Item()];
154 Item[] arr1_org = [Item(), Item()];
155 arr1_org ~= arr2;
156 _d_arrayappendT(arr1, arr2);
158 // postblit should have triggered on at least the items in arr2
159 assert(blitted >= arr2.length);
162 @safe nothrow unittest
164 int blitted;
165 struct Item
167 this(this) nothrow
169 blitted++;
173 Item[][] arr1 = [[Item()]];
174 Item[][] arr2 = [[Item()]];
176 _d_arrayappendT(arr1, arr2);
178 // no postblit should have happened because arr{1,2} contain dynamic arrays
179 assert(blitted == 0);
182 @safe nothrow unittest
184 int copied;
185 struct Item
187 this(const scope ref Item) nothrow
189 copied++;
193 Item[1][] arr1 = [[Item()]];
194 Item[1][] arr2 = [[Item()]];
196 _d_arrayappendT(arr1, arr2);
197 // copy constructor should have been invoked because arr{1,2} contain static arrays
198 assert(copied >= arr2.length);
201 @safe nothrow unittest
203 string str;
204 _d_arrayappendT(str, "a");
205 _d_arrayappendT(str, "b");
206 _d_arrayappendT(str, "c");
207 assert(str == "abc");