xref: /netbsd-src/external/gpl3/gcc.old/dist/libphobos/libdruntime/rt/arrayassign.d (revision 627f7eb200a4419d89b531d55fccd2ee3ffdcde0)
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