1 module lifetime.array_;
2 
3 pragma(LDC_no_moduleinfo);
4 
5 import lifetime.common;
6 
7 /// Copy an array byte-by-byte from `from` to `to`.
8 extern(C) void[] _d_arraycopy(size_t size, void[] from, void[] to) nothrow @nogc
9 {
10     auto fromBytes = cast(ubyte[])from;
11     auto toBytes = cast(ubyte[])to;
12 
13     foreach(size_t i; 0 .. size)
14         toBytes[i] = fromBytes[i];
15 
16     return to;
17 }
18 
19 /// Determine equivalence of two arrays
20 extern(C) int _adEq2(void[] a1, void[] a2, TypeInfo ti) 
21 {
22     if(a1.length != a2.length) return 0;
23     if(!ti.equals(&a1, &a2)) return 0;
24 
25     return 1;
26 }
27 
28 /// Copy items from one slice into another
29 extern(C) void _d_array_slice_copy(void* dst, size_t dstlen, void* src, size_t srclen, size_t elemsz)
30 {
31 	auto d = cast(ubyte*) dst;
32 	auto s = cast(ubyte*) src;
33 	auto len = dstlen * elemsz;
34 
35 	while(len) 
36 	{
37 		*d = *s;
38 		d++;
39 		s++;
40 		len--;
41 	}
42 }
43 
44 version(LWDR_DynamicArray):
45 
46 /**
47 * Allocate a new uninitialized array of length elements.
48 * ti is the type of the resulting array, or pointer to element.
49 */
50 extern(C) void[] _d_newarrayU(const TypeInfo ti, size_t length) nothrow
51 {
52 	auto tinext = unqualify(ti.next);
53 	auto size = tinext.tsize;
54 
55 	void* ptr = lwdrInternal_alloc(size * length);
56 	zeroMem(ptr, size * length);
57 	return ptr[0 .. size * length];
58 }
59 
60 /**
61 * Allocate a new array of length elements.
62 * ti is the type of the resulting array, or pointer to element.
63 * (For when the array is initialized to 0)
64 */
65 extern(C) void[] _d_newarrayT(const TypeInfo ti, size_t length) nothrow
66 {
67 	return _d_newarrayU(ti, length);
68 }
69 
70 /**
71 * For when the array has a non-zero initializer.
72 */
73 extern (C) void[] _d_newarrayiT(const TypeInfo ti, size_t length) nothrow
74 {
75     import core.internal.traits : AliasSeq;
76 
77     void[] result = _d_newarrayU(ti, length);
78     auto tinext = unqualify(ti.next);
79     auto size = tinext.tsize;
80 
81     auto init = tinext.initializer();
82 
83     switch (init.length)
84     {
85 		foreach (T; AliasSeq!(ubyte, ushort, uint, ulong))
86 		{
87 			case T.sizeof:
88 				(cast(T*)result.ptr)[0 .. size * length / T.sizeof] = *cast(T*)init.ptr;
89 				return result;
90 		}
91 
92 		default:
93 			{
94 				import core.stdc..string;
95 				immutable sz = init.length;
96 				for (size_t u = 0; u < size * length; u += sz)
97 					memcpy(result.ptr + u, init.ptr, sz);
98 				return result;
99 			}
100     }
101 }
102 
103 /// Finalize the elements in array `p`
104 void finalize_array(void* p, size_t size, const TypeInfo_Struct si) nothrow
105 {
106     // Due to the fact that the delete operator calls destructors
107     // for arrays from the last element to the first, we maintain
108     // compatibility here by doing the same.
109 	if(si.dtor is null)
110 		return;
111 
112     auto tsize = si.tsize;
113     for (auto curP = p + size - tsize; curP >= p; curP -= tsize)
114     {
115         // call destructor
116         (cast(void function(void*) nothrow)si.dtor)(curP); // pretend to be nothrow
117 		// TODO: depending on exception support flag, enforce nothrow or throw dtor in type info???
118     }
119 }
120 
121 /// Finalize (if possible) and deallocate target array `p`
122 extern(C) void _d_delarray_t(void[]* p, const TypeInfo_Struct ti) nothrow
123 {
124 	if(!p) return;
125 
126 	if(ti) // ti non-null only if ti is a struct with dtor
127 	{
128 		finalize_array(p.ptr, p.length * ti.tsize, ti);
129 	}
130 
131 	lwdrInternal_free((*p).ptr);
132 	*p = null;
133 }
134 
135 /**
136 * Extend an array by n elements.
137 * Caller must initialize those elements.
138 */
139 extern(C) byte[] _d_arrayappendcTX(const TypeInfo ti, return scope ref byte[] px, size_t n)
140 {
141 	auto tinext = unqualify(ti.next);
142 	auto elemSize = tinext.tsize;
143 
144 	auto length = px.length;
145 	auto size = length * elemSize;
146 	auto newLength = length + n;
147 	auto newSize = newLength * elemSize;
148 
149 	auto newArray = _d_newarrayU(ti, newLength);
150 
151 	import core.stdc..string;
152 
153 	memcpy(newArray.ptr, cast(void*)px.ptr, size);
154 	(cast(void **)(&px))[1] = newArray.ptr;
155 	*cast(size_t *)&px = cast(size_t)newLength;
156 	
157 	return px;
158 }
159 
160 /// Concatenate two arrays
161 extern(C) byte[] _d_arraycatT(const TypeInfo ti, byte[] x, byte[] y)
162 {
163 	auto tiNext = unqualify(ti.next);
164 	auto sizeElem = tiNext.tsize;
165 
166 	size_t xlen = x.length * sizeElem;
167 	size_t ylen = y.length * sizeElem;
168 	size_t len = xlen + ylen;
169 
170 	byte[] newArr = cast(byte[])lwdrInternal_alloc(len)[0..len];
171 	
172 	import core.stdc..string;
173 
174 	memcpy(newArr.ptr, x.ptr, xlen);
175 	memcpy(newArr.ptr + xlen, y.ptr, ylen);
176 
177 	return newArr[0..x.length + y.length];
178 }
179 
180 template _d_arraysetlengthTImpl(Tarr : T[], T)
181 {
182     /**
183 	* Resize dynamic array
184 	* Params:
185 	*  arr = the array that will be resized, taken as a reference
186 	*  newlength = new length of array
187 	* Returns:
188 	*  The new length of the array
189 	* Bugs:
190 	*   The safety level of this function is faked. It shows itself as `@trusted pure nothrow` to not break existing code.
191 	*/
192     size_t _d_arraysetlengthT(return scope ref Tarr arr, size_t newlength) @trusted nothrow
193     {
194         pragma(inline, false);
195         version (D_TypeInfo)
196         {
197             auto ti = typeid(Tarr);
198 
199             static if (__traits(isZeroInit, T))
200                 ._d_arraysetlengthT(ti, newlength, cast(void[]*)&arr);
201             else
202                 ._d_arraysetlengthiT(ti, newlength, cast(void[]*)&arr);
203 
204             return arr.length;
205         }
206         else
207             assert(0, errorMessage);
208     }
209 }
210 
211 /// Figure out how many elements to copy
212 private size_t getCopyLength(size_t newlength, size_t originalLength) nothrow @nogc 
213 {
214 	if(newlength > originalLength)
215 		return originalLength;
216 	else return newlength; // newlength less than originalLength
217 }
218 
219 /**
220 * Resize dynamic arrays with 0 initializers.
221 */
222 extern (C) void[] _d_arraysetlengthT(const TypeInfo ti, size_t newlength, void[]* p) nothrow
223 {
224 	auto tiNext = unqualify(ti.next);
225 	auto sizeElem = tiNext.tsize;
226 	auto newArr = _d_newarrayU(ti, newlength);
227 
228 	import core.stdc..string;
229 
230 	auto numElemToCopy = getCopyLength(newlength, p.length);
231 	memcpy(newArr.ptr, p.ptr, numElemToCopy * sizeElem);
232 
233 	*p = newArr[0 .. newlength];
234 	return *p;
235 }
236 
237 /**
238 * Resize arrays for non-zero initializers.
239 *      p               pointer to array lvalue to be updated
240 *      newlength       new .length property of array
241 *      sizeelem        size of each element of array
242 *      initsize        size of initializer
243 *      ...             initializer
244 */
245 extern (C) void[] _d_arraysetlengthiT(const TypeInfo ti, size_t newlength, void[]* p) nothrow
246 {
247 	import core.stdc..string;
248 	static void doInitialize(void *start, void *end, const void[] initializer)
249     {
250         if (initializer.length == 1)
251         {
252             memset(start, *(cast(ubyte*)initializer.ptr), end - start);
253         }
254         else
255         {
256             auto q = initializer.ptr;
257             immutable initsize = initializer.length;
258             for (; start < end; start += initsize)
259             {
260                 memcpy(start, q, initsize);
261             }
262         }
263     }
264 
265 	auto tiNext = unqualify(ti.next);
266 	auto sizeElem = tiNext.tsize;
267 	auto newArr = _d_newarrayU(ti, newlength);
268 
269 	import core.stdc..string;
270 
271 	size_t numElemToCopy = getCopyLength(newlength, p.length);
272 	memcpy(newArr.ptr, p.ptr, numElemToCopy * sizeElem);
273 
274 	if(newlength >= p.length) {
275 		doInitialize(newArr.ptr + p.length * sizeElem, 
276 					 newArr.ptr + newlength * sizeElem,
277 					 tiNext.initializer);
278 	}
279 
280 	*p = newArr[0 .. newlength];
281 	return *p;
282 }