1 module lifetime.array_;
2 
3 import lifetime.common;
4 
5 version(LWDR_DynamicArray):
6 
7 extern(C) void[] _d_newarrayU(const TypeInfo ti, size_t length) nothrow
8 {
9 	auto tinext = unqualify(ti.next);
10 	auto size = tinext.tsize;
11 
12 	void* ptr = lwdrInternal_alloc(size * length);
13 	zeroMem(ptr, size * length);
14 	return ptr[0 .. size * length];
15 }
16 
17 extern(C) void[] _d_newarrayT(const TypeInfo ti, size_t length) nothrow
18 {
19 	return _d_newarrayU(ti, length);
20 }
21 
22 /**
23 * For when the array has a non-zero initializer.
24 */
25 extern (C) void[] _d_newarrayiT(const TypeInfo ti, size_t length) nothrow
26 {
27     import core.internal.traits : AliasSeq;
28 
29     void[] result = _d_newarrayU(ti, length);
30     auto tinext = unqualify(ti.next);
31     auto size = tinext.tsize;
32 
33     auto init = tinext.initializer();
34 
35     switch (init.length)
36     {
37 		foreach (T; AliasSeq!(ubyte, ushort, uint, ulong))
38 		{
39 			case T.sizeof:
40 				(cast(T*)result.ptr)[0 .. size * length / T.sizeof] = *cast(T*)init.ptr;
41 				return result;
42 		}
43 
44 		default:
45 			{
46 				import core.stdc.string;
47 				immutable sz = init.length;
48 				for (size_t u = 0; u < size * length; u += sz)
49 					memcpy(result.ptr + u, init.ptr, sz);
50 				return result;
51 			}
52     }
53 }
54 
55 void finalize_array(void* p, size_t size, const TypeInfo_Struct si)
56 {
57     // Due to the fact that the delete operator calls destructors
58     // for arrays from the last element to the first, we maintain
59     // compatibility here by doing the same.
60     auto tsize = si.tsize;
61     for (auto curP = p + size - tsize; curP >= p; curP -= tsize)
62     {
63         // call destructor
64         si.dtor(curP);
65     }
66 }
67 
68 extern(C) void _d_delarray_t(void[]* p, const TypeInfo_Struct ti) 
69 {
70 	if(!p) return;
71 
72 	if(ti) // ti non-null only if ti is a struct with dtor
73 	{
74 		finalize_array(p.ptr, p.length * ti.tsize, ti);
75 	}
76 
77 	lwdrInternal_free((*p).ptr);
78 	*p = null;
79 }
80 
81 extern(C) void _d_array_slice_copy(void* dst, size_t dstlen, void* src, size_t srclen, size_t elemsz)
82 {
83 	auto d = cast(ubyte*) dst;
84 	auto s = cast(ubyte*) src;
85 	auto len = dstlen * elemsz;
86 
87 	while(len) 
88 	{
89 		*d = *s;
90 		d++;
91 		s++;
92 		len--;
93 	}
94 }
95 
96 extern(C) byte[] _d_arrayappendcTX(const TypeInfo ti, return scope ref byte[] px, size_t n)
97 {
98 	auto tinext = unqualify(ti.next);
99 	auto elemSize = tinext.tsize;
100 
101 	auto length = px.length;
102 	auto size = length * elemSize;
103 	auto newLength = length + n;
104 	auto newSize = newLength * elemSize;
105 
106 	auto newArray = _d_newarrayU(ti, newLength);
107 
108 	import core.stdc.string;
109 
110 	memcpy(newArray.ptr, cast(void*)px.ptr, size);
111 	(cast(void **)(&px))[1] = newArray.ptr;
112 	*cast(size_t *)&px = cast(size_t)newLength;
113 	
114 	return px;
115 }
116 
117 extern(C) byte[] _d_arraycatT(const TypeInfo ti, byte[] x, byte[] y)
118 {
119 	auto tiNext = unqualify(ti.next);
120 	auto sizeElem = tiNext.tsize;
121 
122 	size_t xlen = x.length * sizeElem;
123 	size_t ylen = y.length * sizeElem;
124 	size_t len = xlen + ylen;
125 
126 	byte[] newArr = cast(byte[])lwdrInternal_alloc(len)[0..len];
127 	
128 	import core.stdc.string;
129 
130 	memcpy(newArr.ptr, x.ptr, xlen);
131 	memcpy(newArr.ptr + xlen, y.ptr, ylen);
132 
133 	return newArr[0..x.length + y.length];
134 }
135 
136 template _d_arraysetlengthTImpl(Tarr : T[], T)
137 {
138     /**
139 	* Resize dynamic array
140 	* Params:
141 	*  arr = the array that will be resized, taken as a reference
142 	*  newlength = new length of array
143 	* Returns:
144 	*  The new length of the array
145 	* Bugs:
146 	*   The safety level of this function is faked. It shows itself as `@trusted pure nothrow` to not break existing code.
147 	*/
148     size_t _d_arraysetlengthT(return scope ref Tarr arr, size_t newlength) @trusted nothrow
149     {
150         pragma(inline, false);
151         version (D_TypeInfo)
152         {
153             auto ti = typeid(Tarr);
154 
155             static if (__traits(isZeroInit, T))
156                 ._d_arraysetlengthT(ti, newlength, cast(void[]*)&arr);
157             else
158                 ._d_arraysetlengthiT(ti, newlength, cast(void[]*)&arr);
159 
160             return arr.length;
161         }
162         else
163             assert(0, errorMessage);
164     }
165 }
166 
167 private size_t getCopyLength(size_t newlength, size_t originalLength) nothrow @nogc 
168 {
169 	if(newlength > originalLength)
170 		return originalLength;
171 	else return newlength; // newlength less than originalLength
172 }
173 
174 extern (C) void[] _d_arraysetlengthT(const TypeInfo ti, size_t newlength, void[]* p) nothrow
175 {
176 	auto tiNext = unqualify(ti.next);
177 	auto sizeElem = tiNext.tsize;
178 	auto newArr = _d_newarrayU(ti, newlength);
179 
180 	import core.stdc.string;
181 
182 	auto numElemToCopy = getCopyLength(newlength, p.length);
183 	memcpy(newArr.ptr, p.ptr, numElemToCopy * sizeElem);
184 
185 	*p = newArr[0 .. newlength];
186 	return *p;
187 }
188 
189 extern (C) void[] _d_arraysetlengthiT(const TypeInfo ti, size_t newlength, void[]* p) nothrow
190 {
191 	import core.stdc.string;
192 	static void doInitialize(void *start, void *end, const void[] initializer)
193     {
194         if (initializer.length == 1)
195         {
196             memset(start, *(cast(ubyte*)initializer.ptr), end - start);
197         }
198         else
199         {
200             auto q = initializer.ptr;
201             immutable initsize = initializer.length;
202             for (; start < end; start += initsize)
203             {
204                 memcpy(start, q, initsize);
205             }
206         }
207     }
208 
209 	auto tiNext = unqualify(ti.next);
210 	auto sizeElem = tiNext.tsize;
211 	auto newArr = _d_newarrayU(ti, newlength);
212 
213 	import core.stdc.string;
214 
215 	size_t numElemToCopy = getCopyLength(newlength, p.length);
216 	memcpy(newArr.ptr, p.ptr, numElemToCopy * sizeElem);
217 
218 	if(newlength >= p.length) {
219 		doInitialize(newArr.ptr + p.length * sizeElem, 
220 					 newArr.ptr + newlength * sizeElem,
221 					 tiNext.initializer);
222 	}
223 
224 	*p = newArr[0 .. newlength];
225 	return *p;
226 }