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