1*627f7eb2Smrg /**
2*627f7eb2Smrg * Implementation of array assignment support routines.
3*627f7eb2Smrg *
4*627f7eb2Smrg *
5*627f7eb2Smrg * Copyright: Copyright Digital Mars 2010 - 2016.
6*627f7eb2Smrg * License: Distributed under the
7*627f7eb2Smrg * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0).
8*627f7eb2Smrg * Authors: Walter Bright, Kenji Hara
9*627f7eb2Smrg * Source: $(DRUNTIMESRC src/rt/_arrayassign.d)
10*627f7eb2Smrg */
11*627f7eb2Smrg
12*627f7eb2Smrg module rt.arrayassign;
13*627f7eb2Smrg
14*627f7eb2Smrg private
15*627f7eb2Smrg {
16*627f7eb2Smrg import rt.util.array;
17*627f7eb2Smrg import core.stdc.string;
18*627f7eb2Smrg import core.stdc.stdlib;
19*627f7eb2Smrg debug(PRINTF) import core.stdc.stdio;
20*627f7eb2Smrg }
21*627f7eb2Smrg
22*627f7eb2Smrg /**
23*627f7eb2Smrg * Keep for backward binary compatibility. This function can be removed in the future.
24*627f7eb2Smrg */
_d_arrayassign(TypeInfo ti,void[]from,void[]to)25*627f7eb2Smrg extern (C) void[] _d_arrayassign(TypeInfo ti, void[] from, void[] to)
26*627f7eb2Smrg {
27*627f7eb2Smrg debug(PRINTF) printf("_d_arrayassign(from = %p,%d, to = %p,%d) size = %d\n", from.ptr, from.length, to.ptr, to.length, ti.tsize);
28*627f7eb2Smrg
29*627f7eb2Smrg immutable elementSize = ti.tsize;
30*627f7eb2Smrg
31*627f7eb2Smrg // Need a temporary buffer tmp[] big enough to hold one element
32*627f7eb2Smrg void[16] buf = void;
33*627f7eb2Smrg void* ptmp = (elementSize > buf.sizeof) ? malloc(elementSize) : buf.ptr;
34*627f7eb2Smrg scope (exit)
35*627f7eb2Smrg {
36*627f7eb2Smrg if (ptmp != buf.ptr)
37*627f7eb2Smrg free(ptmp);
38*627f7eb2Smrg }
39*627f7eb2Smrg return _d_arrayassign_l(ti, from, to, ptmp);
40*627f7eb2Smrg }
41*627f7eb2Smrg
42*627f7eb2Smrg /**
43*627f7eb2Smrg * Does array assignment (not construction) from another
44*627f7eb2Smrg * lvalue array of the same element type.
45*627f7eb2Smrg * Handles overlapping copies.
46*627f7eb2Smrg * Input:
47*627f7eb2Smrg * ti TypeInfo of the element type.
48*627f7eb2Smrg * dst Points target memory. Its .length is equal to the element count, not byte length.
49*627f7eb2Smrg * src Points source memory. Its .length is equal to the element count, not byte length.
50*627f7eb2Smrg * ptmp Temporary memory for element swapping.
51*627f7eb2Smrg */
_d_arrayassign_l(TypeInfo ti,void[]src,void[]dst,void * ptmp)52*627f7eb2Smrg extern (C) void[] _d_arrayassign_l(TypeInfo ti, void[] src, void[] dst, void* ptmp)
53*627f7eb2Smrg {
54*627f7eb2Smrg debug(PRINTF) printf("_d_arrayassign_l(src = %p,%d, dst = %p,%d) size = %d\n", src.ptr, src.length, dst.ptr, dst.length, ti.tsize);
55*627f7eb2Smrg
56*627f7eb2Smrg immutable elementSize = ti.tsize;
57*627f7eb2Smrg
58*627f7eb2Smrg enforceRawArraysConformable("copy", elementSize, src, dst, true);
59*627f7eb2Smrg
60*627f7eb2Smrg if (src.ptr < dst.ptr && dst.ptr < src.ptr + elementSize * src.length)
61*627f7eb2Smrg {
62*627f7eb2Smrg // If dst is in the middle of src memory, use reverse order.
63*627f7eb2Smrg for (auto i = dst.length; i--; )
64*627f7eb2Smrg {
65*627f7eb2Smrg void* pdst = dst.ptr + i * elementSize;
66*627f7eb2Smrg void* psrc = src.ptr + i * elementSize;
67*627f7eb2Smrg memcpy(ptmp, pdst, elementSize);
68*627f7eb2Smrg memcpy(pdst, psrc, elementSize);
69*627f7eb2Smrg ti.postblit(pdst);
70*627f7eb2Smrg ti.destroy(ptmp);
71*627f7eb2Smrg }
72*627f7eb2Smrg }
73*627f7eb2Smrg else
74*627f7eb2Smrg {
75*627f7eb2Smrg // Otherwise, use normal order.
76*627f7eb2Smrg foreach (i; 0 .. dst.length)
77*627f7eb2Smrg {
78*627f7eb2Smrg void* pdst = dst.ptr + i * elementSize;
79*627f7eb2Smrg void* psrc = src.ptr + i * elementSize;
80*627f7eb2Smrg memcpy(ptmp, pdst, elementSize);
81*627f7eb2Smrg memcpy(pdst, psrc, elementSize);
82*627f7eb2Smrg ti.postblit(pdst);
83*627f7eb2Smrg ti.destroy(ptmp);
84*627f7eb2Smrg }
85*627f7eb2Smrg }
86*627f7eb2Smrg return dst;
87*627f7eb2Smrg }
88*627f7eb2Smrg
89*627f7eb2Smrg unittest // Bugzilla 14024
90*627f7eb2Smrg {
91*627f7eb2Smrg string op;
92*627f7eb2Smrg
93*627f7eb2Smrg struct S
94*627f7eb2Smrg {
95*627f7eb2Smrg char x = 'x';
thisS96*627f7eb2Smrg this(this) { op ~= x-0x20; } // upper case
~thisS97*627f7eb2Smrg ~this() { op ~= x; } // lower case
98*627f7eb2Smrg }
99*627f7eb2Smrg
100*627f7eb2Smrg S[4] mem;
slice(int a,int b)101*627f7eb2Smrg ref S[2] slice(int a, int b) { return mem[a .. b][0 .. 2]; }
102*627f7eb2Smrg
103*627f7eb2Smrg op = null;
104*627f7eb2Smrg mem[0].x = 'a';
105*627f7eb2Smrg mem[1].x = 'b';
106*627f7eb2Smrg mem[2].x = 'x';
107*627f7eb2Smrg mem[3].x = 'y';
108*627f7eb2Smrg slice(0, 2) = slice(2, 4); // [ab] = [xy]
109*627f7eb2Smrg assert(op == "XaYb", op);
110*627f7eb2Smrg
111*627f7eb2Smrg op = null;
112*627f7eb2Smrg mem[0].x = 'x';
113*627f7eb2Smrg mem[1].x = 'y';
114*627f7eb2Smrg mem[2].x = 'a';
115*627f7eb2Smrg mem[3].x = 'b';
116*627f7eb2Smrg slice(2, 4) = slice(0, 2); // [ab] = [xy]
117*627f7eb2Smrg assert(op == "XaYb", op);
118*627f7eb2Smrg
119*627f7eb2Smrg op = null;
120*627f7eb2Smrg mem[0].x = 'a';
121*627f7eb2Smrg mem[1].x = 'b';
122*627f7eb2Smrg mem[2].x = 'c';
123*627f7eb2Smrg slice(0, 2) = slice(1, 3); // [ab] = [bc]
124*627f7eb2Smrg assert(op == "BaCb", op);
125*627f7eb2Smrg
126*627f7eb2Smrg op = null;
127*627f7eb2Smrg mem[0].x = 'x';
128*627f7eb2Smrg mem[1].x = 'y';
129*627f7eb2Smrg mem[2].x = 'z';
130*627f7eb2Smrg slice(1, 3) = slice(0, 2); // [yz] = [xy]
131*627f7eb2Smrg assert(op == "YzXy", op);
132*627f7eb2Smrg }
133*627f7eb2Smrg
134*627f7eb2Smrg /**
135*627f7eb2Smrg * Does array assignment (not construction) from another
136*627f7eb2Smrg * rvalue array of the same element type.
137*627f7eb2Smrg * Input:
138*627f7eb2Smrg * ti TypeInfo of the element type.
139*627f7eb2Smrg * dst Points target memory. Its .length is equal to the element count, not byte length.
140*627f7eb2Smrg * src Points source memory. Its .length is equal to the element count, not byte length.
141*627f7eb2Smrg * It is always allocated on stack and never overlapping with dst.
142*627f7eb2Smrg * ptmp Temporary memory for element swapping.
143*627f7eb2Smrg */
_d_arrayassign_r(TypeInfo ti,void[]src,void[]dst,void * ptmp)144*627f7eb2Smrg extern (C) void[] _d_arrayassign_r(TypeInfo ti, void[] src, void[] dst, void* ptmp)
145*627f7eb2Smrg {
146*627f7eb2Smrg debug(PRINTF) printf("_d_arrayassign_r(src = %p,%d, dst = %p,%d) size = %d\n", src.ptr, src.length, dst.ptr, dst.length, ti.tsize);
147*627f7eb2Smrg
148*627f7eb2Smrg immutable elementSize = ti.tsize;
149*627f7eb2Smrg
150*627f7eb2Smrg enforceRawArraysConformable("copy", elementSize, src, dst, false);
151*627f7eb2Smrg
152*627f7eb2Smrg // Always use normal order, because we can assume that
153*627f7eb2Smrg // the rvalue src has no overlapping with dst.
154*627f7eb2Smrg foreach (i; 0 .. dst.length)
155*627f7eb2Smrg {
156*627f7eb2Smrg void* pdst = dst.ptr + i * elementSize;
157*627f7eb2Smrg void* psrc = src.ptr + i * elementSize;
158*627f7eb2Smrg memcpy(ptmp, pdst, elementSize);
159*627f7eb2Smrg memcpy(pdst, psrc, elementSize);
160*627f7eb2Smrg ti.destroy(ptmp);
161*627f7eb2Smrg }
162*627f7eb2Smrg return dst;
163*627f7eb2Smrg }
164*627f7eb2Smrg
165*627f7eb2Smrg /**
166*627f7eb2Smrg * Does array initialization (not assignment) from another
167*627f7eb2Smrg * array of the same element type.
168*627f7eb2Smrg * ti is the element type.
169*627f7eb2Smrg */
_d_arrayctor(TypeInfo ti,void[]from,void[]to)170*627f7eb2Smrg extern (C) void[] _d_arrayctor(TypeInfo ti, void[] from, void[] to)
171*627f7eb2Smrg {
172*627f7eb2Smrg debug(PRINTF) printf("_d_arrayctor(from = %p,%d, to = %p,%d) size = %d\n", from.ptr, from.length, to.ptr, to.length, ti.tsize);
173*627f7eb2Smrg
174*627f7eb2Smrg
175*627f7eb2Smrg auto element_size = ti.tsize;
176*627f7eb2Smrg
177*627f7eb2Smrg enforceRawArraysConformable("initialization", element_size, from, to);
178*627f7eb2Smrg
179*627f7eb2Smrg size_t i;
180*627f7eb2Smrg try
181*627f7eb2Smrg {
182*627f7eb2Smrg for (i = 0; i < to.length; i++)
183*627f7eb2Smrg {
184*627f7eb2Smrg // Copy construction is defined as bit copy followed by postblit.
185*627f7eb2Smrg memcpy(to.ptr + i * element_size, from.ptr + i * element_size, element_size);
186*627f7eb2Smrg ti.postblit(to.ptr + i * element_size);
187*627f7eb2Smrg }
188*627f7eb2Smrg }
189*627f7eb2Smrg catch (Throwable o)
190*627f7eb2Smrg {
191*627f7eb2Smrg /* Destroy, in reverse order, what we've constructed so far
192*627f7eb2Smrg */
193*627f7eb2Smrg while (i--)
194*627f7eb2Smrg {
195*627f7eb2Smrg ti.destroy(to.ptr + i * element_size);
196*627f7eb2Smrg }
197*627f7eb2Smrg
198*627f7eb2Smrg throw o;
199*627f7eb2Smrg }
200*627f7eb2Smrg return to;
201*627f7eb2Smrg }
202*627f7eb2Smrg
203*627f7eb2Smrg
204*627f7eb2Smrg /**
205*627f7eb2Smrg * Do assignment to an array.
206*627f7eb2Smrg * p[0 .. count] = value;
207*627f7eb2Smrg */
_d_arraysetassign(void * p,void * value,int count,TypeInfo ti)208*627f7eb2Smrg extern (C) void* _d_arraysetassign(void* p, void* value, int count, TypeInfo ti)
209*627f7eb2Smrg {
210*627f7eb2Smrg void* pstart = p;
211*627f7eb2Smrg
212*627f7eb2Smrg auto element_size = ti.tsize;
213*627f7eb2Smrg
214*627f7eb2Smrg // Need a temporary buffer tmp[] big enough to hold one element
215*627f7eb2Smrg immutable maxAllocaSize = 512;
216*627f7eb2Smrg void *ptmp = (element_size > maxAllocaSize) ? malloc(element_size) : alloca(element_size);
217*627f7eb2Smrg
218*627f7eb2Smrg foreach (i; 0 .. count)
219*627f7eb2Smrg {
220*627f7eb2Smrg memcpy(ptmp, p, element_size);
221*627f7eb2Smrg memcpy(p, value, element_size);
222*627f7eb2Smrg ti.postblit(p);
223*627f7eb2Smrg ti.destroy(ptmp);
224*627f7eb2Smrg p += element_size;
225*627f7eb2Smrg }
226*627f7eb2Smrg if (element_size > maxAllocaSize)
227*627f7eb2Smrg free(ptmp);
228*627f7eb2Smrg return pstart;
229*627f7eb2Smrg }
230*627f7eb2Smrg
231*627f7eb2Smrg /**
232*627f7eb2Smrg * Do construction of an array.
233*627f7eb2Smrg * ti[count] p = value;
234*627f7eb2Smrg */
_d_arraysetctor(void * p,void * value,int count,TypeInfo ti)235*627f7eb2Smrg extern (C) void* _d_arraysetctor(void* p, void* value, int count, TypeInfo ti)
236*627f7eb2Smrg {
237*627f7eb2Smrg void* pstart = p;
238*627f7eb2Smrg auto element_size = ti.tsize;
239*627f7eb2Smrg
240*627f7eb2Smrg try
241*627f7eb2Smrg {
242*627f7eb2Smrg foreach (i; 0 .. count)
243*627f7eb2Smrg {
244*627f7eb2Smrg // Copy construction is defined as bit copy followed by postblit.
245*627f7eb2Smrg memcpy(p, value, element_size);
246*627f7eb2Smrg ti.postblit(p);
247*627f7eb2Smrg p += element_size;
248*627f7eb2Smrg }
249*627f7eb2Smrg }
250*627f7eb2Smrg catch (Throwable o)
251*627f7eb2Smrg {
252*627f7eb2Smrg // Destroy, in reverse order, what we've constructed so far
253*627f7eb2Smrg while (p > pstart)
254*627f7eb2Smrg {
255*627f7eb2Smrg p -= element_size;
256*627f7eb2Smrg ti.destroy(p);
257*627f7eb2Smrg }
258*627f7eb2Smrg
259*627f7eb2Smrg throw o;
260*627f7eb2Smrg }
261*627f7eb2Smrg return pstart;
262*627f7eb2Smrg }
263