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)
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!";
23 * Extend an array `px` by `n` elements.
24 * Caller must initialize those elements.
26 * px = the array that will be extended, taken as a reference
27 * n = how many new elements to extend it with
29 * The new value of `px`
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);
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
];
52 assert(0, errorMessage
);
57 import core
.internal
.array
.utils
: _d_HookTraceImpl
;
60 * TraceGC wrapper around $(REF _d_arrayappendcTX, rt,array,appending,_d_arrayappendcTXImpl).
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
]);
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
++)
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
123 import core
.internal
.array
.utils
: TraceHook
, gcStatsPure
, accumulatePure
;
124 mixin(TraceHook
!(Tarr
.stringof
, "_d_arrayappendT"));
126 return _d_arrayappendT(x
, y
);
129 assert(0, "Cannot append to array if compiling without support for runtime type information!");
137 _d_arrayappendT(arr1
, [cast(double)i
]);
138 assert(arr1
== [0.0, 1.0, 2.0, 3.0]);
152 Item
[] arr1
= [Item(), Item()];
153 Item
[] arr2
= [Item(), Item()];
154 Item
[] arr1_org
= [Item(), Item()];
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
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
187 this(const scope ref Item
) nothrow
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
204 _d_arrayappendT(str, "a");
205 _d_arrayappendT(str, "b");
206 _d_arrayappendT(str, "c");
207 assert(str == "abc");