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 }