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